aboutsummaryrefslogtreecommitdiffstats
path: root/guava/src/com/google
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google')
-rw-r--r--guava/src/com/google/common/annotations/Beta.java11
-rw-r--r--guava/src/com/google/common/annotations/GwtIncompatible.java6
-rw-r--r--guava/src/com/google/common/annotations/VisibleForTesting.java4
-rw-r--r--guava/src/com/google/common/base/Absent.java89
-rw-r--r--guava/src/com/google/common/base/Ascii.java87
-rw-r--r--guava/src/com/google/common/base/CaseFormat.java162
-rw-r--r--guava/src/com/google/common/base/CharMatcher.java800
-rw-r--r--guava/src/com/google/common/base/Charsets.java15
-rw-r--r--guava/src/com/google/common/base/Defaults.java5
-rw-r--r--guava/src/com/google/common/base/Enums.java46
-rw-r--r--guava/src/com/google/common/base/Equivalence.java74
-rw-r--r--guava/src/com/google/common/base/Equivalences.java97
-rw-r--r--guava/src/com/google/common/base/FinalizableReferenceQueue.java41
-rw-r--r--guava/src/com/google/common/base/Function.java8
-rw-r--r--guava/src/com/google/common/base/Functions.java17
-rw-r--r--guava/src/com/google/common/base/Joiner.java26
-rw-r--r--guava/src/com/google/common/base/Objects.java142
-rw-r--r--guava/src/com/google/common/base/Optional.java193
-rw-r--r--guava/src/com/google/common/base/Preconditions.java4
-rw-r--r--guava/src/com/google/common/base/Predicate.java6
-rw-r--r--guava/src/com/google/common/base/Predicates.java28
-rw-r--r--guava/src/com/google/common/base/Present.java92
-rw-r--r--guava/src/com/google/common/base/SmallCharMatcher.java155
-rw-r--r--guava/src/com/google/common/base/Splitter.java136
-rw-r--r--guava/src/com/google/common/base/Stopwatch.java49
-rw-r--r--guava/src/com/google/common/base/Strings.java3
-rw-r--r--guava/src/com/google/common/base/Suppliers.java78
-rw-r--r--guava/src/com/google/common/base/Throwables.java4
-rw-r--r--guava/src/com/google/common/base/Ticker.java7
-rw-r--r--guava/src/com/google/common/base/internal/Finalizer.java61
-rw-r--r--guava/src/com/google/common/base/package-info.java3
-rw-r--r--guava/src/com/google/common/cache/AbstractCache.java110
-rw-r--r--guava/src/com/google/common/cache/AbstractLoadingCache.java9
-rw-r--r--guava/src/com/google/common/cache/Cache.java82
-rw-r--r--guava/src/com/google/common/cache/CacheBuilder.java195
-rw-r--r--guava/src/com/google/common/cache/CacheBuilderSpec.java455
-rw-r--r--guava/src/com/google/common/cache/CacheLoader.java58
-rw-r--r--guava/src/com/google/common/cache/CacheStats.java7
-rw-r--r--guava/src/com/google/common/cache/ForwardingCache.java31
-rw-r--r--guava/src/com/google/common/cache/LoadingCache.java9
-rw-r--r--guava/src/com/google/common/cache/LocalCache.java369
-rw-r--r--guava/src/com/google/common/cache/LongAddable.java33
-rw-r--r--guava/src/com/google/common/cache/LongAddables.java75
-rw-r--r--guava/src/com/google/common/cache/LongAdder.java211
-rw-r--r--guava/src/com/google/common/cache/RemovalCause.java2
-rw-r--r--guava/src/com/google/common/cache/RemovalListener.java2
-rw-r--r--guava/src/com/google/common/cache/RemovalListeners.java4
-rw-r--r--guava/src/com/google/common/cache/RemovalNotification.java2
-rw-r--r--guava/src/com/google/common/cache/Striped64.java347
-rw-r--r--guava/src/com/google/common/cache/Weigher.java19
-rw-r--r--guava/src/com/google/common/cache/package-info.java4
-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
-rw-r--r--guava/src/com/google/common/eventbus/AllowConcurrentEvents.java1
-rw-r--r--guava/src/com/google/common/eventbus/AnnotatedHandlerFinder.java93
-rw-r--r--guava/src/com/google/common/eventbus/AsyncEventBus.java19
-rw-r--r--guava/src/com/google/common/eventbus/DeadEvent.java6
-rw-r--r--guava/src/com/google/common/eventbus/EventBus.java184
-rw-r--r--guava/src/com/google/common/eventbus/EventHandler.java35
-rw-r--r--guava/src/com/google/common/eventbus/HandlerFindingStrategy.java2
-rw-r--r--guava/src/com/google/common/eventbus/Subscribe.java1
-rw-r--r--guava/src/com/google/common/eventbus/package-info.java18
-rw-r--r--guava/src/com/google/common/hash/AbstractByteHasher.java122
-rw-r--r--guava/src/com/google/common/hash/AbstractCompositeHashFunction.java33
-rw-r--r--guava/src/com/google/common/hash/AbstractHasher.java16
-rw-r--r--guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java64
-rw-r--r--guava/src/com/google/common/hash/AbstractStreamingHashFunction.java14
-rw-r--r--guava/src/com/google/common/hash/BloomFilter.java277
-rw-r--r--guava/src/com/google/common/hash/BloomFilterStrategies.java82
-rw-r--r--guava/src/com/google/common/hash/ChecksumHashFunction.java96
-rw-r--r--guava/src/com/google/common/hash/Funnel.java25
-rw-r--r--guava/src/com/google/common/hash/Funnels.java88
-rw-r--r--guava/src/com/google/common/hash/HashCode.java18
-rw-r--r--guava/src/com/google/common/hash/HashCodes.java92
-rw-r--r--guava/src/com/google/common/hash/HashFunction.java34
-rw-r--r--guava/src/com/google/common/hash/Hasher.java34
-rw-r--r--guava/src/com/google/common/hash/Hashing.java231
-rw-r--r--guava/src/com/google/common/hash/MessageDigestHashFunction.java193
-rw-r--r--guava/src/com/google/common/hash/Murmur3_128HashFunction.java103
-rw-r--r--guava/src/com/google/common/hash/Murmur3_32HashFunction.java159
-rw-r--r--guava/src/com/google/common/hash/Sink.java (renamed from guava/src/com/google/common/hash/PrimitiveSink.java)28
-rw-r--r--guava/src/com/google/common/hash/package-info.java4
-rw-r--r--guava/src/com/google/common/io/AppendableWriter.java14
-rw-r--r--guava/src/com/google/common/io/BaseEncoding.java882
-rw-r--r--guava/src/com/google/common/io/ByteArrayDataInput.java22
-rw-r--r--guava/src/com/google/common/io/ByteSink.java144
-rw-r--r--guava/src/com/google/common/io/ByteSource.java343
-rw-r--r--guava/src/com/google/common/io/ByteStreams.java466
-rw-r--r--guava/src/com/google/common/io/CharSink.java150
-rw-r--r--guava/src/com/google/common/io/CharSource.java192
-rw-r--r--guava/src/com/google/common/io/CharStreams.java332
-rw-r--r--guava/src/com/google/common/io/Closeables.java69
-rw-r--r--guava/src/com/google/common/io/Closer.java285
-rw-r--r--guava/src/com/google/common/io/CountingInputStream.java4
-rw-r--r--guava/src/com/google/common/io/CountingOutputStream.java4
-rw-r--r--guava/src/com/google/common/io/FileWriteMode.java28
-rw-r--r--guava/src/com/google/common/io/Files.java377
-rw-r--r--guava/src/com/google/common/io/GwtWorkarounds.java231
-rw-r--r--guava/src/com/google/common/io/LimitInputStream.java3
-rw-r--r--guava/src/com/google/common/io/LineBuffer.java3
-rw-r--r--guava/src/com/google/common/io/MultiInputStream.java8
-rw-r--r--guava/src/com/google/common/io/MultiReader.java4
-rw-r--r--guava/src/com/google/common/io/NullOutputStream.java6
-rw-r--r--guava/src/com/google/common/io/PatternFilenameFilter.java4
-rw-r--r--guava/src/com/google/common/io/Resources.java73
-rw-r--r--guava/src/com/google/common/io/package-info.java1
-rw-r--r--guava/src/com/google/common/math/BigIntegerMath.java118
-rw-r--r--guava/src/com/google/common/math/DoubleMath.java141
-rw-r--r--guava/src/com/google/common/math/DoubleUtils.java97
-rw-r--r--guava/src/com/google/common/math/IntMath.java113
-rw-r--r--guava/src/com/google/common/math/LongMath.java271
-rw-r--r--guava/src/com/google/common/math/MathPreconditions.java41
-rw-r--r--guava/src/com/google/common/math/package-info.java5
-rw-r--r--guava/src/com/google/common/net/HostAndPort.java13
-rw-r--r--guava/src/com/google/common/net/HttpHeaders.java2
-rw-r--r--guava/src/com/google/common/net/InetAddresses.java298
-rw-r--r--guava/src/com/google/common/net/InternetDomainName.java10
-rw-r--r--guava/src/com/google/common/net/MediaType.java703
-rw-r--r--guava/src/com/google/common/net/TldPatterns.java2349
-rw-r--r--guava/src/com/google/common/net/package-info.java1
-rw-r--r--guava/src/com/google/common/primitives/Booleans.java9
-rw-r--r--guava/src/com/google/common/primitives/Bytes.java20
-rw-r--r--guava/src/com/google/common/primitives/Chars.java9
-rw-r--r--guava/src/com/google/common/primitives/Doubles.java86
-rw-r--r--guava/src/com/google/common/primitives/Floats.java62
-rw-r--r--guava/src/com/google/common/primitives/Ints.java20
-rw-r--r--guava/src/com/google/common/primitives/Longs.java98
-rw-r--r--guava/src/com/google/common/primitives/ParseRequest.java57
-rw-r--r--guava/src/com/google/common/primitives/Shorts.java20
-rw-r--r--guava/src/com/google/common/primitives/SignedBytes.java4
-rw-r--r--guava/src/com/google/common/primitives/UnsignedBytes.java388
-rw-r--r--guava/src/com/google/common/primitives/UnsignedInteger.java161
-rw-r--r--guava/src/com/google/common/primitives/UnsignedInts.java82
-rw-r--r--guava/src/com/google/common/primitives/UnsignedLong.java153
-rw-r--r--guava/src/com/google/common/primitives/UnsignedLongs.java113
-rw-r--r--guava/src/com/google/common/primitives/generate.sh604
-rw-r--r--guava/src/com/google/common/primitives/package-info.java8
-rw-r--r--guava/src/com/google/common/reflect/AbstractInvocationHandler.java112
-rw-r--r--guava/src/com/google/common/reflect/ClassPath.java379
-rw-r--r--guava/src/com/google/common/reflect/Element.java164
-rw-r--r--guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java138
-rw-r--r--guava/src/com/google/common/reflect/Invokable.java286
-rw-r--r--guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java89
-rw-r--r--guava/src/com/google/common/reflect/Parameter.java103
-rw-r--r--guava/src/com/google/common/reflect/Reflection.java98
-rw-r--r--guava/src/com/google/common/reflect/TypeCapture.java38
-rw-r--r--guava/src/com/google/common/reflect/TypeParameter.java67
-rw-r--r--guava/src/com/google/common/reflect/TypeResolver.java391
-rw-r--r--guava/src/com/google/common/reflect/TypeToInstanceMap.java92
-rw-r--r--guava/src/com/google/common/reflect/TypeToken.java1146
-rw-r--r--guava/src/com/google/common/reflect/Types.java504
-rw-r--r--guava/src/com/google/common/reflect/package-info.java23
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java42
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractFuture.java65
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractIdleService.java40
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java89
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractScheduledService.java89
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractService.java457
-rw-r--r--guava/src/com/google/common/util/concurrent/AsyncFunction.java3
-rw-r--r--guava/src/com/google/common/util/concurrent/AtomicDouble.java12
-rw-r--r--guava/src/com/google/common/util/concurrent/AtomicDoubleArray.java4
-rw-r--r--guava/src/com/google/common/util/concurrent/AtomicLongMap.java20
-rw-r--r--guava/src/com/google/common/util/concurrent/Atomics.java3
-rw-r--r--guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java1038
-rw-r--r--guava/src/com/google/common/util/concurrent/ExecutionError.java10
-rw-r--r--guava/src/com/google/common/util/concurrent/ExecutionList.java3
-rw-r--r--guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java6
-rw-r--r--guava/src/com/google/common/util/concurrent/ForwardingService.java23
-rw-r--r--guava/src/com/google/common/util/concurrent/FutureCallback.java3
-rw-r--r--guava/src/com/google/common/util/concurrent/FutureFallback.java48
-rw-r--r--guava/src/com/google/common/util/concurrent/Futures.java985
-rw-r--r--guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java34
-rw-r--r--guava/src/com/google/common/util/concurrent/ListenableFuture.java38
-rw-r--r--guava/src/com/google/common/util/concurrent/ListenableFutureTask.java11
-rw-r--r--guava/src/com/google/common/util/concurrent/MoreExecutors.java299
-rw-r--r--guava/src/com/google/common/util/concurrent/RateLimiter.java690
-rw-r--r--guava/src/com/google/common/util/concurrent/Service.java202
-rw-r--r--guava/src/com/google/common/util/concurrent/ServiceManager.java724
-rw-r--r--guava/src/com/google/common/util/concurrent/Striped.java376
-rw-r--r--guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java5
-rw-r--r--guava/src/com/google/common/util/concurrent/UncheckedExecutionException.java18
-rw-r--r--guava/src/com/google/common/util/concurrent/UncheckedTimeoutException.java8
-rw-r--r--guava/src/com/google/common/util/concurrent/Uninterruptibles.java12
-rw-r--r--guava/src/com/google/common/util/concurrent/package-info.java1
364 files changed, 14494 insertions, 40345 deletions
diff --git a/guava/src/com/google/common/annotations/Beta.java b/guava/src/com/google/common/annotations/Beta.java
index 5eefe9a..07009b0 100644
--- a/guava/src/com/google/common/annotations/Beta.java
+++ b/guava/src/com/google/common/annotations/Beta.java
@@ -26,15 +26,7 @@ import java.lang.annotation.Target;
* Signifies that a public API (public class, method or field) is subject to
* incompatible changes, or even removal, in a future release. An API bearing
* this annotation is exempt from any compatibility guarantees made by its
- * containing library. Note that the presence of this annotation implies nothing
- * about the quality or performance of the API in question, only the fact that
- * it is not "API-frozen."
- *
- * <p>It is generally safe for <i>applications</i> to depend on beta APIs, at
- * the cost of some extra work during upgrades. However it is generally
- * inadvisable for <i>libraries</i> (which get included on users' CLASSPATHs,
- * outside the library developers' control) to do so.
- *
+ * containing library.
*
* @author Kevin Bourrillion
*/
@@ -47,4 +39,5 @@ import java.lang.annotation.Target;
ElementType.TYPE})
@Documented
@GwtCompatible
+@Beta
public @interface Beta {}
diff --git a/guava/src/com/google/common/annotations/GwtIncompatible.java b/guava/src/com/google/common/annotations/GwtIncompatible.java
index a56d746..43ae705 100644
--- a/guava/src/com/google/common/annotations/GwtIncompatible.java
+++ b/guava/src/com/google/common/annotations/GwtIncompatible.java
@@ -36,12 +36,11 @@ import java.lang.annotation.Target;
* @author Charles Fry
*/
@Retention(RetentionPolicy.CLASS)
-@Target({
- ElementType.TYPE, ElementType.METHOD,
- ElementType.CONSTRUCTOR, ElementType.FIELD })
+@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD })
@Documented
@GwtCompatible
public @interface GwtIncompatible {
+
/**
* Describes why the annotated element is incompatible with GWT. Since this is
* generally due to a dependence on a type/method which GWT doesn't support,
@@ -49,4 +48,5 @@ public @interface GwtIncompatible {
* "Class.isInstance".
*/
String value();
+
}
diff --git a/guava/src/com/google/common/annotations/VisibleForTesting.java b/guava/src/com/google/common/annotations/VisibleForTesting.java
index 6f867db..e591719 100644
--- a/guava/src/com/google/common/annotations/VisibleForTesting.java
+++ b/guava/src/com/google/common/annotations/VisibleForTesting.java
@@ -17,8 +17,8 @@
package com.google.common.annotations;
/**
- * Annotates a program element that exists, or is more widely visible than
- * otherwise necessary, only for use in test code.
+ * An annotation that indicates that the visibility of a type or member has
+ * been relaxed to make the code testable.
*
* @author Johannes Henkel
*/
diff --git a/guava/src/com/google/common/base/Absent.java b/guava/src/com/google/common/base/Absent.java
deleted file mode 100644
index a182236..0000000
--- a/guava/src/com/google/common/base/Absent.java
+++ /dev/null
@@ -1,89 +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.base;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Collections;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * Implementation of an {@link Optional} not containing a reference.
- */
-@GwtCompatible
-final class Absent extends Optional<Object> {
- static final Absent INSTANCE = new Absent();
-
- private Absent() {}
-
- @Override public boolean isPresent() {
- return false;
- }
-
- @Override public Object get() {
- throw new IllegalStateException("Optional.get() cannot be called on an absent value");
- }
-
- @Override public Object or(Object defaultValue) {
- return checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)");
- }
-
- @SuppressWarnings("unchecked") // safe covariant cast
- @Override public Optional<Object> or(Optional<?> secondChoice) {
- return (Optional) checkNotNull(secondChoice);
- }
-
- @Override public Object or(Supplier<?> supplier) {
- return checkNotNull(supplier.get(),
- "use Optional.orNull() instead of a Supplier that returns null");
- }
-
- @Override @Nullable public Object orNull() {
- return null;
- }
-
- @Override public Set<Object> asSet() {
- return Collections.emptySet();
- }
-
- @Override public <V> Optional<V> transform(Function<Object, V> function) {
- checkNotNull(function);
- return Optional.absent();
- }
-
- @Override public boolean equals(@Nullable Object object) {
- return object == this;
- }
-
- @Override public int hashCode() {
- return 0x598df91c;
- }
-
- @Override public String toString() {
- return "Optional.absent()";
- }
-
- private Object readResolve() {
- return INSTANCE;
- }
-
- private static final long serialVersionUID = 0;
-}
diff --git a/guava/src/com/google/common/base/Ascii.java b/guava/src/com/google/common/base/Ascii.java
index 3ccd0fe..a23a11f 100644
--- a/guava/src/com/google/common/base/Ascii.java
+++ b/guava/src/com/google/common/base/Ascii.java
@@ -16,6 +16,7 @@
package com.google.common.base;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
/**
@@ -213,7 +214,7 @@ public final class Ascii {
public static final byte DLE = 16;
/**
- * Device Control 1. Characters for the control
+ * Device Controls: Characters for the control
* of ancillary devices associated with data processing or
* telecommunication systems, more especially switching devices "on" or
* "off." (If a single "stop" control is required to interrupt or turn
@@ -224,7 +225,7 @@ public final class Ascii {
public static final byte DC1 = 17; // aka XON
/**
- * Transmission On: Although originally defined as DC1, this ASCII
+ * Transmission on/off: Although originally defined as DC1, this ASCII
* control character is now better known as the XON code used for software
* flow control in serial communications. The main use is restarting
* the transmission after the communication has been stopped by the XOFF
@@ -235,40 +236,28 @@ public final class Ascii {
public static final byte XON = 17; // aka DC1
/**
- * Device Control 2. Characters for the control
- * of ancillary devices associated with data processing or
- * telecommunication systems, more especially switching devices "on" or
- * "off." (If a single "stop" control is required to interrupt or turn
- * off ancillary devices, DC4 is the preferred assignment.)
+ * @see #DC1
*
* @since 8.0
*/
public static final byte DC2 = 18;
/**
- * Device Control 3. Characters for the control
- * of ancillary devices associated with data processing or
- * telecommunication systems, more especially switching devices "on" or
- * "off." (If a single "stop" control is required to interrupt or turn
- * off ancillary devices, DC4 is the preferred assignment.)
+ * @see #DC1
*
* @since 8.0
*/
public static final byte DC3 = 19; // aka XOFF
/**
- * Transmission off. See {@link #XON} for explanation.
+ * Transmission off. @see #XON
*
* @since 8.0
*/
public static final byte XOFF = 19; // aka DC3
/**
- * Device Control 4. Characters for the control
- * of ancillary devices associated with data processing or
- * telecommunication systems, more especially switching devices "on" or
- * "off." (If a single "stop" control is required to interrupt or turn
- * off ancillary devices, DC4 is the preferred assignment.)
+ * @see #DC1
*
* @since 8.0
*/
@@ -341,7 +330,7 @@ public final class Ascii {
public static final byte ESC = 27;
/**
- * File Separator: These four information separators may be
+ * File/Group/Record/Unit Separator: These information separators may be
* used within data in optional fashion, except that their hierarchical
* relationship shall be: FS is the most inclusive, then GS, then RS,
* and US is least inclusive. (The content and length of a File, Group,
@@ -352,33 +341,21 @@ public final class Ascii {
public static final byte FS = 28;
/**
- * Group Separator: These four information separators may be
- * used within data in optional fashion, except that their hierarchical
- * relationship shall be: FS is the most inclusive, then GS, then RS,
- * and US is least inclusive. (The content and length of a File, Group,
- * Record, or Unit are not specified.)
+ * @see #FS
*
* @since 8.0
*/
public static final byte GS = 29;
/**
- * Record Separator: These four information separators may be
- * used within data in optional fashion, except that their hierarchical
- * relationship shall be: FS is the most inclusive, then GS, then RS,
- * and US is least inclusive. (The content and length of a File, Group,
- * Record, or Unit are not specified.)
+ * @see #FS
*
* @since 8.0
*/
public static final byte RS = 30;
/**
- * Unit Separator: These four information separators may be
- * used within data in optional fashion, except that their hierarchical
- * relationship shall be: FS is the most inclusive, then GS, then RS,
- * and US is least inclusive. (The content and length of a File, Group,
- * Record, or Unit are not specified.)
+ * @see #FS
*
* @since 8.0
*/
@@ -412,16 +389,18 @@ public final class Ascii {
/**
* The minimum value of an ASCII character.
*
- * @since 9.0 (was type {@code int} before 12.0)
+ * @since 9.0
*/
- public static final char MIN = 0;
+ @Beta
+ public static final int MIN = 0;
/**
* The maximum value of an ASCII character.
*
- * @since 9.0 (was type {@code int} before 12.0)
+ * @since 9.0
*/
- public static final char MAX = 127;
+ @Beta
+ public static final int MAX = 127;
/**
* Returns a copy of the input string in which all {@linkplain #isUpperCase(char) uppercase ASCII
@@ -429,21 +408,10 @@ public final class Ascii {
* modification.
*/
public static String toLowerCase(String string) {
- return toLowerCase((CharSequence) string);
- }
-
- /**
- * Returns a copy of the input character sequence in which all {@linkplain #isUpperCase(char)
- * uppercase ASCII characters} have been converted to lowercase. All other characters are copied
- * without modification.
- *
- * @since 14.0
- */
- public static String toLowerCase(CharSequence chars) {
- int length = chars.length();
+ int length = string.length();
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
- builder.append(toLowerCase(chars.charAt(i)));
+ builder.append(toLowerCase(string.charAt(i)));
}
return builder.toString();
}
@@ -455,28 +423,17 @@ public final class Ascii {
public static char toLowerCase(char c) {
return isUpperCase(c) ? (char) (c ^ 0x20) : c;
}
-
+
/**
* Returns a copy of the input string in which all {@linkplain #isLowerCase(char) lowercase ASCII
* characters} have been converted to uppercase. All other characters are copied without
* modification.
*/
public static String toUpperCase(String string) {
- return toUpperCase((CharSequence) string);
- }
-
- /**
- * Returns a copy of the input character sequence in which all {@linkplain #isLowerCase(char)
- * lowercase ASCII characters} have been converted to uppercase. All other characters are copied
- * without modification.
- *
- * @since 14.0
- */
- public static String toUpperCase(CharSequence chars) {
- int length = chars.length();
+ int length = string.length();
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
- builder.append(toUpperCase(chars.charAt(i)));
+ builder.append(toUpperCase(string.charAt(i)));
}
return builder.toString();
}
diff --git a/guava/src/com/google/common/base/CaseFormat.java b/guava/src/com/google/common/base/CaseFormat.java
index b8b02c9..8ef7c5c 100644
--- a/guava/src/com/google/common/base/CaseFormat.java
+++ b/guava/src/com/google/common/base/CaseFormat.java
@@ -16,8 +16,6 @@
package com.google.common.base;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.GwtCompatible;
/**
@@ -31,74 +29,27 @@ public enum CaseFormat {
/**
* Hyphenated variable naming convention, e.g., "lower-hyphen".
*/
- LOWER_HYPHEN(CharMatcher.is('-'), "-") {
- @Override String normalizeWord(String word) {
- return Ascii.toLowerCase(word);
- }
- @Override String convert(CaseFormat format, String s) {
- if (format == LOWER_UNDERSCORE) {
- return s.replace('-', '_');
- }
- if (format == UPPER_UNDERSCORE) {
- return Ascii.toUpperCase(s.replace('-', '_'));
- }
- return super.convert(format, s);
- }
- },
+ LOWER_HYPHEN(CharMatcher.is('-'), "-"),
/**
* C++ variable naming convention, e.g., "lower_underscore".
*/
- LOWER_UNDERSCORE(CharMatcher.is('_'), "_") {
- @Override String normalizeWord(String word) {
- return Ascii.toLowerCase(word);
- }
- @Override String convert(CaseFormat format, String s) {
- if (format == LOWER_HYPHEN) {
- return s.replace('_', '-');
- }
- if (format == UPPER_UNDERSCORE) {
- return Ascii.toUpperCase(s);
- }
- return super.convert(format, s);
- }
- },
+ LOWER_UNDERSCORE(CharMatcher.is('_'), "_"),
/**
* Java variable naming convention, e.g., "lowerCamel".
*/
- LOWER_CAMEL(CharMatcher.inRange('A', 'Z'), "") {
- @Override String normalizeWord(String word) {
- return firstCharOnlyToUpper(word);
- }
- },
+ LOWER_CAMEL(CharMatcher.inRange('A', 'Z'), ""),
/**
* Java and C++ class naming convention, e.g., "UpperCamel".
*/
- UPPER_CAMEL(CharMatcher.inRange('A', 'Z'), "") {
- @Override String normalizeWord(String word) {
- return firstCharOnlyToUpper(word);
- }
- },
+ UPPER_CAMEL(CharMatcher.inRange('A', 'Z'), ""),
/**
* Java and C++ constant naming convention, e.g., "UPPER_UNDERSCORE".
*/
- UPPER_UNDERSCORE(CharMatcher.is('_'), "_") {
- @Override String normalizeWord(String word) {
- return Ascii.toUpperCase(word);
- }
- @Override String convert(CaseFormat format, String s) {
- if (format == LOWER_HYPHEN) {
- return Ascii.toLowerCase(s.replace('_', '-'));
- }
- if (format == LOWER_UNDERSCORE) {
- return Ascii.toLowerCase(s);
- }
- return super.convert(format, s);
- }
- };
+ UPPER_UNDERSCORE(CharMatcher.is('_'), "_");
private final CharMatcher wordBoundary;
private final String wordSeparator;
@@ -109,21 +60,51 @@ public enum CaseFormat {
}
/**
- * Converts the specified {@code String str} from this format to the specified {@code format}. A
- * "best effort" approach is taken; if {@code str} does not conform to the assumed format, then
- * the behavior of this method is undefined but we make a reasonable effort at converting anyway.
+ * Converts the specified {@code String s} from this format to the specified {@code format}. A
+ * "best effort" approach is taken; if {@code s} does not conform to the assumed format, then the
+ * behavior of this method is undefined but we make a reasonable effort at converting anyway.
*/
- public final String to(CaseFormat format, String str) {
- checkNotNull(format);
- checkNotNull(str);
- return (format == this) ? str : convert(format, str);
- }
+ public String to(CaseFormat format, String s) {
+ if (format == null) {
+ throw new NullPointerException();
+ }
+ if (s == null) {
+ throw new NullPointerException();
+ }
- /**
- * Enum values can override for performance reasons.
- */
- String convert(CaseFormat format, String s) {
- // deal with camel conversion
+ if (format == this) {
+ return s;
+ }
+
+ /* optimize cases where no camel conversion is required */
+ switch (this) {
+ case LOWER_HYPHEN:
+ switch (format) {
+ case LOWER_UNDERSCORE:
+ return s.replace('-', '_');
+ case UPPER_UNDERSCORE:
+ return Ascii.toUpperCase(s.replace('-', '_'));
+ }
+ break;
+ case LOWER_UNDERSCORE:
+ switch (format) {
+ case LOWER_HYPHEN:
+ return s.replace('_', '-');
+ case UPPER_UNDERSCORE:
+ return Ascii.toUpperCase(s);
+ }
+ break;
+ case UPPER_UNDERSCORE:
+ switch (format) {
+ case LOWER_HYPHEN:
+ return Ascii.toLowerCase(s.replace('_', '-'));
+ case LOWER_UNDERSCORE:
+ return Ascii.toLowerCase(s);
+ }
+ break;
+ }
+
+ // otherwise, deal with camel conversion
StringBuilder out = null;
int i = 0;
int j = -1;
@@ -138,23 +119,46 @@ public enum CaseFormat {
out.append(format.wordSeparator);
i = j + wordSeparator.length();
}
- return (i == 0)
- ? format.normalizeFirstWord(s)
- : out.append(format.normalizeWord(s.substring(i))).toString();
+ if (i == 0) {
+ return format.normalizeFirstWord(s);
+ }
+ out.append(format.normalizeWord(s.substring(i)));
+ return out.toString();
}
- abstract String normalizeWord(String word);
-
private String normalizeFirstWord(String word) {
- return (this == LOWER_CAMEL) ? Ascii.toLowerCase(word) : normalizeWord(word);
+ switch (this) {
+ case LOWER_CAMEL:
+ return Ascii.toLowerCase(word);
+ default:
+ return normalizeWord(word);
+ }
+ }
+
+ private String normalizeWord(String word) {
+ switch (this) {
+ case LOWER_HYPHEN:
+ return Ascii.toLowerCase(word);
+ case LOWER_UNDERSCORE:
+ return Ascii.toLowerCase(word);
+ case LOWER_CAMEL:
+ return firstCharOnlyToUpper(word);
+ case UPPER_CAMEL:
+ return firstCharOnlyToUpper(word);
+ case UPPER_UNDERSCORE:
+ return Ascii.toUpperCase(word);
+ }
+ throw new RuntimeException("unknown case: " + this);
}
private static String firstCharOnlyToUpper(String word) {
- return (word.isEmpty())
- ? word
- : new StringBuilder(word.length())
- .append(Ascii.toUpperCase(word.charAt(0)))
- .append(Ascii.toLowerCase(word.substring(1)))
- .toString();
+ int length = word.length();
+ if (length == 0) {
+ return word;
+ }
+ return new StringBuilder(length)
+ .append(Ascii.toUpperCase(word.charAt(0)))
+ .append(Ascii.toLowerCase(word.substring(1)))
+ .toString();
}
}
diff --git a/guava/src/com/google/common/base/CharMatcher.java b/guava/src/com/google/common/base/CharMatcher.java
index e79f7d4..1bea5c8 100644
--- a/guava/src/com/google/common/base/CharMatcher.java
+++ b/guava/src/com/google/common/base/CharMatcher.java
@@ -21,10 +21,10 @@ 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.ArrayList;
import java.util.Arrays;
-import java.util.BitSet;
+import java.util.List;
import javax.annotation.CheckReturnValue;
@@ -45,17 +45,38 @@ import javax.annotation.CheckReturnValue;
* String trimmed = {@link #WHITESPACE WHITESPACE}.{@link #trimFrom trimFrom}(userInput);
* if ({@link #ASCII ASCII}.{@link #matchesAllOf matchesAllOf}(s)) { ... }</pre>
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#CharMatcher">
- * {@code CharMatcher}</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
@Beta // Possibly change from chars to code points; decide constants vs. methods
-@GwtCompatible(emulated = true)
+@GwtCompatible
public abstract class CharMatcher implements Predicate<Character> {
// Constants
+
+ // Excludes 2000-2000a, which is handled as a range
+ private static final String BREAKING_WHITESPACE_CHARS =
+ "\t\n\013\f\r \u0085\u1680\u2028\u2029\u205f\u3000";
+
+ // Excludes 2007, which is handled as a gap in a pair of ranges
+ private static final String NON_BREAKING_WHITESPACE_CHARS =
+ "\u00a0\u180e\u202f";
+
+ /**
+ * Determines whether a character is whitespace according to the latest Unicode standard, as
+ * illustrated
+ * <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bwhitespace%7D">here</a>.
+ * This is not the same definition used by other Java APIs. (See a
+ * <a href="http://spreadsheets.google.com/pub?key=pd8dAQyHbdewRsnE5x5GzKQ">comparison of several
+ * definitions of "whitespace"</a>.)
+ *
+ * <p><b>Note:</b> as the Unicode definition evolves, we will modify this constant to keep it up
+ * to date.
+ */
+ public static final CharMatcher WHITESPACE =
+ anyOf(BREAKING_WHITESPACE_CHARS + NON_BREAKING_WHITESPACE_CHARS)
+ .or(inRange('\u2000', '\u200a'))
+ .precomputed();
+
/**
* Determines whether a character is a breaking whitespace (that is, a whitespace which can be
* interpreted as a break between words for formatting purposes). See {@link #WHITESPACE} for a
@@ -63,96 +84,40 @@ public abstract class CharMatcher implements Predicate<Character> {
*
* @since 2.0
*/
- public static final CharMatcher BREAKING_WHITESPACE = new CharMatcher() {
- @Override
- public boolean matches(char c) {
- switch (c) {
- case '\t':
- case '\n':
- case '\013':
- case '\f':
- case '\r':
- case ' ':
- case '\u0085':
- case '\u1680':
- case '\u2028':
- case '\u2029':
- case '\u205f':
- case '\u3000':
- return true;
- case '\u2007':
- return false;
- default:
- return c >= '\u2000' && c <= '\u200a';
- }
- }
-
- @Override
- public String toString() {
- return "CharMatcher.BREAKING_WHITESPACE";
- }
- };
+ public static final CharMatcher BREAKING_WHITESPACE =
+ anyOf(BREAKING_WHITESPACE_CHARS)
+ .or(inRange('\u2000', '\u2006'))
+ .or(inRange('\u2008', '\u200a'))
+ .precomputed();
/**
* Determines whether a character is ASCII, meaning that its code point is less than 128.
*/
- public static final CharMatcher ASCII = inRange('\0', '\u007f', "CharMatcher.ASCII");
-
- private static class RangesMatcher extends CharMatcher {
- private final char[] rangeStarts;
- private final char[] rangeEnds;
-
- RangesMatcher(String description, char[] rangeStarts, char[] rangeEnds) {
- super(description);
- this.rangeStarts = rangeStarts;
- this.rangeEnds = rangeEnds;
- checkArgument(rangeStarts.length == rangeEnds.length);
- for (int i = 0; i < rangeStarts.length; i++) {
- checkArgument(rangeStarts[i] <= rangeEnds[i]);
- if (i + 1 < rangeStarts.length) {
- checkArgument(rangeEnds[i] < rangeStarts[i + 1]);
- }
- }
- }
-
- @Override
- public boolean matches(char c) {
- int index = Arrays.binarySearch(rangeStarts, c);
- if (index >= 0) {
- return true;
- } else {
- index = ~index - 1;
- return index >= 0 && c <= rangeEnds[index];
- }
- }
- }
-
- // Must be in ascending order.
- private static final String ZEROES = "0\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6"
- + "\u0c66\u0ce6\u0d66\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946\u19d0\u1b50\u1bb0"
- + "\u1c40\u1c50\ua620\ua8d0\ua900\uaa50\uff10";
-
- private static final String NINES;
- static {
- StringBuilder builder = new StringBuilder(ZEROES.length());
- for (int i = 0; i < ZEROES.length(); i++) {
- builder.append((char) (ZEROES.charAt(i) + 9));
- }
- NINES = builder.toString();
- }
+ public static final CharMatcher ASCII = inRange('\0', '\u007f');
/**
* Determines whether a character is a digit according to
* <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bdigit%7D">Unicode</a>.
*/
- public static final CharMatcher DIGIT = new RangesMatcher(
- "CharMatcher.DIGIT", ZEROES.toCharArray(), NINES.toCharArray());
+ public static final CharMatcher DIGIT;
+
+ static {
+ CharMatcher digit = inRange('0', '9');
+ String zeroes =
+ "\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6\u0c66"
+ + "\u0ce6\u0d66\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946"
+ + "\u19d0\u1b50\u1bb0\u1c40\u1c50\ua620\ua8d0\ua900\uaa50\uff10";
+ for (char base : zeroes.toCharArray()) {
+ digit = digit.or(inRange(base, (char) (base + 9)));
+ }
+ DIGIT = digit.precomputed();
+ }
/**
* Determines whether a character is a digit according to {@link Character#isDigit(char) Java's
* definition}. If you only care to match ASCII digits, you can use {@code inRange('0', '9')}.
*/
- public static final CharMatcher JAVA_DIGIT = new CharMatcher("CharMatcher.JAVA_DIGIT") {
+ public static final CharMatcher JAVA_DIGIT = new CharMatcher() {
@Override public boolean matches(char c) {
return Character.isDigit(c);
}
@@ -163,7 +128,7 @@ public abstract class CharMatcher implements Predicate<Character> {
* definition}. If you only care to match letters of the Latin alphabet, you can use {@code
* inRange('a', 'z').or(inRange('A', 'Z'))}.
*/
- public static final CharMatcher JAVA_LETTER = new CharMatcher("CharMatcher.JAVA_LETTER") {
+ public static final CharMatcher JAVA_LETTER = new CharMatcher() {
@Override public boolean matches(char c) {
return Character.isLetter(c);
}
@@ -173,8 +138,7 @@ public abstract class CharMatcher implements Predicate<Character> {
* Determines whether a character is a letter or digit according to {@link
* Character#isLetterOrDigit(char) Java's definition}.
*/
- public static final CharMatcher JAVA_LETTER_OR_DIGIT =
- new CharMatcher("CharMatcher.JAVA_LETTER_OR_DIGIT") {
+ public static final CharMatcher JAVA_LETTER_OR_DIGIT = new CharMatcher() {
@Override public boolean matches(char c) {
return Character.isLetterOrDigit(c);
}
@@ -184,8 +148,7 @@ public abstract class CharMatcher implements Predicate<Character> {
* Determines whether a character is upper case according to {@link Character#isUpperCase(char)
* Java's definition}.
*/
- public static final CharMatcher JAVA_UPPER_CASE =
- new CharMatcher("CharMatcher.JAVA_UPPER_CASE") {
+ public static final CharMatcher JAVA_UPPER_CASE = new CharMatcher() {
@Override public boolean matches(char c) {
return Character.isUpperCase(c);
}
@@ -195,8 +158,7 @@ public abstract class CharMatcher implements Predicate<Character> {
* Determines whether a character is lower case according to {@link Character#isLowerCase(char)
* Java's definition}.
*/
- public static final CharMatcher JAVA_LOWER_CASE =
- new CharMatcher("CharMatcher.JAVA_LOWER_CASE") {
+ public static final CharMatcher JAVA_LOWER_CASE = new CharMatcher() {
@Override public boolean matches(char c) {
return Character.isLowerCase(c);
}
@@ -207,31 +169,26 @@ public abstract class CharMatcher implements Predicate<Character> {
* Character#isISOControl(char)}.
*/
public static final CharMatcher JAVA_ISO_CONTROL =
- inRange('\u0000', '\u001f')
- .or(inRange('\u007f', '\u009f'))
- .withToString("CharMatcher.JAVA_ISO_CONTROL");
+ inRange('\u0000', '\u001f').or(inRange('\u007f', '\u009f'));
/**
* Determines whether a character is invisible; that is, if its Unicode category is any of
* SPACE_SEPARATOR, LINE_SEPARATOR, PARAGRAPH_SEPARATOR, CONTROL, FORMAT, SURROGATE, and
* PRIVATE_USE according to ICU4J.
*/
- public static final CharMatcher INVISIBLE = new RangesMatcher("CharMatcher.INVISIBLE", (
- "\u0000\u007f\u00ad\u0600\u06dd\u070f\u1680\u180e\u2000\u2028\u205f\u206a\u3000\ud800\ufeff"
- + "\ufff9\ufffa").toCharArray(), (
- "\u0020\u00a0\u00ad\u0604\u06dd\u070f\u1680\u180e\u200f\u202f\u2064\u206f\u3000\uf8ff\ufeff"
- + "\ufff9\ufffb").toCharArray());
-
- private static String showCharacter(char c) {
- String hex = "0123456789ABCDEF";
- char[] tmp = {'\\', 'u', '\0', '\0', '\0', '\0'};
- for (int i = 0; i < 4; i++) {
- tmp[5 - i] = hex.charAt(c & 0xF);
- c >>= 4;
- }
- return String.copyValueOf(tmp);
-
- }
+ public static final CharMatcher INVISIBLE = inRange('\u0000', '\u0020')
+ .or(inRange('\u007f', '\u00a0'))
+ .or(is('\u00ad'))
+ .or(inRange('\u0600', '\u0603'))
+ .or(anyOf("\u06dd\u070f\u1680\u17b4\u17b5\u180e"))
+ .or(inRange('\u2000', '\u200f'))
+ .or(inRange('\u2028', '\u202f'))
+ .or(inRange('\u205f', '\u2064'))
+ .or(inRange('\u206a', '\u206f'))
+ .or(is('\u3000'))
+ .or(inRange('\ud800', '\uf8ff'))
+ .or(anyOf("\ufeff\ufff9\ufffa\ufffb"))
+ .precomputed();
/**
* Determines whether a character is single-width (not double-width). When in doubt, this matcher
@@ -241,13 +198,24 @@ public abstract class CharMatcher implements Predicate<Character> {
* <p><b>Note:</b> as the reference file evolves, we will modify this constant to keep it up to
* date.
*/
- public static final CharMatcher SINGLE_WIDTH = new RangesMatcher("CharMatcher.SINGLE_WIDTH",
- "\u0000\u05be\u05d0\u05f3\u0600\u0750\u0e00\u1e00\u2100\ufb50\ufe70\uff61".toCharArray(),
- "\u04f9\u05be\u05ea\u05f4\u06ff\u077f\u0e7f\u20af\u213a\ufdff\ufeff\uffdc".toCharArray());
+ public static final CharMatcher SINGLE_WIDTH = inRange('\u0000', '\u04f9')
+ .or(is('\u05be'))
+ .or(inRange('\u05d0', '\u05ea'))
+ .or(is('\u05f3'))
+ .or(is('\u05f4'))
+ .or(inRange('\u0600', '\u06ff'))
+ .or(inRange('\u0750', '\u077f'))
+ .or(inRange('\u0e00', '\u0e7f'))
+ .or(inRange('\u1e00', '\u20af'))
+ .or(inRange('\u2100', '\u213a'))
+ .or(inRange('\ufb50', '\ufdff'))
+ .or(inRange('\ufe70', '\ufeff'))
+ .or(inRange('\uff61', '\uffdc'))
+ .precomputed();
/** Matches any character. */
public static final CharMatcher ANY =
- new FastMatcher("CharMatcher.ANY") {
+ new CharMatcher() {
@Override public boolean matches(char c) {
return true;
}
@@ -319,11 +287,15 @@ public abstract class CharMatcher implements Predicate<Character> {
@Override public CharMatcher negate() {
return NONE;
}
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
};
/** Matches no characters. */
public static final CharMatcher NONE =
- new FastMatcher("CharMatcher.NONE") {
+ new CharMatcher() {
@Override public boolean matches(char c) {
return false;
}
@@ -374,16 +346,6 @@ public abstract class CharMatcher implements Predicate<Character> {
return sequence.toString();
}
- @Override
- public String trimLeadingFrom(CharSequence sequence) {
- return sequence.toString();
- }
-
- @Override
- public String trimTrailingFrom(CharSequence sequence) {
- return sequence.toString();
- }
-
@Override public int countIn(CharSequence sequence) {
checkNotNull(sequence);
return 0;
@@ -401,6 +363,12 @@ public abstract class CharMatcher implements Predicate<Character> {
@Override public CharMatcher negate() {
return ANY;
}
+
+ @Override void setBits(LookupTable table) {}
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
};
// Static factories
@@ -409,8 +377,7 @@ public abstract class CharMatcher implements Predicate<Character> {
* Returns a {@code char} matcher that matches only one specified character.
*/
public static CharMatcher is(final char match) {
- String description = "CharMatcher.is('" + showCharacter(match) + "')";
- return new FastMatcher(description) {
+ return new CharMatcher() {
@Override public boolean matches(char c) {
return c == match;
}
@@ -431,11 +398,13 @@ public abstract class CharMatcher implements Predicate<Character> {
return isNot(match);
}
- @GwtIncompatible("java.util.BitSet")
- @Override
- void setBits(BitSet table) {
+ @Override void setBits(LookupTable table) {
table.set(match);
}
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
};
}
@@ -445,8 +414,7 @@ public abstract class CharMatcher implements Predicate<Character> {
* <p>To negate another {@code CharMatcher}, use {@link #negate()}.
*/
public static CharMatcher isNot(final char match) {
- String description = "CharMatcher.isNot(" + Integer.toHexString(match) + ")";
- return new FastMatcher(description) {
+ return new CharMatcher() {
@Override public boolean matches(char c) {
return c != match;
}
@@ -459,13 +427,6 @@ public abstract class CharMatcher implements Predicate<Character> {
return other.matches(match) ? ANY : this;
}
- @GwtIncompatible("java.util.BitSet")
- @Override
- void setBits(BitSet table) {
- table.set(0, match);
- table.set(match + 1, Character.MAX_VALUE + 1);
- }
-
@Override public CharMatcher negate() {
return is(match);
}
@@ -483,26 +444,33 @@ public abstract class CharMatcher implements Predicate<Character> {
case 1:
return is(sequence.charAt(0));
case 2:
- return isEither(sequence.charAt(0), sequence.charAt(1));
- default:
- // continue below to handle the general case
+ final char match1 = sequence.charAt(0);
+ final char match2 = sequence.charAt(1);
+ return new CharMatcher() {
+ @Override public boolean matches(char c) {
+ return c == match1 || c == match2;
+ }
+
+ @Override void setBits(LookupTable table) {
+ table.set(match1);
+ table.set(match2);
+ }
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
+ };
}
- // TODO(user): is it potentially worth just going ahead and building a precomputed matcher?
+
final char[] chars = sequence.toString().toCharArray();
- Arrays.sort(chars);
- StringBuilder description = new StringBuilder("CharMatcher.anyOf(\"");
- for (char c : chars) {
- description.append(showCharacter(c));
- }
- description.append("\")");
- return new CharMatcher(description.toString()) {
+ Arrays.sort(chars); // not worth collapsing duplicates
+
+ return new CharMatcher() {
@Override public boolean matches(char c) {
return Arrays.binarySearch(chars, c) >= 0;
}
- @Override
- @GwtIncompatible("java.util.BitSet")
- void setBits(BitSet table) {
+ @Override void setBits(LookupTable table) {
for (char c : chars) {
table.set(c);
}
@@ -510,24 +478,6 @@ public abstract class CharMatcher implements Predicate<Character> {
};
}
- private static CharMatcher isEither(
- final char match1,
- final char match2) {
- String description = "CharMatcher.anyOf(\"" +
- showCharacter(match1) + showCharacter(match2) + "\")";
- return new FastMatcher(description) {
- @Override public boolean matches(char c) {
- return c == match1 || c == match2;
- }
-
- @GwtIncompatible("java.util.BitSet")
- @Override void setBits(BitSet table) {
- table.set(match1);
- table.set(match2);
- }
- };
- }
-
/**
* Returns a {@code char} matcher that matches any character not present in the given character
* sequence.
@@ -545,22 +495,23 @@ public abstract class CharMatcher implements Predicate<Character> {
*/
public static CharMatcher inRange(final char startInclusive, final char endInclusive) {
checkArgument(endInclusive >= startInclusive);
- String description = "CharMatcher.inRange('" +
- showCharacter(startInclusive) + "', '" +
- showCharacter(endInclusive) + "')";
- return inRange(startInclusive, endInclusive, description);
- }
-
- static CharMatcher inRange(final char startInclusive, final char endInclusive,
- String description) {
- return new FastMatcher(description) {
+ return new CharMatcher() {
@Override public boolean matches(char c) {
return startInclusive <= c && c <= endInclusive;
}
- @GwtIncompatible("java.util.BitSet")
- @Override void setBits(BitSet table) {
- table.set(startInclusive, endInclusive + 1);
+ @Override void setBits(LookupTable table) {
+ char c = startInclusive;
+ while (true) {
+ table.set(c);
+ if (c++ == endInclusive) {
+ break;
+ }
+ }
+ }
+
+ @Override public CharMatcher precomputed() {
+ return this;
}
};
}
@@ -574,8 +525,7 @@ public abstract class CharMatcher implements Predicate<Character> {
if (predicate instanceof CharMatcher) {
return (CharMatcher) predicate;
}
- String description = "CharMatcher.forPredicate(" + predicate + ")";
- return new CharMatcher(description) {
+ return new CharMatcher() {
@Override public boolean matches(char c) {
return predicate.apply(c);
}
@@ -586,25 +536,12 @@ public abstract class CharMatcher implements Predicate<Character> {
};
}
- // State
- final String description;
-
// Constructors
/**
- * Sets the {@code toString()} from the given description.
+ * Constructor for use by subclasses.
*/
- CharMatcher(String description) {
- this.description = description;
- }
-
- /**
- * Constructor for use by subclasses. When subclassing, you may want to override
- * {@code toString()} to provide a useful description.
- */
- protected CharMatcher() {
- description = super.toString();
- }
+ protected CharMatcher() {}
// Abstract methods
@@ -617,96 +554,57 @@ public abstract class CharMatcher implements Predicate<Character> {
* Returns a matcher that matches any character not matched by this matcher.
*/
public CharMatcher negate() {
- return new NegatedMatcher(this);
- }
-
- private static class NegatedMatcher extends CharMatcher {
- final CharMatcher original;
-
- NegatedMatcher(String toString, CharMatcher original) {
- super(toString);
- this.original = original;
- }
-
- NegatedMatcher(CharMatcher original) {
- this(original + ".negate()", original);
- }
-
- @Override public boolean matches(char c) {
- return !original.matches(c);
- }
-
- @Override public boolean matchesAllOf(CharSequence sequence) {
- return original.matchesNoneOf(sequence);
- }
-
- @Override public boolean matchesNoneOf(CharSequence sequence) {
- return original.matchesAllOf(sequence);
- }
+ final CharMatcher original = this;
+ return new CharMatcher() {
+ @Override public boolean matches(char c) {
+ return !original.matches(c);
+ }
- @Override public int countIn(CharSequence sequence) {
- return sequence.length() - original.countIn(sequence);
- }
+ @Override public boolean matchesAllOf(CharSequence sequence) {
+ return original.matchesNoneOf(sequence);
+ }
- @GwtIncompatible("java.util.BitSet")
- @Override
- void setBits(BitSet table) {
- BitSet tmp = new BitSet();
- original.setBits(tmp);
- tmp.flip(Character.MIN_VALUE, Character.MAX_VALUE + 1);
- table.or(tmp);
- }
+ @Override public boolean matchesNoneOf(CharSequence sequence) {
+ return original.matchesAllOf(sequence);
+ }
- @Override public CharMatcher negate() {
- return original;
- }
+ @Override public int countIn(CharSequence sequence) {
+ return sequence.length() - original.countIn(sequence);
+ }
- @Override
- CharMatcher withToString(String description) {
- return new NegatedMatcher(description, original);
- }
+ @Override public CharMatcher negate() {
+ return original;
+ }
+ };
}
/**
* Returns a matcher that matches any character matched by both this matcher and {@code other}.
*/
public CharMatcher and(CharMatcher other) {
- return new And(this, checkNotNull(other));
+ return new And(Arrays.asList(this, checkNotNull(other)));
}
private static class And extends CharMatcher {
- final CharMatcher first;
- final CharMatcher second;
+ List<CharMatcher> components;
- And(CharMatcher a, CharMatcher b) {
- this(a, b, "CharMatcher.and(" + a + ", " + b + ")");
+ And(List<CharMatcher> components) {
+ this.components = components; // Skip defensive copy (private)
}
- And(CharMatcher a, CharMatcher b, String description) {
- super(description);
- first = checkNotNull(a);
- second = checkNotNull(b);
- }
-
- @Override
- public boolean matches(char c) {
- return first.matches(c) && second.matches(c);
- }
-
- @GwtIncompatible("java.util.BitSet")
- @Override
- void setBits(BitSet table) {
- BitSet tmp1 = new BitSet();
- first.setBits(tmp1);
- BitSet tmp2 = new BitSet();
- second.setBits(tmp2);
- tmp1.and(tmp2);
- table.or(tmp1);
+ @Override public boolean matches(char c) {
+ for (CharMatcher matcher : components) {
+ if (!matcher.matches(c)) {
+ return false;
+ }
+ }
+ return true;
}
- @Override
- CharMatcher withToString(String description) {
- return new And(first, second, description);
+ @Override public CharMatcher and(CharMatcher other) {
+ List<CharMatcher> newComponents = new ArrayList<CharMatcher>(components);
+ newComponents.add(checkNotNull(other));
+ return new And(newComponents);
}
}
@@ -714,38 +612,35 @@ public abstract class CharMatcher implements Predicate<Character> {
* Returns a matcher that matches any character matched by either this matcher or {@code other}.
*/
public CharMatcher or(CharMatcher other) {
- return new Or(this, checkNotNull(other));
+ return new Or(Arrays.asList(this, checkNotNull(other)));
}
private static class Or extends CharMatcher {
- final CharMatcher first;
- final CharMatcher second;
-
- Or(CharMatcher a, CharMatcher b, String description) {
- super(description);
- first = checkNotNull(a);
- second = checkNotNull(b);
- }
+ List<CharMatcher> components;
- Or(CharMatcher a, CharMatcher b) {
- this(a, b, "CharMatcher.or(" + a + ", " + b + ")");
+ Or(List<CharMatcher> components) {
+ this.components = components; // Skip defensive copy (private)
}
- @GwtIncompatible("java.util.BitSet")
- @Override
- void setBits(BitSet table) {
- first.setBits(table);
- second.setBits(table);
+ @Override public boolean matches(char c) {
+ for (CharMatcher matcher : components) {
+ if (matcher.matches(c)) {
+ return true;
+ }
+ }
+ return false;
}
- @Override
- public boolean matches(char c) {
- return first.matches(c) || second.matches(c);
+ @Override public CharMatcher or(CharMatcher other) {
+ List<CharMatcher> newComponents = new ArrayList<CharMatcher>(components);
+ newComponents.add(checkNotNull(other));
+ return new Or(newComponents);
}
- @Override
- CharMatcher withToString(String description) {
- return new Or(first, second, description);
+ @Override void setBits(LookupTable table) {
+ for (CharMatcher matcher : components) {
+ matcher.setBits(table);
+ }
}
}
@@ -763,147 +658,67 @@ public abstract class CharMatcher implements Predicate<Character> {
}
/**
- * Subclasses should provide a new CharMatcher with the same characteristics as {@code this},
- * but with their {@code toString} method overridden with the new description.
+ * This is the actual implementation of {@link #precomputed}, but we bounce calls through a method
+ * on {@link Platform} so that we can have different behavior in GWT.
*
- * <p>This is unsupported by default.
- */
- CharMatcher withToString(String description) {
- throw new UnsupportedOperationException();
- }
-
- private static final int DISTINCT_CHARS = Character.MAX_VALUE - Character.MIN_VALUE + 1;
-
- /**
- * This is the actual implementation of {@link #precomputed}, but we bounce calls through a
- * method on {@link Platform} so that we can have different behavior in GWT.
+ * <p>The default precomputation is to cache the configuration of the original matcher in an
+ * eight-kilobyte bit array. In some situations this produces a matcher which is faster to query
+ * than the original.
*
- * <p>This implementation tries to be smart in a number of ways. It recognizes cases where
- * the negation is cheaper to precompute than the matcher itself; it tries to build small
- * hash tables for matchers that only match a few characters, and so on. In the worst-case
- * scenario, it constructs an eight-kilobyte bit array and queries that.
- * In many situations this produces a matcher which is faster to query than the original.
+ * <p>The default implementation creates a new bit array and passes it to {@link
+ * #setBits(LookupTable)}.
*/
- @GwtIncompatible("java.util.BitSet")
CharMatcher precomputedInternal() {
- final BitSet table = new BitSet();
+ final LookupTable table = new LookupTable();
setBits(table);
- int totalCharacters = table.cardinality();
- if (totalCharacters * 2 <= DISTINCT_CHARS) {
- return precomputedPositive(totalCharacters, table, description);
- } else {
- // TODO(user): is it worth it to worry about the last character of large matchers?
- table.flip(Character.MIN_VALUE, Character.MAX_VALUE + 1);
- int negatedCharacters = DISTINCT_CHARS - totalCharacters;
- return new NegatedFastMatcher(toString(),
- precomputedPositive(negatedCharacters, table, description + ".negate()"));
- }
- }
- /**
- * A matcher for which precomputation will not yield any significant benefit.
- */
- abstract static class FastMatcher extends CharMatcher {
- FastMatcher() {
- super();
- }
-
- FastMatcher(String description) {
- super(description);
- }
-
- @Override
- public final CharMatcher precomputed() {
- return this;
- }
-
- @Override
- public CharMatcher negate() {
- return new NegatedFastMatcher(this);
- }
- }
-
- static final class NegatedFastMatcher extends NegatedMatcher {
- NegatedFastMatcher(CharMatcher original) {
- super(original);
- }
-
- NegatedFastMatcher(String toString, CharMatcher original) {
- super(toString, original);
- }
+ return new CharMatcher() {
+ @Override public boolean matches(char c) {
+ return table.get(c);
+ }
- @Override
- public final CharMatcher precomputed() {
- return this;
- }
+ // TODO(kevinb): make methods like negate() smart?
- @Override
- CharMatcher withToString(String description) {
- return new NegatedFastMatcher(description, original);
- }
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
+ };
}
/**
- * Helper method for {@link #precomputedInternal} that doesn't test if the negation is cheaper.
+ * For use by implementors; sets the bit corresponding to each character ('\0' to '{@literal
+ * \}uFFFF') that matches this matcher in the given bit array, leaving all other bits untouched.
+ *
+ * <p>The default implementation loops over every possible character value, invoking {@link
+ * #matches} for each one.
*/
- @GwtIncompatible("java.util.BitSet")
- private static CharMatcher precomputedPositive(
- int totalCharacters,
- BitSet table,
- String description) {
- switch (totalCharacters) {
- case 0:
- return NONE;
- case 1:
- return is((char) table.nextSetBit(0));
- case 2:
- char c1 = (char) table.nextSetBit(0);
- char c2 = (char) table.nextSetBit(c1 + 1);
- return isEither(c1, c2);
- default:
- return isSmall(totalCharacters, table.length())
- ? SmallCharMatcher.from(table, description)
- : new BitSetMatcher(table, description);
- }
- }
-
- private static boolean isSmall(int totalCharacters, int tableLength) {
- return totalCharacters <= SmallCharMatcher.MAX_SIZE
- && tableLength > (totalCharacters * Character.SIZE);
- }
-
- @GwtIncompatible("java.util.BitSet")
- private static class BitSetMatcher extends FastMatcher {
- private final BitSet table;
-
- private BitSetMatcher(BitSet table, String description) {
- super(description);
- if (table.length() + Long.SIZE < table.size()) {
- table = (BitSet) table.clone();
- // If only we could actually call BitSet.trimToSize() ourselves...
+ void setBits(LookupTable table) {
+ char c = Character.MIN_VALUE;
+ while (true) {
+ if (matches(c)) {
+ table.set(c);
+ }
+ if (c++ == Character.MAX_VALUE) {
+ break;
}
- this.table = table;
- }
-
- @Override public boolean matches(char c) {
- return table.get(c);
- }
-
- @Override
- void setBits(BitSet bitSet) {
- bitSet.or(table);
}
}
/**
- * Sets bits in {@code table} matched by this matcher.
+ * A bit array with one bit per {@code char} value, used by {@link CharMatcher#precomputed}.
+ *
+ * <p>TODO(kevinb): possibly share a common BitArray class with BloomFilter and others... a
+ * simpler java.util.BitSet.
*/
- @GwtIncompatible("java.util.BitSet")
- void setBits(BitSet table) {
- for (int c = Character.MAX_VALUE; c >= Character.MIN_VALUE; c--) {
- if (matches((char) c)) {
- table.set(c);
- }
+ private static final class LookupTable {
+ int[] data = new int[2048];
+
+ void set(char index) {
+ data[index >> 5] |= (1 << index);
+ }
+
+ boolean get(char index) {
+ return (data[index >> 5] & (1 << index)) != 0;
}
}
@@ -958,6 +773,8 @@ public abstract class CharMatcher implements Predicate<Character> {
return indexIn(sequence) == -1;
}
+ // TODO(kevinb): add matchesAnyOf()
+
/**
* Returns the index of the first matching character in a character sequence, or {@code -1} if no
* matching character is present.
@@ -1212,12 +1029,15 @@ public abstract class CharMatcher implements Predicate<Character> {
@CheckReturnValue
public String trimLeadingFrom(CharSequence sequence) {
int len = sequence.length();
- for (int first = 0; first < len; first++) {
+ int first;
+
+ for (first = 0; first < len; first++) {
if (!matches(sequence.charAt(first))) {
- return sequence.subSequence(first, len).toString();
+ break;
}
}
- return "";
+
+ return sequence.subSequence(first, len).toString();
}
/**
@@ -1231,12 +1051,15 @@ public abstract class CharMatcher implements Predicate<Character> {
@CheckReturnValue
public String trimTrailingFrom(CharSequence sequence) {
int len = sequence.length();
- for (int last = len - 1; last >= 0; last--) {
+ int last;
+
+ for (last = len - 1; last >= 0; last--) {
if (!matches(sequence.charAt(last))) {
- return sequence.subSequence(0, last + 1).toString();
+ break;
}
}
- return "";
+
+ return sequence.subSequence(0, last + 1).toString();
}
/**
@@ -1259,25 +1082,29 @@ public abstract class CharMatcher implements Predicate<Character> {
*/
@CheckReturnValue
public String collapseFrom(CharSequence sequence, char replacement) {
- // This implementation avoids unnecessary allocation.
- int len = sequence.length();
- for (int i = 0; i < len; i++) {
+ int first = indexIn(sequence);
+ if (first == -1) {
+ return sequence.toString();
+ }
+
+ // TODO(kevinb): see if this implementation can be made faster
+ StringBuilder builder = new StringBuilder(sequence.length())
+ .append(sequence.subSequence(0, first))
+ .append(replacement);
+ boolean in = true;
+ for (int i = first + 1; i < sequence.length(); i++) {
char c = sequence.charAt(i);
- if (matches(c)) {
- if (c == replacement
- && (i == len - 1 || !matches(sequence.charAt(i + 1)))) {
- // a no-op replacement
- i++;
- } else {
- StringBuilder builder = new StringBuilder(len)
- .append(sequence.subSequence(0, i))
- .append(replacement);
- return finishCollapseFrom(sequence, i + 1, len, replacement, builder, true);
+ if (apply(c)) {
+ if (!in) {
+ builder.append(replacement);
+ in = true;
}
+ } else {
+ builder.append(c);
+ in = false;
}
}
- // no replacement needed
- return sequence.toString();
+ return builder.toString();
}
/**
@@ -1287,35 +1114,22 @@ public abstract class CharMatcher implements Predicate<Character> {
*/
@CheckReturnValue
public String trimAndCollapseFrom(CharSequence sequence, char replacement) {
- // This implementation avoids unnecessary allocation.
- int len = sequence.length();
- int first;
- int last;
-
- for (first = 0; first < len && matches(sequence.charAt(first)); first++) {}
- for (last = len - 1; last > first && matches(sequence.charAt(last)); last--) {}
-
- return (first == 0 && last == len - 1)
- ? collapseFrom(sequence, replacement)
- : finishCollapseFrom(
- sequence, first, last + 1, replacement,
- new StringBuilder(last + 1 - first),
- false);
- }
-
- private String finishCollapseFrom(
- CharSequence sequence, int start, int end, char replacement,
- StringBuilder builder, boolean inMatchingGroup) {
- for (int i = start; i < end; i++) {
+ int first = negate().indexIn(sequence);
+ if (first == -1) {
+ return ""; // everything matches. nothing's left.
+ }
+ StringBuilder builder = new StringBuilder(sequence.length());
+ boolean inMatchingGroup = false;
+ for (int i = first; i < sequence.length(); i++) {
char c = sequence.charAt(i);
- if (matches(c)) {
- if (!inMatchingGroup) {
+ if (apply(c)) {
+ inMatchingGroup = true;
+ } else {
+ if (inMatchingGroup) {
builder.append(replacement);
- inMatchingGroup = true;
+ inMatchingGroup = false;
}
- } else {
builder.append(c);
- inMatchingGroup = false;
}
}
return builder.toString();
@@ -1324,67 +1138,11 @@ public abstract class CharMatcher implements Predicate<Character> {
// Predicate interface
/**
- * Equivalent to {@link #matches}; provided only to satisfy the {@link Predicate} interface. When
- * using a reference of type {@code CharMatcher}, invoke {@link #matches} directly instead.
+ * Returns {@code true} if this matcher matches the given character.
+ *
+ * @throws NullPointerException if {@code character} is null
*/
@Override public boolean apply(Character character) {
return matches(character);
}
-
- /**
- * Returns a string representation of this {@code CharMatcher}, such as
- * {@code CharMatcher.or(WHITESPACE, JAVA_DIGIT)}.
- */
- @Override
- public String toString() {
- return description;
- }
-
- /**
- * A special-case CharMatcher for Unicode whitespace characters that is extremely
- * efficient both in space required and in time to check for matches.
- *
- * Implementation details.
- * It turns out that all current (early 2012) Unicode characters are unique modulo 79:
- * so we can construct a lookup table of exactly 79 entries, and just check the character code
- * mod 79, and see if that character is in the table.
- *
- * There is a 1 at the beginning of the table so that the null character is not listed
- * as whitespace.
- *
- * Other things we tried that did not prove to be beneficial, mostly due to speed concerns:
- *
- * * Binary search into the sorted list of characters, i.e., what
- * CharMatcher.anyOf() does</li>
- * * Perfect hash function into a table of size 26 (using an offset table and a special
- * Jenkins hash function)</li>
- * * Perfect-ish hash function that required two lookups into a single table of size 26.</li>
- * * Using a power-of-2 sized hash table (size 64) with linear probing.</li>
- *
- * --Christopher Swenson, February 2012.
- */
- private static final String WHITESPACE_TABLE = "\u0001\u0000\u00a0\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0009\n\u000b\u000c\r\u0000\u0000\u2028\u2029\u0000\u0000\u0000\u0000\u0000\u202f"
- + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0020\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0000\u0000\u0000\u0000\u3000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0000\u0085\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a"
- + "\u0000\u0000\u0000\u0000\u0000\u205f\u1680\u0000\u0000\u180e\u0000\u0000\u0000";
-
- /**
- * Determines whether a character is whitespace according to the latest Unicode standard, as
- * illustrated
- * <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bwhitespace%7D">here</a>.
- * This is not the same definition used by other Java APIs. (See a
- * <a href="http://spreadsheets.google.com/pub?key=pd8dAQyHbdewRsnE5x5GzKQ">comparison of several
- * definitions of "whitespace"</a>.)
- *
- * <p><b>Note:</b> as the Unicode definition evolves, we will modify this constant to keep it up
- * to date.
- */
- public static final CharMatcher WHITESPACE = new FastMatcher("CharMatcher.WHITESPACE") {
-
- @Override public boolean matches(char c) {
- return WHITESPACE_TABLE.charAt(c % 79) == c;
- }
- };
}
diff --git a/guava/src/com/google/common/base/Charsets.java b/guava/src/com/google/common/base/Charsets.java
index 79c9128..407e798 100644
--- a/guava/src/com/google/common/base/Charsets.java
+++ b/guava/src/com/google/common/base/Charsets.java
@@ -16,38 +16,26 @@
package com.google.common.base;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-
import java.nio.charset.Charset;
/**
* Contains constant definitions for the six standard {@link Charset} instances, which are
* guaranteed to be supported by all Java platform implementations.
*
- * <p>Assuming you're free to choose, note that <b>{@link #UTF_8} is widely preferred</b>.
- *
- * <p>See the Guava User Guide article on <a
- * href="http://code.google.com/p/guava-libraries/wiki/StringsExplained#Charsets">
- * {@code Charsets}</a>.
- *
* @author Mike Bostock
* @since 1.0
*/
-@GwtCompatible(emulated = true)
public final class Charsets {
private Charsets() {}
/**
* US-ASCII: seven-bit ASCII, the Basic Latin block of the Unicode character set (ISO646-US).
*/
- @GwtIncompatible("Non-UTF-8 Charset")
public static final Charset US_ASCII = Charset.forName("US-ASCII");
/**
* ISO-8859-1: ISO Latin Alphabet Number 1 (ISO-LATIN-1).
*/
- @GwtIncompatible("Non-UTF-8 Charset")
public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
/**
@@ -58,20 +46,17 @@ public final class Charsets {
/**
* UTF-16BE: sixteen-bit UCS Transformation Format, big-endian byte order.
*/
- @GwtIncompatible("Non-UTF-8 Charset")
public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
/**
* UTF-16LE: sixteen-bit UCS Transformation Format, little-endian byte order.
*/
- @GwtIncompatible("Non-UTF-8 Charset")
public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
/**
* UTF-16: sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order
* mark.
*/
- @GwtIncompatible("Non-UTF-8 Charset")
public static final Charset UTF_16 = Charset.forName("UTF-16");
/*
diff --git a/guava/src/com/google/common/base/Defaults.java b/guava/src/com/google/common/base/Defaults.java
index 50717fc..f98cbbf 100644
--- a/guava/src/com/google/common/base/Defaults.java
+++ b/guava/src/com/google/common/base/Defaults.java
@@ -16,8 +16,6 @@
package com.google.common.base;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -26,7 +24,6 @@ import java.util.Map;
* This class provides default values for all Java types, as defined by the JLS.
*
* @author Ben Yu
- * @since 1.0
*/
public final class Defaults {
private Defaults() {}
@@ -57,6 +54,6 @@ public final class Defaults {
*/
@SuppressWarnings("unchecked")
public static <T> T defaultValue(Class<T> type) {
- return (T) DEFAULTS.get(checkNotNull(type));
+ return (T) DEFAULTS.get(type);
}
}
diff --git a/guava/src/com/google/common/base/Enums.java b/guava/src/com/google/common/base/Enums.java
index 6105410..f98e164 100644
--- a/guava/src/com/google/common/base/Enums.java
+++ b/guava/src/com/google/common/base/Enums.java
@@ -20,10 +20,8 @@ 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.io.Serializable;
-import java.lang.reflect.Field;
import javax.annotation.Nullable;
@@ -34,31 +32,13 @@ import javax.annotation.Nullable;
*
* @since 9.0
*/
-@GwtCompatible(emulated = true)
+@GwtCompatible
@Beta
public final class Enums {
private Enums() {}
/**
- * Returns the {@link Field} in which {@code enumValue} is defined.
- * For example, to get the {@code Description} annotation on the {@code GOLF}
- * constant of enum {@code Sport}, use
- * {@code Enums.getField(Sport.GOLF).getAnnotation(Description.class)}.
- *
- * @since 12.0
- */
- @GwtIncompatible("reflection")
- public static Field getField(Enum<?> enumValue) {
- Class<?> clazz = enumValue.getDeclaringClass();
- try {
- return clazz.getDeclaredField(enumValue.name());
- } catch (NoSuchFieldException impossible) {
- throw new AssertionError(impossible);
- }
- }
-
- /**
* Returns a {@link Function} that maps an {@link Enum} name to the associated
* {@code Enum} constant. The {@code Function} will return {@code null} if the
* {@code Enum} constant does not exist.
@@ -71,11 +51,11 @@ public final class Enums {
}
/**
- * A {@link Function} that maps an {@link Enum} name to the associated
+ * {@link Function} that maps an {@link Enum} name to the associated
* constant, or {@code null} if the constant does not exist.
*/
- private static final class ValueOfFunction<T extends Enum<T>>
- implements Function<String, T>, Serializable {
+ private static final class ValueOfFunction<T extends Enum<T>> implements
+ Function<String, T>, Serializable {
private final Class<T> enumClass;
@@ -107,22 +87,4 @@ public final class Enums {
private static final long serialVersionUID = 0;
}
-
- /**
- * Returns an optional enum constant for the given type, using {@link Enum#valueOf}. If the
- * constant does not exist, {@link Optional#absent} is returned. A common use case is for parsing
- * user input or falling back to a default enum constant. For example,
- * {@code Enums.getIfPresent(Country.class, countryInput).or(Country.DEFAULT);}
- *
- * @since 12.0
- */
- public static <T extends Enum<T>> Optional<T> getIfPresent(Class<T> enumClass, String value) {
- checkNotNull(enumClass);
- checkNotNull(value);
- try {
- return Optional.of(Enum.valueOf(enumClass, value));
- } catch (IllegalArgumentException iae) {
- return Optional.absent();
- }
- }
}
diff --git a/guava/src/com/google/common/base/Equivalence.java b/guava/src/com/google/common/base/Equivalence.java
index 339bec0..f6e89bd 100644
--- a/guava/src/com/google/common/base/Equivalence.java
+++ b/guava/src/com/google/common/base/Equivalence.java
@@ -27,8 +27,8 @@ import javax.annotation.Nullable;
/**
* A strategy for determining whether two instances are considered equivalent. Examples of
- * equivalences are the {@linkplain #identity() identity equivalence} and {@linkplain #equals equals
- * equivalence}.
+ * equivalences are the {@link Equivalences#identity() identity equivalence} and {@link
+ * Equivalences#equals equals equivalence}.
*
* @author Bob Lee
* @author Ben Yu
@@ -36,6 +36,7 @@ import javax.annotation.Nullable;
* @since 10.0 (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility"
* >mostly source-compatible</a> since 4.0)
*/
+@Beta
@GwtCompatible
public abstract class Equivalence<T> {
/**
@@ -122,7 +123,7 @@ public abstract class Equivalence<T> {
*
* <p>For example: <pre> {@code
*
- * Equivalence<Person> SAME_AGE = Equivalence.equals().onResultOf(GET_PERSON_AGE);
+ * Equivalence<Person> SAME_AGE = Equivalences.equals().onResultOf(GET_PERSON_AGE);
* }</pre>
*
* <p>{@code function} will never be invoked with a null value.
@@ -130,7 +131,7 @@ public abstract class Equivalence<T> {
* <p>Note that {@code function} must be consistent according to {@code this} equivalence
* relation. That is, invoking {@link Function#apply} multiple times for a given value must return
* equivalent results.
- * For example, {@code Equivalence.identity().onResultOf(Functions.toStringFunction())} is broken
+ * For example, {@code Equivalences.identity().onResultOf(Functions.toStringFunction())} is broken
* because it's not guaranteed that {@link Object#toString}) always returns the same string
* instance.
*
@@ -171,6 +172,7 @@ public abstract class Equivalence<T> {
*
* @since 10.0
*/
+ @Beta
public static final class Wrapper<T> implements Serializable {
private final Equivalence<? super T> equivalence;
@Nullable private final T reference;
@@ -251,7 +253,6 @@ public abstract class Equivalence<T> {
*
* @since 10.0
*/
- @Beta
public final Predicate<T> equivalentTo(@Nullable T target) {
return new EquivalentToPredicate<T>(this, target);
}
@@ -292,67 +293,4 @@ public abstract class Equivalence<T> {
private static final long serialVersionUID = 0;
}
-
- /**
- * Returns an equivalence that delegates to {@link Object#equals} and {@link Object#hashCode}.
- * {@link Equivalence#equivalent} returns {@code true} if both values are null, or if neither
- * value is null and {@link Object#equals} returns {@code true}. {@link Equivalence#hash} returns
- * {@code 0} if passed a null value.
- *
- * @since 13.0
- * @since 8.0 (in Equivalences with null-friendly behavior)
- * @since 4.0 (in Equivalences)
- */
- public static Equivalence<Object> equals() {
- return Equals.INSTANCE;
- }
-
- /**
- * Returns an equivalence that uses {@code ==} to compare values and {@link
- * System#identityHashCode(Object)} to compute the hash code. {@link Equivalence#equivalent}
- * returns {@code true} if {@code a == b}, including in the case that a and b are both null.
- *
- * @since 13.0
- * @since 4.0 (in Equivalences)
- */
- public static Equivalence<Object> identity() {
- return Identity.INSTANCE;
- }
-
- static final class Equals extends Equivalence<Object>
- implements Serializable {
-
- static final Equals INSTANCE = new Equals();
-
- @Override protected boolean doEquivalent(Object a, Object b) {
- return a.equals(b);
- }
- @Override public int doHash(Object o) {
- return o.hashCode();
- }
-
- private Object readResolve() {
- return INSTANCE;
- }
- private static final long serialVersionUID = 1;
- }
-
- static final class Identity extends Equivalence<Object>
- implements Serializable {
-
- static final Identity INSTANCE = new Identity();
-
- @Override protected boolean doEquivalent(Object a, Object b) {
- return false;
- }
-
- @Override protected int doHash(Object o) {
- return System.identityHashCode(o);
- }
-
- private Object readResolve() {
- return INSTANCE;
- }
- private static final long serialVersionUID = 1;
- }
}
diff --git a/guava/src/com/google/common/base/Equivalences.java b/guava/src/com/google/common/base/Equivalences.java
new file mode 100644
index 0000000..6c88dcf
--- /dev/null
+++ b/guava/src/com/google/common/base/Equivalences.java
@@ -0,0 +1,97 @@
+/*
+ * 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.base;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+
+/**
+ * Contains static factory methods for creating {@code Equivalence} instances.
+ *
+ * <p>All methods return serializable instances.
+ *
+ * @author Bob Lee
+ * @author Kurt Alfred Kluever
+ * @author Gregory Kick
+ * @since 4.0
+ */
+@Beta
+@GwtCompatible
+public final class Equivalences {
+ private Equivalences() {}
+
+ /**
+ * Returns an equivalence that delegates to {@link Object#equals} and {@link Object#hashCode}.
+ * {@link Equivalence#equivalent} returns {@code true} if both values are null, or if neither
+ * value is null and {@link Object#equals} returns {@code true}. {@link Equivalence#hash} returns
+ * {@code 0} if passed a null value.
+ *
+ * @since 8.0 (present null-friendly behavior)
+ * @since 4.0 (otherwise)
+ */
+ public static Equivalence<Object> equals() {
+ return Equals.INSTANCE;
+ }
+
+ /**
+ * Returns an equivalence that uses {@code ==} to compare values and {@link
+ * System#identityHashCode(Object)} to compute the hash code. {@link Equivalence#equivalent}
+ * returns {@code true} if {@code a == b}, including in the case that a and b are both null.
+ */
+ public static Equivalence<Object> identity() {
+ return Identity.INSTANCE;
+ }
+
+ private static final class Equals extends Equivalence<Object>
+ implements Serializable {
+
+ static final Equals INSTANCE = new Equals();
+
+ @Override protected boolean doEquivalent(Object a, Object b) {
+ return a.equals(b);
+ }
+ @Override public int doHash(Object o) {
+ return o.hashCode();
+ }
+
+ private Object readResolve() {
+ return INSTANCE;
+ }
+ private static final long serialVersionUID = 1;
+ }
+
+ private static final class Identity extends Equivalence<Object>
+ implements Serializable {
+
+ static final Identity INSTANCE = new Identity();
+
+ @Override protected boolean doEquivalent(Object a, Object b) {
+ return false;
+ }
+
+ @Override protected int doHash(Object o) {
+ return System.identityHashCode(o);
+ }
+
+ private Object readResolve() {
+ return INSTANCE;
+ }
+ private static final long serialVersionUID = 1;
+ }
+}
diff --git a/guava/src/com/google/common/base/FinalizableReferenceQueue.java b/guava/src/com/google/common/base/FinalizableReferenceQueue.java
index 2ca3681..f300b33 100644
--- a/guava/src/com/google/common/base/FinalizableReferenceQueue.java
+++ b/guava/src/com/google/common/base/FinalizableReferenceQueue.java
@@ -16,12 +16,8 @@
package com.google.common.base;
-import com.google.common.annotations.VisibleForTesting;
-import java.io.Closeable;
-
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Method;
@@ -41,7 +37,7 @@ import java.util.logging.Logger;
* @author Bob Lee
* @since 2.0 (imported from Google Collections Library)
*/
-public class FinalizableReferenceQueue implements Closeable {
+public class FinalizableReferenceQueue {
/*
* The Finalizer thread keeps a phantom reference to this object. When the client (for example, a
* map built by MapMaker) no longer has a strong reference to this object, the garbage collector
@@ -95,8 +91,6 @@ public class FinalizableReferenceQueue implements Closeable {
*/
final ReferenceQueue<Object> queue;
- final PhantomReference<Object> frqRef;
-
/**
* Whether or not the background thread started successfully.
*/
@@ -108,28 +102,24 @@ public class FinalizableReferenceQueue implements Closeable {
@SuppressWarnings("unchecked")
public FinalizableReferenceQueue() {
// We could start the finalizer lazily, but I'd rather it blow up early.
- queue = new ReferenceQueue<Object>();
- frqRef = new PhantomReference<Object>(this, queue);
+ ReferenceQueue<Object> queue;
boolean threadStarted = false;
try {
- startFinalizer.invoke(null, FinalizableReference.class, queue, frqRef);
+ queue = (ReferenceQueue<Object>)
+ startFinalizer.invoke(null, FinalizableReference.class, this);
threadStarted = true;
} catch (IllegalAccessException impossible) {
throw new AssertionError(impossible); // startFinalizer() is public
} catch (Throwable t) {
logger.log(Level.INFO, "Failed to start reference finalizer thread."
+ " Reference cleanup will only occur when new references are created.", t);
+ queue = new ReferenceQueue<Object>();
}
+ this.queue = queue;
this.threadStarted = threadStarted;
}
- @Override
- public void close() {
- frqRef.enqueue();
- cleanUp();
- }
-
/**
* Repeatedly dequeues references from the queue and invokes {@link
* FinalizableReference#finalizeReferent()} on them until the queue is empty. This method is a
@@ -189,16 +179,8 @@ public class FinalizableReferenceQueue implements Closeable {
* we needn't create a separate loader.
*/
static class SystemLoader implements FinalizerLoader {
- // This is used by the ClassLoader-leak test in FinalizableReferenceQueueTest to disable
- // finding Finalizer on the system class path even if it is there.
- @VisibleForTesting
- static boolean disabled;
-
@Override
public Class<?> loadFinalizer() {
- if (disabled) {
- return null;
- }
ClassLoader systemLoader;
try {
systemLoader = ClassLoader.getSystemClassLoader();
@@ -272,10 +254,7 @@ public class FinalizableReferenceQueue implements Closeable {
/** Creates a class loader with the given base URL as its classpath. */
URLClassLoader newLoader(URL base) {
- // We use the bootstrap class loader as the parent because Finalizer by design uses
- // only standard Java classes. That also means that FinalizableReferenceQueueTest
- // doesn't pick up the wrong version of the Finalizer class.
- return new URLClassLoader(new URL[] {base}, null);
+ return new URLClassLoader(new URL[] {base});
}
}
@@ -299,11 +278,7 @@ public class FinalizableReferenceQueue implements Closeable {
*/
static Method getStartFinalizer(Class<?> finalizer) {
try {
- return finalizer.getMethod(
- "startFinalizer",
- Class.class,
- ReferenceQueue.class,
- PhantomReference.class);
+ return finalizer.getMethod("startFinalizer", Class.class, Object.class);
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
diff --git a/guava/src/com/google/common/base/Function.java b/guava/src/com/google/common/base/Function.java
index f969b4a..6289fa4 100644
--- a/guava/src/com/google/common/base/Function.java
+++ b/guava/src/com/google/common/base/Function.java
@@ -23,12 +23,6 @@ import javax.annotation.Nullable;
/**
* Determines an output value based on an input value.
*
- * <p>The {@link Functions} class provides common functions and related utilites.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the use of {@code
- * Function}</a>.
- *
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
*/
@@ -48,7 +42,7 @@ public interface Function<F, T> {
* @throws NullPointerException if {@code input} is null and this function does not accept null
* arguments
*/
- @Nullable T apply(@Nullable F input);
+ T apply(@Nullable F input);
/**
* Indicates whether another object is equal to this function.
diff --git a/guava/src/com/google/common/base/Functions.java b/guava/src/com/google/common/base/Functions.java
index 9336e02..cca629a 100644
--- a/guava/src/com/google/common/base/Functions.java
+++ b/guava/src/com/google/common/base/Functions.java
@@ -30,11 +30,7 @@ import javax.annotation.Nullable;
/**
* Static utility methods pertaining to {@code Function} instances.
*
- * <p>All methods return serializable functions as long as they're given serializable parameters.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the use of {@code
- * Function}</a>.
+ * <p>All methods returns serializable functions as long as they're given serializable parameters.
*
* @author Mike Bostock
* @author Jared Levy
@@ -84,8 +80,7 @@ public final class Functions {
INSTANCE;
@Override
- @Nullable
- public Object apply(@Nullable Object o) {
+ public Object apply(Object o) {
return o;
}
@@ -110,7 +105,7 @@ public final class Functions {
}
@Override
- public V apply(@Nullable K key) {
+ public V apply(K key) {
V result = map.get(key);
checkArgument(result != null || map.containsKey(key), "Key '%s' not present in map", key);
return result;
@@ -159,7 +154,7 @@ public final class Functions {
}
@Override
- public V apply(@Nullable K key) {
+ public V apply(K key) {
V result = map.get(key);
return (result != null || map.containsKey(key)) ? result : defaultValue;
}
@@ -206,7 +201,7 @@ public final class Functions {
}
@Override
- public C apply(@Nullable A a) {
+ public C apply(A a) {
return g.apply(f.apply(a));
}
@@ -248,7 +243,7 @@ public final class Functions {
}
@Override
- public Boolean apply(@Nullable T t) {
+ public Boolean apply(T t) {
return predicate.apply(t);
}
diff --git a/guava/src/com/google/common/base/Joiner.java b/guava/src/com/google/common/base/Joiner.java
index 8a2e9a2..048e477 100644
--- a/guava/src/com/google/common/base/Joiner.java
+++ b/guava/src/com/google/common/base/Joiner.java
@@ -56,9 +56,6 @@ import javax.annotation.Nullable;
* joiner.skipNulls(); // does nothing!
* return joiner.join("wrong", null, "wrong");}</pre>
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#Joiner">{@code Joiner}</a>.
- *
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
*/
@@ -98,8 +95,7 @@ public class Joiner {
*/
@Beta
@Deprecated
- public
- final <A extends Appendable, I extends Object & Iterable<?> & Iterator<?>> A
+ public final <A extends Appendable, I extends Object & Iterable<?> & Iterator<?>> A
appendTo(A appendable, I parts) throws IOException {
return appendTo(appendable, (Iterator<?>) parts);
}
@@ -118,6 +114,7 @@ public class Joiner {
*
* @since 11.0
*/
+ @Beta
public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
checkNotNull(appendable);
if (parts.hasNext()) {
@@ -157,8 +154,7 @@ public class Joiner {
*/
@Beta
@Deprecated
- public
- final <I extends Object & Iterable<?> & Iterator<?>> StringBuilder
+ public final <I extends Object & Iterable<?> & Iterator<?>> StringBuilder
appendTo(StringBuilder builder, I parts) {
return appendTo(builder, (Iterator<?>) parts);
}
@@ -179,6 +175,7 @@ public class Joiner {
*
* @since 11.0
*/
+ @Beta
public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
try {
appendTo((Appendable) builder, parts);
@@ -217,8 +214,7 @@ public class Joiner {
*/
@Beta
@Deprecated
- public
- final <I extends Object & Iterable<?> & Iterator<?>> String join(I parts) {
+ public final <I extends Object & Iterable<?> & Iterator<?>> String join(I parts) {
return join((Iterator<?>) parts);
}
@@ -236,6 +232,7 @@ public class Joiner {
*
* @since 11.0
*/
+ @Beta
public final String join(Iterator<?> parts) {
return appendTo(new StringBuilder(), parts).toString();
}
@@ -264,7 +261,7 @@ public class Joiner {
public Joiner useForNull(final String nullText) {
checkNotNull(nullText);
return new Joiner(this) {
- @Override CharSequence toString(@Nullable Object part) {
+ @Override CharSequence toString(Object part) {
return (part == null) ? nullText : Joiner.this.toString(part);
}
@@ -391,8 +388,7 @@ public class Joiner {
*/
@Beta
@Deprecated
- public
- <A extends Appendable,
+ public <A extends Appendable,
I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
A appendTo(A appendable, I entries) throws IOException {
Iterator<? extends Entry<?, ?>> iterator = entries;
@@ -448,8 +444,7 @@ public class Joiner {
*/
@Beta
@Deprecated
- public
- <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
+ public <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
StringBuilder appendTo(StringBuilder builder, I entries) throws IOException {
Iterator<? extends Entry<?, ?>> iterator = entries;
return appendTo(builder, iterator);
@@ -495,8 +490,7 @@ public class Joiner {
*/
@Beta
@Deprecated
- public
- <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
+ public <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
String join(I entries) throws IOException {
Iterator<? extends Entry<?, ?>> iterator = entries;
return join(iterator);
diff --git a/guava/src/com/google/common/base/Objects.java b/guava/src/com/google/common/base/Objects.java
index c65f84b..ffac9c4 100644
--- a/guava/src/com/google/common/base/Objects.java
+++ b/guava/src/com/google/common/base/Objects.java
@@ -27,10 +27,6 @@ import javax.annotation.Nullable;
/**
* Helper functions that can operate on any {@code Object}.
*
- * <p>See the Guava User Guide on <a
- * href="http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained">writing
- * {@code Object} methods with {@code Objects}</a>.
- *
* @author Laurence Gonsalves
* @since 2.0 (imported from Google Collections Library)
*/
@@ -98,14 +94,6 @@ public final class Objects {
* .add("x", 1)
* .add("y", "foo")
* .toString();
- * }}
- *
- * // Returns "ClassName{x=1}"
- * Objects.toStringHelper(this)
- * .omitNullValues()
- * .add("x", 1)
- * .add("y", null)
- * .toString();
* }}</pre>
*
* <p>Note that in GWT, class names are often obfuscated.
@@ -193,38 +181,25 @@ public final class Objects {
* @since 2.0
*/
public static final class ToStringHelper {
- private final String className;
- private ValueHolder holderHead = new ValueHolder();
- private ValueHolder holderTail = holderHead;
- private boolean omitNullValues = false;
+ private final StringBuilder builder;
+ private boolean needsSeparator = false;
/**
* Use {@link Objects#toStringHelper(Object)} to create an instance.
*/
private ToStringHelper(String className) {
- this.className = checkNotNull(className);
- }
-
- /**
- * Configures the {@link ToStringHelper} so {@link #toString()} will ignore
- * properties with null value. The order of calling this method, relative
- * to the {@code add()}/{@code addValue()} methods, is not significant.
- *
- * @since 12.0
- */
- public ToStringHelper omitNullValues() {
- omitNullValues = true;
- return this;
+ checkNotNull(className);
+ this.builder = new StringBuilder(32).append(className).append('{');
}
/**
* Adds a name/value pair to the formatted output in {@code name=value}
* format. If {@code value} is {@code null}, the string {@code "null"}
- * is used, unless {@link #omitNullValues()} is called, in which case this
- * name/value pair will not be added.
+ * is used.
*/
public ToStringHelper add(String name, @Nullable Object value) {
- return addHolder(name, value);
+ checkNameAndAppend(name).append(value);
+ return this;
}
/**
@@ -234,7 +209,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper add(String name, boolean value) {
- return addHolder(name, String.valueOf(value));
+ checkNameAndAppend(name).append(value);
+ return this;
}
/**
@@ -244,7 +220,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper add(String name, char value) {
- return addHolder(name, String.valueOf(value));
+ checkNameAndAppend(name).append(value);
+ return this;
}
/**
@@ -254,7 +231,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper add(String name, double value) {
- return addHolder(name, String.valueOf(value));
+ checkNameAndAppend(name).append(value);
+ return this;
}
/**
@@ -264,7 +242,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper add(String name, float value) {
- return addHolder(name, String.valueOf(value));
+ checkNameAndAppend(name).append(value);
+ return this;
}
/**
@@ -274,7 +253,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper add(String name, int value) {
- return addHolder(name, String.valueOf(value));
+ checkNameAndAppend(name).append(value);
+ return this;
}
/**
@@ -284,7 +264,13 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper add(String name, long value) {
- return addHolder(name, String.valueOf(value));
+ checkNameAndAppend(name).append(value);
+ return this;
+ }
+
+ private StringBuilder checkNameAndAppend(String name) {
+ checkNotNull(name);
+ return maybeAppendSeparator().append(name).append('=');
}
/**
@@ -294,7 +280,8 @@ public final class Objects {
* and give value a readable name.
*/
public ToStringHelper addValue(@Nullable Object value) {
- return addHolder(value);
+ maybeAppendSeparator().append(value);
+ return this;
}
/**
@@ -306,7 +293,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper addValue(boolean value) {
- return addHolder(String.valueOf(value));
+ maybeAppendSeparator().append(value);
+ return this;
}
/**
@@ -318,7 +306,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper addValue(char value) {
- return addHolder(String.valueOf(value));
+ maybeAppendSeparator().append(value);
+ return this;
}
/**
@@ -330,7 +319,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper addValue(double value) {
- return addHolder(String.valueOf(value));
+ maybeAppendSeparator().append(value);
+ return this;
}
/**
@@ -342,7 +332,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper addValue(float value) {
- return addHolder(String.valueOf(value));
+ maybeAppendSeparator().append(value);
+ return this;
}
/**
@@ -354,7 +345,8 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper addValue(int value) {
- return addHolder(String.valueOf(value));
+ maybeAppendSeparator().append(value);
+ return this;
}
/**
@@ -366,63 +358,31 @@ public final class Objects {
* @since 11.0 (source-compatible since 2.0)
*/
public ToStringHelper addValue(long value) {
- return addHolder(String.valueOf(value));
+ maybeAppendSeparator().append(value);
+ return this;
}
/**
* Returns a string in the format specified by {@link
* Objects#toStringHelper(Object)}.
- *
- * <p>After calling this method, you can keep adding more properties to later
- * call toString() again and get a more complete representation of the
- * same object; but properties cannot be removed, so this only allows
- * limited reuse of the helper instance. The helper allows duplication of
- * properties (multiple name/value pairs with the same name can be added).
*/
@Override public String toString() {
- // create a copy to keep it consistent in case value changes
- boolean omitNullValuesSnapshot = omitNullValues;
- String nextSeparator = "";
- StringBuilder builder = new StringBuilder(32).append(className)
- .append('{');
- for (ValueHolder valueHolder = holderHead.next; valueHolder != null;
- valueHolder = valueHolder.next) {
- if (!omitNullValuesSnapshot || valueHolder.value != null) {
- builder.append(nextSeparator);
- nextSeparator = ", ";
-
- if (valueHolder.name != null) {
- builder.append(valueHolder.name).append('=');
- }
- builder.append(valueHolder.value);
- }
+ try {
+ return builder.append('}').toString();
+ } finally {
+ // Slice off the closing brace in case there are additional calls to
+ // #add or #addValue.
+ builder.setLength(builder.length() - 1);
}
- return builder.append('}').toString();
}
- private ValueHolder addHolder() {
- ValueHolder valueHolder = new ValueHolder();
- holderTail = holderTail.next = valueHolder;
- return valueHolder;
- }
-
- private ToStringHelper addHolder(@Nullable Object value) {
- ValueHolder valueHolder = addHolder();
- valueHolder.value = value;
- return this;
- }
-
- private ToStringHelper addHolder(String name, @Nullable Object value) {
- ValueHolder valueHolder = addHolder();
- valueHolder.value = value;
- valueHolder.name = checkNotNull(name);
- return this;
- }
-
- private static final class ValueHolder {
- String name;
- Object value;
- ValueHolder next;
+ private StringBuilder maybeAppendSeparator() {
+ if (needsSeparator) {
+ return builder.append(", ");
+ } else {
+ needsSeparator = true;
+ return builder;
+ }
}
}
}
diff --git a/guava/src/com/google/common/base/Optional.java b/guava/src/com/google/common/base/Optional.java
index de3139c..035f96c 100644
--- a/guava/src/com/google/common/base/Optional.java
+++ b/guava/src/com/google/common/base/Optional.java
@@ -22,6 +22,7 @@ import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import java.io.Serializable;
+import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
@@ -58,10 +59,6 @@ import javax.annotation.Nullable;
* <p>This class is not intended as a direct analogue of any existing "option" or "maybe"
* construct from other programming environments, though it may bear some similarities.
*
- * <p>See the Guava User Guide article on <a
- * href="http://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional">
- * using {@code Optional}</a>.
- *
* @param <T> the type of instance that can be contained. {@code Optional} is naturally
* covariant on this type, so it is safe to cast an {@code Optional<T>} to {@code
* Optional<S>} for any supertype {@code S} of {@code T}.
@@ -69,7 +66,8 @@ import javax.annotation.Nullable;
* @author Kevin Bourrillion
* @since 10.0
*/
-@GwtCompatible(serializable = true)
+@Beta
+@GwtCompatible
public abstract class Optional<T> implements Serializable {
/**
* Returns an {@code Optional} instance with no contained reference.
@@ -96,7 +94,7 @@ public abstract class Optional<T> implements Serializable {
: new Present<T>(nullableReference);
}
- Optional() {}
+ private Optional() {}
/**
* Returns {@code true} if this holder contains a (non-null) instance.
@@ -116,30 +114,6 @@ public abstract class Optional<T> implements Serializable {
* Returns the contained instance if it is present; {@code defaultValue} otherwise. If
* no default value should be required because the instance is known to be present, use
* {@link #get()} instead. For a default value of {@code null}, use {@link #orNull}.
- *
- * <p>Note about generics: The signature {@code public T or(T defaultValue)} is overly
- * restrictive. However, the ideal signature, {@code public <S super T> S or(S)}, is not legal
- * Java. As a result, some sensible operations involving subtypes are compile errors:
- * <pre> {@code
- *
- * Optional<Integer> optionalInt = getSomeOptionalInt();
- * Number value = optionalInt.or(0.5); // error
- *
- * FluentIterable<? extends Number> numbers = getSomeNumbers();
- * Optional<? extends Number> first = numbers.first();
- * Number value = first.or(0.5); // error}</pre>
- *
- * As a workaround, it is always safe to cast an {@code Optional<? extends T>} to {@code
- * Optional<T>}. Casting either of the above example {@code Optional} instances to {@code
- * Optional<Number>} (where {@code Number} is the desired output type) solves the problem:
- * <pre> {@code
- *
- * Optional<Number> optionalInt = (Optional) getSomeOptionalInt();
- * Number value = optionalInt.or(0.5); // fine
- *
- * FluentIterable<? extends Number> numbers = getSomeNumbers();
- * Optional<Number> first = (Optional) numbers.first();
- * Number value = first.or(0.5); // fine}</pre>
*/
public abstract T or(T defaultValue);
@@ -151,83 +125,63 @@ public abstract class Optional<T> implements Serializable {
/**
* Returns the contained instance if it is present; {@code supplier.get()} otherwise. If the
- * supplier returns {@code null}, a {@link NullPointerException} is thrown.
+ * supplier returns {@code null}, a {@link NullPointerException} will be thrown.
*
* @throws NullPointerException if the supplier returns {@code null}
*/
- @Beta
public abstract T or(Supplier<? extends T> supplier);
/**
* Returns the contained instance if it is present; {@code null} otherwise. If the
* instance is known to be present, use {@link #get()} instead.
*/
- @Nullable
- public abstract T orNull();
+ @Nullable public abstract T orNull();
/**
- * Returns an immutable singleton {@link Set} whose only element is the contained instance
- * if it is present; an empty immutable {@link Set} otherwise.
+ * Returns an immutable singleton {@link Set} whose only element is the
+ * contained instance if it is present; an empty immutable {@link Set}
+ * otherwise.
*
* @since 11.0
*/
public abstract Set<T> asSet();
/**
- * If the instance is present, it is transformed with the given {@link Function}; otherwise,
- * {@link Optional#absent} is returned. If the function returns {@code null}, a
- * {@link NullPointerException} is thrown.
- *
- * @throws NullPointerException if the function returns {@code null}
- *
- * @since 12.0
- */
- public abstract <V> Optional<V> transform(Function<? super T, V> function);
-
- /**
* Returns {@code true} if {@code object} is an {@code Optional} instance, and either
* the contained references are {@linkplain Object#equals equal} to each other or both
* are absent. Note that {@code Optional} instances of differing parameterized types can
* be equal.
*/
- @Override
- public abstract boolean equals(@Nullable Object object);
+ @Override public abstract boolean equals(@Nullable Object object);
/**
* Returns a hash code for this instance.
*/
- @Override
- public abstract int hashCode();
+ @Override public abstract int hashCode();
/**
* Returns a string representation for this instance. The form of this string
* representation is unspecified.
*/
- @Override
- public abstract String toString();
+ @Override public abstract String toString();
/**
* Returns the value of each present instance from the supplied {@code optionals}, in order,
* skipping over occurrences of {@link Optional#absent}. Iterators are unmodifiable and are
* evaluated lazily.
*
- * @since 11.0 (generics widened in 13.0)
+ * @since 11.0
*/
- @Beta
- public static <T> Iterable<T> presentInstances(
- final Iterable<? extends Optional<? extends T>> optionals) {
+ public static <T> Iterable<T> presentInstances(final Iterable<Optional<T>> optionals) {
checkNotNull(optionals);
return new Iterable<T>() {
- @Override
- public Iterator<T> iterator() {
+ @Override public Iterator<T> iterator() {
return new AbstractIterator<T>() {
- private final Iterator<? extends Optional<? extends T>> iterator =
- checkNotNull(optionals.iterator());
+ private final Iterator<Optional<T>> iterator = checkNotNull(optionals.iterator());
- @Override
- protected T computeNext() {
+ @Override protected T computeNext() {
while (iterator.hasNext()) {
- Optional<? extends T> optional = iterator.next();
+ Optional<T> optional = iterator.next();
if (optional.isPresent()) {
return optional.get();
}
@@ -235,9 +189,118 @@ public abstract class Optional<T> implements Serializable {
return endOfData();
}
};
- }
+ };
};
}
private static final long serialVersionUID = 0;
+
+ private static final class Present<T> extends Optional<T> {
+ private final T reference;
+
+ Present(T reference) {
+ this.reference = reference;
+ }
+
+ @Override public boolean isPresent() {
+ return true;
+ }
+
+ @Override public T get() {
+ return reference;
+ }
+
+ @Override public T or(T defaultValue) {
+ checkNotNull(defaultValue, "use orNull() instead of or(null)");
+ return reference;
+ }
+
+ @Override public Optional<T> or(Optional<? extends T> secondChoice) {
+ checkNotNull(secondChoice);
+ return this;
+ }
+
+ @Override public T or(Supplier<? extends T> supplier) {
+ checkNotNull(supplier);
+ return reference;
+ }
+
+ @Override public T orNull() {
+ return reference;
+ }
+
+ @Override public Set<T> asSet() {
+ return Collections.singleton(reference);
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Present) {
+ Present<?> other = (Present<?>) object;
+ return reference.equals(other.reference);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return 0x598df91c + reference.hashCode();
+ }
+
+ @Override public String toString() {
+ return "Optional.of(" + reference + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static final class Absent extends Optional<Object> {
+ private static final Absent INSTANCE = new Absent();
+
+ @Override public boolean isPresent() {
+ return false;
+ }
+
+ @Override public Object get() {
+ throw new IllegalStateException("value is absent");
+ }
+
+ @Override public Object or(Object defaultValue) {
+ return checkNotNull(defaultValue, "use orNull() instead of or(null)");
+ }
+
+ @SuppressWarnings("unchecked") // safe covariant cast
+ @Override public Optional<Object> or(Optional<?> secondChoice) {
+ return (Optional) checkNotNull(secondChoice);
+ }
+
+ @Override public Object or(Supplier<?> supplier) {
+ return checkNotNull(supplier.get(),
+ "use orNull() instead of a Supplier that returns null");
+ }
+
+ @Override @Nullable public Object orNull() {
+ return null;
+ }
+
+ @Override public Set<Object> asSet() {
+ return Collections.emptySet();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return object == this;
+ }
+
+ @Override public int hashCode() {
+ return 0x598df91c;
+ }
+
+ @Override public String toString() {
+ return "Optional.absent()";
+ }
+
+ private Object readResolve() {
+ return INSTANCE;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
}
diff --git a/guava/src/com/google/common/base/Preconditions.java b/guava/src/com/google/common/base/Preconditions.java
index 802a309..4c22f1e 100644
--- a/guava/src/com/google/common/base/Preconditions.java
+++ b/guava/src/com/google/common/base/Preconditions.java
@@ -53,10 +53,6 @@ import javax.annotation.Nullable;
* perhaps ever. Postcondition or other invariant failures should not throw
* these types of exceptions.
*
- * <p>See the Guava User Guide on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PreconditionsExplained">
- * using {@code Preconditions}</a>.
- *
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
*/
diff --git a/guava/src/com/google/common/base/Predicate.java b/guava/src/com/google/common/base/Predicate.java
index 7345742..08d9f64 100644
--- a/guava/src/com/google/common/base/Predicate.java
+++ b/guava/src/com/google/common/base/Predicate.java
@@ -23,12 +23,6 @@ import javax.annotation.Nullable;
/**
* Determines a true or false value for a given input.
*
- * <p>The {@link Predicates} class provides common predicates and related utilities.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the use of {@code
- * Predicate}</a>.
- *
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
*/
diff --git a/guava/src/com/google/common/base/Predicates.java b/guava/src/com/google/common/base/Predicates.java
index aa12750..5c77a28 100644
--- a/guava/src/com/google/common/base/Predicates.java
+++ b/guava/src/com/google/common/base/Predicates.java
@@ -37,10 +37,6 @@ import javax.annotation.Nullable;
* <p>All methods returns serializable predicates as long as they're given
* serializable parameters.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the
- * use of {@code Predicate}</a>.
- *
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
*/
@@ -200,12 +196,12 @@ public final class Predicates {
public static Predicate<Object> instanceOf(Class<?> clazz) {
return new InstanceOfPredicate(clazz);
}
-
+
/**
* Returns a predicate that evaluates to {@code true} if the class being
* tested is assignable from the given class. The returned predicate
* does not allow null inputs.
- *
+ *
* @since 10.0
*/
@GwtIncompatible("Class.isAssignableFrom")
@@ -293,7 +289,7 @@ public final class Predicates {
return o != null;
}
};
-
+
@SuppressWarnings("unchecked") // these Object predicates work for any T
<T> Predicate<T> withNarrowedType() {
return (Predicate<T>) this;
@@ -308,7 +304,7 @@ public final class Predicates {
this.predicate = checkNotNull(predicate);
}
@Override
- public boolean apply(@Nullable T t) {
+ public boolean apply(T t) {
return !predicate.apply(t);
}
@Override public int hashCode() {
@@ -337,8 +333,7 @@ public final class Predicates {
this.components = components;
}
@Override
- public boolean apply(@Nullable T t) {
- // Avoid using the Iterator to avoid generating garbage (issue 820).
+ public boolean apply(T t) {
for (int i = 0; i < components.size(); i++) {
if (!components.get(i).apply(t)) {
return false;
@@ -347,7 +342,7 @@ public final class Predicates {
return true;
}
@Override public int hashCode() {
- // add a random number to avoid collisions with OrPredicate
+ // 0x12472c2c is a random number to help avoid collisions with OrPredicate
return components.hashCode() + 0x12472c2c;
}
@Override public boolean equals(@Nullable Object obj) {
@@ -371,8 +366,7 @@ public final class Predicates {
this.components = components;
}
@Override
- public boolean apply(@Nullable T t) {
- // Avoid using the Iterator to avoid generating garbage (issue 820).
+ public boolean apply(T t) {
for (int i = 0; i < components.size(); i++) {
if (components.get(i).apply(t)) {
return true;
@@ -381,7 +375,7 @@ public final class Predicates {
return false;
}
@Override public int hashCode() {
- // add a random number to avoid collisions with AndPredicate
+ // 0x053c91cf is a random number to help avoid collisions with AndPredicate
return components.hashCode() + 0x053c91cf;
}
@Override public boolean equals(@Nullable Object obj) {
@@ -453,7 +447,7 @@ public final class Predicates {
}
private static final long serialVersionUID = 0;
}
-
+
/** @see Predicates#assignableFrom(Class) */
@GwtIncompatible("Class.isAssignableFrom")
private static class AssignableFromPredicate
@@ -492,7 +486,7 @@ public final class Predicates {
}
@Override
- public boolean apply(@Nullable T t) {
+ public boolean apply(T t) {
try {
return target.contains(t);
} catch (NullPointerException e) {
@@ -532,7 +526,7 @@ public final class Predicates {
}
@Override
- public boolean apply(@Nullable A a) {
+ public boolean apply(A a) {
return p.apply(f.apply(a));
}
diff --git a/guava/src/com/google/common/base/Present.java b/guava/src/com/google/common/base/Present.java
deleted file mode 100644
index bcde922..0000000
--- a/guava/src/com/google/common/base/Present.java
+++ /dev/null
@@ -1,92 +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.base;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Collections;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * Implementation of an {@link Optional} containing a reference.
- */
-@GwtCompatible
-final class Present<T> extends Optional<T> {
- private final T reference;
-
- Present(T reference) {
- this.reference = reference;
- }
-
- @Override public boolean isPresent() {
- return true;
- }
-
- @Override public T get() {
- return reference;
- }
-
- @Override public T or(T defaultValue) {
- checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)");
- return reference;
- }
-
- @Override public Optional<T> or(Optional<? extends T> secondChoice) {
- checkNotNull(secondChoice);
- return this;
- }
-
- @Override public T or(Supplier<? extends T> supplier) {
- checkNotNull(supplier);
- return reference;
- }
-
- @Override public T orNull() {
- return reference;
- }
-
- @Override public Set<T> asSet() {
- return Collections.singleton(reference);
- }
-
- @Override public <V> Optional<V> transform(Function<? super T, V> function) {
- return new Present<V>(checkNotNull(function.apply(reference),
- "the Function passed to Optional.transform() must not return null."));
- }
-
- @Override public boolean equals(@Nullable Object object) {
- if (object instanceof Present) {
- Present<?> other = (Present<?>) object;
- return reference.equals(other.reference);
- }
- return false;
- }
-
- @Override public int hashCode() {
- return 0x598df91c + reference.hashCode();
- }
-
- @Override public String toString() {
- return "Optional.of(" + reference + ")";
- }
-
- private static final long serialVersionUID = 0;
-}
diff --git a/guava/src/com/google/common/base/SmallCharMatcher.java b/guava/src/com/google/common/base/SmallCharMatcher.java
deleted file mode 100644
index 10234c5..0000000
--- a/guava/src/com/google/common/base/SmallCharMatcher.java
+++ /dev/null
@@ -1,155 +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.base;
-
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.CharMatcher.FastMatcher;
-
-import java.util.BitSet;
-
-/**
- * An immutable version of CharMatcher for smallish sets of characters that uses a hash table
- * with linear probing to check for matches.
- *
- * @author Christopher Swenson
- */
-@GwtIncompatible("no precomputation is done in GWT")
-final class SmallCharMatcher extends FastMatcher {
- static final int MAX_SIZE = 1023;
- private final char[] table;
- private final boolean containsZero;
- private final long filter;
-
- private SmallCharMatcher(char[] table, long filter, boolean containsZero,
- String description) {
- super(description);
- this.table = table;
- this.filter = filter;
- this.containsZero = containsZero;
- }
-
- 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.
- */
- static int smear(int hashCode) {
- return C2 * Integer.rotateLeft(hashCode * C1, 15);
- }
-
- private boolean checkFilter(int c) {
- return 1 == (1 & (filter >> c));
- }
-
- // This is all essentially copied from ImmutableSet, but we have to duplicate because
- // of dependencies.
-
- // Represents how tightly we can pack things, as a maximum.
- private static final double DESIRED_LOAD_FACTOR = 0.5;
-
- /**
- * 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.
- */
- @VisibleForTesting static int chooseTableSize(int setSize) {
- if (setSize == 1) {
- return 2;
- }
- // Correct the size for open addressing to match desired load factor.
- // 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;
- }
-
- @GwtIncompatible("java.util.BitSet")
- static CharMatcher from(BitSet chars, String description) {
- // Compute the filter.
- long filter = 0;
- int size = chars.cardinality();
- boolean containsZero = chars.get(0);
- // Compute the hash table.
- char[] table = new char[chooseTableSize(size)];
- int mask = table.length - 1;
- for (int c = chars.nextSetBit(0); c != -1; c = chars.nextSetBit(c + 1)) {
- // Compute the filter at the same time.
- filter |= 1L << c;
- int index = smear(c) & mask;
- while (true) {
- // Check for empty.
- if (table[index] == 0) {
- table[index] = (char) c;
- break;
- }
- // Linear probing.
- index = (index + 1) & mask;
- }
- }
- return new SmallCharMatcher(table, filter, containsZero, description);
- }
-
- @Override
- public boolean matches(char c) {
- if (c == 0) {
- return containsZero;
- }
- if (!checkFilter(c)) {
- return false;
- }
- int mask = table.length - 1;
- int startingIndex = smear(c) & mask;
- int index = startingIndex;
- do {
- // Check for empty.
- if (table[index] == 0) {
- return false;
- // Check for match.
- } else if (table[index] == c) {
- return true;
- } else {
- // Linear probing.
- index = (index + 1) & mask;
- }
- // Check to see if we wrapped around the whole table.
- } while (index != startingIndex);
- return false;
- }
-
- @GwtIncompatible("java.util.BitSet")
- @Override
- void setBits(BitSet table) {
- if (containsZero) {
- table.set(0);
- }
- for (char c : this.table) {
- if (c != 0) {
- table.set(c);
- }
- }
- }
-}
diff --git a/guava/src/com/google/common/base/Splitter.java b/guava/src/com/google/common/base/Splitter.java
index b9e820f..da7da95 100644
--- a/guava/src/com/google/common/base/Splitter.java
+++ b/guava/src/com/google/common/base/Splitter.java
@@ -33,63 +33,60 @@ import java.util.regex.Pattern;
import javax.annotation.CheckReturnValue;
/**
- * Extracts non-overlapping substrings from an input string, typically by
- * recognizing appearances of a <i>separator</i> sequence. This separator can be
- * specified as a single {@linkplain #on(char) character}, fixed {@linkplain
- * #on(String) string}, {@linkplain #onPattern regular expression} or {@link
- * #on(CharMatcher) CharMatcher} instance. Or, instead of using a separator at
- * all, a splitter can extract adjacent substrings of a given {@linkplain
- * #fixedLength fixed length}.
+ * An object that divides strings (or other instances of {@code CharSequence})
+ * into substrings, by recognizing a <i>separator</i> (a.k.a. "delimiter")
+ * which can be expressed as a single character, literal string, regular
+ * expression, {@code CharMatcher}, or by using a fixed substring length. This
+ * class provides the complementary functionality to {@link Joiner}.
*
- * <p>For example, this expression: <pre> {@code
+ * <p>Here is the most basic example of {@code Splitter} usage: <pre> {@code
*
- * Splitter.on(',').split("foo,bar,qux")}</pre>
+ * Splitter.on(',').split("foo,bar")}</pre>
*
- * ... produces an {@code Iterable} containing {@code "foo"}, {@code "bar"} and
- * {@code "qux"}, in that order.
+ * This invocation returns an {@code Iterable<String>} containing {@code "foo"}
+ * and {@code "bar"}, in that order.
*
- * <p>By default, {@code Splitter}'s behavior is simplistic and unassuming. The
- * following expression: <pre> {@code
+ * <p>By default {@code Splitter}'s behavior is very simplistic: <pre> {@code
*
- * Splitter.on(',').split(" foo,,, bar ,")}</pre>
+ * Splitter.on(',').split("foo,,bar, quux")}</pre>
*
- * ... yields the substrings {@code [" foo", "", "", " bar ", ""]}. If this
- * is not the desired behavior, use configuration methods to obtain a <i>new</i>
- * splitter instance with modified behavior: <pre> {@code
+ * This returns an iterable containing {@code ["foo", "", "bar", " quux"]}.
+ * Notice that the splitter does not assume that you want empty strings removed,
+ * or that you wish to trim whitespace. If you want features like these, simply
+ * ask for them: <pre> {@code
*
* private static final Splitter MY_SPLITTER = Splitter.on(',')
* .trimResults()
* .omitEmptyStrings();}</pre>
*
- * Now {@code MY_SPLITTER.split("foo,,, bar ,")} returns just {@code ["foo",
- * "bar"]}. Note that the order in which these configuration methods are called
- * is never significant.
+ * Now {@code MY_SPLITTER.split("foo, ,bar, quux,")} returns an iterable
+ * containing just {@code ["foo", "bar", "quux"]}. Note that the order in which
+ * the configuration methods are called is never significant; for instance,
+ * trimming is always applied first before checking for an empty result,
+ * regardless of the order in which the {@link #trimResults()} and
+ * {@link #omitEmptyStrings()} methods were invoked.
*
- * <p><b>Warning:</b> Splitter instances are immutable. Invoking a configuration
- * method has no effect on the receiving instance; you must store and use the
- * new splitter instance it returns instead. <pre> {@code
+ * <p><b>Warning: splitter instances are always immutable</b>; a configuration
+ * method such as {@code omitEmptyStrings} has no effect on the instance it
+ * is invoked on! You must store and use the new splitter instance returned by
+ * the method. This makes splitters thread-safe, and safe to store as {@code
+ * static final} constants (as illustrated above). <pre> {@code
*
- * // Do NOT do this
+ * // Bad! Do not do this!
* Splitter splitter = Splitter.on('/');
* splitter.trimResults(); // does nothing!
* return splitter.split("wrong / wrong / wrong");}</pre>
*
- * <p>For separator-based splitters that do not use {@code omitEmptyStrings}, an
- * input string containing {@code n} occurrences of the separator naturally
- * yields an iterable of size {@code n + 1}. So if the separator does not occur
- * anywhere in the input, a single substring is returned containing the entire
- * input. Consequently, all splitters split the empty string to {@code [""]}
- * (note: even fixed-length splitters).
+ * The separator recognized by the splitter does not have to be a single
+ * literal character as in the examples above. See the methods {@link
+ * #on(String)}, {@link #on(Pattern)} and {@link #on(CharMatcher)} for examples
+ * of other ways to specify separators.
*
- * <p>Splitter instances are thread-safe immutable, and are therefore safe to
- * store as {@code static final} constants.
- *
- * <p>The {@link Joiner} class provides the inverse operation to splitting, but
- * note that a round-trip between the two should be assumed to be lossy.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#Splitter">
- * {@code Splitter}</a>.
+ * <p><b>Note:</b> this class does not mimic any of the quirky behaviors of
+ * similar JDK methods; for instance, it does not silently discard trailing
+ * separators, as does {@link String#split(String)}, nor does it have a default
+ * behavior of using five particular whitespace characters as separators, like
+ * {@link java.util.StringTokenizer}.
*
* @author Julien Silland
* @author Jesse Wilson
@@ -159,8 +156,8 @@ public final class Splitter {
/**
* Returns a splitter that uses the given fixed string as a separator. For
- * example, {@code Splitter.on(", ").split("foo, bar,baz")} returns an
- * iterable containing {@code ["foo", "bar,baz"]}.
+ * example, {@code Splitter.on(", ").split("foo, bar, baz,qux")} returns an
+ * iterable containing {@code ["foo", "bar", "baz,qux"]}.
*
* @param separator the literal, nonempty string to recognize as a separator
* @return a splitter, with default settings, that recognizes that separator
@@ -258,18 +255,9 @@ public final class Splitter {
* iterable containing {@code ["ab", "cd", "e"]}. The last piece can be
* smaller than {@code length} but will never be empty.
*
- * <p><b>Exception:</b> for consistency with separator-based splitters, {@code
- * split("")} does not yield an empty iterable, but an iterable containing
- * {@code ""}. This is the only case in which {@code
- * Iterables.size(split(input))} does not equal {@code
- * IntMath.divide(input.length(), length, CEILING)}. To avoid this behavior,
- * use {@code omitEmptyStrings}.
- *
- * @param length the desired length of pieces after splitting, a positive
- * integer
+ * @param length the desired length of pieces after splitting
* @return a splitter, with default settings, that can split into fixed sized
* pieces
- * @throws IllegalArgumentException if {@code length} is zero or negative
*/
public static Splitter fixedLength(final int length) {
checkArgument(length > 0, "The length may not be less than 1");
@@ -386,12 +374,6 @@ public final class Splitter {
@Override public Iterator<String> iterator() {
return spliterator(sequence);
}
- @Override public String toString() {
- return Joiner.on(", ")
- .appendTo(new StringBuilder().append('['), this)
- .append(']')
- .toString();
- }
};
}
@@ -413,18 +395,6 @@ public final class Splitter {
/**
* Returns a {@code MapSplitter} which splits entries based on this splitter,
- * and splits entries into keys and values using the specified separator.
- *
- * @since 14.0
- */
- @CheckReturnValue
- @Beta
- public MapSplitter withKeyValueSeparator(char separator) {
- return withKeyValueSeparator(on(separator));
- }
-
- /**
- * Returns a {@code MapSplitter} which splits entries based on this splitter,
* and splits entries into keys and values using the specified key-value
* splitter.
*
@@ -493,7 +463,8 @@ public final class Splitter {
Iterator<String> iterator(Splitter splitter, CharSequence toSplit);
}
- private abstract static class SplittingIterator extends AbstractIterator<String> {
+ private abstract static class SplittingIterator
+ extends AbstractIterator<String> {
final CharSequence toSplit;
final CharMatcher trimmer;
final boolean omitEmptyStrings;
@@ -522,15 +493,8 @@ public final class Splitter {
}
@Override protected String computeNext() {
- /*
- * The returned string will be from the end of the last match to the
- * beginning of the next one. nextStart is the start position of the
- * returned substring, while offset is the place to start looking for a
- * separator.
- */
- int nextStart = offset;
while (offset != -1) {
- int start = nextStart;
+ int start = offset;
int end;
int separatorPosition = separatorStart(offset);
@@ -541,20 +505,6 @@ public final class Splitter {
end = separatorPosition;
offset = separatorEnd(separatorPosition);
}
- if (offset == nextStart) {
- /*
- * This occurs when some pattern has an empty match, even if it
- * doesn't match the empty string -- for example, if it requires
- * lookahead or the like. The offset must be increased to look for
- * separators beyond this point, without changing the start position
- * of the next returned substring -- so nextStart stays the same.
- */
- offset++;
- if (offset >= toSplit.length()) {
- offset = -1;
- }
- continue;
- }
while (start < end && trimmer.matches(toSplit.charAt(start))) {
start++;
@@ -564,8 +514,6 @@ public final class Splitter {
}
if (omitEmptyStrings && start == end) {
- // Don't include the (unused) separator in next split string.
- nextStart = offset;
continue;
}
diff --git a/guava/src/com/google/common/base/Stopwatch.java b/guava/src/com/google/common/base/Stopwatch.java
index bcd898a..ec9cc9c 100644
--- a/guava/src/com/google/common/base/Stopwatch.java
+++ b/guava/src/com/google/common/base/Stopwatch.java
@@ -50,7 +50,7 @@ import java.util.concurrent.TimeUnit;
* doSomething();
* stopwatch.{@link #stop stop}(); // optional
*
- * long millis = stopwatch.elapsed(MILLISECONDS);
+ * long millis = stopwatch.{@link #elapsedMillis elapsedMillis}();
*
* log.info("that took: " + stopwatch); // formatted string like "12.3 ms"
* </pre>
@@ -69,7 +69,7 @@ import java.util.concurrent.TimeUnit;
* @since 10.0
*/
@Beta
-@GwtCompatible(emulated = true)
+@GwtCompatible(emulated=true)
public final class Stopwatch {
private final Ticker ticker;
private boolean isRunning;
@@ -89,7 +89,7 @@ public final class Stopwatch {
* source.
*/
public Stopwatch(Ticker ticker) {
- this.ticker = checkNotNull(ticker, "ticker");
+ this.ticker = checkNotNull(ticker);
}
/**
@@ -108,8 +108,7 @@ public final class Stopwatch {
* @throws IllegalStateException if the stopwatch is already running.
*/
public Stopwatch start() {
- checkState(!isRunning,
- "This stopwatch is already running; it cannot be started more than once.");
+ checkState(!isRunning);
isRunning = true;
startTick = ticker.read();
return this;
@@ -124,8 +123,7 @@ public final class Stopwatch {
*/
public Stopwatch stop() {
long tick = ticker.read();
- checkState(isRunning,
- "This stopwatch is already stopped; it cannot be stopped more than once.");
+ checkState(isRunning);
isRunning = false;
elapsedNanos += tick - startTick;
return this;
@@ -154,44 +152,23 @@ public final class Stopwatch {
* <p>Note that the overhead of measurement can be more than a microsecond, so
* it is generally not useful to specify {@link TimeUnit#NANOSECONDS}
* precision here.
- *
- * @since 14.0 (since 10.0 as {@code elapsedTime()})
- */
- public long elapsed(TimeUnit desiredUnit) {
- return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
- }
-
- /**
- * Returns the current elapsed time shown on this stopwatch, expressed
- * in the desired time unit, with any fraction rounded down.
- *
- * <p>Note that the overhead of measurement can be more than a microsecond, so
- * it is generally not useful to specify {@link TimeUnit#NANOSECONDS}
- * precision here.
- *
- * @deprecated Use {@link Stopwatch#elapsed(TimeUnit)} instead. This method is
- * scheduled to be removed in Guava release 16.0.
*/
- @Deprecated
public long elapsedTime(TimeUnit desiredUnit) {
- return elapsed(desiredUnit);
+ return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
}
/**
* Returns the current elapsed time shown on this stopwatch, expressed
* in milliseconds, with any fraction rounded down. This is identical to
- * {@code elapsed(TimeUnit.MILLISECONDS)}.
- *
- * @deprecated Use {@code stopwatch.elapsed(MILLISECONDS)} instead. This
- * method is scheduled to be removed in Guava release 16.0.
+ * {@code elapsedTime(TimeUnit.MILLISECONDS}.
*/
- @Deprecated
public long elapsedMillis() {
- return elapsed(MILLISECONDS);
+ return elapsedTime(MILLISECONDS);
}
/**
- * Returns a string representation of the current elapsed time.
+ * Returns a string representation of the current elapsed time; equivalent to
+ * {@code toString(4)} (four significant figures).
*/
@GwtIncompatible("String.format()")
@Override public String toString() {
@@ -201,13 +178,9 @@ public final class Stopwatch {
/**
* Returns a string representation of the current elapsed time, choosing an
* appropriate unit and using the specified number of significant figures.
- * For example, at the instant when {@code elapsed(NANOSECONDS)} would
+ * For example, at the instant when {@code elapsedTime(NANOSECONDS)} would
* return {1234567}, {@code toString(4)} returns {@code "1.235 ms"}.
- *
- * @deprecated Use {@link #toString()} instead. This method is scheduled
- * to be removed in Guava release 15.0.
*/
- @Deprecated
@GwtIncompatible("String.format()")
public String toString(int significantDigits) {
long nanos = elapsedNanos();
diff --git a/guava/src/com/google/common/base/Strings.java b/guava/src/com/google/common/base/Strings.java
index 45007fd..7697452 100644
--- a/guava/src/com/google/common/base/Strings.java
+++ b/guava/src/com/google/common/base/Strings.java
@@ -19,6 +19,7 @@ package com.google.common.base;
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;
@@ -185,6 +186,7 @@ public final class Strings {
*
* @since 11.0
*/
+ @Beta
public static String commonPrefix(CharSequence a, CharSequence b) {
checkNotNull(a);
checkNotNull(b);
@@ -208,6 +210,7 @@ public final class Strings {
*
* @since 11.0
*/
+ @Beta
public static String commonSuffix(CharSequence a, CharSequence b) {
checkNotNull(a);
checkNotNull(b);
diff --git a/guava/src/com/google/common/base/Suppliers.java b/guava/src/com/google/common/base/Suppliers.java
index 468ce8b..5f418c0 100644
--- a/guava/src/com/google/common/base/Suppliers.java
+++ b/guava/src/com/google/common/base/Suppliers.java
@@ -62,27 +62,10 @@ public final class Suppliers {
this.function = function;
this.supplier = supplier;
}
-
- @Override public T get() {
+ @Override
+ public T get() {
return function.apply(supplier.get());
}
-
- @Override public boolean equals(@Nullable Object obj) {
- if (obj instanceof SupplierComposition) {
- SupplierComposition<?, ?> that = (SupplierComposition<?, ?>) obj;
- return function.equals(that.function) && supplier.equals(that.supplier);
- }
- return false;
- }
-
- @Override public int hashCode() {
- return Objects.hashCode(function, supplier);
- }
-
- @Override public String toString() {
- return "Suppliers.compose(" + function + ", " + supplier + ")";
- }
-
private static final long serialVersionUID = 0;
}
@@ -117,7 +100,8 @@ public final class Suppliers {
this.delegate = delegate;
}
- @Override public T get() {
+ @Override
+ public T get() {
// A 2-field variant of Double Checked Locking.
if (!initialized) {
synchronized (this) {
@@ -132,10 +116,6 @@ public final class Suppliers {
return value;
}
- @Override public String toString() {
- return "Suppliers.memoize(" + delegate + ")";
- }
-
private static final long serialVersionUID = 0;
}
@@ -177,7 +157,8 @@ public final class Suppliers {
Preconditions.checkArgument(duration > 0);
}
- @Override public T get() {
+ @Override
+ public T get() {
// Another variant of Double Checked Locking.
//
// We use two volatile reads. We could reduce this to one by
@@ -202,13 +183,6 @@ public final class Suppliers {
return value;
}
- @Override public String toString() {
- // This is a little strange if the unit the user provided was not NANOS,
- // but we don't want to store the unit just for toString
- return "Suppliers.memoizeWithExpiration(" + delegate + ", " +
- durationNanos + ", NANOS)";
- }
-
private static final long serialVersionUID = 0;
}
@@ -226,27 +200,10 @@ public final class Suppliers {
SupplierOfInstance(@Nullable T instance) {
this.instance = instance;
}
-
- @Override public T get() {
+ @Override
+ public T get() {
return instance;
}
-
- @Override public boolean equals(@Nullable Object obj) {
- if (obj instanceof SupplierOfInstance) {
- SupplierOfInstance<?> that = (SupplierOfInstance<?>) obj;
- return Objects.equal(instance, that.instance);
- }
- return false;
- }
-
- @Override public int hashCode() {
- return Objects.hashCode(instance);
- }
-
- @Override public String toString() {
- return "Suppliers.ofInstance(" + instance + ")";
- }
-
private static final long serialVersionUID = 0;
}
@@ -265,17 +222,12 @@ public final class Suppliers {
ThreadSafeSupplier(Supplier<T> delegate) {
this.delegate = delegate;
}
-
- @Override public T get() {
+ @Override
+ public T get() {
synchronized (delegate) {
return delegate.get();
}
}
-
- @Override public String toString() {
- return "Suppliers.synchronizedSupplier(" + delegate + ")";
- }
-
private static final long serialVersionUID = 0;
}
@@ -286,8 +238,7 @@ public final class Suppliers {
* @since 8.0
*/
@Beta
- //SupplierFunction works for any T.
- @SuppressWarnings({"unchecked", "rawtypes"})
+ @SuppressWarnings("unchecked") // SupplierFunction works for any T.
public static <T> Function<Supplier<T>, T> supplierFunction() {
return (Function) SupplierFunction.INSTANCE;
}
@@ -295,12 +246,9 @@ public final class Suppliers {
private enum SupplierFunction implements Function<Supplier<?>, Object> {
INSTANCE;
- @Override public Object apply(Supplier<?> input) {
+ @Override
+ public Object apply(Supplier<?> input) {
return input.get();
}
-
- @Override public String toString() {
- return "Suppliers.supplierFunction()";
- }
}
}
diff --git a/guava/src/com/google/common/base/Throwables.java b/guava/src/com/google/common/base/Throwables.java
index 5e4d6ec..793c5f9 100644
--- a/guava/src/com/google/common/base/Throwables.java
+++ b/guava/src/com/google/common/base/Throwables.java
@@ -31,10 +31,6 @@ import javax.annotation.Nullable;
/**
* Static utility methods pertaining to instances of {@link Throwable}.
*
- * <p>See the Guava User Guide entry on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ThrowablesExplained">
- * Throwables</a>.
- *
* @author Kevin Bourrillion
* @author Ben Yu
* @since 1.0
diff --git a/guava/src/com/google/common/base/Ticker.java b/guava/src/com/google/common/base/Ticker.java
index 6c34aef..e074cf1 100644
--- a/guava/src/com/google/common/base/Ticker.java
+++ b/guava/src/com/google/common/base/Ticker.java
@@ -20,11 +20,8 @@ import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
/**
- * A time source; returns a time value representing the number of nanoseconds elapsed since some
- * fixed but arbitrary point in time. Note that most users should use {@link Stopwatch} instead of
- * interacting with this class directly.
- *
- * <p><b>Warning:</b> this interface can only be used to measure elapsed time, not wall time.
+ * A time source; returns a time value representing the number of nanoseconds
+ * elapsed since some fixed but arbitrary point in time.
*
* @author Kevin Bourrillion
* @since 10.0
diff --git a/guava/src/com/google/common/base/internal/Finalizer.java b/guava/src/com/google/common/base/internal/Finalizer.java
index ebef272..6be4eec 100644
--- a/guava/src/com/google/common/base/internal/Finalizer.java
+++ b/guava/src/com/google/common/base/internal/Finalizer.java
@@ -46,7 +46,7 @@ import java.util.logging.Logger;
* class loader from getting garbage collected, and this class can detect when
* the main class loader has been garbage collected and stop itself.
*/
-public class Finalizer implements Runnable {
+public class Finalizer extends Thread {
private static final Logger logger
= Logger.getLogger(Finalizer.class.getName());
@@ -59,16 +59,13 @@ public class Finalizer implements Runnable {
* Starts the Finalizer thread. FinalizableReferenceQueue calls this method
* reflectively.
*
- * @param finalizableReferenceClass FinalizableReference.class.
- * @param queue a reference queue that the thread will poll.
- * @param frqReference a phantom reference to the FinalizableReferenceQueue, which will be
- * queued either when the FinalizableReferenceQueue is no longer referenced anywhere, or when
- * its close() method is called.
+ * @param finalizableReferenceClass FinalizableReference.class
+ * @param frq reference to instance of FinalizableReferenceQueue that started
+ * this thread
+ * @return ReferenceQueue which Finalizer will poll
*/
- public static void startFinalizer(
- Class<?> finalizableReferenceClass,
- ReferenceQueue<Object> queue,
- PhantomReference<Object> frqReference) {
+ public static ReferenceQueue<Object> startFinalizer(
+ Class<?> finalizableReferenceClass, Object frq) {
/*
* We use FinalizableReference.class for two things:
*
@@ -82,42 +79,40 @@ public class Finalizer implements Runnable {
"Expected " + FINALIZABLE_REFERENCE + ".");
}
- Finalizer finalizer = new Finalizer(finalizableReferenceClass, queue, frqReference);
- Thread thread = new Thread(finalizer);
- thread.setName(Finalizer.class.getName());
- thread.setDaemon(true);
-
- try {
- if (inheritableThreadLocals != null) {
- inheritableThreadLocals.set(thread, null);
- }
- } catch (Throwable t) {
- logger.log(Level.INFO, "Failed to clear thread local values inherited"
- + " by reference finalizer thread.", t);
- }
-
- thread.start();
+ Finalizer finalizer = new Finalizer(finalizableReferenceClass, frq);
+ finalizer.start();
+ return finalizer.queue;
}
private final WeakReference<Class<?>> finalizableReferenceClassReference;
private final PhantomReference<Object> frqReference;
- private final ReferenceQueue<Object> queue;
+ private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
private static final Field inheritableThreadLocals
= getInheritableThreadLocalsField();
/** Constructs a new finalizer thread. */
- private Finalizer(
- Class<?> finalizableReferenceClass,
- ReferenceQueue<Object> queue,
- PhantomReference<Object> frqReference) {
- this.queue = queue;
+ private Finalizer(Class<?> finalizableReferenceClass, Object frq) {
+ super(Finalizer.class.getName());
this.finalizableReferenceClassReference
= new WeakReference<Class<?>>(finalizableReferenceClass);
// Keep track of the FRQ that started us so we know when to stop.
- this.frqReference = frqReference;
+ this.frqReference = new PhantomReference<Object>(frq, queue);
+
+ setDaemon(true);
+
+ try {
+ if (inheritableThreadLocals != null) {
+ inheritableThreadLocals.set(this, null);
+ }
+ } catch (Throwable t) {
+ logger.log(Level.INFO, "Failed to clear thread local values inherited"
+ + " by reference finalizer thread.", t);
+ }
+
+ // TODO(fry): Priority?
}
/**
@@ -208,5 +203,5 @@ public class Finalizer implements Runnable {
/** Indicates that it's time to shut down the Finalizer. */
@SuppressWarnings("serial") // Never serialized or thrown out of this class.
- private static class ShutDown extends Exception {}
+ private static class ShutDown extends Exception { }
}
diff --git a/guava/src/com/google/common/base/package-info.java b/guava/src/com/google/common/base/package-info.java
index c18bd58..66e7177 100644
--- a/guava/src/com/google/common/base/package-info.java
+++ b/guava/src/com/google/common/base/package-info.java
@@ -41,7 +41,8 @@
* {@link com.google.common.base.Functions}
* <li>{@link com.google.common.base.Predicate},
* {@link com.google.common.base.Predicates}
- * <li>{@link com.google.common.base.Equivalence}
+ * <li>{@link com.google.common.base.Equivalence},
+ * {@link com.google.common.base.Equivalences}
* <li>{@link com.google.common.base.Supplier},
* {@link com.google.common.base.Suppliers}
* </ul>
diff --git a/guava/src/com/google/common/cache/AbstractCache.java b/guava/src/com/google/common/cache/AbstractCache.java
index a8af810..8ce941d 100644
--- a/guava/src/com/google/common/cache/AbstractCache.java
+++ b/guava/src/com/google/common/cache/AbstractCache.java
@@ -20,21 +20,22 @@ import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.UncheckedExecutionException;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicLong;
/**
* This class provides a skeletal implementation of the {@code Cache} interface to minimize the
* effort required to implement this interface.
*
* <p>To implement a cache, the programmer needs only to extend this class and provide an
- * implementation for the {@link #put} and {@link #getIfPresent} methods. {@link #getAllPresent} is
- * implemented in terms of {@link #getIfPresent}; {@link #putAll} is implemented in terms of
- * {@link #put}, {@link #invalidateAll(Iterable)} is implemented in terms of {@link #invalidate}.
- * The method {@link #cleanUp} is a no-op. All other methods throw an
+ * implementation for the {@link #getIfPresent} method. {@link #getAllPresent} is implemented in
+ * terms of {@code getIfPresent}; {@link #invalidateAll(Iterable)} is implemented in terms of
+ * {@link #invalidate}. The method {@link #cleanUp} is a no-op. All other methods throw an
* {@link UnsupportedOperationException}.
*
* @author Charles Fry
@@ -56,22 +57,14 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
}
/**
- * This implementation of {@code getAllPresent} lacks any insight into the internal cache data
- * structure, and is thus forced to return the query keys instead of the cached keys. This is only
- * possible with an unsafe cast which requires {@code keys} to actually be of type {@code K}.
- *
- * {@inheritDoc}
- *
* @since 11.0
*/
@Override
- public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) {
+ public ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys) {
Map<K, V> result = Maps.newLinkedHashMap();
- for (Object key : keys) {
+ for (K key : keys) {
if (!result.containsKey(key)) {
- @SuppressWarnings("unchecked")
- K castKey = (K) key;
- result.put(castKey, getIfPresent(key));
+ result.put(key, getIfPresent(key));
}
}
return ImmutableMap.copyOf(result);
@@ -85,16 +78,6 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
throw new UnsupportedOperationException();
}
- /**
- * @since 12.0
- */
- @Override
- public void putAll(Map<? extends K, ? extends V> m) {
- for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
- put(entry.getKey(), entry.getValue());
- }
- }
-
@Override
public void cleanUp() {}
@@ -133,6 +116,22 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
throw new UnsupportedOperationException();
}
+ @Deprecated
+ @Override
+ public V getUnchecked(K key) {
+ try {
+ return get(key);
+ } catch (ExecutionException e) {
+ throw new UncheckedExecutionException(e.getCause());
+ }
+ }
+
+ @Deprecated
+ @Override
+ public V apply(K key) {
+ return getUnchecked(key);
+ }
+
/**
* Accumulates statistics during the operation of a {@link Cache} for presentation by {@link
* Cache#stats}. This is solely intended for consumption by {@code Cache} implementors.
@@ -165,7 +164,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
/**
* Records the successful load of a new entry. This should be called when a cache request
* causes an entry to be loaded, and the loading completes successfully. In contrast to
- * {@link #recordMisses}, this method should only be called by the loading thread.
+ * {@link #recordConcurrentMiss}, this method should only be called by the loading thread.
*
* @param loadTime the number of nanoseconds the cache spent computing or retrieving the new
* value
@@ -175,7 +174,7 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
/**
* Records the failed load of a new entry. This should be called when a cache request causes
* an entry to be loaded, but an exception is thrown while loading the entry. In contrast to
- * {@link #recordMisses}, this method should only be called by the loading thread.
+ * {@link #recordConcurrentMiss}, this method should only be called by the loading thread.
*
* @param loadTime the number of nanoseconds the cache spent computing or retrieving the new
* value prior to an exception being thrown
@@ -202,25 +201,20 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
* @since 10.0
*/
@Beta
- public static final class SimpleStatsCounter implements StatsCounter {
- private final LongAddable hitCount = LongAddables.create();
- private final LongAddable missCount = LongAddables.create();
- private final LongAddable loadSuccessCount = LongAddables.create();
- private final LongAddable loadExceptionCount = LongAddables.create();
- private final LongAddable totalLoadTime = LongAddables.create();
- private final LongAddable evictionCount = LongAddables.create();
-
- /**
- * Constructs an instance with all counts initialized to zero.
- */
- public SimpleStatsCounter() {}
+ public static class SimpleStatsCounter implements StatsCounter {
+ private final AtomicLong hitCount = new AtomicLong();
+ private final AtomicLong missCount = new AtomicLong();
+ private final AtomicLong loadSuccessCount = new AtomicLong();
+ private final AtomicLong loadExceptionCount = new AtomicLong();
+ private final AtomicLong totalLoadTime = new AtomicLong();
+ private final AtomicLong evictionCount = new AtomicLong();
/**
* @since 11.0
*/
@Override
public void recordHits(int count) {
- hitCount.add(count);
+ hitCount.addAndGet(count);
}
/**
@@ -228,35 +222,35 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
*/
@Override
public void recordMisses(int count) {
- missCount.add(count);
+ missCount.addAndGet(count);
}
@Override
public void recordLoadSuccess(long loadTime) {
- loadSuccessCount.increment();
- totalLoadTime.add(loadTime);
+ loadSuccessCount.incrementAndGet();
+ totalLoadTime.addAndGet(loadTime);
}
@Override
public void recordLoadException(long loadTime) {
- loadExceptionCount.increment();
- totalLoadTime.add(loadTime);
+ loadExceptionCount.incrementAndGet();
+ totalLoadTime.addAndGet(loadTime);
}
@Override
public void recordEviction() {
- evictionCount.increment();
+ evictionCount.incrementAndGet();
}
@Override
public CacheStats snapshot() {
return new CacheStats(
- hitCount.sum(),
- missCount.sum(),
- loadSuccessCount.sum(),
- loadExceptionCount.sum(),
- totalLoadTime.sum(),
- evictionCount.sum());
+ hitCount.get(),
+ missCount.get(),
+ loadSuccessCount.get(),
+ loadExceptionCount.get(),
+ totalLoadTime.get(),
+ evictionCount.get());
}
/**
@@ -264,12 +258,12 @@ public abstract class AbstractCache<K, V> implements Cache<K, V> {
*/
public void incrementBy(StatsCounter other) {
CacheStats otherStats = other.snapshot();
- hitCount.add(otherStats.hitCount());
- missCount.add(otherStats.missCount());
- loadSuccessCount.add(otherStats.loadSuccessCount());
- loadExceptionCount.add(otherStats.loadExceptionCount());
- totalLoadTime.add(otherStats.totalLoadTime());
- evictionCount.add(otherStats.evictionCount());
+ hitCount.addAndGet(otherStats.hitCount());
+ missCount.addAndGet(otherStats.missCount());
+ loadSuccessCount.addAndGet(otherStats.loadSuccessCount());
+ loadExceptionCount.addAndGet(otherStats.loadExceptionCount());
+ totalLoadTime.addAndGet(otherStats.totalLoadTime());
+ evictionCount.addAndGet(otherStats.evictionCount());
}
}
}
diff --git a/guava/src/com/google/common/cache/AbstractLoadingCache.java b/guava/src/com/google/common/cache/AbstractLoadingCache.java
index 6a12c40..22ef81b 100644
--- a/guava/src/com/google/common/cache/AbstractLoadingCache.java
+++ b/guava/src/com/google/common/cache/AbstractLoadingCache.java
@@ -30,11 +30,10 @@ import java.util.concurrent.ExecutionException;
* effort required to implement this interface.
*
* <p>To implement a cache, the programmer needs only to extend this class and provide an
- * implementation for the {@link #get(Object)} and {@link #getIfPresent} methods.
- * {@link #getUnchecked}, {@link #get(Object, Callable)}, and {@link #getAll} are implemented in
- * terms of {@code get}; {@link #getAllPresent} is implemented in terms of {@code getIfPresent};
- * {@link #putAll} is implemented in terms of {@link #put}, {@link #invalidateAll(Iterable)} is
- * implemented in terms of {@link #invalidate}. The method {@link #cleanUp} is a no-op. All other
+ * implementation for the {@link #get} and {@link #getIfPresent} methods. {@link #getUnchecked},
+ * {@link #get(K, Callable)}, and {@link #getAll} are implemented in terms of {@code get};
+ * {@link #getAllPresent} is implemented in terms of {@code get}; {@link #invalidateAll(Iterable)}
+ * is implemented in terms of {@link #invalidate}. The method {@link #cleanUp} is a no-op. All other
* methods throw an {@link UnsupportedOperationException}.
*
* @author Charles Fry
diff --git a/guava/src/com/google/common/cache/Cache.java b/guava/src/com/google/common/cache/Cache.java
index cfe5764..f243adc 100644
--- a/guava/src/com/google/common/cache/Cache.java
+++ b/guava/src/com/google/common/cache/Cache.java
@@ -18,11 +18,11 @@ package com.google.common.cache;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ExecutionError;
import com.google.common.util.concurrent.UncheckedExecutionException;
-import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
@@ -31,23 +31,24 @@ import javax.annotation.Nullable;
/**
* A semi-persistent mapping from keys to values. Cache entries are manually added using
- * {@link #get(Object, Callable)} or {@link #put(Object, Object)}, and are stored in the cache until
- * either evicted or manually invalidated.
+ * {@link #get(K, Callable)} or {@link #put(K, V)}, and are stored in the cache until either
+ * evicted or manually invalidated.
+ *
+ * <p><b>Note:</b> in release 12.0, all methods moved from {@code Cache} to {@link LoadingCache}
+ * will be deleted from {@code Cache}. As part of this transition {@code Cache} will no longer
+ * extend {@link Function}.
*
* <p>Implementations of this interface are expected to be thread-safe, and can be safely accessed
* by multiple concurrent threads.
*
- * <p>Note that while this class is still annotated as {@link Beta}, the API is frozen from a
- * consumer's standpoint. In other words existing methods are all considered {@code non-Beta} and
- * won't be changed without going through an 18 month deprecation cycle; however new methods may be
- * added at any time.
+ * <p>All methods other than {@link #getIfPresent} are optional.
*
* @author Charles Fry
* @since 10.0
*/
@Beta
@GwtCompatible
-public interface Cache<K, V> {
+public interface Cache<K, V> extends Function<K, V> {
/**
* Returns the value associated with {@code key} in this cache, or {@code null} if there is no
@@ -56,7 +57,7 @@ public interface Cache<K, V> {
* @since 11.0
*/
@Nullable
- V getIfPresent(Object key);
+ V getIfPresent(K key);
/**
* Returns the value associated with {@code key} in this cache, obtaining that value from
@@ -82,7 +83,7 @@ public interface Cache<K, V> {
*
* @since 11.0
*/
- ImmutableMap<K, V> getAllPresent(Iterable<?> keys);
+ ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys);
/**
* Associates {@code value} with {@code key} in this cache. If the cache previously contained a
@@ -96,16 +97,6 @@ public interface Cache<K, V> {
void put(K key, V value);
/**
- * Copies all of the mappings from the specified map to the cache. The effect of this call is
- * equivalent to that of calling {@code put(k, v)} on this map once for each mapping from key
- * {@code k} to value {@code v} in the specified map. The behavior of this operation is undefined
- * if the specified map is modified while the operation is in progress.
- *
- * @since 12.0
- */
- void putAll(Map<? extends K,? extends V> m);
-
- /**
* Discards any cached value for key {@code key}.
*/
void invalidate(Object key);
@@ -144,4 +135,55 @@ public interface Cache<K, V> {
* performed -- if any -- is implementation-dependent.
*/
void cleanUp();
+
+ /**
+ * Returns the value associated with {@code key} in this cache, first loading that value if
+ * necessary. No observable state associated with this cache is modified until loading completes.
+ *
+ * @throws ExecutionException if a checked exception was thrown while loading the value
+ * @throws UncheckedExecutionException if an unchecked exception was thrown while loading the
+ * value
+ * @throws ExecutionError if an error was thrown while loading the value
+ * @deprecated This method has been split out into the {@link LoadingCache} interface, and will be
+ * removed from {@code Cache} in Guava release 12.0. Note that
+ * {@link CacheBuilder#build(CacheLoader)} now returns a {@code LoadingCache}, so this deprecation
+ * (migration) can be dealt with by simply changing the type of references to the results of
+ * {@link CacheBuilder#build(CacheLoader)}.
+ */
+ @Deprecated V get(K key) throws ExecutionException;
+
+ /**
+ * Returns the value associated with {@code key} in this cache, first loading that value if
+ * necessary. No observable state associated with this cache is modified until computation
+ * completes. Unlike {@link #get}, this method does not throw a checked exception, and thus should
+ * only be used in situations where checked exceptions are not thrown by the cache loader.
+ *
+ * <p><b>Warning:</b> this method silently converts checked exceptions to unchecked exceptions,
+ * and should not be used with cache loaders which throw checked exceptions.
+ *
+ * @throws UncheckedExecutionException if an exception was thrown while loading the value,
+ * regardless of whether the exception was checked or unchecked
+ * @throws ExecutionError if an error was thrown while loading the value
+ * @deprecated This method has been split out into the {@link LoadingCache} interface, and will be
+ * removed from {@code Cache} in Guava release 12.0. Note that
+ * {@link CacheBuilder#build(CacheLoader)} now returns a {@code LoadingCache}, so this deprecation
+ * (migration) can be dealt with by simply changing the type of references to the results of
+ * {@link CacheBuilder#build(CacheLoader)}.
+ */
+ @Deprecated V getUnchecked(K key);
+
+ /**
+ * Discouraged. Provided to satisfy the {@code Function} interface; use {@link #get} or
+ * {@link #getUnchecked} instead.
+ *
+ * @throws UncheckedExecutionException if an exception was thrown while loading the value,
+ * regardless of whether the exception was checked or unchecked
+ * @throws ExecutionError if an error was thrown while loading the value
+ * @deprecated This method has been split out into the {@link LoadingCache} interface, and will be
+ * removed from {@code Cache} in Guava release 12.0. Note that
+ * {@link CacheBuilder#build(CacheLoader)} now returns a {@code LoadingCache}, so this deprecation
+ * (migration) can be dealt with by simply changing the type of references to the results of
+ * {@link CacheBuilder#build(CacheLoader)}.
+ */
+ @Deprecated V apply(K key);
}
diff --git a/guava/src/com/google/common/cache/CacheBuilder.java b/guava/src/com/google/common/cache/CacheBuilder.java
index 105ff73..8eef200 100644
--- a/guava/src/com/google/common/cache/CacheBuilder.java
+++ b/guava/src/com/google/common/cache/CacheBuilder.java
@@ -26,6 +26,7 @@ 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.Objects;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
@@ -56,12 +57,8 @@ import javax.annotation.CheckReturnValue;
* <li>values automatically wrapped in {@linkplain WeakReference weak} or
* {@linkplain SoftReference soft} references
* <li>notification of evicted (or otherwise removed) entries
- * <li>accumulation of cache access statistics
* </ul>
*
- * These features are all optional; caches can be created using all or none of them. By default
- * cache instances created by {@code CacheBuilder} will not perform any type of eviction.
- *
* <p>Usage example: <pre> {@code
*
* LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
@@ -75,19 +72,8 @@ import javax.annotation.CheckReturnValue;
* }
* });}</pre>
*
- * Or equivalently, <pre> {@code
- *
- * // In real life this would come from a command-line flag or config file
- * String spec = "maximumSize=10000,expireAfterWrite=10m";
*
- * LoadingCache<Key, Graph> graphs = CacheBuilder.from(spec)
- * .removalListener(MY_LISTENER)
- * .build(
- * new CacheLoader<Key, Graph>() {
- * public Graph load(Key key) throws AnyException {
- * return createExpensiveGraph(key);
- * }
- * });}</pre>
+ * These features are all optional.
*
* <p>The returned cache is implemented as a hash table with similar performance characteristics to
* {@link ConcurrentHashMap}. It implements all optional operations of the {@link LoadingCache} and
@@ -139,16 +125,13 @@ import javax.annotation.CheckReturnValue;
* retain all the configuration properties of the original cache. Note that the serialized form does
* <i>not</i> include cache contents, but only configuration.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CachesExplained">caching</a> for a higher-level
- * explanation.
- *
* @param <K> the base key type for all caches created by this builder
* @param <V> the base value type for all caches created by this builder
* @author Charles Fry
* @author Kevin Bourrillion
* @since 10.0
*/
+@Beta
@GwtCompatible(emulated = true)
public final class CacheBuilder<K, V> {
private static final int DEFAULT_INITIAL_CAPACITY = 16;
@@ -180,10 +163,10 @@ public final class CacheBuilder<K, V> {
});
static final CacheStats EMPTY_STATS = new CacheStats(0, 0, 0, 0, 0, 0);
- static final Supplier<StatsCounter> CACHE_STATS_COUNTER =
- new Supplier<StatsCounter>() {
+ static final Supplier<SimpleStatsCounter> CACHE_STATS_COUNTER =
+ new Supplier<SimpleStatsCounter>() {
@Override
- public StatsCounter get() {
+ public SimpleStatsCounter get() {
return new SimpleStatsCounter();
}
};
@@ -236,7 +219,7 @@ public final class CacheBuilder<K, V> {
RemovalListener<? super K, ? super V> removalListener;
Ticker ticker;
- Supplier<? extends StatsCounter> statsCounterSupplier = NULL_STATS_COUNTER;
+ Supplier<? extends StatsCounter> statsCounterSupplier = CACHE_STATS_COUNTER;
// TODO(fry): make constructor private and update tests to use newBuilder
CacheBuilder() {}
@@ -250,34 +233,8 @@ public final class CacheBuilder<K, V> {
}
/**
- * Constructs a new {@code CacheBuilder} instance with the settings specified in {@code spec}.
- *
- * @since 12.0
- */
- @Beta
- @GwtIncompatible("To be supported")
- public static CacheBuilder<Object, Object> from(CacheBuilderSpec spec) {
- return spec.toCacheBuilder()
- .lenientParsing();
- }
-
- /**
- * Constructs a new {@code CacheBuilder} instance with the settings specified in {@code spec}.
- * This is especially useful for command-line configuration of a {@code CacheBuilder}.
- *
- * @param spec a String in the format specified by {@link CacheBuilderSpec}
- * @since 12.0
- */
- @Beta
- @GwtIncompatible("To be supported")
- public static CacheBuilder<Object, Object> from(String spec) {
- return from(CacheBuilderSpec.parse(spec));
- }
-
- /**
* Enables lenient parsing. Useful for tests and spec parsing.
*/
- @GwtIncompatible("To be supported")
CacheBuilder<K, V> lenientParsing() {
strictParsing = false;
return this;
@@ -286,10 +243,9 @@ public final class CacheBuilder<K, V> {
/**
* Sets a custom {@code Equivalence} strategy for comparing keys.
*
- * <p>By default, the cache uses {@link Equivalence#identity} to determine key equality when
- * {@link #weakKeys} is specified, and {@link Equivalence#equals()} otherwise.
+ * <p>By default, the cache uses {@link Equivalences#identity} to determine key equality when
+ * {@link #weakKeys} is specified, and {@link Equivalences#equals()} otherwise.
*/
- @GwtIncompatible("To be supported")
CacheBuilder<K, V> keyEquivalence(Equivalence<Object> equivalence) {
checkState(keyEquivalence == null, "key equivalence was already set to %s", keyEquivalence);
keyEquivalence = checkNotNull(equivalence);
@@ -303,11 +259,10 @@ public final class CacheBuilder<K, V> {
/**
* Sets a custom {@code Equivalence} strategy for comparing values.
*
- * <p>By default, the cache uses {@link Equivalence#identity} to determine value equality when
- * {@link #weakValues} or {@link #softValues} is specified, and {@link Equivalence#equals()}
+ * <p>By default, the cache 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")
CacheBuilder<K, V> valueEquivalence(Equivalence<Object> equivalence) {
checkState(valueEquivalence == null,
"value equivalence was already set to %s", valueEquivalence);
@@ -350,23 +305,11 @@ public final class CacheBuilder<K, V> {
* higher value than you need can waste space and time, and a significantly lower value can lead
* to thread contention. But overestimates and underestimates within an order of magnitude do not
* usually have much noticeable impact. A value of one permits only one thread to modify the cache
- * at a time, but since read operations and cache loading computations can proceed concurrently,
- * this still yields higher concurrency than full synchronization.
- *
- * <p> Defaults to 4. <b>Note:</b>The default may change in the future. If you care about this
- * value, you should always choose it explicitly.
- *
- * <p>The current implementation uses the concurrency level to create a fixed number of hashtable
- * segments, each governed by its own write lock. The segment lock is taken once for each explicit
- * write, and twice for each cache loading computation (once prior to loading the new value,
- * and once after loading completes). Much internal cache management is performed at the segment
- * granularity. For example, access queues and write queues are kept per segment when they are
- * required by the selected eviction algorithm. As such, when writing unit tests it is not
- * uncommon to specify {@code concurrencyLevel(1)} in order to achieve more deterministic eviction
- * behavior.
+ * at a time, but since read operations can proceed concurrently, this still yields higher
+ * concurrency than full synchronization. Defaults to 4.
*
- * <p>Note that future implementations may abandon segment locking in favor of more advanced
- * concurrency controls.
+ * <p><b>Note:</b>The default may change in the future. If you care about this value, you should
+ * always choose it explicitly.
*
* @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive
* @throws IllegalStateException if a concurrency level was already set
@@ -392,11 +335,9 @@ public final class CacheBuilder<K, V> {
* <p>When {@code size} is zero, elements will be evicted immediately after being loaded into the
* cache. This can be useful in testing, or to disable caching temporarily without a code change.
*
- * <p>This feature cannot be used in conjunction with {@link #maximumWeight}.
- *
* @param size the maximum size of the cache
* @throws IllegalArgumentException if {@code size} is negative
- * @throws IllegalStateException if a maximum size or weight was already set
+ * @throws IllegalStateException if a maximum size was already set
*/
public CacheBuilder<K, V> maximumSize(long size) {
checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
@@ -423,17 +364,11 @@ public final class CacheBuilder<K, V> {
* cache. This can be useful in testing, or to disable caching temporarily without a code
* change.
*
- * <p>Note that weight is only used to determine whether the cache is over capacity; it has no
- * effect on selecting which entry should be evicted next.
- *
- * <p>This feature cannot be used in conjunction with {@link #maximumSize}.
- *
- * @param weight the maximum total weight of entries the cache may contain
- * @throws IllegalArgumentException if {@code weight} is negative
- * @throws IllegalStateException if a maximum weight or size was already set
+ * @param weight the maximum weight the cache may contain
+ * @throws IllegalArgumentException if {@code size} is negative
+ * @throws IllegalStateException if a maximum size was already set
* @since 11.0
*/
- @GwtIncompatible("To be supported")
public CacheBuilder<K, V> maximumWeight(long weight) {
checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s",
this.maximumWeight);
@@ -472,7 +407,6 @@ public final class CacheBuilder<K, V> {
* @throws IllegalStateException if a maximum size was already set
* @since 11.0
*/
- @GwtIncompatible("To be supported")
public <K1 extends K, V1 extends V> CacheBuilder<K1, V1> weigher(
Weigher<? super K1, ? super V1> weigher) {
checkState(this.weigher == null);
@@ -502,6 +436,15 @@ public final class CacheBuilder<K, V> {
}
/**
+ * Specifies that each key (not value) stored in the cache should be strongly referenced.
+ *
+ * @throws IllegalStateException if the key strength was already set
+ */
+ CacheBuilder<K, V> strongKeys() {
+ return setKeyStrength(Strength.STRONG);
+ }
+
+ /**
* Specifies that each key (not value) stored in the cache should be wrapped in a {@link
* WeakReference} (by default, strong references are used).
*
@@ -530,6 +473,15 @@ public final class CacheBuilder<K, V> {
}
/**
+ * Specifies that each value (not key) stored in the cache should be strongly referenced.
+ *
+ * @throws IllegalStateException if the value strength was already set
+ */
+ CacheBuilder<K, V> strongValues() {
+ return setValueStrength(Strength.STRONG);
+ }
+
+ /**
* Specifies that each value (not key) stored in the cache should be wrapped in a
* {@link WeakReference} (by default, strong references are used).
*
@@ -657,9 +609,8 @@ public final class CacheBuilder<K, V> {
* {@link CacheLoader#reload}.
*
* <p>As the default implementation of {@link CacheLoader#reload} is synchronous, it is
- * recommended that users of this method override {@link CacheLoader#reload} with an asynchronous
- * implementation; otherwise refreshes will be performed during unrelated cache read and write
- * operations.
+ * recommended that users of this method override {@link CacheLoader#reload} with an asynchrnous
+ * implementation; otherwise refreshes will block other cache operations.
*
* <p>Currently automatic refreshes are performed when the first stale request for an entry
* occurs. The request triggering refresh will make a blocking call to {@link CacheLoader#reload}
@@ -675,8 +626,7 @@ public final class CacheBuilder<K, V> {
* @throws IllegalStateException if the refresh interval was already set
* @since 11.0
*/
- @Beta
- @GwtIncompatible("To be supported (synchronously).")
+ @GwtIncompatible("To be supported")
public CacheBuilder<K, V> refreshAfterWrite(long duration, TimeUnit unit) {
checkNotNull(unit);
checkState(refreshNanos == UNSET_INT, "refresh was already set to %s ns", refreshNanos);
@@ -698,6 +648,7 @@ public final class CacheBuilder<K, V> {
*
* @throws IllegalStateException if a ticker was already set
*/
+ @GwtIncompatible("To be supported")
public CacheBuilder<K, V> ticker(Ticker ticker) {
checkState(this.ticker == null);
this.ticker = checkNotNull(ticker);
@@ -712,27 +663,34 @@ public final class CacheBuilder<K, V> {
}
/**
- * Specifies a listener instance that caches should notify each time an entry is removed for any
- * {@linkplain RemovalCause reason}. Each cache created by this builder will invoke this listener
- * as part of the routine maintenance described in the class documentation above.
- *
- * <p><b>Warning:</b> after invoking this method, do not continue to use <i>this</i> cache
- * builder reference; instead use the reference this method <i>returns</i>. At runtime, these
- * point to the same instance, but only the returned reference has the correct generic type
- * information so as to ensure type safety. For best results, use the standard method-chaining
- * idiom illustrated in the class documentation above, configuring a builder and building your
- * cache in a single statement. Failure to heed this advice can result in a {@link
- * ClassCastException} being thrown by a cache operation at some <i>undefined</i> point in the
- * future.
- *
- * <p><b>Warning:</b> any exception thrown by {@code listener} will <i>not</i> be propagated to
- * the {@code Cache} user, only logged via a {@link Logger}.
- *
- * @return the cache builder reference that should be used instead of {@code this} for any
- * remaining configuration and cache building
+ * Specifies a listener instance, which all caches built using this {@code CacheBuilder} will
+ * notify each time an entry is removed from the cache by any means.
+ *
+ * <p>Each cache built by this {@code CacheBuilder} after this method is called invokes the
+ * supplied listener after removing an element for any reason (see removal causes in {@link
+ * RemovalCause}). It will invoke the listener as part of the routine maintenance described
+ * in the class javadoc.
+ *
+ * <p><b>Note:</b> <i>all exceptions thrown by {@code listener} will be logged (using
+ * {@link java.util.logging.Logger})and then swallowed</i>.
+ *
+ * <p><b>Important note:</b> Instead of returning <em>this</em> as a {@code CacheBuilder}
+ * instance, this method returns {@code CacheBuilder<K1, V1>}. From this point on, either the
+ * original reference or the returned reference may be used to complete configuration and build
+ * the cache, but only the "generic" one is type-safe. That is, it will properly prevent you from
+ * building caches whose key or value types are incompatible with the types accepted by the
+ * listener already provided; the {@code CacheBuilder} type cannot do this. For best results,
+ * simply use the standard method-chaining idiom, as illustrated in the documentation at top,
+ * configuring a {@code CacheBuilder} and building your {@link Cache} all in a single statement.
+ *
+ * <p><b>Warning:</b> if you ignore the above advice, and use this {@code CacheBuilder} to build
+ * a cache whose key or value type is incompatible with the listener, you will likely experience
+ * a {@link ClassCastException} at some <i>undefined</i> point in the future.
+ *
* @throws IllegalStateException if a removal listener was already set
*/
@CheckReturnValue
+ @GwtIncompatible("To be supported")
public <K1 extends K, V1 extends V> CacheBuilder<K1, V1> removalListener(
RemovalListener<? super K1, ? super V1> listener) {
checkState(this.removalListener == null);
@@ -751,15 +709,11 @@ public final class CacheBuilder<K, V> {
}
/**
- * Enable the accumulation of {@link CacheStats} during the operation of the cache. Without this
- * {@link Cache#stats} will return zero for all statistics. Note that recording stats requires
- * bookkeeping to be performed with each operation, and thus imposes a performance penalty on
- * cache operation.
- *
- * @since 12.0 (previously, stats collection was automatic)
+ * Disable the accumulation of {@link CacheStats} during the operation of the cache.
*/
- public CacheBuilder<K, V> recordStats() {
- statsCounterSupplier = CACHE_STATS_COUNTER;
+ CacheBuilder<K, V> disableStats() {
+ checkState(statsCounterSupplier == CACHE_STATS_COUNTER);
+ statsCounterSupplier = NULL_STATS_COUNTER;
return this;
}
@@ -834,11 +788,12 @@ public final class CacheBuilder<K, V> {
if (concurrencyLevel != UNSET_INT) {
s.add("concurrencyLevel", concurrencyLevel);
}
- if (maximumSize != UNSET_INT) {
- s.add("maximumSize", maximumSize);
- }
if (maximumWeight != UNSET_INT) {
- s.add("maximumWeight", maximumWeight);
+ if (weigher == null) {
+ s.add("maximumSize", maximumWeight);
+ } else {
+ s.add("maximumWeight", maximumWeight);
+ }
}
if (expireAfterWriteNanos != UNSET_INT) {
s.add("expireAfterWrite", expireAfterWriteNanos + "ns");
diff --git a/guava/src/com/google/common/cache/CacheBuilderSpec.java b/guava/src/com/google/common/cache/CacheBuilderSpec.java
deleted file mode 100644
index 1e03335..0000000
--- a/guava/src/com/google/common/cache/CacheBuilderSpec.java
+++ /dev/null
@@ -1,455 +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.cache;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import com.google.common.base.Splitter;
-import com.google.common.cache.LocalCache.Strength;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import javax.annotation.Nullable;
-
-/**
- * A specification of a {@link CacheBuilder} configuration.
- *
- * <p>{@code CacheBuilderSpec} supports parsing configuration off of a string, which
- * makes it especially useful for command-line configuration of a {@code CacheBuilder}.
- *
- * <p>The string syntax is a series of comma-separated keys or key-value pairs,
- * each corresponding to a {@code CacheBuilder} method.
- * <ul>
- * <li>{@code concurrencyLevel=[integer]}: sets {@link CacheBuilder#concurrencyLevel}.
- * <li>{@code initialCapacity=[integer]}: sets {@link CacheBuilder#initialCapacity}.
- * <li>{@code maximumSize=[long]}: sets {@link CacheBuilder#maximumSize}.
- * <li>{@code maximumWeight=[long]}: sets {@link CacheBuilder#maximumWeight}.
- * <li>{@code expireAfterAccess=[duration]}: sets {@link CacheBuilder#expireAfterAccess}.
- * <li>{@code expireAfterWrite=[duration]}: sets {@link CacheBuilder#expireAfterWrite}.
- * <li>{@code refreshAfterWrite=[duration]}: sets {@link CacheBuilder#refreshAfterWrite}.
- * <li>{@code weakKeys}: sets {@link CacheBuilder#weakKeys}.
- * <li>{@code softValues}: sets {@link CacheBuilder#softValues}.
- * <li>{@code weakValues}: sets {@link CacheBuilder#weakValues}.
- * </ul>
- *
- * The set of supported keys will grow as {@code CacheBuilder} evolves, but existing keys
- * will never be removed.
- *
- * <p>Durations are represented by an integer, followed by one of "d", "h", "m",
- * or "s", representing days, hours, minutes, or seconds respectively. (There
- * is currently no syntax to request expiration in milliseconds, microseconds,
- * or nanoseconds.)
- *
- * <p>Whitespace before and after commas and equal signs is ignored. Keys may
- * not be repeated; it is also illegal to use the following pairs of keys in
- * a single value:
- * <ul>
- * <li>{@code maximumSize} and {@code maximumWeight}
- * <li>{@code softValues} and {@code weakValues}
- * </ul>
- *
- * <p>{@code CacheBuilderSpec} does not support configuring {@code CacheBuilder} methods
- * with non-value parameters. These must be configured in code.
- *
- * <p>A new {@code CacheBuilder} can be instantiated from a {@code CacheBuilderSpec} using
- * {@link CacheBuilder#from(CacheBuilderSpec)} or {@link CacheBuilder#from(String)}.
- *
- * @author Adam Winer
- * @since 12.0
- */
-@Beta
-public final class CacheBuilderSpec {
- /** Parses a single value. */
- private interface ValueParser {
- void parse(CacheBuilderSpec spec, String key, @Nullable String value);
- }
-
- /** Splits each key-value pair. */
- private static final Splitter KEYS_SPLITTER = Splitter.on(',').trimResults();
-
- /** Splits the key from the value. */
- private static final Splitter KEY_VALUE_SPLITTER = Splitter.on('=').trimResults();
-
- /** Map of names to ValueParser. */
- private static final ImmutableMap<String, ValueParser> VALUE_PARSERS =
- ImmutableMap.<String, ValueParser>builder()
- .put("initialCapacity", new InitialCapacityParser())
- .put("maximumSize", new MaximumSizeParser())
- .put("maximumWeight", new MaximumWeightParser())
- .put("concurrencyLevel", new ConcurrencyLevelParser())
- .put("weakKeys", new KeyStrengthParser(Strength.WEAK))
- .put("softValues", new ValueStrengthParser(Strength.SOFT))
- .put("weakValues", new ValueStrengthParser(Strength.WEAK))
- .put("expireAfterAccess", new AccessDurationParser())
- .put("expireAfterWrite", new WriteDurationParser())
- .put("refreshAfterWrite", new RefreshDurationParser())
- .put("refreshInterval", new RefreshDurationParser())
- .build();
-
- @VisibleForTesting Integer initialCapacity;
- @VisibleForTesting Long maximumSize;
- @VisibleForTesting Long maximumWeight;
- @VisibleForTesting Integer concurrencyLevel;
- @VisibleForTesting Strength keyStrength;
- @VisibleForTesting Strength valueStrength;
- @VisibleForTesting long writeExpirationDuration;
- @VisibleForTesting TimeUnit writeExpirationTimeUnit;
- @VisibleForTesting long accessExpirationDuration;
- @VisibleForTesting TimeUnit accessExpirationTimeUnit;
- @VisibleForTesting long refreshDuration;
- @VisibleForTesting TimeUnit refreshTimeUnit;
- /** Specification; used for toParseableString(). */
- private final String specification;
-
- private CacheBuilderSpec(String specification) {
- this.specification = specification;
- }
-
- /**
- * Creates a CacheBuilderSpec from a string.
- *
- * @param cacheBuilderSpecification the string form
- */
- public static CacheBuilderSpec parse(String cacheBuilderSpecification) {
- CacheBuilderSpec spec = new CacheBuilderSpec(cacheBuilderSpecification);
- if (!cacheBuilderSpecification.isEmpty()) {
- for (String keyValuePair : KEYS_SPLITTER.split(cacheBuilderSpecification)) {
- List<String> keyAndValue = ImmutableList.copyOf(KEY_VALUE_SPLITTER.split(keyValuePair));
- checkArgument(!keyAndValue.isEmpty(), "blank key-value pair");
- checkArgument(keyAndValue.size() <= 2,
- "key-value pair %s with more than one equals sign", keyValuePair);
-
- // Find the ValueParser for the current key.
- String key = keyAndValue.get(0);
- ValueParser valueParser = VALUE_PARSERS.get(key);
- checkArgument(valueParser != null, "unknown key %s", key);
-
- String value = keyAndValue.size() == 1 ? null : keyAndValue.get(1);
- valueParser.parse(spec, key, value);
- }
- }
-
- return spec;
- }
-
- /**
- * Returns a CacheBuilderSpec that will prevent caching.
- */
- public static CacheBuilderSpec disableCaching() {
- // Maximum size of zero is one way to block caching
- return CacheBuilderSpec.parse("maximumSize=0");
- }
-
- /**
- * Returns a CacheBuilder configured according to this instance's specification.
- */
- CacheBuilder<Object, Object> toCacheBuilder() {
- CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
- if (initialCapacity != null) {
- builder.initialCapacity(initialCapacity);
- }
- if (maximumSize != null) {
- builder.maximumSize(maximumSize);
- }
- if (maximumWeight != null) {
- builder.maximumWeight(maximumWeight);
- }
- if (concurrencyLevel != null) {
- builder.concurrencyLevel(concurrencyLevel);
- }
- if (keyStrength != null) {
- switch (keyStrength) {
- case WEAK:
- builder.weakKeys();
- break;
- default:
- throw new AssertionError();
- }
- }
- if (valueStrength != null) {
- switch (valueStrength) {
- case SOFT:
- builder.softValues();
- break;
- case WEAK:
- builder.weakValues();
- break;
- default:
- throw new AssertionError();
- }
- }
- if (writeExpirationTimeUnit != null) {
- builder.expireAfterWrite(writeExpirationDuration, writeExpirationTimeUnit);
- }
- if (accessExpirationTimeUnit != null) {
- builder.expireAfterAccess(accessExpirationDuration, accessExpirationTimeUnit);
- }
- if (refreshTimeUnit != null) {
- builder.refreshAfterWrite(refreshDuration, refreshTimeUnit);
- }
-
- return builder;
- }
-
- /**
- * Returns a string that can be used to parse an equivalent
- * {@code CacheBuilderSpec}. The order and form of this representation is
- * not guaranteed, except that reparsing its output will produce
- * a {@code CacheBuilderSpec} equal to this instance.
- */
- public String toParsableString() {
- return specification;
- }
-
- /**
- * Returns a string representation for this CacheBuilderSpec instance.
- * The form of this representation is not guaranteed.
- */
- @Override
- public String toString() {
- return Objects.toStringHelper(this).addValue(toParsableString()).toString();
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(
- initialCapacity,
- maximumSize,
- maximumWeight,
- concurrencyLevel,
- keyStrength,
- valueStrength,
- durationInNanos(writeExpirationDuration, writeExpirationTimeUnit),
- durationInNanos(accessExpirationDuration, accessExpirationTimeUnit),
- durationInNanos(refreshDuration, refreshTimeUnit));
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof CacheBuilderSpec)) {
- return false;
- }
- CacheBuilderSpec that = (CacheBuilderSpec) obj;
- return Objects.equal(initialCapacity, that.initialCapacity)
- && Objects.equal(maximumSize, that.maximumSize)
- && Objects.equal(maximumWeight, that.maximumWeight)
- && Objects.equal(concurrencyLevel, that.concurrencyLevel)
- && Objects.equal(keyStrength, that.keyStrength)
- && Objects.equal(valueStrength, that.valueStrength)
- && Objects.equal(durationInNanos(writeExpirationDuration, writeExpirationTimeUnit),
- durationInNanos(that.writeExpirationDuration, that.writeExpirationTimeUnit))
- && Objects.equal(durationInNanos(accessExpirationDuration, accessExpirationTimeUnit),
- durationInNanos(that.accessExpirationDuration, that.accessExpirationTimeUnit))
- && Objects.equal(durationInNanos(refreshDuration, refreshTimeUnit),
- durationInNanos(that.refreshDuration, that.refreshTimeUnit));
- }
-
- /**
- * Converts an expiration duration/unit pair into a single Long for hashing and equality.
- * Uses nanos to match CacheBuilder implementation.
- */
- @Nullable private static Long durationInNanos(long duration, @Nullable TimeUnit unit) {
- return (unit == null) ? null : unit.toNanos(duration);
- }
-
- /** Base class for parsing integers. */
- abstract static class IntegerParser implements ValueParser {
- protected abstract void parseInteger(CacheBuilderSpec spec, int value);
-
- @Override
- public void parse(CacheBuilderSpec spec, String key, String value) {
- checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key);
- try {
- parseInteger(spec, Integer.parseInt(value));
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(
- String.format("key %s value set to %s, must be integer", key, value), e);
- }
- }
- }
-
- /** Base class for parsing integers. */
- abstract static class LongParser implements ValueParser {
- protected abstract void parseLong(CacheBuilderSpec spec, long value);
-
- @Override
- public void parse(CacheBuilderSpec spec, String key, String value) {
- checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key);
- try {
- parseLong(spec, Long.parseLong(value));
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(
- String.format("key %s value set to %s, must be integer", key, value), e);
- }
- }
- }
-
- /** Parse initialCapacity */
- static class InitialCapacityParser extends IntegerParser {
- @Override
- protected void parseInteger(CacheBuilderSpec spec, int value) {
- checkArgument(spec.initialCapacity == null,
- "initial capacity was already set to ", spec.initialCapacity);
- spec.initialCapacity = value;
- }
- }
-
- /** Parse maximumSize */
- static class MaximumSizeParser extends LongParser {
- @Override
- protected void parseLong(CacheBuilderSpec spec, long value) {
- checkArgument(spec.maximumSize == null,
- "maximum size was already set to ", spec.maximumSize);
- checkArgument(spec.maximumWeight == null,
- "maximum weight was already set to ", spec.maximumWeight);
- spec.maximumSize = value;
- }
- }
-
- /** Parse maximumWeight */
- static class MaximumWeightParser extends LongParser {
- @Override
- protected void parseLong(CacheBuilderSpec spec, long value) {
- checkArgument(spec.maximumWeight == null,
- "maximum weight was already set to ", spec.maximumWeight);
- checkArgument(spec.maximumSize == null,
- "maximum size was already set to ", spec.maximumSize);
- spec.maximumWeight = value;
- }
- }
-
- /** Parse concurrencyLevel */
- static class ConcurrencyLevelParser extends IntegerParser {
- @Override
- protected void parseInteger(CacheBuilderSpec spec, int value) {
- checkArgument(spec.concurrencyLevel == null,
- "concurrency level was already set to ", spec.concurrencyLevel);
- spec.concurrencyLevel = value;
- }
- }
-
- /** Parse weakKeys */
- static class KeyStrengthParser implements ValueParser {
- private final Strength strength;
-
- public KeyStrengthParser(Strength strength) {
- this.strength = strength;
- }
-
- @Override
- public void parse(CacheBuilderSpec spec, String key, @Nullable String value) {
- checkArgument(value == null, "key %s does not take values", key);
- checkArgument(spec.keyStrength == null, "%s was already set to %s", key, spec.keyStrength);
- spec.keyStrength = strength;
- }
- }
-
- /** Parse weakValues and softValues */
- static class ValueStrengthParser implements ValueParser {
- private final Strength strength;
-
- public ValueStrengthParser(Strength strength) {
- this.strength = strength;
- }
-
- @Override
- public void parse(CacheBuilderSpec spec, String key, @Nullable String value) {
- checkArgument(value == null, "key %s does not take values", key);
- checkArgument(spec.valueStrength == null,
- "%s was already set to %s", key, spec.valueStrength);
-
- spec.valueStrength = strength;
- }
- }
-
- /** Base class for parsing times with durations */
- abstract static class DurationParser implements ValueParser {
- protected abstract void parseDuration(
- CacheBuilderSpec spec,
- long duration,
- TimeUnit unit);
-
- @Override
- public void parse(CacheBuilderSpec spec, String key, String value) {
- checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key);
- try {
- char lastChar = value.charAt(value.length() - 1);
- TimeUnit timeUnit;
- switch (lastChar) {
- case 'd':
- timeUnit = TimeUnit.DAYS;
- break;
- case 'h':
- timeUnit = TimeUnit.HOURS;
- break;
- case 'm':
- timeUnit = TimeUnit.MINUTES;
- break;
- case 's':
- timeUnit = TimeUnit.SECONDS;
- break;
- default:
- throw new IllegalArgumentException(
- String.format("key %s invalid format. was %s, must end with one of [dDhHmMsS]",
- key, value));
- }
-
- long duration = Long.parseLong(value.substring(0, value.length() - 1));
- parseDuration(spec, duration, timeUnit);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException(
- String.format("key %s value set to %s, must be integer", key, value));
- }
- }
- }
-
- /** Parse expireAfterAccess */
- static class AccessDurationParser extends DurationParser {
- @Override protected void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit) {
- checkArgument(spec.accessExpirationTimeUnit == null, "expireAfterAccess already set");
- spec.accessExpirationDuration = duration;
- spec.accessExpirationTimeUnit = unit;
- }
- }
-
- /** Parse expireAfterWrite */
- static class WriteDurationParser extends DurationParser {
- @Override protected void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit) {
- checkArgument(spec.writeExpirationTimeUnit == null, "expireAfterWrite already set");
- spec.writeExpirationDuration = duration;
- spec.writeExpirationTimeUnit = unit;
- }
- }
-
- /** Parse refreshAfterWrite */
- static class RefreshDurationParser extends DurationParser {
- @Override protected void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit) {
- checkArgument(spec.refreshTimeUnit == null, "refreshAfterWrite already set");
- spec.refreshDuration = duration;
- spec.refreshTimeUnit = unit;
- }
- }
-}
diff --git a/guava/src/com/google/common/cache/CacheLoader.java b/guava/src/com/google/common/cache/CacheLoader.java
index 2f014a3..21811e8 100644
--- a/guava/src/com/google/common/cache/CacheLoader.java
+++ b/guava/src/com/google/common/cache/CacheLoader.java
@@ -30,23 +30,15 @@ import java.io.Serializable;
import java.util.Map;
/**
- * Computes or retrieves values, based on a key, for use in populating a {@link LoadingCache}.
+ * Computes or retrieves values, based on a key, for use in populating a {@code Cache}.
*
* <p>Most implementations will only need to implement {@link #load}. Other methods may be
* overridden as desired.
*
- * <p>Usage example: <pre> {@code
- *
- * CacheLoader<Key, Graph> loader = new CacheLoader<Key, Graph>() {
- * public Graph load(Key key) throws AnyException {
- * return createExpensiveGraph(key);
- * }
- * };
- * LoadingCache<Key, Graph> cache = CacheBuilder.newBuilder().build(loader);}</pre>
- *
* @author Charles Fry
* @since 10.0
*/
+@Beta
@GwtCompatible(emulated = true)
public abstract class CacheLoader<K, V> {
/**
@@ -59,17 +51,13 @@ public abstract class CacheLoader<K, V> {
*
* @param key the non-null key whose value should be loaded
* @return the value associated with {@code key}; <b>must not be null</b>
- * @throws Exception if unable to load the result
- * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
- * treated like any other {@code Exception} in all respects except that, when it is caught,
- * the thread's interrupt status is set
*/
public abstract V load(K key) throws Exception;
/**
* Computes or retrieves a replacement value corresponding to an already-cached {@code key}. This
* method is called when an existing cache entry is refreshed by
- * {@link CacheBuilder#refreshAfterWrite}, or through a call to {@link LoadingCache#refresh}.
+ * {@link CacheBuilder#refreshAfterWrite}, or through a call to {@link Cache#refresh}.
*
* <p>This implementation synchronously delegates to {@link #load}. It is recommended that it be
* overridden with an asynchronous implementation when using
@@ -81,22 +69,16 @@ public abstract class CacheLoader<K, V> {
* @param oldValue the non-null old value corresponding to {@code key}
* @return the future new value associated with {@code key};
* <b>must not be null, must not return null</b>
- * @throws Exception if unable to reload the result
- * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
- * treated like any other {@code Exception} in all respects except that, when it is caught,
- * the thread's interrupt status is set
* @since 11.0
*/
@GwtIncompatible("Futures")
public ListenableFuture<V> reload(K key, V oldValue) throws Exception {
- checkNotNull(key);
- checkNotNull(oldValue);
return Futures.immediateFuture(load(key));
}
/**
* Computes or retrieves the values corresponding to {@code keys}. This method is called by
- * {@link LoadingCache#getAll}.
+ * {@link Cache#getAll}.
*
* <p>If the returned map doesn't contain all requested {@code keys} then the entries it does
* contain will be cached, but {@code getAll} will throw an exception. If the returned map
@@ -104,33 +86,22 @@ public abstract class CacheLoader<K, V> {
* but only the entries for {@code keys} will be returned from {@code getAll}.
*
* <p>This method should be overriden when bulk retrieval is significantly more efficient than
- * many individual lookups. Note that {@link LoadingCache#getAll} will defer to individual calls
- * to {@link LoadingCache#get} if this method is not overriden.
+ * many individual lookups. Note that {@link Cache#getAll} will defer to individual calls to
+ * {@link Cache#get} if this method is not overriden.
*
* @param keys the unique, non-null keys whose values should be loaded
* @return a map from each key in {@code keys} to the value associated with that key;
* <b>may not contain null values</b>
- * @throws Exception if unable to load the result
- * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
- * treated like any other {@code Exception} in all respects except that, when it is caught,
- * the thread's interrupt status is set
* @since 11.0
*/
public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
- // This will be caught by getAll(), causing it to fall back to multiple calls to
- // LoadingCache.get
+ // This will be caught by getAll(), causing it to fall back to multiple calls to Cache.get
throw new UnsupportedLoadingOperationException();
}
/**
- * Returns a cache loader based on an <i>existing</i> function instance. Note that there's no need
- * to create a <i>new</i> function just to pass it in here; just subclass {@code CacheLoader} and
- * implement {@link #load load} instead.
- *
- * @param function the function to be used for loading values; must never return {@code null}
- * @return a cache loader that loads values by passing each key to {@code function}
+ * Returns a {@code CacheLoader} which creates values by applying a {@code Function} to the key.
*/
- @Beta
public static <K, V> CacheLoader<K, V> from(Function<K, V> function) {
return new FunctionToCacheLoader<K, V>(function);
}
@@ -145,22 +116,16 @@ public abstract class CacheLoader<K, V> {
@Override
public V load(K key) {
- return computingFunction.apply(checkNotNull(key));
+ return computingFunction.apply(key);
}
private static final long serialVersionUID = 0;
}
/**
- * Returns a cache loader based on an <i>existing</i> supplier instance. Note that there's no need
- * to create a <i>new</i> supplier just to pass it in here; just subclass {@code CacheLoader} and
- * implement {@link #load load} instead.
- *
- * @param supplier the supplier to be used for loading values; must never return {@code null}
- * @return a cache loader that loads values by calling {@link Supplier#get}, irrespective of the
- * key
+ * Returns a {@code CacheLoader} which obtains values from a {@code Supplier} (independent of the
+ * key).
*/
- @Beta
public static <V> CacheLoader<Object, V> from(Supplier<V> supplier) {
return new SupplierToCacheLoader<V>(supplier);
}
@@ -175,7 +140,6 @@ public abstract class CacheLoader<K, V> {
@Override
public V load(Object key) {
- checkNotNull(key);
return computingSupplier.get();
}
diff --git a/guava/src/com/google/common/cache/CacheStats.java b/guava/src/com/google/common/cache/CacheStats.java
index d8c9eb7..04d442c 100644
--- a/guava/src/com/google/common/cache/CacheStats.java
+++ b/guava/src/com/google/common/cache/CacheStats.java
@@ -22,8 +22,6 @@ import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Objects;
-import java.util.concurrent.Callable;
-
import javax.annotation.Nullable;
/**
@@ -46,14 +44,9 @@ import javax.annotation.Nullable;
* </ul>
* <li>When an entry is evicted from the cache, {@code evictionCount} is incremented.
* <li>No stats are modified when a cache entry is invalidated or manually removed.
- * <li>No stats are modified on a query to {@link Cache#getIfPresent}.
* <li>No stats are modified by operations invoked on the {@linkplain Cache#asMap asMap} view of
* the cache.
* </ul>
- *
- * <p>A lookup is specifically defined as an invocation of one of the methods
- * {@link LoadingCache#get(Object)}, {@link LoadingCache#getUnchecked(Object)},
- * {@link Cache#get(Object, Callable)}, or {@link LoadingCache#getAll(Iterable)}.
*
* @author Charles Fry
* @since 10.0
diff --git a/guava/src/com/google/common/cache/ForwardingCache.java b/guava/src/com/google/common/cache/ForwardingCache.java
index 44fe683..4404593 100644
--- a/guava/src/com/google/common/cache/ForwardingCache.java
+++ b/guava/src/com/google/common/cache/ForwardingCache.java
@@ -21,7 +21,6 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ForwardingObject;
import com.google.common.collect.ImmutableMap;
-import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
@@ -50,7 +49,7 @@ public abstract class ForwardingCache<K, V> extends ForwardingObject implements
*/
@Override
@Nullable
- public V getIfPresent(Object key) {
+ public V getIfPresent(K key) {
return delegate().getIfPresent(key);
}
@@ -66,7 +65,7 @@ public abstract class ForwardingCache<K, V> extends ForwardingObject implements
* @since 11.0
*/
@Override
- public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) {
+ public ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys) {
return delegate().getAllPresent(keys);
}
@@ -78,14 +77,6 @@ public abstract class ForwardingCache<K, V> extends ForwardingObject implements
delegate().put(key, value);
}
- /**
- * @since 12.0
- */
- @Override
- public void putAll(Map<? extends K,? extends V> m) {
- delegate().putAll(m);
- }
-
@Override
public void invalidate(Object key) {
delegate().invalidate(key);
@@ -124,6 +115,24 @@ public abstract class ForwardingCache<K, V> extends ForwardingObject implements
delegate().cleanUp();
}
+ @Deprecated
+ @Override
+ public V get(K key) throws ExecutionException {
+ return delegate().get(key);
+ }
+
+ @Deprecated
+ @Override
+ public V getUnchecked(K key) {
+ return delegate().getUnchecked(key);
+ }
+
+ @Deprecated
+ @Override
+ public V apply(K key) {
+ return delegate().apply(key);
+ }
+
/**
* A simplified version of {@link ForwardingCache} where subclasses can pass in an already
* constructed {@link Cache} as the delegete.
diff --git a/guava/src/com/google/common/cache/LoadingCache.java b/guava/src/com/google/common/cache/LoadingCache.java
index 05b1312..471c31a 100644
--- a/guava/src/com/google/common/cache/LoadingCache.java
+++ b/guava/src/com/google/common/cache/LoadingCache.java
@@ -33,14 +33,11 @@ import java.util.concurrent.ExecutionException;
* <p>Implementations of this interface are expected to be thread-safe, and can be safely accessed
* by multiple concurrent threads.
*
+ * <p>All methods other than {@link #get} and {@link #getUnchecked} are optional.
+ *
* <p>When evaluated as a {@link Function}, a cache yields the same result as invoking
* {@link #getUnchecked}.
*
- * <p>Note that while this class is still annotated as {@link Beta}, the API is frozen from a
- * consumer's standpoint. In other words existing methods are all considered {@code non-Beta} and
- * won't be changed without going through an 18 month deprecation cycle; however new methods may be
- * added at any time.
- *
* @author Charles Fry
* @since 11.0
*/
@@ -141,8 +138,6 @@ public interface LoadingCache<K, V> extends Cache<K, V>, Function<K, V> {
*
* <p>Caches loaded by a {@link CacheLoader} will call {@link CacheLoader#reload} if the
* cache currently contains a value for {@code key}, and {@link CacheLoader#load} otherwise.
- * Loading is asynchronous only if {@link CacheLoader#reload} was overridden with an
- * asynchronous implementation.
*
* <p>Returns without doing anything if another thread is currently loading the value for
* {@code key}. If the cache loader associated with this cache performs refresh asynchronously
diff --git a/guava/src/com/google/common/cache/LocalCache.java b/guava/src/com/google/common/cache/LocalCache.java
index d7c5bd7..4973429 100644
--- a/guava/src/com/google/common/cache/LocalCache.java
+++ b/guava/src/com/google/common/cache/LocalCache.java
@@ -23,10 +23,9 @@ import static com.google.common.cache.CacheBuilder.UNSET_INT;
import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalences;
import com.google.common.base.Stopwatch;
import com.google.common.base.Ticker;
import com.google.common.cache.AbstractCache.SimpleStatsCounter;
@@ -35,7 +34,7 @@ import com.google.common.cache.CacheBuilder.NullListener;
import com.google.common.cache.CacheBuilder.OneWeigher;
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
import com.google.common.cache.CacheLoader.UnsupportedLoadingOperationException;
-import com.google.common.collect.AbstractSequentialIterator;
+import com.google.common.collect.AbstractLinkedIterator;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterators;
import com.google.common.collect.Maps;
@@ -48,7 +47,6 @@ import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import com.google.common.util.concurrent.UncheckedExecutionException;
-import com.google.common.util.concurrent.Uninterruptibles;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -57,6 +55,7 @@ import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
+import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractQueue;
import java.util.AbstractSet;
@@ -90,7 +89,6 @@ import javax.annotation.concurrent.GuardedBy;
* @author Bob Lee ({@code com.google.common.collect.MapMaker})
* @author Doug Lea ({@code ConcurrentHashMap})
*/
-@GwtCompatible(emulated = true)
class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> {
/*
@@ -232,8 +230,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
/**
* Creates a new, empty map with the specified strategy, initial capacity and concurrency level.
*/
- LocalCache(
- CacheBuilder<? super K, ? super V> builder, @Nullable CacheLoader<? super K, V> loader) {
+ LocalCache(CacheBuilder<? super K, ? super V> builder, CacheLoader<? super K, V> loader) {
concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS);
keyStrength = builder.getKeyStrength();
@@ -263,15 +260,13 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
initialCapacity = Math.min(initialCapacity, (int) maxWeight);
}
- // Find the lowest power-of-two segmentCount that exceeds concurrencyLevel, unless
- // maximumSize/Weight is specified in which case ensure that each segment gets at least 10
- // entries. The special casing for size-based eviction is only necessary because that eviction
- // happens per segment instead of globally, so too many segments compared to the maximum size
- // will result in random eviction behavior.
+ // Find power-of-two sizes best matching arguments. Constraints:
+ // (segmentCount <= maxWeight)
+ // && (concurrencyLevel > maxWeight || segmentCount > concurrencyLevel)
int segmentShift = 0;
int segmentCount = 1;
while (segmentCount < concurrencyLevel
- && (!evictsBySize() || segmentCount * 20 <= maxWeight)) {
+ && (!evictsBySize() || customWeigher() || segmentCount * 2 <= maxWeight)) {
++segmentShift;
segmentCount <<= 1;
}
@@ -386,7 +381,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
@Override
Equivalence<Object> defaultEquivalence() {
- return Equivalence.equals();
+ return Equivalences.equals();
}
},
@@ -402,7 +397,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
@Override
Equivalence<Object> defaultEquivalence() {
- return Equivalence.identity();
+ return Equivalences.identity();
}
},
@@ -418,7 +413,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
@Override
Equivalence<Object> defaultEquivalence() {
- return Equivalence.identity();
+ return Equivalences.identity();
}
};
@@ -652,11 +647,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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);
/**
* Notifify pending loads that a new value was set. This is only relevant to loading
@@ -701,8 +693,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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;
}
@@ -1664,8 +1656,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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
@@ -1710,9 +1702,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
public void notifyNewValue(V newValue) {}
@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
@@ -1757,8 +1748,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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;
}
@@ -1800,8 +1790,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
@Override
public ValueReference<K, V> copyFor(
- ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
- return new WeightedWeakValueReference<K, V>(queue, value, entry, weight);
+ ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
+ return new WeightedWeakValueReference<K, V>(queue, get(), entry, weight);
}
}
@@ -1822,9 +1812,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
return weight;
}
@Override
- public ValueReference<K, V> copyFor(
- ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
- return new WeightedSoftValueReference<K, V>(queue, value, entry, weight);
+ public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
+ return new WeightedSoftValueReference<K, V>(queue, get(), entry, weight);
}
}
@@ -1892,10 +1881,10 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
@VisibleForTesting
ValueReference<K, V> newValueReference(ReferenceEntry<K, V> entry, V value, int weight) {
int hash = entry.getHash();
- return valueStrength.referenceValue(segmentFor(hash), entry, checkNotNull(value), weight);
+ return valueStrength.referenceValue(segmentFor(hash), entry, value, weight);
}
- int hash(@Nullable Object key) {
+ int hash(Object key) {
int h = keyEquivalence.hash(key);
return rehash(h);
}
@@ -1964,13 +1953,12 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
* Returns true if the entry has expired.
*/
boolean isExpired(ReferenceEntry<K, V> entry, long now) {
- checkNotNull(entry);
if (expiresAfterAccess()
- && (now - entry.getAccessTime() >= expireAfterAccessNanos)) {
+ && (now - entry.getAccessTime() > expireAfterAccessNanos)) {
return true;
}
if (expiresAfterWrite()
- && (now - entry.getWriteTime() >= expireAfterWriteNanos)) {
+ && (now - entry.getWriteTime() > expireAfterWriteNanos)) {
return true;
}
return false;
@@ -2150,7 +2138,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
StatsCounter statsCounter) {
this.map = map;
this.maxSegmentWeight = maxSegmentWeight;
- this.statsCounter = checkNotNull(statsCounter);
+ this.statsCounter = statsCounter;
initTable(newEntryArray(initialCapacity));
keyReferenceQueue = map.usesKeyReferences()
@@ -2187,29 +2175,14 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
@GuardedBy("Segment.this")
ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
- return map.entryFactory.newEntry(this, checkNotNull(key), hash, next);
+ 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.isActive()) {
- // 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;
}
@@ -2232,8 +2205,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
// loading
V get(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException {
- checkNotNull(key);
- checkNotNull(loader);
try {
if (count != 0) { // read-volatile
// don't call getLiveEntry, which would ignore loading values
@@ -2424,9 +2395,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
V scheduleRefresh(ReferenceEntry<K, V> entry, K key, int hash, V oldValue, long now,
CacheLoader<? super K, V> loader) {
- if (map.refreshes() && (now - entry.getWriteTime() > map.refreshNanos)
- && !entry.getValueReference().isLoading()) {
- V newValue = refresh(key, hash, loader, true);
+ if (map.refreshes() && (now - entry.getWriteTime() > map.refreshNanos)) {
+ V newValue = refresh(key, hash, loader);
if (newValue != null) {
return newValue;
}
@@ -2441,9 +2411,9 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
* refresh.
*/
@Nullable
- V refresh(K key, int hash, CacheLoader<? super K, V> loader, boolean checkTime) {
+ V refresh(K key, int hash, CacheLoader<? super K, V> loader) {
final LoadingValueReference<K, V> loadingValueReference =
- insertLoadingValueReference(key, hash, checkTime);
+ insertLoadingValueReference(key, hash);
if (loadingValueReference == null) {
return null;
}
@@ -2451,7 +2421,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
ListenableFuture<V> result = loadAsync(key, hash, loadingValueReference, loader);
if (result.isDone()) {
try {
- return Uninterruptibles.getUninterruptibly(result);
+ return result.get();
} catch (Throwable t) {
// don't let refresh exceptions propagate; error was already logged
}
@@ -2464,8 +2434,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
* is already loading.
*/
@Nullable
- LoadingValueReference<K, V> insertLoadingValueReference(final K key, final int hash,
- boolean checkTime) {
+ LoadingValueReference<K, V> insertLoadingValueReference(final K key, final int hash) {
ReferenceEntry<K, V> e = null;
lock();
try {
@@ -2484,11 +2453,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
// We found an existing entry.
ValueReference<K, V> valueReference = e.getValueReference();
- if (valueReference.isLoading()
- || (checkTime && (now - e.getWriteTime() < map.refreshNanos))) {
+ if (valueReference.isLoading()) {
// refresh is a no-op if loading is pending
- // if checkTime, we want to check *after* acquiring the lock if refresh still needs
- // to be scheduled
return null;
}
@@ -3008,14 +2974,14 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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);
}
}
}
@@ -3177,11 +3143,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
preWriteCleanup(now);
int newCount = this.count + 1;
- if (newCount > this.threshold) { // ensure capacity
- expand();
- newCount = this.count + 1;
- }
-
AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
int index = hash & (table.length() - 1);
ReferenceEntry<K, V> first = table.get(index);
@@ -3192,10 +3153,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
&& map.keyEquivalence.equivalent(key, entryKey)) {
ValueReference<K, V> valueReference = e.getValueReference();
V entryValue = valueReference.get();
- // replace the old LoadingValueReference if it's live, otherwise
- // perform a putIfAbsent
- if (oldValueReference == valueReference
- || (entryValue == null && valueReference != UNSET)) {
+ if (entryValue == null || oldValueReference == valueReference) {
++modCount;
if (oldValueReference.isActive()) {
RemovalCause cause =
@@ -3328,12 +3286,11 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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;
@@ -3470,6 +3427,18 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
}
/**
+ * Returns true if the entry has been partially collected, meaning that either the key is null,
+ * or the value is active but null.
+ */
+ boolean isCollected(ReferenceEntry<K, V> entry) {
+ if (entry.getKey() == null) {
+ return true;
+ }
+ ValueReference<K, V> valueReference = entry.getValueReference();
+ return (valueReference.get() == null) && valueReference.isActive();
+ }
+
+ /**
* Performs routine cleanup following a read. Normally cleanup happens during writes. If cleanup
* is not observed after a sufficient number of reads, try cleaning up from the read thread.
*/
@@ -3604,15 +3573,12 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
return newValue != null ? newValue : Futures.<V>immediateFuture(null);
}
} catch (Throwable t) {
- if (t instanceof InterruptedException) {
- Thread.currentThread().interrupt();
- }
return setException(t) ? futureValue : fullyFailedFuture(t);
}
}
public long elapsedNanos() {
- return stopwatch.elapsed(NANOSECONDS);
+ return stopwatch.elapsedTime(NANOSECONDS);
}
@Override
@@ -3635,8 +3601,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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;
}
}
@@ -3770,7 +3735,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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.getNextInWriteQueue();
@@ -3907,7 +3872,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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.getNextInAccessQueue();
@@ -4004,20 +3969,17 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
return get(key, defaultLoader);
}
- ImmutableMap<K, V> getAllPresent(Iterable<?> keys) {
+ ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys) {
int hits = 0;
int misses = 0;
Map<K, V> result = Maps.newLinkedHashMap();
- for (Object key : keys) {
+ for (K key : keys) {
V value = get(key);
if (value == null) {
misses++;
} else {
- // TODO(fry): store entry key instead of query key
- @SuppressWarnings("unchecked")
- K castKey = (K) key;
- result.put(castKey, value);
+ result.put(key, value);
hits++;
}
}
@@ -4026,7 +3988,8 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
return ImmutableMap.copyOf(result);
}
- ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
+ ImmutableMap<K, V> getAll(Iterable<? extends K> keys)
+ throws ExecutionException {
int hits = 0;
int misses = 0;
@@ -4078,8 +4041,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
@Nullable
Map<K, V> loadAll(Set<? extends K> keys, CacheLoader<? super K, V> loader)
throws ExecutionException {
- checkNotNull(loader);
- checkNotNull(keys);
Stopwatch stopwatch = new Stopwatch().start();
Map<K, V> result;
boolean success = false;
@@ -4091,9 +4052,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
} catch (UnsupportedLoadingOperationException e) {
success = true;
throw e;
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new ExecutionException(e);
} catch (RuntimeException e) {
throw new UncheckedExecutionException(e);
} catch (Exception e) {
@@ -4102,12 +4060,12 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
throw new ExecutionError(e);
} finally {
if (!success) {
- globalStatsCounter.recordLoadException(stopwatch.elapsed(NANOSECONDS));
+ globalStatsCounter.recordLoadException(stopwatch.elapsedTime(NANOSECONDS));
}
}
if (result == null) {
- globalStatsCounter.recordLoadException(stopwatch.elapsed(NANOSECONDS));
+ globalStatsCounter.recordLoadException(stopwatch.elapsedTime(NANOSECONDS));
throw new InvalidCacheLoadException(loader + " returned null map from loadAll");
}
@@ -4126,12 +4084,12 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
}
if (nullsPresent) {
- globalStatsCounter.recordLoadException(stopwatch.elapsed(NANOSECONDS));
+ globalStatsCounter.recordLoadException(stopwatch.elapsedTime(NANOSECONDS));
throw new InvalidCacheLoadException(loader + " returned null keys or values from loadAll");
}
// TODO(fry): record count of loaded entries
- globalStatsCounter.recordLoadSuccess(stopwatch.elapsed(NANOSECONDS));
+ globalStatsCounter.recordLoadSuccess(stopwatch.elapsedTime(NANOSECONDS));
return result;
}
@@ -4148,9 +4106,21 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
return segmentFor(hash).getEntry(key, hash);
}
+ /**
+ * Returns the live internal entry for the specified key.
+ */
+ ReferenceEntry<K, V> getLiveEntry(@Nullable Object key) {
+ // does not impact recency ordering
+ if (key == null) {
+ return null;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).getLiveEntry(key, hash, ticker.read());
+ }
+
void refresh(K key) {
int hash = hash(checkNotNull(key));
- segmentFor(hash).refresh(key, hash, defaultLoader, false);
+ segmentFor(hash).refresh(key, hash, defaultLoader);
}
@Override
@@ -4284,7 +4254,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
public Set<K> keySet() {
// does not impact recency ordering
Set<K> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet(this));
+ return (ks != null) ? ks : (keySet = new KeySet());
}
Collection<V> values;
@@ -4293,22 +4263,21 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
public Collection<V> values() {
// does not impact recency ordering
Collection<V> vs = values;
- return (vs != null) ? vs : (values = new Values(this));
+ return (vs != null) ? vs : (values = new Values());
}
Set<Entry<K, V>> entrySet;
@Override
- @GwtIncompatible("Not supported.")
public Set<Entry<K, V>> entrySet() {
// does not impact recency ordering
Set<Entry<K, V>> es = entrySet;
- return (es != null) ? es : (entrySet = new EntrySet(this));
+ return (es != null) ? es : (entrySet = new EntrySet());
}
// Iterator Support
- abstract class HashIterator<T> implements Iterator<T> {
+ abstract class HashIterator {
int nextSegmentIndex;
int nextTableIndex;
@@ -4324,9 +4293,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
advance();
}
- @Override
- public abstract T next();
-
final void advance() {
nextExternal = null;
@@ -4399,7 +4365,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
}
}
- @Override
public boolean hasNext() {
return nextExternal != null;
}
@@ -4413,7 +4378,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
return lastReturned;
}
- @Override
public void remove() {
checkState(lastReturned != null);
LocalCache.this.remove(lastReturned.getKey());
@@ -4421,7 +4385,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
}
}
- final class KeyIterator extends HashIterator<K> {
+ final class KeyIterator extends HashIterator implements Iterator<K> {
@Override
public K next() {
@@ -4429,7 +4393,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
}
}
- final class ValueIterator extends HashIterator<V> {
+ final class ValueIterator extends HashIterator implements Iterator<V> {
@Override
public V next() {
@@ -4489,7 +4453,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<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() {
@@ -4497,73 +4461,68 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
}
}
- abstract class AbstractCacheSet<T> extends AbstractSet<T> {
- final ConcurrentMap<?, ?> map;
+ final class KeySet extends AbstractSet<K> {
- AbstractCacheSet(ConcurrentMap<?, ?> map) {
- this.map = map;
+ @Override
+ public Iterator<K> iterator() {
+ return new KeyIterator();
}
@Override
public int size() {
- return map.size();
+ return LocalCache.this.size();
}
@Override
public boolean isEmpty() {
- return map.isEmpty();
+ return LocalCache.this.isEmpty();
}
@Override
- public void clear() {
- map.clear();
+ public boolean contains(Object o) {
+ return LocalCache.this.containsKey(o);
}
- }
- final class KeySet extends AbstractCacheSet<K> {
-
- KeySet(ConcurrentMap<?, ?> map) {
- super(map);
+ @Override
+ public boolean remove(Object o) {
+ return LocalCache.this.remove(o) != null;
}
@Override
- public Iterator<K> iterator() {
- return new KeyIterator();
+ public void clear() {
+ LocalCache.this.clear();
}
+ }
+
+ final class Values extends AbstractCollection<V> {
@Override
- public boolean contains(Object o) {
- return map.containsKey(o);
+ public Iterator<V> iterator() {
+ return new ValueIterator();
}
@Override
- public boolean remove(Object o) {
- return map.remove(o) != null;
+ public int size() {
+ return LocalCache.this.size();
}
- }
-
- final class Values extends AbstractCacheSet<V> {
- Values(ConcurrentMap<?, ?> map) {
- super(map);
+ @Override
+ public boolean isEmpty() {
+ return LocalCache.this.isEmpty();
}
@Override
- public Iterator<V> iterator() {
- return new ValueIterator();
+ public boolean contains(Object o) {
+ return LocalCache.this.containsValue(o);
}
@Override
- public boolean contains(Object o) {
- return map.containsValue(o);
+ public void clear() {
+ LocalCache.this.clear();
}
}
- final class EntrySet extends AbstractCacheSet<Entry<K, V>> {
-
- EntrySet(ConcurrentMap<?, ?> map) {
- super(map);
- }
+ final class EntrySet extends AbstractSet<Entry<K, V>> {
@Override
public Iterator<Entry<K, V>> iterator() {
@@ -4594,6 +4553,21 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
Object key = e.getKey();
return key != null && LocalCache.this.remove(key, e.getValue());
}
+
+ @Override
+ public int size() {
+ return LocalCache.this.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return LocalCache.this.isEmpty();
+ }
+
+ @Override
+ public void clear() {
+ LocalCache.this.clear();
+ }
}
// Serialization Support
@@ -4663,15 +4637,15 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
this.loader = loader;
}
- CacheBuilder<K, V> recreateCacheBuilder() {
- CacheBuilder<K, V> builder = CacheBuilder.newBuilder()
+ CacheBuilder<Object, Object> recreateCacheBuilder() {
+ CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder()
.setKeyStrength(keyStrength)
.setValueStrength(valueStrength)
.keyEquivalence(keyEquivalence)
.valueEquivalence(valueEquivalence)
- .concurrencyLevel(concurrencyLevel)
- .removalListener(removalListener);
+ .concurrencyLevel(concurrencyLevel);
builder.strictParsing = false;
+ builder.removalListener(removalListener);
if (expireAfterWriteNanos > 0) {
builder.expireAfterWrite(expireAfterWriteNanos, TimeUnit.NANOSECONDS);
}
@@ -4696,7 +4670,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
- CacheBuilder<K, V> builder = recreateCacheBuilder();
+ CacheBuilder<Object, Object> builder = recreateCacheBuilder();
this.delegate = builder.build();
}
@@ -4730,7 +4704,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
- CacheBuilder<K, V> builder = recreateCacheBuilder();
+ CacheBuilder<Object, Object> builder = recreateCacheBuilder();
this.autoDelegate = builder.build(loader);
}
@@ -4768,18 +4742,19 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
final LocalCache<K, V> localCache;
LocalManualCache(CacheBuilder<? super K, ? super V> builder) {
- this(new LocalCache<K, V>(builder, null));
+ this(builder, null);
}
- private LocalManualCache(LocalCache<K, V> localCache) {
- this.localCache = localCache;
+ protected LocalManualCache(CacheBuilder<? super K, ? super V> builder,
+ CacheLoader<? super K, V> loader) {
+ this.localCache = new LocalCache<K, V>(builder, loader);
}
// Cache methods
@Override
@Nullable
- public V getIfPresent(Object key) {
+ public V getIfPresent(K key) {
return localCache.getIfPresent(key);
}
@@ -4795,7 +4770,7 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
}
@Override
- public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) {
+ public ImmutableMap<K, V> getAllPresent(Iterable<? extends K> keys) {
return localCache.getAllPresent(keys);
}
@@ -4805,11 +4780,6 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
}
@Override
- public void putAll(Map<? extends K, ? extends V> m) {
- localCache.putAll(m);
- }
-
- @Override
public void invalidate(Object key) {
checkNotNull(key);
localCache.remove(key);
@@ -4850,6 +4820,27 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
localCache.cleanUp();
}
+ /*
+ * These methods have been moved to LoadingCache, but they temporarily
+ * remain in Cache in Guava.
+ */
+
+ public V get(K key) throws ExecutionException {
+ return localCache.getOrLoad(key);
+ }
+
+ public V getUnchecked(K key) {
+ try {
+ return get(key);
+ } catch (ExecutionException e) {
+ throw new UncheckedExecutionException(e.getCause());
+ }
+ }
+
+ public final V apply(K key) {
+ return getUnchecked(key);
+ }
+
// Serialization Support
private static final long serialVersionUID = 1;
@@ -4864,24 +4855,10 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
LocalLoadingCache(CacheBuilder<? super K, ? super V> builder,
CacheLoader<? super K, V> loader) {
- super(new LocalCache<K, V>(builder, checkNotNull(loader)));
+ super(builder, checkNotNull(loader));
}
- // LoadingCache methods
-
- @Override
- public V get(K key) throws ExecutionException {
- return localCache.getOrLoad(key);
- }
-
- @Override
- public V getUnchecked(K key) {
- try {
- return get(key);
- } catch (ExecutionException e) {
- throw new UncheckedExecutionException(e.getCause());
- }
- }
+ // Cache methods
@Override
public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
@@ -4893,16 +4870,10 @@ class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V>
localCache.refresh(key);
}
- @Override
- public final V apply(K key) {
- return getUnchecked(key);
- }
-
// Serialization Support
private static final long serialVersionUID = 1;
- @Override
Object writeReplace() {
return new LoadingSerializationProxy<K, V>(localCache);
}
diff --git a/guava/src/com/google/common/cache/LongAddable.java b/guava/src/com/google/common/cache/LongAddable.java
deleted file mode 100644
index 48ddbfc..0000000
--- a/guava/src/com/google/common/cache/LongAddable.java
+++ /dev/null
@@ -1,33 +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.cache;
-
-import com.google.common.annotations.GwtCompatible;
-
-/**
- * Abstract interface for objects that can concurrently add longs.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible
-interface LongAddable {
- void increment();
-
- void add(long x);
-
- long sum();
-}
diff --git a/guava/src/com/google/common/cache/LongAddables.java b/guava/src/com/google/common/cache/LongAddables.java
deleted file mode 100644
index a110c6c..0000000
--- a/guava/src/com/google/common/cache/LongAddables.java
+++ /dev/null
@@ -1,75 +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.cache;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Supplier;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Source of {@link LongAddable} objects that deals with GWT, Unsafe, and all
- * that.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-final class LongAddables {
- private static final Supplier<LongAddable> SUPPLIER;
-
- static {
- Supplier<LongAddable> supplier;
- try {
- new LongAdder();
- supplier = new Supplier<LongAddable>() {
- @Override
- public LongAddable get() {
- return new LongAdder();
- }
- };
- } catch (Throwable t) { // we really want to catch *everything*
- supplier = new Supplier<LongAddable>() {
- @Override
- public LongAddable get() {
- return new PureJavaLongAddable();
- }
- };
- }
- SUPPLIER = supplier;
- }
-
- public static LongAddable create() {
- return SUPPLIER.get();
- }
-
- private static final class PureJavaLongAddable extends AtomicLong implements LongAddable {
- @Override
- public void increment() {
- getAndIncrement();
- }
-
- @Override
- public void add(long x) {
- getAndAdd(x);
- }
-
- @Override
- public long sum() {
- return get();
- }
- }
-}
diff --git a/guava/src/com/google/common/cache/LongAdder.java b/guava/src/com/google/common/cache/LongAdder.java
deleted file mode 100644
index 5af81e1..0000000
--- a/guava/src/com/google/common/cache/LongAdder.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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/publicdomain/zero/1.0/
- */
-
-/*
- * Source:
- * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/LongAdder.java?revision=1.8
- */
-
-package com.google.common.cache;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.concurrent.atomic.AtomicLong;
-import java.io.IOException;
-import java.io.Serializable;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-/**
- * One or more variables that together maintain an initially zero
- * {@code long} sum. When updates (method {@link #add}) are contended
- * across threads, the set of variables may grow dynamically to reduce
- * contention. Method {@link #sum} (or, equivalently, {@link
- * #longValue}) returns the current total combined across the
- * variables maintaining the sum.
- *
- * <p> This class is usually preferable to {@link AtomicLong} when
- * multiple threads update a common sum that is used for purposes such
- * as collecting statistics, not for fine-grained synchronization
- * control. Under low update contention, the two classes have similar
- * characteristics. But under high contention, expected throughput of
- * this class is significantly higher, at the expense of higher space
- * consumption.
- *
- * <p>This class extends {@link Number}, but does <em>not</em> define
- * methods such as {@code hashCode} and {@code compareTo} because
- * instances are expected to be mutated, and so are not useful as
- * collection keys.
- *
- * <p><em>jsr166e note: This class is targeted to be placed in
- * java.util.concurrent.atomic<em>
- *
- * @since 1.8
- * @author Doug Lea
- */
-@GwtCompatible(emulated = true)
-final class LongAdder extends Striped64 implements Serializable, LongAddable {
- private static final long serialVersionUID = 7249069246863182397L;
-
- /**
- * Version of plus for use in retryUpdate
- */
- final long fn(long v, long x) { return v + x; }
-
- /**
- * Creates a new adder with initial sum of zero.
- */
- public LongAdder() {
- }
-
- /**
- * Adds the given value.
- *
- * @param x the value to add
- */
- public void add(long x) {
- Cell[] as; long b, v; HashCode hc; Cell a; int n;
- if ((as = cells) != null || !casBase(b = base, b + x)) {
- boolean uncontended = true;
- int h = (hc = threadHashCode.get()).code;
- if (as == null || (n = as.length) < 1 ||
- (a = as[(n - 1) & h]) == null ||
- !(uncontended = a.cas(v = a.value, v + x)))
- retryUpdate(x, hc, uncontended);
- }
- }
-
- /**
- * Equivalent to {@code add(1)}.
- */
- public void increment() {
- add(1L);
- }
-
- /**
- * Equivalent to {@code add(-1)}.
- */
- public void decrement() {
- add(-1L);
- }
-
- /**
- * Returns the current sum. The returned value is <em>NOT</em> an
- * atomic snapshot: Invocation in the absence of concurrent
- * updates returns an accurate result, but concurrent updates that
- * occur while the sum is being calculated might not be
- * incorporated.
- *
- * @return the sum
- */
- public long sum() {
- long sum = base;
- Cell[] as = cells;
- if (as != null) {
- int n = as.length;
- for (int i = 0; i < n; ++i) {
- Cell a = as[i];
- if (a != null)
- sum += a.value;
- }
- }
- return sum;
- }
-
- /**
- * Resets variables maintaining the sum to zero. This method may
- * be a useful alternative to creating a new adder, but is only
- * effective if there are no concurrent updates. Because this
- * method is intrinsically racy, it should only be used when it is
- * known that no threads are concurrently updating.
- */
- public void reset() {
- internalReset(0L);
- }
-
- /**
- * Equivalent in effect to {@link #sum} followed by {@link
- * #reset}. This method may apply for example during quiescent
- * points between multithreaded computations. If there are
- * updates concurrent with this method, the returned value is
- * <em>not</em> guaranteed to be the final value occurring before
- * the reset.
- *
- * @return the sum
- */
- public long sumThenReset() {
- long sum = base;
- Cell[] as = cells;
- base = 0L;
- if (as != null) {
- int n = as.length;
- for (int i = 0; i < n; ++i) {
- Cell a = as[i];
- if (a != null) {
- sum += a.value;
- a.value = 0L;
- }
- }
- }
- return sum;
- }
-
- /**
- * Returns the String representation of the {@link #sum}.
- * @return the String representation of the {@link #sum}
- */
- public String toString() {
- return Long.toString(sum());
- }
-
- /**
- * Equivalent to {@link #sum}.
- *
- * @return the sum
- */
- public long longValue() {
- return sum();
- }
-
- /**
- * Returns the {@link #sum} as an {@code int} after a narrowing
- * primitive conversion.
- */
- public int intValue() {
- return (int)sum();
- }
-
- /**
- * Returns the {@link #sum} as a {@code float}
- * after a widening primitive conversion.
- */
- public float floatValue() {
- return (float)sum();
- }
-
- /**
- * Returns the {@link #sum} as a {@code double} after a widening
- * primitive conversion.
- */
- public double doubleValue() {
- return (double)sum();
- }
-
- private void writeObject(ObjectOutputStream s)
- throws java.io.IOException {
- s.defaultWriteObject();
- s.writeLong(sum());
- }
-
- private void readObject(ObjectInputStream s)
- throws IOException, ClassNotFoundException {
- s.defaultReadObject();
- busy = 0;
- cells = null;
- base = s.readLong();
- }
-
-}
diff --git a/guava/src/com/google/common/cache/RemovalCause.java b/guava/src/com/google/common/cache/RemovalCause.java
index 0be9b5b..6574b0e 100644
--- a/guava/src/com/google/common/cache/RemovalCause.java
+++ b/guava/src/com/google/common/cache/RemovalCause.java
@@ -17,7 +17,6 @@
package com.google.common.cache;
import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
import java.util.Iterator;
import java.util.Map;
@@ -30,7 +29,6 @@ import java.util.concurrent.ConcurrentMap;
* @since 10.0
*/
@Beta
-@GwtCompatible
public enum RemovalCause {
/**
* The entry was manually removed by the user. This can result from the user invoking
diff --git a/guava/src/com/google/common/cache/RemovalListener.java b/guava/src/com/google/common/cache/RemovalListener.java
index 270a7c4..e9b6c2c 100644
--- a/guava/src/com/google/common/cache/RemovalListener.java
+++ b/guava/src/com/google/common/cache/RemovalListener.java
@@ -17,7 +17,6 @@
package com.google.common.cache;
import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
/**
* An object that can receive a notification when an entry is removed from a cache. The removal
@@ -37,7 +36,6 @@ import com.google.common.annotations.GwtCompatible;
* @since 10.0
*/
@Beta
-@GwtCompatible
public interface RemovalListener<K, V> {
/**
* Notifies the listener that a removal occurred at some point in the past.
diff --git a/guava/src/com/google/common/cache/RemovalListeners.java b/guava/src/com/google/common/cache/RemovalListeners.java
index dbb9efc..18292fd 100644
--- a/guava/src/com/google/common/cache/RemovalListeners.java
+++ b/guava/src/com/google/common/cache/RemovalListeners.java
@@ -16,8 +16,6 @@
package com.google.common.cache;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.Beta;
import java.util.concurrent.Executor;
@@ -43,8 +41,6 @@ public final class RemovalListeners {
*/
public static <K, V> RemovalListener<K, V> asynchronous(
final RemovalListener<K, V> listener, final Executor executor) {
- checkNotNull(listener);
- checkNotNull(executor);
return new RemovalListener<K, V>() {
@Override
public void onRemoval(final RemovalNotification<K, V> notification) {
diff --git a/guava/src/com/google/common/cache/RemovalNotification.java b/guava/src/com/google/common/cache/RemovalNotification.java
index 2565dba..8e0066e 100644
--- a/guava/src/com/google/common/cache/RemovalNotification.java
+++ b/guava/src/com/google/common/cache/RemovalNotification.java
@@ -19,7 +19,6 @@ package com.google.common.cache;
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 java.util.Map.Entry;
@@ -38,7 +37,6 @@ import javax.annotation.Nullable;
* @since 10.0
*/
@Beta
-@GwtCompatible
public final class RemovalNotification<K, V> implements Entry<K, V> {
@Nullable private final K key;
@Nullable private final V value;
diff --git a/guava/src/com/google/common/cache/Striped64.java b/guava/src/com/google/common/cache/Striped64.java
deleted file mode 100644
index e045453..0000000
--- a/guava/src/com/google/common/cache/Striped64.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * 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/publicdomain/zero/1.0/
- */
-
-/*
- * Source:
- * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.7
- */
-
-package com.google.common.cache;
-
-import java.util.Random;
-
-/**
- * A package-local class holding common representation and mechanics
- * for classes supporting dynamic striping on 64bit values. The class
- * extends Number so that concrete subclasses must publicly do so.
- */
-abstract class Striped64 extends Number {
- /*
- * This class maintains a lazily-initialized table of atomically
- * updated variables, plus an extra "base" field. The table size
- * is a power of two. Indexing uses masked per-thread hash codes.
- * Nearly all declarations in this class are package-private,
- * accessed directly by subclasses.
- *
- * Table entries are of class Cell; a variant of AtomicLong padded
- * to reduce cache contention on most processors. Padding is
- * overkill for most Atomics because they are usually irregularly
- * scattered in memory and thus don't interfere much with each
- * other. But Atomic objects residing in arrays will tend to be
- * placed adjacent to each other, and so will most often share
- * cache lines (with a huge negative performance impact) without
- * this precaution.
- *
- * In part because Cells are relatively large, we avoid creating
- * them until they are needed. When there is no contention, all
- * updates are made to the base field. Upon first contention (a
- * failed CAS on base update), the table is initialized to size 2.
- * The table size is doubled upon further contention until
- * reaching the nearest power of two greater than or equal to the
- * number of CPUS. Table slots remain empty (null) until they are
- * needed.
- *
- * A single spinlock ("busy") is used for initializing and
- * resizing the table, as well as populating slots with new Cells.
- * There is no need for a blocking lock: When the lock is not
- * available, threads try other slots (or the base). During these
- * retries, there is increased contention and reduced locality,
- * which is still better than alternatives.
- *
- * Per-thread hash codes are initialized to random values.
- * Contention and/or table collisions are indicated by failed
- * CASes when performing an update operation (see method
- * retryUpdate). Upon a collision, if the table size is less than
- * the capacity, it is doubled in size unless some other thread
- * holds the lock. If a hashed slot is empty, and lock is
- * available, a new Cell is created. Otherwise, if the slot
- * exists, a CAS is tried. Retries proceed by "double hashing",
- * using a secondary hash (Marsaglia XorShift) to try to find a
- * free slot.
- *
- * The table size is capped because, when there are more threads
- * than CPUs, supposing that each thread were bound to a CPU,
- * there would exist a perfect hash function mapping threads to
- * slots that eliminates collisions. When we reach capacity, we
- * search for this mapping by randomly varying the hash codes of
- * colliding threads. Because search is random, and collisions
- * only become known via CAS failures, convergence can be slow,
- * and because threads are typically not bound to CPUS forever,
- * may not occur at all. However, despite these limitations,
- * observed contention rates are typically low in these cases.
- *
- * It is possible for a Cell to become unused when threads that
- * once hashed to it terminate, as well as in the case where
- * doubling the table causes no thread to hash to it under
- * expanded mask. We do not try to detect or remove such cells,
- * under the assumption that for long-running instances, observed
- * contention levels will recur, so the cells will eventually be
- * needed again; and for short-lived ones, it does not matter.
- */
-
- /**
- * Padded variant of AtomicLong supporting only raw accesses plus CAS.
- * The value field is placed between pads, hoping that the JVM doesn't
- * reorder them.
- *
- * JVM intrinsics note: It would be possible to use a release-only
- * form of CAS here, if it were provided.
- */
- static final class Cell {
- volatile long p0, p1, p2, p3, p4, p5, p6;
- volatile long value;
- volatile long q0, q1, q2, q3, q4, q5, q6;
- Cell(long x) { value = x; }
-
- final boolean cas(long cmp, long val) {
- return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val);
- }
-
- // Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long valueOffset;
- static {
- try {
- UNSAFE = getUnsafe();
- Class<?> ak = Cell.class;
- valueOffset = UNSAFE.objectFieldOffset
- (ak.getDeclaredField("value"));
- } catch (Exception e) {
- throw new Error(e);
- }
- }
-
- }
-
- /**
- * Holder for the thread-local hash code. The code is initially
- * random, but may be set to a different value upon collisions.
- */
- static final class HashCode {
- static final Random rng = new Random();
- int code;
- HashCode() {
- int h = rng.nextInt(); // Avoid zero to allow xorShift rehash
- code = (h == 0) ? 1 : h;
- }
- }
-
- /**
- * The corresponding ThreadLocal class
- */
- static final class ThreadHashCode extends ThreadLocal<HashCode> {
- public HashCode initialValue() { return new HashCode(); }
- }
-
- /**
- * Static per-thread hash codes. Shared across all instances to
- * reduce ThreadLocal pollution and because adjustments due to
- * collisions in one table are likely to be appropriate for
- * others.
- */
- static final ThreadHashCode threadHashCode = new ThreadHashCode();
-
- /** Number of CPUS, to place bound on table size */
- static final int NCPU = Runtime.getRuntime().availableProcessors();
-
- /**
- * Table of cells. When non-null, size is a power of 2.
- */
- transient volatile Cell[] cells;
-
- /**
- * Base value, used mainly when there is no contention, but also as
- * a fallback during table initialization races. Updated via CAS.
- */
- transient volatile long base;
-
- /**
- * Spinlock (locked via CAS) used when resizing and/or creating Cells.
- */
- transient volatile int busy;
-
- /**
- * Package-private default constructor
- */
- Striped64() {
- }
-
- /**
- * CASes the base field.
- */
- final boolean casBase(long cmp, long val) {
- return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val);
- }
-
- /**
- * CASes the busy field from 0 to 1 to acquire lock.
- */
- final boolean casBusy() {
- return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1);
- }
-
- /**
- * Computes the function of current and new value. Subclasses
- * should open-code this update function for most uses, but the
- * virtualized form is needed within retryUpdate.
- *
- * @param currentValue the current value (of either base or a cell)
- * @param newValue the argument from a user update call
- * @return result of the update function
- */
- abstract long fn(long currentValue, long newValue);
-
- /**
- * Handles cases of updates involving initialization, resizing,
- * creating new Cells, and/or contention. See above for
- * explanation. This method suffers the usual non-modularity
- * problems of optimistic retry code, relying on rechecked sets of
- * reads.
- *
- * @param x the value
- * @param hc the hash code holder
- * @param wasUncontended false if CAS failed before call
- */
- final void retryUpdate(long x, HashCode hc, boolean wasUncontended) {
- int h = hc.code;
- boolean collide = false; // True if last slot nonempty
- for (;;) {
- Cell[] as; Cell a; int n; long v;
- if ((as = cells) != null && (n = as.length) > 0) {
- if ((a = as[(n - 1) & h]) == null) {
- if (busy == 0) { // Try to attach new Cell
- Cell r = new Cell(x); // Optimistically create
- if (busy == 0 && casBusy()) {
- boolean created = false;
- try { // Recheck under lock
- Cell[] rs; int m, j;
- if ((rs = cells) != null &&
- (m = rs.length) > 0 &&
- rs[j = (m - 1) & h] == null) {
- rs[j] = r;
- created = true;
- }
- } finally {
- busy = 0;
- }
- if (created)
- break;
- continue; // Slot is now non-empty
- }
- }
- collide = false;
- }
- else if (!wasUncontended) // CAS already known to fail
- wasUncontended = true; // Continue after rehash
- else if (a.cas(v = a.value, fn(v, x)))
- break;
- else if (n >= NCPU || cells != as)
- collide = false; // At max size or stale
- else if (!collide)
- collide = true;
- else if (busy == 0 && casBusy()) {
- try {
- if (cells == as) { // Expand table unless stale
- Cell[] rs = new Cell[n << 1];
- for (int i = 0; i < n; ++i)
- rs[i] = as[i];
- cells = rs;
- }
- } finally {
- busy = 0;
- }
- collide = false;
- continue; // Retry with expanded table
- }
- h ^= h << 13; // Rehash
- h ^= h >>> 17;
- h ^= h << 5;
- }
- else if (busy == 0 && cells == as && casBusy()) {
- boolean init = false;
- try { // Initialize table
- if (cells == as) {
- Cell[] rs = new Cell[2];
- rs[h & 1] = new Cell(x);
- cells = rs;
- init = true;
- }
- } finally {
- busy = 0;
- }
- if (init)
- break;
- }
- else if (casBase(v = base, fn(v, x)))
- break; // Fall back on using base
- }
- hc.code = h; // Record index for next time
- }
-
- /**
- * Sets base and all cells to the given value.
- */
- final void internalReset(long initialValue) {
- Cell[] as = cells;
- base = initialValue;
- if (as != null) {
- int n = as.length;
- for (int i = 0; i < n; ++i) {
- Cell a = as[i];
- if (a != null)
- a.value = initialValue;
- }
- }
- }
-
- // Unsafe mechanics
- private static final sun.misc.Unsafe UNSAFE;
- private static final long baseOffset;
- private static final long busyOffset;
- static {
- try {
- UNSAFE = getUnsafe();
- Class<?> sk = Striped64.class;
- baseOffset = UNSAFE.objectFieldOffset
- (sk.getDeclaredField("base"));
- busyOffset = UNSAFE.objectFieldOffset
- (sk.getDeclaredField("busy"));
- } catch (Exception e) {
- throw new Error(e);
- }
- }
-
- /**
- * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
- * Replace with a simple call to Unsafe.getUnsafe when integrating
- * into a jdk.
- *
- * @return a sun.misc.Unsafe
- */
- private static sun.misc.Unsafe getUnsafe() {
- try {
- return sun.misc.Unsafe.getUnsafe();
- } catch (SecurityException tryReflectionInstead) {}
- try {
- return java.security.AccessController.doPrivileged
- (new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
- public sun.misc.Unsafe run() throws Exception {
- Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
- for (java.lang.reflect.Field f : k.getDeclaredFields()) {
- f.setAccessible(true);
- Object x = f.get(null);
- if (k.isInstance(x))
- return k.cast(x);
- }
- throw new NoSuchFieldError("the Unsafe");
- }});
- } catch (java.security.PrivilegedActionException e) {
- throw new RuntimeException("Could not initialize intrinsics",
- e.getCause());
- }
- }
-
-}
diff --git a/guava/src/com/google/common/cache/Weigher.java b/guava/src/com/google/common/cache/Weigher.java
index 5720cb8..bbb0a33 100644
--- a/guava/src/com/google/common/cache/Weigher.java
+++ b/guava/src/com/google/common/cache/Weigher.java
@@ -1,30 +1,30 @@
/*
* 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
+ * 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.cache;
import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
/**
* Calculates the weights of cache entries.
*
- * @author Charles Fry
+ * @author fry@google.com (Charles Fry)
* @since 11.0
*/
@Beta
-@GwtCompatible
public interface Weigher<K, V> {
/**
@@ -34,4 +34,5 @@ public interface Weigher<K, V> {
* @return the weight of the entry; must be non-negative
*/
int weigh(K key, V value);
+
}
diff --git a/guava/src/com/google/common/cache/package-info.java b/guava/src/com/google/common/cache/package-info.java
index ea0297b..1c5391c 100644
--- a/guava/src/com/google/common/cache/package-info.java
+++ b/guava/src/com/google/common/cache/package-info.java
@@ -22,9 +22,6 @@
* {@link com.google.common.cache.CacheBuilder}, with cache entries being loaded by
* {@link com.google.common.cache.CacheLoader}. Statistics about cache performance are exposed using
* {@link com.google.common.cache.CacheStats}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CachesExplained">caches</a>.
*
* <p>This package is a part of the open-source
* <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
@@ -35,4 +32,3 @@
package com.google.common.cache;
import javax.annotation.ParametersAreNonnullByDefault;
-
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}
diff --git a/guava/src/com/google/common/eventbus/AllowConcurrentEvents.java b/guava/src/com/google/common/eventbus/AllowConcurrentEvents.java
index f614598..5699d73 100644
--- a/guava/src/com/google/common/eventbus/AllowConcurrentEvents.java
+++ b/guava/src/com/google/common/eventbus/AllowConcurrentEvents.java
@@ -17,7 +17,6 @@
package com.google.common.eventbus;
import com.google.common.annotations.Beta;
-
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/guava/src/com/google/common/eventbus/AnnotatedHandlerFinder.java b/guava/src/com/google/common/eventbus/AnnotatedHandlerFinder.java
index fe93b21..7153c66 100644
--- a/guava/src/com/google/common/eventbus/AnnotatedHandlerFinder.java
+++ b/guava/src/com/google/common/eventbus/AnnotatedHandlerFinder.java
@@ -16,97 +16,50 @@
package com.google.common.eventbus;
-import com.google.common.base.Throwables;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
-import com.google.common.reflect.TypeToken;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-
import java.lang.reflect.Method;
-import java.util.Set;
/**
- * A {@link HandlerFindingStrategy} for collecting all event handler methods that are marked with
- * the {@link Subscribe} annotation.
+ * A {@link HandlerFindingStrategy} for collecting all event handler methods
+ * that are marked with the {@link Subscribe} annotation.
*
* @author Cliff Biffle
- * @author Louis Wasserman
*/
class AnnotatedHandlerFinder implements HandlerFindingStrategy {
- /**
- * A thread-safe cache that contains the mapping from each class to all methods in that class and
- * all super-classes, that are annotated with {@code @Subscribe}. The cache is shared across all
- * instances of this class; this greatly improves performance if multiple EventBus instances are
- * created and objects of the same class are registered on all of them.
- */
- private static final LoadingCache<Class<?>, ImmutableList<Method>> handlerMethodsCache =
- CacheBuilder.newBuilder()
- .weakKeys()
- .build(new CacheLoader<Class<?>, ImmutableList<Method>>() {
- @Override
- public ImmutableList<Method> load(Class<?> concreteClass) throws Exception {
- return getAnnotatedMethodsInternal(concreteClass);
- }
- });
/**
* {@inheritDoc}
*
- * This implementation finds all methods marked with a {@link Subscribe} annotation.
+ * This implementation finds all methods marked with a {@link Subscribe}
+ * annotation.
*/
@Override
public Multimap<Class<?>, EventHandler> findAllHandlers(Object listener) {
- Multimap<Class<?>, EventHandler> methodsInListener = HashMultimap.create();
- Class<?> clazz = listener.getClass();
- for (Method method : getAnnotatedMethods(clazz)) {
- Class<?>[] parameterTypes = method.getParameterTypes();
- Class<?> eventType = parameterTypes[0];
- EventHandler handler = makeHandler(listener, method);
- methodsInListener.put(eventType, handler);
- }
- return methodsInListener;
- }
+ Multimap<Class<?>, EventHandler> methodsInListener =
+ HashMultimap.create();
+ Class clazz = listener.getClass();
+ while (clazz != null) {
+ for (Method method : clazz.getMethods()) {
+ Subscribe annotation = method.getAnnotation(Subscribe.class);
- private static ImmutableList<Method> getAnnotatedMethods(Class<?> clazz) {
- try {
- return handlerMethodsCache.getUnchecked(clazz);
- } catch (UncheckedExecutionException e) {
- throw Throwables.propagate(e.getCause());
- }
- }
-
- private static ImmutableList<Method> getAnnotatedMethodsInternal(Class<?> clazz) {
- Set<? extends Class<?>> supers = TypeToken.of(clazz).getTypes().rawTypes();
- ImmutableList.Builder<Method> result = ImmutableList.builder();
- for (Method method : clazz.getMethods()) {
- /*
- * Iterate over each distinct method of {@code clazz}, checking if it is annotated with
- * @Subscribe by any of the superclasses or superinterfaces that declare it.
- */
- for (Class<?> c : supers) {
- try {
- Method m = c.getMethod(method.getName(), method.getParameterTypes());
- if (m.isAnnotationPresent(Subscribe.class)) {
- Class<?>[] parameterTypes = method.getParameterTypes();
- if (parameterTypes.length != 1) {
- throw new IllegalArgumentException("Method " + method
- + " has @Subscribe annotation, but requires " + parameterTypes.length
- + " arguments. Event handler methods must require a single argument.");
- }
- Class<?> eventType = parameterTypes[0];
- result.add(method);
- break;
+ if (annotation != null) {
+ Class<?>[] parameterTypes = method.getParameterTypes();
+ if (parameterTypes.length != 1) {
+ throw new IllegalArgumentException(
+ "Method " + method + " has @Subscribe annotation, but requires " +
+ parameterTypes.length + " arguments. Event handler methods " +
+ "must require a single argument.");
}
- } catch (NoSuchMethodException ignored) {
- // Move on.
+ Class<?> eventType = parameterTypes[0];
+ EventHandler handler = makeHandler(listener, method);
+
+ methodsInListener.put(eventType, handler);
}
}
+ clazz = clazz.getSuperclass();
}
- return result.build();
+ return methodsInListener;
}
/**
diff --git a/guava/src/com/google/common/eventbus/AsyncEventBus.java b/guava/src/com/google/common/eventbus/AsyncEventBus.java
index eb57aba..8018cee 100644
--- a/guava/src/com/google/common/eventbus/AsyncEventBus.java
+++ b/guava/src/com/google/common/eventbus/AsyncEventBus.java
@@ -16,10 +16,7 @@
package com.google.common.eventbus;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.Beta;
-
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
@@ -49,7 +46,7 @@ public class AsyncEventBus extends EventBus {
*/
public AsyncEventBus(String identifier, Executor executor) {
super(identifier);
- this.executor = checkNotNull(executor);
+ this.executor = executor;
}
/**
@@ -61,11 +58,11 @@ public class AsyncEventBus extends EventBus {
* been posted to this event bus.
*/
public AsyncEventBus(Executor executor) {
- this.executor = checkNotNull(executor);
+ this.executor = executor;
}
@Override
- void enqueueEvent(Object event, EventHandler handler) {
+ protected void enqueueEvent(Object event, EventHandler handler) {
eventsToDispatch.offer(new EventWithHandler(event, handler));
}
@@ -73,7 +70,6 @@ public class AsyncEventBus extends EventBus {
* Dispatch {@code events} in the order they were posted, regardless of
* the posting thread.
*/
- @SuppressWarnings("deprecation") // only deprecated for external subclasses
@Override
protected void dispatchQueuedEvents() {
while (true) {
@@ -90,15 +86,14 @@ public class AsyncEventBus extends EventBus {
* Calls the {@link #executor} to dispatch {@code event} to {@code handler}.
*/
@Override
- void dispatch(final Object event, final EventHandler handler) {
- checkNotNull(event);
- checkNotNull(handler);
- executor.execute(
- new Runnable() {
+ protected void dispatch(final Object event, final EventHandler handler) {
+ executor.execute(new Runnable() {
@Override
+ @SuppressWarnings("synthetic-access")
public void run() {
AsyncEventBus.super.dispatch(event, handler);
}
});
}
+
}
diff --git a/guava/src/com/google/common/eventbus/DeadEvent.java b/guava/src/com/google/common/eventbus/DeadEvent.java
index 03b4a2e..8265d5a 100644
--- a/guava/src/com/google/common/eventbus/DeadEvent.java
+++ b/guava/src/com/google/common/eventbus/DeadEvent.java
@@ -16,8 +16,6 @@
package com.google.common.eventbus;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.Beta;
/**
@@ -44,8 +42,8 @@ public class DeadEvent {
* @param event the event that could not be delivered.
*/
public DeadEvent(Object source, Object event) {
- this.source = checkNotNull(source);
- this.event = checkNotNull(event);
+ this.source = source;
+ this.event = event;
}
/**
diff --git a/guava/src/com/google/common/eventbus/EventBus.java b/guava/src/com/google/common/eventbus/EventBus.java
index 94cf2e9..a962fa8 100644
--- a/guava/src/com/google/common/eventbus/EventBus.java
+++ b/guava/src/com/google/common/eventbus/EventBus.java
@@ -16,28 +16,28 @@
package com.google.common.eventbus;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
-import com.google.common.reflect.TypeToken;
-import com.google.common.util.concurrent.UncheckedExecutionException;
+import com.google.common.collect.Sets;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
-import java.util.LinkedList;
+import java.util.List;
import java.util.Map.Entry;
-import java.util.Queue;
import java.util.Set;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -101,10 +101,6 @@ import java.util.logging.Logger;
* receive any Object will never receive a DeadEvent.
*
* <p>This class is safe for concurrent use.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/EventBusExplained">
- * {@code EventBus}</a>.
*
* @author Cliff Biffle
* @since 10.0
@@ -113,32 +109,18 @@ import java.util.logging.Logger;
public class EventBus {
/**
- * A thread-safe cache for flattenHierarchy(). The Class class is immutable. This cache is shared
- * across all EventBus instances, which greatly improves performance if multiple such instances
- * are created and objects of the same class are posted on all of them.
+ * All registered event handlers, indexed by event type.
*/
- private static final LoadingCache<Class<?>, Set<Class<?>>> flattenHierarchyCache =
- CacheBuilder.newBuilder()
- .weakKeys()
- .build(new CacheLoader<Class<?>, Set<Class<?>>>() {
- @SuppressWarnings({"unchecked", "rawtypes"}) // safe cast
+ private final SetMultimap<Class<?>, EventHandler> handlersByType =
+ Multimaps.newSetMultimap(new ConcurrentHashMap<Class<?>, Collection<EventHandler>>(),
+ new Supplier<Set<EventHandler>>() {
@Override
- public Set<Class<?>> load(Class<?> concreteClass) {
- return (Set) TypeToken.of(concreteClass).getTypes().rawTypes();
+ public Set<EventHandler> get() {
+ return new CopyOnWriteArraySet<EventHandler>();
}
});
/**
- * All registered event handlers, indexed by event type.
- *
- * <p>This SetMultimap is NOT safe for concurrent use; all access should be
- * made after acquiring a read or write lock via {@link #handlersByTypeLock}.
- */
- private final SetMultimap<Class<?>, EventHandler> handlersByType =
- HashMultimap.create();
- private final ReadWriteLock handlersByTypeLock = new ReentrantReadWriteLock();
-
- /**
* Logger for event dispatch failures. Named by the fully-qualified name of
* this class, followed by the identifier provided at construction.
*/
@@ -152,10 +134,11 @@ public class EventBus {
private final HandlerFindingStrategy finder = new AnnotatedHandlerFinder();
/** queues of events for the current thread to dispatch */
- private final ThreadLocal<Queue<EventWithHandler>> eventsToDispatch =
- new ThreadLocal<Queue<EventWithHandler>>() {
- @Override protected Queue<EventWithHandler> initialValue() {
- return new LinkedList<EventWithHandler>();
+ private final ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>>
+ eventsToDispatch =
+ new ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>>() {
+ @Override protected ConcurrentLinkedQueue<EventWithHandler> initialValue() {
+ return new ConcurrentLinkedQueue<EventWithHandler>();
}
};
@@ -168,6 +151,38 @@ public class EventBus {
};
/**
+ * A thread-safe cache for flattenHierarch(). The Class class is immutable.
+ */
+ private LoadingCache<Class<?>, Set<Class<?>>> flattenHierarchyCache =
+ CacheBuilder.newBuilder()
+ .weakKeys()
+ .build(new CacheLoader<Class<?>, Set<Class<?>>>() {
+ @Override
+ public Set<Class<?>> load(Class<?> concreteClass) throws Exception {
+ List<Class<?>> parents = Lists.newLinkedList();
+ Set<Class<?>> classes = Sets.newHashSet();
+
+ parents.add(concreteClass);
+
+ while (!parents.isEmpty()) {
+ Class<?> clazz = parents.remove(0);
+ classes.add(clazz);
+
+ Class<?> parent = clazz.getSuperclass();
+ if (parent != null) {
+ parents.add(parent);
+ }
+
+ for (Class<?> iface : clazz.getInterfaces()) {
+ parents.add(iface);
+ }
+ }
+
+ return classes;
+ }
+ });
+
+ /**
* Creates a new EventBus named "default".
*/
public EventBus() {
@@ -181,7 +196,7 @@ public class EventBus {
* be a valid Java identifier.
*/
public EventBus(String identifier) {
- logger = Logger.getLogger(EventBus.class.getName() + "." + checkNotNull(identifier));
+ logger = Logger.getLogger(EventBus.class.getName() + "." + identifier);
}
/**
@@ -193,14 +208,7 @@ public class EventBus {
* @param object object whose handler methods should be registered.
*/
public void register(Object object) {
- Multimap<Class<?>, EventHandler> methodsInListener =
- finder.findAllHandlers(object);
- handlersByTypeLock.writeLock().lock();
- try {
- handlersByType.putAll(methodsInListener);
- } finally {
- handlersByTypeLock.writeLock().unlock();
- }
+ handlersByType.putAll(finder.findAllHandlers(object));
}
/**
@@ -212,20 +220,14 @@ public class EventBus {
public void unregister(Object object) {
Multimap<Class<?>, EventHandler> methodsInListener = finder.findAllHandlers(object);
for (Entry<Class<?>, Collection<EventHandler>> entry : methodsInListener.asMap().entrySet()) {
- Class<?> eventType = entry.getKey();
+ Set<EventHandler> currentHandlers = getHandlersForEventType(entry.getKey());
Collection<EventHandler> eventMethodsInListener = entry.getValue();
-
- handlersByTypeLock.writeLock().lock();
- try {
- Set<EventHandler> currentHandlers = handlersByType.get(eventType);
- if (!currentHandlers.containsAll(eventMethodsInListener)) {
- throw new IllegalArgumentException(
- "missing event handler for an annotated method. Is " + object + " registered?");
- }
- currentHandlers.removeAll(eventMethodsInListener);
- } finally {
- handlersByTypeLock.writeLock().unlock();
+
+ if (currentHandlers == null || !currentHandlers.containsAll(entry.getValue())) {
+ throw new IllegalArgumentException(
+ "missing event handler for an annotated method. Is " + object + " registered?");
}
+ currentHandlers.removeAll(eventMethodsInListener);
}
}
@@ -245,18 +247,13 @@ public class EventBus {
boolean dispatched = false;
for (Class<?> eventType : dispatchTypes) {
- handlersByTypeLock.readLock().lock();
- try {
- Set<EventHandler> wrappers = handlersByType.get(eventType);
-
- if (!wrappers.isEmpty()) {
- dispatched = true;
- for (EventHandler wrapper : wrappers) {
- enqueueEvent(event, wrapper);
- }
+ Set<EventHandler> wrappers = getHandlersForEventType(eventType);
+
+ if (wrappers != null && !wrappers.isEmpty()) {
+ dispatched = true;
+ for (EventHandler wrapper : wrappers) {
+ enqueueEvent(event, wrapper);
}
- } finally {
- handlersByTypeLock.readLock().unlock();
}
}
@@ -272,7 +269,7 @@ public class EventBus {
* {@link #dispatchQueuedEvents()}. Events are queued in-order of occurrence
* so they can be dispatched in the same order.
*/
- void enqueueEvent(Object event, EventHandler handler) {
+ protected void enqueueEvent(Object event, EventHandler handler) {
eventsToDispatch.get().offer(new EventWithHandler(event, handler));
}
@@ -280,7 +277,7 @@ public class EventBus {
* Drain the queue of events to be dispatched. As the queue is being drained,
* new events may be posted to the end of the queue.
*/
- void dispatchQueuedEvents() {
+ protected void dispatchQueuedEvents() {
// don't dispatch if we're already dispatching, that would allow reentrancy
// and out-of-order events. Instead, leave the events to be dispatched
// after the in-progress dispatch is complete.
@@ -290,14 +287,16 @@ public class EventBus {
isDispatching.set(true);
try {
- Queue<EventWithHandler> events = eventsToDispatch.get();
- EventWithHandler eventWithHandler;
- while ((eventWithHandler = events.poll()) != null) {
+ while (true) {
+ EventWithHandler eventWithHandler = eventsToDispatch.get().poll();
+ if (eventWithHandler == null) {
+ break;
+ }
+
dispatch(eventWithHandler.event, eventWithHandler.handler);
}
} finally {
- isDispatching.remove();
- eventsToDispatch.remove();
+ isDispatching.set(false);
}
}
@@ -309,7 +308,7 @@ public class EventBus {
* @param event event to dispatch.
* @param wrapper wrapper that will call the handler.
*/
- void dispatch(Object event, EventHandler wrapper) {
+ protected void dispatch(Object event, EventHandler wrapper) {
try {
wrapper.handleEvent(event);
} catch (InvocationTargetException e) {
@@ -319,6 +318,29 @@ public class EventBus {
}
/**
+ * Retrieves a mutable set of the currently registered handlers for
+ * {@code type}. If no handlers are currently registered for {@code type},
+ * this method may either return {@code null} or an empty set.
+ *
+ * @param type type of handlers to retrieve.
+ * @return currently registered handlers, or {@code null}.
+ */
+ Set<EventHandler> getHandlersForEventType(Class<?> type) {
+ return handlersByType.get(type);
+ }
+
+ /**
+ * Creates a new Set for insertion into the handler map. This is provided
+ * as an override point for subclasses. The returned set should support
+ * concurrent access.
+ *
+ * @return a new, mutable set for handlers.
+ */
+ protected Set<EventHandler> newHandlerSet() {
+ return new CopyOnWriteArraySet<EventHandler>();
+ }
+
+ /**
* Flattens a class's type hierarchy into a set of Class objects. The set
* will include all superclasses (transitively), and all interfaces
* implemented by these superclasses.
@@ -329,8 +351,8 @@ public class EventBus {
@VisibleForTesting
Set<Class<?>> flattenHierarchy(Class<?> concreteClass) {
try {
- return flattenHierarchyCache.getUnchecked(concreteClass);
- } catch (UncheckedExecutionException e) {
+ return flattenHierarchyCache.get(concreteClass);
+ } catch (ExecutionException e) {
throw Throwables.propagate(e.getCause());
}
}
@@ -340,8 +362,8 @@ public class EventBus {
final Object event;
final EventHandler handler;
public EventWithHandler(Object event, EventHandler handler) {
- this.event = checkNotNull(event);
- this.handler = checkNotNull(handler);
+ this.event = event;
+ this.handler = handler;
}
}
}
diff --git a/guava/src/com/google/common/eventbus/EventHandler.java b/guava/src/com/google/common/eventbus/EventHandler.java
index 45efa80..be89973 100644
--- a/guava/src/com/google/common/eventbus/EventHandler.java
+++ b/guava/src/com/google/common/eventbus/EventHandler.java
@@ -16,15 +16,10 @@
package com.google.common.eventbus;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.base.Preconditions;
-
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import javax.annotation.Nullable;
-
/**
* Wraps a single-argument 'handler' method on a specific object.
*
@@ -65,11 +60,10 @@ class EventHandler {
*
* @param event event to handle
* @throws InvocationTargetException if the wrapped method throws any
- * {@link Throwable} that is not an {@link Error} ({@code Error} instances are
+ * {@link Throwable} that is not an {@link Error} ({@code Error}s are
* propagated as-is).
*/
public void handleEvent(Object event) throws InvocationTargetException {
- checkNotNull(event);
try {
method.invoke(target, new Object[] { event });
} catch (IllegalArgumentException e) {
@@ -90,18 +84,25 @@ class EventHandler {
@Override public int hashCode() {
final int PRIME = 31;
- return (PRIME + method.hashCode()) * PRIME
- + System.identityHashCode(target);
+ return (PRIME + method.hashCode()) * PRIME + target.hashCode();
}
- @Override public boolean equals(@Nullable Object obj) {
- if (obj instanceof EventHandler) {
- EventHandler that = (EventHandler) obj;
- // Use == so that different equal instances will still receive events.
- // We only guard against the case that the same object is registered
- // multiple times
- return target == that.target && method.equals(that.method);
+ @Override public boolean equals(Object obj) {
+ if(this == obj) {
+ return true;
+ }
+
+ if(obj == null) {
+ return false;
}
- return false;
+
+ if(getClass() != obj.getClass()) {
+ return false;
+ }
+
+ final EventHandler other = (EventHandler) obj;
+
+ return method.equals(other.method) && target == other.target;
}
+
}
diff --git a/guava/src/com/google/common/eventbus/HandlerFindingStrategy.java b/guava/src/com/google/common/eventbus/HandlerFindingStrategy.java
index 3f62cae..7144203 100644
--- a/guava/src/com/google/common/eventbus/HandlerFindingStrategy.java
+++ b/guava/src/com/google/common/eventbus/HandlerFindingStrategy.java
@@ -28,7 +28,7 @@ interface HandlerFindingStrategy {
/**
* Finds all suitable event handler methods in {@code source}, organizes them
- * by the type of event they handle, and wraps them in {@link EventHandler} instances.
+ * by the type of event they handle, and wraps them in {@link EventHandler}s.
*
* @param source object whose handlers are desired.
* @return EventHandler objects for each handler method, organized by event
diff --git a/guava/src/com/google/common/eventbus/Subscribe.java b/guava/src/com/google/common/eventbus/Subscribe.java
index 34cb587..568c1c0 100644
--- a/guava/src/com/google/common/eventbus/Subscribe.java
+++ b/guava/src/com/google/common/eventbus/Subscribe.java
@@ -17,7 +17,6 @@
package com.google.common.eventbus;
import com.google.common.annotations.Beta;
-
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/guava/src/com/google/common/eventbus/package-info.java b/guava/src/com/google/common/eventbus/package-info.java
index 28637cd..0c83104 100644
--- a/guava/src/com/google/common/eventbus/package-info.java
+++ b/guava/src/com/google/common/eventbus/package-info.java
@@ -21,10 +21,6 @@
* traditional Java in-process event distribution using explicit registration.
* It is <em>not</em> a general-purpose publish-subscribe system, nor is it
* intended for interprocess communication.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/EventBusExplained">
- * {@code EventBus}</a>.
*
* <h2>One-Minute Guide</h2>
*
@@ -123,6 +119,20 @@
* <p>In short, the EventBus is not a singleton because we'd rather not make
* that decision for you. Use it how you like.
*
+ * <h3>Can I unregister a listener from the Event Bus?</h3>
+ * Currently, no -- a listener registered with an EventBus instance will
+ * continue to receive events until the EventBus itself is disposed.
+ *
+ * <p>In the apps using EventBus so far, this has not been a problem:
+ * <ul>
+ * <li>Most listeners are registered on startup or lazy initialization, and
+ * persist for the life of the application.
+ * <li>Scope-specific EventBus instances can handle temporary event
+ * distribution (e.g. distributing events among request-scoped objects)
+ * <li>For testing, EventBus instances can be easily created and thrown away,
+ * removing the need for explicit unregistration.
+ * </ul>
+ *
* <h3>Why use an annotation to mark handler methods, rather than requiring the
* listener to implement an interface?</h3>
* We feel that the Event Bus's {@code @Subscribe} annotation conveys your
diff --git a/guava/src/com/google/common/hash/AbstractByteHasher.java b/guava/src/com/google/common/hash/AbstractByteHasher.java
deleted file mode 100644
index 90210df..0000000
--- a/guava/src/com/google/common/hash/AbstractByteHasher.java
+++ /dev/null
@@ -1,122 +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.hash;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndexes;
-
-import com.google.common.primitives.Chars;
-import com.google.common.primitives.Ints;
-import com.google.common.primitives.Longs;
-import com.google.common.primitives.Shorts;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * Abstract {@link Hasher} that handles converting primitives to bytes using a scratch {@code
- * ByteBuffer} and streams all bytes to a sink to compute the hash.
- *
- * @author Colin Decker
- */
-abstract class AbstractByteHasher extends AbstractHasher {
-
- private final ByteBuffer scratch = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
-
- /**
- * Updates this hasher with the given byte.
- */
- protected abstract void update(byte b);
-
- /**
- * Updates this hasher with the given bytes.
- */
- protected void update(byte[] b) {
- update(b, 0, b.length);
- }
-
- /**
- * Updates this hasher with {@code len} bytes starting at {@code off} in the given buffer.
- */
- protected void update(byte[] b, int off, int len) {
- for (int i = off; i < off + len; i++) {
- update(b[i]);
- }
- }
-
- @Override
- public Hasher putByte(byte b) {
- update(b);
- return this;
- }
-
- @Override
- public Hasher putBytes(byte[] bytes) {
- checkNotNull(bytes);
- update(bytes);
- return this;
- }
-
- @Override
- public Hasher putBytes(byte[] bytes, int off, int len) {
- checkPositionIndexes(off, off + len, bytes.length);
- update(bytes, off, len);
- return this;
- }
-
- /**
- * Updates the sink with the given number of bytes from the buffer.
- */
- private Hasher update(int bytes) {
- try {
- update(scratch.array(), 0, bytes);
- } finally {
- scratch.clear();
- }
- return this;
- }
-
- @Override
- public Hasher putShort(short s) {
- scratch.putShort(s);
- return update(Shorts.BYTES);
- }
-
- @Override
- public Hasher putInt(int i) {
- scratch.putInt(i);
- return update(Ints.BYTES);
- }
-
- @Override
- public Hasher putLong(long l) {
- scratch.putLong(l);
- return update(Longs.BYTES);
- }
-
- @Override
- public Hasher putChar(char c) {
- scratch.putChar(c);
- return update(Chars.BYTES);
- }
-
- @Override
- public <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
- funnel.funnel(instance, this);
- return this;
- }
-}
diff --git a/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java b/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java
index 6a0f452..41c4836 100644
--- a/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java
+++ b/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java
@@ -1,42 +1,23 @@
-/*
- * 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.
- */
+// Copyright 2011 Google Inc. All Rights Reserved.
package com.google.common.hash;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import java.nio.charset.Charset;
/**
* An abstract composition of multiple hash functions. {@linkplain #newHasher()} delegates to the
* {@code Hasher} objects of the delegate hash functions, and in the end, they are used by
* {@linkplain #makeHash(Hasher[])} that constructs the final {@code HashCode}.
- *
- * @author Dimitris Andreou
+ *
+ * @author andreou@google.com (Dimitris Andreou)
*/
abstract class AbstractCompositeHashFunction extends AbstractStreamingHashFunction {
final HashFunction[] functions;
-
+
AbstractCompositeHashFunction(HashFunction... functions) {
- for (HashFunction function : functions) {
- checkNotNull(function);
- }
this.functions = functions;
}
-
+
/**
* Constructs a {@code HashCode} from the {@code Hasher} objects of the functions. Each of them
* has consumed the entire input and they are ready to output a {@code HashCode}. The order of
@@ -44,7 +25,7 @@ abstract class AbstractCompositeHashFunction extends AbstractStreamingHashFuncti
*/
// this could be cleaner if it passed HashCode[], but that would create yet another array...
/* protected */ abstract HashCode makeHash(Hasher[] hashers);
-
+
@Override
public Hasher newHasher() {
final Hasher[] hashers = new Hasher[functions.length];
@@ -148,6 +129,6 @@ abstract class AbstractCompositeHashFunction extends AbstractStreamingHashFuncti
}
};
}
-
+
private static final long serialVersionUID = 0L;
}
diff --git a/guava/src/com/google/common/hash/AbstractHasher.java b/guava/src/com/google/common/hash/AbstractHasher.java
index f60f928..4abc6a3 100644
--- a/guava/src/com/google/common/hash/AbstractHasher.java
+++ b/guava/src/com/google/common/hash/AbstractHasher.java
@@ -14,6 +14,8 @@
package com.google.common.hash;
+import com.google.common.base.Charsets;
+
import java.nio.charset.Charset;
/**
@@ -21,7 +23,7 @@ import java.nio.charset.Charset;
* {@link #putFloat(float)}, {@link #putString(CharSequence)}, and
* {@link #putString(CharSequence, Charset)} as prescribed by {@link Hasher}.
*
- * @author Dimitris Andreou
+ * @author andreou@google.com (Dimitris Andreou)
*/
abstract class AbstractHasher implements Hasher {
@Override public final Hasher putBoolean(boolean b) {
@@ -37,13 +39,15 @@ abstract class AbstractHasher implements Hasher {
}
@Override public Hasher putString(CharSequence charSequence) {
- for (int i = 0, len = charSequence.length(); i < len; i++) {
- putChar(charSequence.charAt(i));
- }
- return this;
+ // TODO(user): Should we instead loop over the CharSequence and call #putChar?
+ return putString(charSequence, Charsets.UTF_16LE);
}
@Override public Hasher putString(CharSequence charSequence, Charset charset) {
- return putBytes(charSequence.toString().getBytes(charset));
+ try {
+ return putBytes(charSequence.toString().getBytes(charset.name()));
+ } catch (java.io.UnsupportedEncodingException impossible) {
+ throw new AssertionError(impossible);
+ }
}
}
diff --git a/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java b/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java
index 0025d3c..68e9ace 100644
--- a/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java
+++ b/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java
@@ -1,18 +1,4 @@
-/*
- * 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.
- */
+// Copyright 2011 Google Inc. All Rights Reserved.
package com.google.common.hash;
@@ -21,14 +7,13 @@ import com.google.common.base.Throwables;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.nio.charset.Charset;
/**
* Skeleton implementation of {@link HashFunction}, appropriate for non-streaming algorithms.
- * All the hash computation done using {@linkplain #newHasher()} are delegated to the {@linkplain
- * #hashBytes(byte[], int, int)} method.
- *
- * @author Dimitris Andreou
+ * All the hash computation done using {@linkplain #newHasher()} are delegated to the {@linkplain
+ * #hashBytes(byte[], int, int)} method.
+ *
+ * @author andreou@google.com (Dimitris Andreou)
*/
abstract class AbstractNonStreamingHashFunction implements HashFunction {
@Override
@@ -41,43 +26,14 @@ abstract class AbstractNonStreamingHashFunction implements HashFunction {
Preconditions.checkArgument(expectedInputSize >= 0);
return new BufferingHasher(expectedInputSize);
}
-
- @Override public <T> HashCode hashObject(T instance, Funnel<? super T> funnel) {
- return newHasher().putObject(instance, funnel).hash();
- }
-
- @Override public HashCode hashString(CharSequence input) {
- int len = input.length();
- Hasher hasher = newHasher(len * 2);
- for (int i = 0; i < len; i++) {
- hasher.putChar(input.charAt(i));
- }
- return hasher.hash();
- }
-
- @Override public HashCode hashString(CharSequence input, Charset charset) {
- return hashBytes(input.toString().getBytes(charset));
- }
-
- @Override public HashCode hashInt(int input) {
- return newHasher(4).putInt(input).hash();
- }
-
- @Override public HashCode hashLong(long input) {
- return newHasher(8).putLong(input).hash();
- }
-
- @Override public HashCode hashBytes(byte[] input) {
- return hashBytes(input, 0, input.length);
- }
-
+
/**
- * In-memory stream-based implementation of Hasher.
+ * In-memory stream-based implementation of Hasher.
*/
private final class BufferingHasher extends AbstractHasher {
final ExposedByteArrayOutputStream stream;
static final int BOTTOM_BYTE = 0xFF;
-
+
BufferingHasher(int expectedInputSize) {
this.stream = new ExposedByteArrayOutputStream(expectedInputSize);
}
@@ -97,7 +53,7 @@ abstract class AbstractNonStreamingHashFunction implements HashFunction {
}
return this;
}
-
+
@Override
public Hasher putBytes(byte[] bytes, int off, int len) {
stream.write(bytes, off, len);
@@ -146,7 +102,7 @@ abstract class AbstractNonStreamingHashFunction implements HashFunction {
return hashBytes(stream.byteArray(), 0, stream.length());
}
}
-
+
// Just to access the byte[] without introducing an unnecessary copy
private static final class ExposedByteArrayOutputStream extends ByteArrayOutputStream {
ExposedByteArrayOutputStream(int expectedInputSize) {
diff --git a/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java b/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java
index ea6f692..de7748f 100644
--- a/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java
+++ b/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java
@@ -33,10 +33,6 @@ import java.nio.charset.Charset;
* @author Kevin Bourrillion
*/
abstract class AbstractStreamingHashFunction implements HashFunction {
- @Override public <T> HashCode hashObject(T instance, Funnel<? super T> funnel) {
- return newHasher().putObject(instance, funnel).hash();
- }
-
@Override public HashCode hashString(CharSequence input) {
return newHasher().putString(input).hash();
}
@@ -45,10 +41,6 @@ abstract class AbstractStreamingHashFunction implements HashFunction {
return newHasher().putString(input, charset).hash();
}
- @Override public HashCode hashInt(int input) {
- return newHasher().putInt(input).hash();
- }
-
@Override public HashCode hashLong(long input) {
return newHasher().putLong(input).hash();
}
@@ -70,8 +62,8 @@ abstract class AbstractStreamingHashFunction implements HashFunction {
* A convenience base class for implementors of {@code Hasher}; handles accumulating data
* until an entire "chunk" (of implementation-dependent length) is ready to be hashed.
*
- * @author Kevin Bourrillion
- * @author Dimitris Andreou
+ * @author kevinb@google.com (Kevin Bourrillion)
+ * @author andreou@google.com (Dimitris Andreou)
*/
// TODO(kevinb): this class still needs some design-and-document-for-inheritance love
protected static abstract class AbstractStreamingHasher extends AbstractHasher {
@@ -150,7 +142,7 @@ abstract class AbstractStreamingHashFunction implements HashFunction {
return putBytes(ByteBuffer.wrap(bytes, off, len).order(ByteOrder.LITTLE_ENDIAN));
}
- private Hasher putBytes(ByteBuffer readBuffer) {
+ private final Hasher putBytes(ByteBuffer readBuffer) {
// If we have room for all of it, this is easy
if (readBuffer.remaining() <= buffer.remaining()) {
buffer.put(readBuffer);
diff --git a/guava/src/com/google/common/hash/BloomFilter.java b/guava/src/com/google/common/hash/BloomFilter.java
index 4f78bb9..04bba08 100644
--- a/guava/src/com/google/common/hash/BloomFilter.java
+++ b/guava/src/com/google/common/hash/BloomFilter.java
@@ -19,305 +19,206 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
+import com.google.common.base.Preconditions;
import com.google.common.hash.BloomFilterStrategies.BitArray;
import java.io.Serializable;
-import javax.annotation.Nullable;
-
/**
* A Bloom filter for instances of {@code T}. A Bloom filter offers an approximate containment test
- * with one-sided error: if it claims that an element is contained in it, this might be in error,
+ * with one-sided error: if it claims that an element is contained in it, this might be in error,
* but if it claims that an element is <i>not</i> contained in it, then this is definitely true.
- *
- * <p>If you are unfamiliar with Bloom filters, this nice
- * <a href="http://llimllib.github.com/bloomfilter-tutorial/">tutorial</a> may help you understand
+ *
+ * <p>If you are unfamiliar with Bloom filters, this nice
+ * <a href="http://llimllib.github.com/bloomfilter-tutorial/">tutorial</a> may help you understand
* how they work.
- *
- * <p>The false positive probability ({@code FPP}) of a bloom filter is defined as the probability
- * that {@linkplain #mightContain(Object)} will erroneously return {@code true} for an object that
- * has not actually been put in the {@code BloomFilter}.
- *
- *
+ *
* @param <T> the type of instances that the {@code BloomFilter} accepts
- * @author Dimitris Andreou
* @author Kevin Bourrillion
+ * @author Dimitris Andreou
* @since 11.0
*/
@Beta
-public final class BloomFilter<T> implements Predicate<T>, Serializable {
+public final class BloomFilter<T> implements Serializable {
/**
* A strategy to translate T instances, to {@code numHashFunctions} bit indexes.
- *
- * <p>Implementations should be collections of pure functions (i.e. stateless).
*/
interface Strategy extends java.io.Serializable {
-
/**
- * Sets {@code numHashFunctions} bits of the given bit array, by hashing a user element.
- *
- * <p>Returns whether any bits changed as a result of this operation.
+ * Sets {@code numHashFunctions} bits of the given bit array, by hashing a user element.
*/
- <T> boolean put(T object, Funnel<? super T> funnel, int numHashFunctions, BitArray bits);
-
+ <T> void put(T object, Funnel<? super T> funnel, int numHashFunctions, BitArray bits);
+
/**
* Queries {@code numHashFunctions} bits of the given bit array, by hashing a user element;
- * returns {@code true} if and only if all selected bits are set.
+ * returns {@code true} if and only if all selected bits are set.
*/
<T> boolean mightContain(
T object, Funnel<? super T> funnel, int numHashFunctions, BitArray bits);
-
- /**
- * Identifier used to encode this strategy, when marshalled as part of a BloomFilter.
- * Only values in the [-128, 127] range are valid for the compact serial form.
- * Non-negative values are reserved for enums defined in BloomFilterStrategies;
- * negative values are reserved for any custom, stateful strategy we may define
- * (e.g. any kind of strategy that would depend on user input).
- */
- int ordinal();
}
-
+
/** The bit set of the BloomFilter (not necessarily power of 2!)*/
private final BitArray bits;
-
- /** Number of hashes per element */
+
+ /** Number of hashes per element */
private final int numHashFunctions;
-
+
/** The funnel to translate Ts to bytes */
private final Funnel<T> funnel;
-
+
/**
* The strategy we employ to map an element T to {@code numHashFunctions} bit indexes.
*/
private final Strategy strategy;
-
+
/**
- * Creates a BloomFilter.
+ * Creates a BloomFilter.
*/
private BloomFilter(BitArray bits, int numHashFunctions, Funnel<T> funnel,
Strategy strategy) {
- checkArgument(numHashFunctions > 0,
- "numHashFunctions (%s) must be > 0", numHashFunctions);
- checkArgument(numHashFunctions <= 255,
- "numHashFunctions (%s) must be <= 255", numHashFunctions);
+ Preconditions.checkArgument(numHashFunctions > 0, "numHashFunctions zero or negative");
this.bits = checkNotNull(bits);
this.numHashFunctions = numHashFunctions;
this.funnel = checkNotNull(funnel);
- this.strategy = checkNotNull(strategy);
- }
-
- /**
- * Creates a new {@code BloomFilter} that's a copy of this instance. The new instance is equal to
- * this instance but shares no mutable state.
- *
- * @since 12.0
- */
- public BloomFilter<T> copy() {
- return new BloomFilter<T>(bits.copy(), numHashFunctions, funnel, strategy);
+ this.strategy = strategy;
}
-
+
/**
- * Returns {@code true} if the element <i>might</i> have been put in this Bloom filter,
- * {@code false} if this is <i>definitely</i> not the case.
+ * Returns {@code true} if the element <i>might</i> have been put in this Bloom filter,
+ * {@code false} if this is <i>definitely</i> not the case.
*/
public boolean mightContain(T object) {
return strategy.mightContain(object, funnel, numHashFunctions, bits);
}
/**
- * Equivalent to {@link #mightContain}; provided only to satisfy the {@link Predicate} interface.
- * When using a reference of type {@code BloomFilter}, always invoke {@link #mightContain}
- * directly instead.
- */
- @Override public boolean apply(T input) {
- return mightContain(input);
- }
-
- /**
- * Puts an element into this {@code BloomFilter}. Ensures that subsequent invocations of
+ * Puts an element into this {@code BloomFilter}. Ensures that subsequent invocations of
* {@link #mightContain(Object)} with the same element will always return {@code true}.
- *
- * @return true if the bloom filter's bits changed as a result of this operation. If the bits
- * changed, this is <i>definitely</i> the first time {@code object} has been added to the
- * filter. If the bits haven't changed, this <i>might</i> be the first time {@code object}
- * has been added to the filter. Note that {@code put(t)} always returns the
- * <i>opposite</i> result to what {@code mightContain(t)} would have returned at the time
- * it is called."
- * @since 12.0 (present in 11.0 with {@code void} return type})
- */
- public boolean put(T object) {
- return strategy.put(object, funnel, numHashFunctions, bits);
- }
-
- /**
- * Returns the probability that {@linkplain #mightContain(Object)} will erroneously return
- * {@code true} for an object that has not actually been put in the {@code BloomFilter}.
- *
- * <p>Ideally, this number should be close to the {@code fpp} parameter
- * passed in {@linkplain #create(Funnel, int, double)}, or smaller. If it is
- * significantly higher, it is usually the case that too many elements (more than
- * expected) have been put in the {@code BloomFilter}, degenerating it.
- *
- * @since 14.0 (since 11.0 as expectedFalsePositiveProbability())
- */
- public double expectedFpp() {
- // You down with FPP? (Yeah you know me!) Who's down with FPP? (Every last homie!)
- return Math.pow((double) bits.bitCount() / bits.size(), numHashFunctions);
- }
-
- /**
- * @deprecated Use {@link #expectedFpp} instead.
*/
- @Deprecated
- public double expectedFalsePositiveProbability() {
- return expectedFpp();
+ public void put(T object) {
+ strategy.put(object, funnel, numHashFunctions, bits);
}
-
- @Override
- public boolean equals(@Nullable Object object) {
- if (object == this) {
- return true;
- }
- if (object instanceof BloomFilter) {
- BloomFilter<?> that = (BloomFilter<?>) object;
- return this.numHashFunctions == that.numHashFunctions
- && this.funnel.equals(that.funnel)
- && this.bits.equals(that.bits)
- && this.strategy.equals(that.strategy);
- }
- return false;
+
+ @VisibleForTesting int getHashCount() {
+ return numHashFunctions;
}
-
- @Override
- public int hashCode() {
- return Objects.hashCode(numHashFunctions, funnel, strategy, bits);
+
+ @VisibleForTesting double computeExpectedFalsePositiveRate(int insertions) {
+ return Math.pow(
+ 1 - Math.exp(-numHashFunctions * ((double) insertions / (bits.size()))),
+ numHashFunctions);
}
-
+
/**
- * Creates a {@code Builder} of a {@link BloomFilter BloomFilter<T>}, with the expected number
+ * Creates a {@code Builder} of a {@link BloomFilter BloomFilter<T>}, with the expected number
* of insertions and expected false positive probability.
- *
- * <p>Note that overflowing a {@code BloomFilter} with significantly more elements
+ *
+ * <p>Note that overflowing a {@code BloomFilter} with significantly more elements
* than specified, will result in its saturation, and a sharp deterioration of its
* false positive probability.
- *
- * <p>The constructed {@code BloomFilter<T>} will be serializable if the provided
+ *
+ * <p>The constructed {@code BloomFilter<T>} will be serializable if the provided
* {@code Funnel<T>} is.
- *
- * <p>It is recommended the funnel is implemented as a Java enum. This has the benefit of ensuring
- * proper serialization and deserialization, which is important since {@link #equals} also relies
- * on object identity of funnels.
- *
+ *
* @param funnel the funnel of T's that the constructed {@code BloomFilter<T>} will use
- * @param expectedInsertions the number of expected insertions to the constructed
- * {@code BloomFilter<T>}; must be positive
- * @param fpp the desired false positive probability (must be positive and less than 1.0)
- * @return a {@code BloomFilter}
+ * @param expectedInsertions the number of expected insertions to the constructed
+ * {@code BloomFilter<T>}; must be positive
+ * @param falsePositiveProbability the desired false positive probability (must be positive and
+ * less than 1.0)
+ * @return a {@code Builder}
*/
- public static <T> BloomFilter<T> create(
- Funnel<T> funnel, int expectedInsertions /* n */, double fpp) {
+ public static <T> BloomFilter<T> create(Funnel<T> funnel, int expectedInsertions /* n */,
+ double falsePositiveProbability) {
checkNotNull(funnel);
- checkArgument(expectedInsertions >= 0, "Expected insertions (%s) must be >= 0",
- expectedInsertions);
- checkArgument(fpp > 0.0, "False positive probability (%s) must be > 0.0", fpp);
- checkArgument(fpp < 1.0, "False positive probability (%s) must be < 1.0", fpp);
- if (expectedInsertions == 0) {
- expectedInsertions = 1;
- }
- /*
- * TODO(user): Put a warning in the javadoc about tiny fpp values,
+ checkArgument(expectedInsertions > 0, "Expected insertions must be positive");
+ checkArgument(falsePositiveProbability > 0.0 & falsePositiveProbability < 1.0,
+ "False positive probability in (0.0, 1.0)");
+ /*
+ * andreou: I wanted to put a warning in the javadoc about tiny fpp values,
* since the resulting size is proportional to -log(p), but there is not
* much of a point after all, e.g. optimalM(1000, 0.0000000000000001) = 76680
* which is less that 10kb. Who cares!
*/
- long numBits = optimalNumOfBits(expectedInsertions, fpp);
+ int numBits = optimalNumOfBits(expectedInsertions, falsePositiveProbability);
int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);
- try {
- return new BloomFilter<T>(new BitArray(numBits), numHashFunctions, funnel,
- BloomFilterStrategies.MURMUR128_MITZ_32);
- } catch (IllegalArgumentException e) {
- throw new IllegalArgumentException("Could not create BloomFilter of " + numBits + " bits", e);
- }
+ return new BloomFilter<T>(new BitArray(numBits), numHashFunctions, funnel,
+ BloomFilterStrategies.MURMUR128_MITZ_32);
}
-
+
/**
- * Creates a {@code Builder} of a {@link BloomFilter BloomFilter<T>}, with the expected number
+ * Creates a {@code Builder} of a {@link BloomFilter BloomFilter<T>}, with the expected number
* of insertions, and a default expected false positive probability of 3%.
- *
- * <p>Note that overflowing a {@code BloomFilter} with significantly more elements
+ *
+ * <p>Note that overflowing a {@code BloomFilter} with significantly more elements
* than specified, will result in its saturation, and a sharp deterioration of its
* false positive probability.
- *
- * <p>The constructed {@code BloomFilter<T>} will be serializable if the provided
+ *
+ * <p>The constructed {@code BloomFilter<T>} will be serializable if the provided
* {@code Funnel<T>} is.
- *
+ *
* @param funnel the funnel of T's that the constructed {@code BloomFilter<T>} will use
- * @param expectedInsertions the number of expected insertions to the constructed
- * {@code BloomFilter<T>}; must be positive
- * @return a {@code BloomFilter}
+ * @param expectedInsertions the number of expected insertions to the constructed
+ * {@code BloomFilter<T>}; must be positive
+ * @return a {@code Builder}
*/
public static <T> BloomFilter<T> create(Funnel<T> funnel, int expectedInsertions /* n */) {
- return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions
+ return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions
}
-
+
/*
* Cheat sheet:
- *
+ *
* m: total bits
* n: expected insertions
* b: m/n, bits per insertion
* p: expected false positive probability
- *
+ *
* 1) Optimal k = b * ln2
* 2) p = (1 - e ^ (-kn/m))^k
* 3) For optimal k: p = 2 ^ (-k) ~= 0.6185^b
* 4) For optimal k: m = -nlnp / ((ln2) ^ 2)
*/
-
+
+ private static final double LN2 = Math.log(2);
+ private static final double LN2_SQUARED = LN2 * LN2;
+
/**
- * Computes the optimal k (number of hashes per element inserted in Bloom filter), given the
+ * Computes the optimal k (number of hashes per element inserted in Bloom filter), given the
* expected insertions and total number of bits in the Bloom filter.
- *
+ *
* See http://en.wikipedia.org/wiki/File:Bloom_filter_fp_probability.svg for the formula.
- *
+ *
* @param n expected insertions (must be positive)
* @param m total number of bits in Bloom filter (must be positive)
*/
- @VisibleForTesting
- static int optimalNumOfHashFunctions(long n, long m) {
- return Math.max(1, (int) Math.round(m / n * Math.log(2)));
+ @VisibleForTesting static int optimalNumOfHashFunctions(int n, int m) {
+ return Math.max(1, (int) Math.round(m / n * LN2));
}
-
+
/**
- * Computes m (total bits of Bloom filter) which is expected to achieve, for the specified
+ * Computes m (total bits of Bloom filter) which is expected to achieve, for the specified
* expected insertions, the required false positive probability.
- *
+ *
* See http://en.wikipedia.org/wiki/Bloom_filter#Probability_of_false_positives for the formula.
- *
+ *
* @param n expected insertions (must be positive)
* @param p false positive rate (must be 0 < p < 1)
*/
- @VisibleForTesting
- static long optimalNumOfBits(long n, double p) {
- if (p == 0) {
- p = Double.MIN_VALUE;
- }
- return (long) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
+ @VisibleForTesting static int optimalNumOfBits(int n, double p) {
+ return (int) (-n * Math.log(p) / LN2_SQUARED);
}
-
+
private Object writeReplace() {
return new SerialForm<T>(this);
}
-
+
private static class SerialForm<T> implements Serializable {
final long[] data;
final int numHashFunctions;
final Funnel<T> funnel;
final Strategy strategy;
-
+
SerialForm(BloomFilter<T> bf) {
this.data = bf.bits.data;
this.numHashFunctions = bf.numHashFunctions;
diff --git a/guava/src/com/google/common/hash/BloomFilterStrategies.java b/guava/src/com/google/common/hash/BloomFilterStrategies.java
index 0a4fa79..8c215e5 100644
--- a/guava/src/com/google/common/hash/BloomFilterStrategies.java
+++ b/guava/src/com/google/common/hash/BloomFilterStrategies.java
@@ -1,37 +1,20 @@
-/*
- * 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.
- */
+// Copyright 2011 Google Inc. All Rights Reserved.
package com.google.common.hash;
import static com.google.common.base.Preconditions.checkArgument;
-import com.google.common.math.LongMath;
-import com.google.common.primitives.Ints;
+import com.google.common.math.IntMath;
import java.math.RoundingMode;
-import java.util.Arrays;
/**
- * Collections of strategies of generating the k * log(M) bits required for an element to
- * be mapped to a BloomFilter of M bits and k hash functions. These
+ * Collections of strategies of generating the {@code k * log(M)} bits required for an element to
+ * be mapped to a {@link BloomFilter} of {@code M} bits and {@code k} hash functions. These
* strategies are part of the serialized form of the Bloom filters that use them, thus they must be
* preserved as is (no updates allowed, only introduction of new versions).
*
- * Important: the order of the constants cannot change, and they cannot be deleted - we depend
- * on their ordinal for BloomFilter serialization.
- *
- * @author Dimitris Andreou
+ * @author andreou@google.com (Dimitris Andreou)
*/
enum BloomFilterStrategies implements BloomFilter.Strategy {
/**
@@ -40,25 +23,25 @@ enum BloomFilterStrategies implements BloomFilter.Strategy {
* performance of a Bloom filter (yet only needs two 32bit hash functions).
*/
MURMUR128_MITZ_32() {
- @Override public <T> boolean put(T object, Funnel<? super T> funnel,
+ @Override public <T> void put(T object, Funnel<? super T> funnel,
int numHashFunctions, BitArray bits) {
- long hash64 = Hashing.murmur3_128().hashObject(object, funnel).asLong();
+ // TODO(user): when the murmur's shortcuts are implemented, update this code
+ long hash64 = Hashing.murmur3_128().newHasher().putObject(object, funnel).hash().asLong();
int hash1 = (int) hash64;
int hash2 = (int) (hash64 >>> 32);
- boolean bitsChanged = false;
for (int i = 1; i <= numHashFunctions; i++) {
int nextHash = hash1 + i * hash2;
if (nextHash < 0) {
nextHash = ~nextHash;
}
- bitsChanged |= bits.set(nextHash % bits.size());
+ // up to here, the code is identical with the next method
+ bits.set(nextHash % bits.size());
}
- return bitsChanged;
}
@Override public <T> boolean mightContain(T object, Funnel<? super T> funnel,
int numHashFunctions, BitArray bits) {
- long hash64 = Hashing.murmur3_128().hashObject(object, funnel).asLong();
+ long hash64 = Hashing.murmur3_128().newHasher().putObject(object, funnel).hash().asLong();
int hash1 = (int) hash64;
int hash2 = (int) (hash64 >>> 32);
for (int i = 1; i <= numHashFunctions; i++) {
@@ -66,6 +49,7 @@ enum BloomFilterStrategies implements BloomFilter.Strategy {
if (nextHash < 0) {
nextHash = ~nextHash;
}
+ // up to here, the code is identical with the previous method
if (!bits.get(nextHash % bits.size())) {
return false;
}
@@ -74,34 +58,21 @@ enum BloomFilterStrategies implements BloomFilter.Strategy {
}
};
- // Note: We use this instead of java.util.BitSet because we need access to the long[] data field
static class BitArray {
final long[] data;
- int bitCount;
- BitArray(long bits) {
- this(new long[Ints.checkedCast(LongMath.divide(bits, 64, RoundingMode.CEILING))]);
+ BitArray(int bits) {
+ this(new long[IntMath.divide(bits, 64, RoundingMode.CEILING)]);
}
// Used by serialization
BitArray(long[] data) {
checkArgument(data.length > 0, "data length is zero!");
this.data = data;
- int bitCount = 0;
- for (long value : data) {
- bitCount += Long.bitCount(value);
- }
- this.bitCount = bitCount;
}
- /** Returns true if the bit changed value. */
- boolean set(int index) {
- if (!get(index)) {
- data[index >> 6] |= (1L << index);
- bitCount++;
- return true;
- }
- return false;
+ void set(int index) {
+ data[index >> 6] |= (1L << index);
}
boolean get(int index) {
@@ -112,26 +83,5 @@ enum BloomFilterStrategies implements BloomFilter.Strategy {
int size() {
return data.length * Long.SIZE;
}
-
- /** Number of set bits (1s) */
- int bitCount() {
- return bitCount;
- }
-
- BitArray copy() {
- return new BitArray(data.clone());
- }
-
- @Override public boolean equals(Object o) {
- if (o instanceof BitArray) {
- BitArray bitArray = (BitArray) o;
- return Arrays.equals(data, bitArray.data);
- }
- return false;
- }
-
- @Override public int hashCode() {
- return Arrays.hashCode(data);
- }
}
}
diff --git a/guava/src/com/google/common/hash/ChecksumHashFunction.java b/guava/src/com/google/common/hash/ChecksumHashFunction.java
deleted file mode 100644
index bbcc00f..0000000
--- a/guava/src/com/google/common/hash/ChecksumHashFunction.java
+++ /dev/null
@@ -1,96 +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.hash;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.base.Supplier;
-
-import java.io.Serializable;
-import java.util.zip.Checksum;
-
-/**
- * {@link HashFunction} adapter for {@link Checksum} instances.
- *
- * @author Colin Decker
- */
-final class ChecksumHashFunction extends AbstractStreamingHashFunction implements Serializable {
-
- private final Supplier<? extends Checksum> checksumSupplier;
- private final int bits;
- private final String toString;
-
- ChecksumHashFunction(Supplier<? extends Checksum> checksumSupplier, int bits, String toString) {
- this.checksumSupplier = checkNotNull(checksumSupplier);
- checkArgument(bits == 32 || bits == 64, "bits (%s) must be either 32 or 64", bits);
- this.bits = bits;
- this.toString = checkNotNull(toString);
- }
-
- @Override
- public int bits() {
- return bits;
- }
-
- @Override
- public Hasher newHasher() {
- return new ChecksumHasher(checksumSupplier.get());
- }
-
- @Override
- public String toString() {
- return toString;
- }
-
- /**
- * Hasher that updates a checksum.
- */
- private final class ChecksumHasher extends AbstractByteHasher {
-
- private final Checksum checksum;
-
- private ChecksumHasher(Checksum checksum) {
- this.checksum = checkNotNull(checksum);
- }
-
- @Override
- protected void update(byte b) {
- checksum.update(b);
- }
-
- @Override
- protected void update(byte[] bytes, int off, int len) {
- checksum.update(bytes, off, len);
- }
-
- @Override
- public HashCode hash() {
- long value = checksum.getValue();
- if (bits == 32) {
- /*
- * The long returned from a 32-bit Checksum will have all 0s for its second word, so the
- * cast won't lose any information and is necessary to return a HashCode of the correct
- * size.
- */
- return HashCodes.fromInt((int) value);
- } else {
- return HashCodes.fromLong(value);
- }
- }
- }
-
- private static final long serialVersionUID = 0L;
-}
diff --git a/guava/src/com/google/common/hash/Funnel.java b/guava/src/com/google/common/hash/Funnel.java
index 6d62648..61cff7b 100644
--- a/guava/src/com/google/common/hash/Funnel.java
+++ b/guava/src/com/google/common/hash/Funnel.java
@@ -16,37 +16,18 @@ package com.google.common.hash;
import com.google.common.annotations.Beta;
-import java.io.Serializable;
-
/**
- * An object which can send data from an object of type {@code T} into a {@code PrimitiveSink}.
- *
- * <p>Note that serialization of {@linkplain BloomFilter bloom filters} requires the proper
- * serialization of funnels. When possible, it is recommended that funnels be implemented as a
- * single-element enum to maintain serialization guarantees. See Effective Java (2nd Edition),
- * Item 3: "Enforce the singleton property with a private constructor or an enum type". For example:
- * <pre> {@code
- * public enum PersonFunnel implements Funnel<Person> {
- * INSTANCE;
- * public void funnel(Person person, PrimitiveSink into) {
- * into.putString(person.getFirstName())
- * .putString(person.getLastName())
- * .putInt(person.getAge());
- * }
- * }}</pre>
+ * An object which can send data from an object of type {@code T} into a {@code Sink}.
*
* @author Dimitris Andreou
* @since 11.0
*/
@Beta
-public interface Funnel<T> extends Serializable {
-
+public interface Funnel<T> {
/**
* Sends a stream of data from the {@code from} object into the sink {@code into}. There
* is no requirement that this data be complete enough to fully reconstitute the object
* later.
- *
- * @since 12.0 (in Guava 11.0, {@code PrimitiveSink} was named {@code Sink})
*/
- void funnel(T from, PrimitiveSink into);
+ void funnel(T from, Sink into);
}
diff --git a/guava/src/com/google/common/hash/Funnels.java b/guava/src/com/google/common/hash/Funnels.java
index 7f76202..2cb04f4 100644
--- a/guava/src/com/google/common/hash/Funnels.java
+++ b/guava/src/com/google/common/hash/Funnels.java
@@ -15,13 +15,10 @@
package com.google.common.hash;
import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-
-import java.io.OutputStream;
/**
* Funnels for common types. All implementations are serializable.
- *
+ *
* @author Dimitris Andreou
* @since 11.0
*/
@@ -39,7 +36,7 @@ public final class Funnels {
private enum ByteArrayFunnel implements Funnel<byte[]> {
INSTANCE;
- public void funnel(byte[] from, PrimitiveSink into) {
+ public void funnel(byte[] from, Sink into) {
into.putBytes(from);
}
@@ -58,7 +55,7 @@ public final class Funnels {
private enum StringFunnel implements Funnel<CharSequence> {
INSTANCE;
- public void funnel(CharSequence from, PrimitiveSink into) {
+ public void funnel(CharSequence from, Sink into) {
into.putString(from);
}
@@ -66,83 +63,4 @@ public final class Funnels {
return "Funnels.stringFunnel()";
}
}
-
- /**
- * Returns a funnel for integers.
- *
- * @since 13.0
- */
- public static Funnel<Integer> integerFunnel() {
- return IntegerFunnel.INSTANCE;
- }
-
- private enum IntegerFunnel implements Funnel<Integer> {
- INSTANCE;
-
- public void funnel(Integer from, PrimitiveSink into) {
- into.putInt(from);
- }
-
- @Override public String toString() {
- return "Funnels.integerFunnel()";
- }
- }
-
- /**
- * Returns a funnel for longs.
- *
- * @since 13.0
- */
- public static Funnel<Long> longFunnel() {
- return LongFunnel.INSTANCE;
- }
-
- private enum LongFunnel implements Funnel<Long> {
- INSTANCE;
-
- public void funnel(Long from, PrimitiveSink into) {
- into.putLong(from);
- }
-
- @Override public String toString() {
- return "Funnels.longFunnel()";
- }
- }
-
- /**
- * Wraps a {@code PrimitiveSink} as an {@link OutputStream}, so it is easy to
- * {@link Funnel#funnel funnel} an object to a {@code PrimitiveSink}
- * if there is already a way to write the contents of the object to an {@code OutputStream}.
- *
- * <p>The {@code close} and {@code flush} methods of the returned {@code OutputStream}
- * do nothing, and no method throws {@code IOException}.
- *
- * @since 13.0
- */
- public static OutputStream asOutputStream(PrimitiveSink sink) {
- return new SinkAsStream(sink);
- }
-
- private static class SinkAsStream extends OutputStream {
- final PrimitiveSink sink;
- SinkAsStream(PrimitiveSink sink) {
- this.sink = Preconditions.checkNotNull(sink);
- }
-
- @Override public void write(int b) {
- sink.putByte((byte) b);
- }
-
- @Override public void write(byte[] bytes) {
- sink.putBytes(bytes);
- }
-
- @Override public void write(byte[] bytes, int off, int len) {
- sink.putBytes(bytes, off, len);
- }
-
- @Override public String toString() {
- return "Funnels.asOutputStream(" + sink + ")";
- }
- }
}
diff --git a/guava/src/com/google/common/hash/HashCode.java b/guava/src/com/google/common/hash/HashCode.java
index f955699..ecd8706 100644
--- a/guava/src/com/google/common/hash/HashCode.java
+++ b/guava/src/com/google/common/hash/HashCode.java
@@ -20,8 +20,6 @@ import com.google.common.primitives.Ints;
import java.security.MessageDigest;
-import javax.annotation.Nullable;
-
/**
* An immutable hash code of arbitrary bit length.
*
@@ -35,8 +33,6 @@ public abstract class HashCode {
/**
* Returns the first four bytes of {@linkplain #asBytes() this hashcode's bytes}, converted to
* an {@code int} value in little-endian order.
- *
- * @throws IllegalStateException if {@code bits() < 32}
*/
public abstract int asInt();
@@ -49,15 +45,6 @@ public abstract class HashCode {
public abstract long asLong();
/**
- * If this hashcode has enough bits, returns {@code asLong()}, otherwise returns a {@code long}
- * value with {@code asInt()} as the least-significant four bytes and {@code 0x00} as
- * each of the most-significant four bytes.
- *
- * @since 14.0 (since 11.0 as {@code Hashing.padToLong(HashCode)})
- */
- public abstract long padToLong();
-
- /**
* Returns the value of this hash code as a byte array. The caller may modify the byte array;
* changes to it will <i>not</i> be reflected in this {@code HashCode} object or any other arrays
* returned by this method.
@@ -83,11 +70,11 @@ public abstract class HashCode {
}
/**
- * Returns the number of bits in this hash code; a positive multiple of 8.
+ * Returns the number of bits in this hash code; a positive multiple of 32.
*/
public abstract int bits();
- @Override public boolean equals(@Nullable Object object) {
+ @Override public boolean equals(Object object) {
if (object instanceof HashCode) {
HashCode that = (HashCode) object;
// Undocumented: this is a non-short-circuiting equals(), in case this is a cryptographic
@@ -121,6 +108,7 @@ public abstract class HashCode {
*/
@Override public String toString() {
byte[] bytes = asBytes();
+ // TODO(user): Use c.g.common.base.ByteArrays once it is open sourced.
StringBuilder sb = new StringBuilder(2 * bytes.length);
for (byte b : bytes) {
sb.append(hexDigits[(b >> 4) & 0xf]).append(hexDigits[b & 0xf]);
diff --git a/guava/src/com/google/common/hash/HashCodes.java b/guava/src/com/google/common/hash/HashCodes.java
index b911c28..b6101a5 100644
--- a/guava/src/com/google/common/hash/HashCodes.java
+++ b/guava/src/com/google/common/hash/HashCodes.java
@@ -14,35 +14,23 @@
package com.google.common.hash;
-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.primitives.UnsignedInts;
-
-import java.io.Serializable;
-
/**
- * Static factories for creating {@link HashCode} instances; most users should never have to use
- * this. All returned instances are {@link Serializable}.
- *
- * @author Dimitris Andreou
- * @since 12.0
+ * Static factories for {@link HashCode} instances.
+ *
+ * @author andreou@google.com (Dimitris Andreou)
*/
-@Beta
-public final class HashCodes {
- private HashCodes() {}
-
+final class HashCodes {
+ private HashCodes() { }
+
/**
* Creates a 32-bit {@code HashCode}, of which the bytes will form the passed int, interpreted
* in little endian order.
*/
- public static HashCode fromInt(int hash) {
+ static HashCode fromInt(int hash) {
return new IntHashCode(hash);
}
- private static final class IntHashCode extends HashCode implements Serializable {
+ private static class IntHashCode extends HashCode {
final int hash;
IntHashCode(int hash) {
@@ -68,24 +56,17 @@ public final class HashCodes {
@Override public long asLong() {
throw new IllegalStateException("this HashCode only has 32 bits; cannot create a long");
}
-
- @Override
- public long padToLong() {
- return UnsignedInts.toLong(hash);
- }
-
- private static final long serialVersionUID = 0;
}
/**
* Creates a 64-bit {@code HashCode}, of which the bytes will form the passed long, interpreted
* in little endian order.
*/
- public static HashCode fromLong(long hash) {
+ static HashCode fromLong(long hash) {
return new LongHashCode(hash);
}
- private static final class LongHashCode extends HashCode implements Serializable {
+ private static class LongHashCode extends HashCode {
final long hash;
LongHashCode(long hash) {
@@ -115,37 +96,22 @@ public final class HashCodes {
@Override public long asLong() {
return hash;
}
-
- @Override
- public long padToLong() {
- return hash;
- }
-
- private static final long serialVersionUID = 0;
}
-
- /**
- * Creates a {@code HashCode} from a byte array. The array is defensively copied to preserve
- * the immutability contract of {@code HashCode}. The array cannot be empty.
- */
- public static HashCode fromBytes(byte[] bytes) {
- checkArgument(bytes.length >= 1, "A HashCode must contain at least 1 byte.");
- return fromBytesNoCopy(bytes.clone());
- }
-
+
/**
* Creates a {@code HashCode} from a byte array. The array is <i>not</i> copied defensively,
* so it must be handed-off so as to preserve the immutability contract of {@code HashCode}.
+ * The array must be at least of length 4 (not checked).
*/
- static HashCode fromBytesNoCopy(byte[] bytes) {
+ static HashCode fromBytes(byte[] bytes) {
return new BytesHashCode(bytes);
}
- private static final class BytesHashCode extends HashCode implements Serializable {
+ private static class BytesHashCode extends HashCode {
final byte[] bytes;
BytesHashCode(byte[] bytes) {
- this.bytes = checkNotNull(bytes);
+ this.bytes = bytes;
}
@Override public int bits() {
@@ -157,8 +123,6 @@ public final class HashCodes {
}
@Override public int asInt() {
- checkState(bytes.length >= 4,
- "HashCode#asInt() requires >= 4 bytes (it only has %s bytes).", bytes.length);
return (bytes[0] & 0xFF)
| ((bytes[1] & 0xFF) << 8)
| ((bytes[2] & 0xFF) << 16)
@@ -166,8 +130,10 @@ public final class HashCodes {
}
@Override public long asLong() {
- checkState(bytes.length >= 8,
- "HashCode#asLong() requires >= 8 bytes (it only has %s bytes).", bytes.length);
+ if (bytes.length < 8) {
+ // Checking this to throw the correct type of exception
+ throw new IllegalStateException("Not enough bytes");
+ }
return (bytes[0] & 0xFFL)
| ((bytes[1] & 0xFFL) << 8)
| ((bytes[2] & 0xFFL) << 16)
@@ -177,25 +143,5 @@ public final class HashCodes {
| ((bytes[6] & 0xFFL) << 48)
| ((bytes[7] & 0xFFL) << 56);
}
-
- @Override
- public long padToLong() {
- return (bytes.length < 8) ? UnsignedInts.toLong(asInt()) : asLong();
- }
-
- @Override
- public int hashCode() {
- if (bytes.length >= 4) {
- return asInt();
- } else {
- int val = (bytes[0] & 0xFF);
- for (int i = 1; i < bytes.length; i++) {
- val |= ((bytes[i] & 0xFF) << (i * 8));
- }
- return val;
- }
- }
-
- private static final long serialVersionUID = 0;
}
}
diff --git a/guava/src/com/google/common/hash/HashFunction.java b/guava/src/com/google/common/hash/HashFunction.java
index 0386261..ba3c992 100644
--- a/guava/src/com/google/common/hash/HashFunction.java
+++ b/guava/src/com/google/common/hash/HashFunction.java
@@ -40,8 +40,7 @@ import java.nio.charset.Charset;
* represents a hash code as an instance of {@link HashCode}.
*
* <li><b>pure function:</b> the value produced must depend only on the input bytes, in
- * the order they appear. Input data is never modified. {@link HashFunction} instances
- * should always be stateless, and therefore thread-safe.
+ * the order they appear. Input data is never modified.
*
* <li><b>collision-averse:</b> while it can't be helped that a hash function will
* sometimes produce the same hash code for distinct inputs (a "collision"), every
@@ -143,21 +142,12 @@ public interface HashFunction {
Hasher newHasher();
/**
- * Begins a new hash code computation as {@link #newHasher()}, but provides a hint of the
+ * Begins a new hash code computation as {@link #newHasher()}, but provides a hint of the
* expected size of the input (in bytes). This is only important for non-streaming hash
- * functions (hash functions that need to buffer their whole input before processing any
- * of it).
+ * functions (hash functions that need to buffer their whole input before processing any
+ * of it).
*/
- Hasher newHasher(int expectedInputSize);
-
- /**
- * Shortcut for {@code newHasher().putInt(input).hash()}; returns the hash code for the given
- * {@code int} value, interpreted in little-endian byte order. The implementation <i>might</i>
- * perform better than its longhand equivalent, but should not perform worse.
- *
- * @since 12.0
- */
- HashCode hashInt(int input);
+ Hasher newHasher(int expectedInputSize);
/**
* Shortcut for {@code newHasher().putLong(input).hash()}; returns the hash code for the
@@ -175,9 +165,9 @@ public interface HashFunction {
/**
* Shortcut for {@code newHasher().putBytes(input, off, len).hash()}. The implementation
- * <i>might</i> perform better than its longhand equivalent, but should not perform
- * worse.
- *
+ * <i>might</i> perform better than its longhand equivalent, but should not perform
+ * worse.
+ *
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > bytes.length}
* or {@code len < 0}
*/
@@ -200,14 +190,6 @@ public interface HashFunction {
HashCode hashString(CharSequence input, Charset charset);
/**
- * Shortcut for {@code newHasher().putObject(instance, funnel).hash()}. The implementation
- * <i>might</i> perform better than its longhand equivalent, but should not perform worse.
- *
- * @since 14.0
- */
- <T> HashCode hashObject(T instance, Funnel<? super T> funnel);
-
- /**
* Returns the number of bits (a multiple of 32) that each hash code produced by this
* hash function has.
*/
diff --git a/guava/src/com/google/common/hash/Hasher.java b/guava/src/com/google/common/hash/Hasher.java
index e7adc82..b10d536 100644
--- a/guava/src/com/google/common/hash/Hasher.java
+++ b/guava/src/com/google/common/hash/Hasher.java
@@ -19,62 +19,40 @@ import com.google.common.annotations.Beta;
import java.nio.charset.Charset;
/**
- * A {@link PrimitiveSink} that can compute a hash code after reading the input. Each hasher should
- * translate all multibyte values ({@link #putInt(int)}, {@link #putLong(long)}, etc) to bytes
+ * A {@link Sink} that can compute a hash code after reading the input. Each hasher should
+ * translate all multibyte values ({@link #putInt(int)}, {@link #putLong(long)}, etc) to bytes
* in little-endian order.
*
- * <p>The result of calling any methods after calling {@link #hash} is undefined.
- *
- * <p><b>Warning:</b> Chunks of data that are put into the {@link Hasher} are not delimited.
- * The resulting {@link HashCode} is dependent only on the bytes inserted, and the order in which
- * they were inserted, not how those bytes were chunked into discrete put() operations. For example,
- * the following three expressions all generate colliding hash codes: <pre> {@code
- *
- * newHasher().putString("ab").putString("c").hash()
- * newHasher().putString("a").putString("bc").hash()
- * newHasher().putChar('a').putChar('b').putChar('c').hash()}</pre>
- *
- * If you wish to avoid this, you should either prepend or append the size of each chunk.
- * For example:
- * <pre> {@code
- * newHasher().putInt(s1.length()).putString(s1).putInt(s2.length()).putString(s2).hash()}</pre>
- *
* @author Kevin Bourrillion
* @since 11.0
*/
@Beta
-public interface Hasher extends PrimitiveSink {
+public interface Hasher extends Sink {
@Override Hasher putByte(byte b);
@Override Hasher putBytes(byte[] bytes);
@Override Hasher putBytes(byte[] bytes, int off, int len);
@Override Hasher putShort(short s);
@Override Hasher putInt(int i);
@Override Hasher putLong(long l);
-
/**
* Equivalent to {@code putInt(Float.floatToRawIntBits(f))}.
*/
@Override Hasher putFloat(float f);
-
/**
* Equivalent to {@code putLong(Double.doubleToRawLongBits(d))}.
*/
@Override Hasher putDouble(double d);
-
/**
* Equivalent to {@code putByte(b ? (byte) 1 : (byte) 0)}.
*/
@Override Hasher putBoolean(boolean b);
@Override Hasher putChar(char c);
-
/**
- * Equivalent to processing each {@code char} value in the {@code CharSequence}, in order.
- * The input must not be updated while this method is in progress.
+ * Equivalent to {@code putBytes(charSequence.toString().getBytes(Charsets.UTF_16LE)}.
*/
@Override Hasher putString(CharSequence charSequence);
-
/**
- * Equivalent to {@code putBytes(charSequence.toString().getBytes(charset))}.
+ * Equivalent to {@code putBytes(charSequence.toString().getBytes(charset)}.
*/
@Override Hasher putString(CharSequence charSequence, Charset charset);
@@ -85,7 +63,7 @@ public interface Hasher extends PrimitiveSink {
/**
* Computes a hash code based on the data that have been provided to this hasher. The result is
- * unspecified if this method is called more than once on the same instance.
+ * unspecified if this method is called more than once on the same instance.
*/
HashCode hash();
}
diff --git a/guava/src/com/google/common/hash/Hashing.java b/guava/src/com/google/common/hash/Hashing.java
index 0e81d0e..f2582c7 100644
--- a/guava/src/com/google/common/hash/Hashing.java
+++ b/guava/src/com/google/common/hash/Hashing.java
@@ -17,19 +17,15 @@ package com.google.common.hash;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Supplier;
+import com.google.common.primitives.UnsignedInts;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.Iterator;
-import java.util.zip.Adler32;
-import java.util.zip.CRC32;
-import java.util.zip.Checksum;
/**
- * Static methods to obtain {@link HashFunction} instances, and other static hashing-related
- * utilities.
+ * Static methods to obtain {@link HashFunction} instances, and other static
+ * hashing-related utilities.
*
* @author Kevin Bourrillion
* @author Dimitris Andreou
@@ -41,27 +37,11 @@ public final class Hashing {
private Hashing() {}
/**
- * Used to randomize {@link #goodFastHash} instances, so that programs which persist anything
- * dependent on hashcodes of those, will fail sooner than later.
- */
- private static final int GOOD_FAST_HASH_SEED = (int) System.currentTimeMillis();
-
- // Used by goodFastHash when minimumBits == 32.
- private static final HashFunction GOOD_FAST_HASH_FUNCTION_32 = murmur3_32(GOOD_FAST_HASH_SEED);
-
- // Used by goodFastHash when 32 < minimumBits <= 128.
- private static final HashFunction GOOD_FAST_HASH_FUNCTION_128 = murmur3_128(GOOD_FAST_HASH_SEED);
-
- /**
* Returns a general-purpose, <b>non-cryptographic-strength</b>, streaming hash function that
* produces hash codes of length at least {@code minimumBits}. Users without specific
* compatibility requirements and who do not persist the hash codes are encouraged to
* choose this hash function.
*
- * <p>Repeated calls to {@link #goodFastHash} with the same {@code minimumBits} value will
- * return {@link HashFunction} instances with identical behavior (but not necessarily the
- * same instance) for the duration of the current virtual machine.
- *
* <p><b>Warning: the implementation is unspecified and is subject to change.</b>
*
* @throws IllegalArgumentException if {@code minimumBits} is not positive
@@ -70,31 +50,24 @@ public final class Hashing {
int bits = checkPositiveAndMakeMultipleOf32(minimumBits);
if (bits == 32) {
- return GOOD_FAST_HASH_FUNCTION_32;
- }
- if (bits <= 128) {
- return GOOD_FAST_HASH_FUNCTION_128;
- }
-
- // Otherwise, join together some 128-bit murmur3s
- int hashFunctionsNeeded = (bits + 127) / 128;
- HashFunction[] hashFunctions = new HashFunction[hashFunctionsNeeded];
- hashFunctions[0] = GOOD_FAST_HASH_FUNCTION_128;
- int seed = GOOD_FAST_HASH_SEED;
- for (int i = 1; i < hashFunctionsNeeded; i++) {
- seed += 1500450271; // a prime; shouldn't matter
- hashFunctions[i] = murmur3_128(seed);
+ return murmur3_32();
+ } else if (bits <= 128) {
+ return murmur3_128();
+ } else {
+ // Join some 128-bit murmur3s
+ int hashFunctionsNeeded = (bits + 127) / 128;
+ HashFunction[] hashFunctions = new HashFunction[hashFunctionsNeeded];
+ for (int i = 0; i < hashFunctionsNeeded; i++) {
+ hashFunctions[i] = murmur3_128(i * 1500450271 /* a prime; shouldn't matter */);
+ }
+ return new ConcatenatedHashFunction(hashFunctions);
}
- return new ConcatenatedHashFunction(hashFunctions);
}
/**
* Returns a hash function implementing the
- * <a href="http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp">
- * 32-bit murmur3 algorithm, x86 variant</a> (little-endian variant),
- * using the given seed value.
- *
- * <p>The exact C++ equivalent is the MurmurHash3_x86_32 function (Murmur3A).
+ * <a href="http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp">32-bit murmur3
+ * algorithm</a> (little-endian variant), using the given seed value.
*/
public static HashFunction murmur3_32(int seed) {
return new Murmur3_32HashFunction(seed);
@@ -102,25 +75,20 @@ public final class Hashing {
/**
* Returns a hash function implementing the
- * <a href="http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp">
- * 32-bit murmur3 algorithm, x86 variant</a> (little-endian variant),
- * using a seed value of zero.
- *
- * <p>The exact C++ equivalent is the MurmurHash3_x86_32 function (Murmur3A).
+ * <a href="http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp">32-bit murmur3
+ * algorithm</a> (little-endian variant), using a seed value of zero.
*/
public static HashFunction murmur3_32() {
return MURMUR3_32;
}
- private static final HashFunction MURMUR3_32 = new Murmur3_32HashFunction(0);
+ private static final Murmur3_32HashFunction MURMUR3_32 = new Murmur3_32HashFunction(0);
/**
* Returns a hash function implementing the
* <a href="http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp">
- * 128-bit murmur3 algorithm, x64 variant</a> (little-endian variant),
- * using the given seed value.
- *
- * <p>The exact C++ equivalent is the MurmurHash3_x64_128 function (Murmur3F).
+ * 128-bit murmur3 algorithm, x64 variant</a> (little-endian variant), using the given seed
+ * value.
*/
public static HashFunction murmur3_128(int seed) {
return new Murmur3_128HashFunction(seed);
@@ -129,133 +97,62 @@ public final class Hashing {
/**
* Returns a hash function implementing the
* <a href="http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp">
- * 128-bit murmur3 algorithm, x64 variant</a> (little-endian variant),
- * using a seed value of zero.
- *
- * <p>The exact C++ equivalent is the MurmurHash3_x64_128 function (Murmur3F).
+ * 128-bit murmur3 algorithm, x64 variant</a> (little-endian variant), using a seed value
+ * of zero.
*/
public static HashFunction murmur3_128() {
return MURMUR3_128;
}
- private static final HashFunction MURMUR3_128 = new Murmur3_128HashFunction(0);
+ private static final Murmur3_128HashFunction MURMUR3_128 = new Murmur3_128HashFunction(0);
/**
- * Returns a hash function implementing the MD5 hash algorithm (128 hash bits) by delegating to
- * the MD5 {@link MessageDigest}.
+ * Returns a hash function implementing the MD5 hash algorithm by delegating to the MD5
+ * {@link MessageDigest}.
*/
public static HashFunction md5() {
return MD5;
}
- private static final HashFunction MD5 = new MessageDigestHashFunction("MD5", "Hashing.md5()");
+ private static final HashFunction MD5 = new MessageDigestHashFunction("MD5");
/**
- * Returns a hash function implementing the SHA-1 algorithm (160 hash bits) by delegating to the
- * SHA-1 {@link MessageDigest}.
+ * Returns a hash function implementing the SHA-1 algorithm by delegating to the SHA-1
+ * {@link MessageDigest}.
*/
public static HashFunction sha1() {
return SHA_1;
}
- private static final HashFunction SHA_1 =
- new MessageDigestHashFunction("SHA-1", "Hashing.sha1()");
+ private static final HashFunction SHA_1 = new MessageDigestHashFunction("SHA-1");
/**
- * Returns a hash function implementing the SHA-256 algorithm (256 hash bits) by delegating to
- * the SHA-256 {@link MessageDigest}.
+ * Returns a hash function implementing the SHA-256 algorithm by delegating to the SHA-256
+ * {@link MessageDigest}.
*/
public static HashFunction sha256() {
return SHA_256;
}
- private static final HashFunction SHA_256 =
- new MessageDigestHashFunction("SHA-256", "Hashing.sha256()");
+ private static final HashFunction SHA_256 = new MessageDigestHashFunction("SHA-256");
/**
- * Returns a hash function implementing the SHA-512 algorithm (512 hash bits) by delegating to the
- * SHA-512 {@link MessageDigest}.
+ * Returns a hash function implementing the SHA-512 algorithm by delegating to the SHA-512
+ * {@link MessageDigest}.
*/
public static HashFunction sha512() {
return SHA_512;
}
- private static final HashFunction SHA_512 =
- new MessageDigestHashFunction("SHA-512", "Hashing.sha512()");
-
- /**
- * Returns a hash function implementing the CRC-32 checksum algorithm (32 hash bits) by delegating
- * to the {@link CRC32} {@link Checksum}.
- *
- * <p>To get the {@code long} value equivalent to {@link Checksum#getValue()} for a
- * {@code HashCode} produced by this function, use {@link HashCode#padToLong()}.
- *
- * @since 14.0
- */
- public static HashFunction crc32() {
- return CRC_32;
- }
-
- private static final HashFunction CRC_32 =
- checksumHashFunction(ChecksumType.CRC_32, "Hashing.crc32()");
-
- /**
- * Returns a hash function implementing the Adler-32 checksum algorithm (32 hash bits) by
- * delegating to the {@link Adler32} {@link Checksum}.
- *
- * <p>To get the {@code long} value equivalent to {@link Checksum#getValue()} for a
- * {@code HashCode} produced by this function, use {@link HashCode#padToLong()}.
- *
- * @since 14.0
- */
- public static HashFunction adler32() {
- return ADLER_32;
- }
-
- private static final HashFunction ADLER_32 =
- checksumHashFunction(ChecksumType.ADLER_32, "Hashing.adler32()");
-
- private static HashFunction checksumHashFunction(ChecksumType type, String toString) {
- return new ChecksumHashFunction(type, type.bits, toString);
- }
-
- enum ChecksumType implements Supplier<Checksum> {
- CRC_32(32) {
- @Override
- public Checksum get() {
- return new CRC32();
- }
- },
- ADLER_32(32) {
- @Override
- public Checksum get() {
- return new Adler32();
- }
- };
-
- private final int bits;
-
- ChecksumType(int bits) {
- this.bits = bits;
- }
-
- @Override
- public abstract Checksum get();
- }
-
- // Lazy initialization holder class idiom.
+ private static final HashFunction SHA_512 = new MessageDigestHashFunction("SHA-512");
/**
* If {@code hashCode} has enough bits, returns {@code hashCode.asLong()}, otherwise
* returns a {@code long} value with {@code hashCode.asInt()} as the least-significant
* four bytes and {@code 0x00} as each of the most-significant four bytes.
- *
- * @deprecated Use {@code HashCode.padToLong()} instead. This method is scheduled to be
- * removed in Guava 15.0.
*/
- @Deprecated
public static long padToLong(HashCode hashCode) {
- return hashCode.padToLong();
+ return (hashCode.bits() < 64) ? UnsignedInts.toLong(hashCode.asInt()) : hashCode.asLong();
}
/**
@@ -270,12 +167,9 @@ public final class Hashing {
*
* <p>See the <a href="http://en.wikipedia.org/wiki/Consistent_hashing">wikipedia
* article on consistent hashing</a> for more information.
- * <p>
- * If you might want to have weights for the buckets in the future, take a look at
- * {@code weightedConsistentHash}.
*/
public static int consistentHash(HashCode hashCode, int buckets) {
- return consistentHash(hashCode.padToLong(), buckets);
+ return consistentHash(padToLong(hashCode), buckets);
}
/**
@@ -290,19 +184,21 @@ public final class Hashing {
*
* <p>See the <a href="http://en.wikipedia.org/wiki/Consistent_hashing">wikipedia
* article on consistent hashing</a> for more information.
- * <p>
- * If you might want to have weights for the buckets in the future, take a look at
- * {@code weightedConsistentHash}.
*/
public static int consistentHash(long input, int buckets) {
checkArgument(buckets > 0, "buckets must be positive: %s", buckets);
- LinearCongruentialGenerator generator = new LinearCongruentialGenerator(input);
+ long h = input;
int candidate = 0;
int next;
// Jump from bucket to bucket until we go out of range
while (true) {
- next = (int) ((candidate + 1) / generator.nextDouble());
+ // See http://en.wikipedia.org/wiki/Linear_congruential_generator
+ // These values for a and m come from the C++ version of this function.
+ h = 2862933555777941757L * h + 1;
+ double inv = 0x1.0p31 / ((int) (h >>> 33) + 1);
+ next = (int) ((candidate + 1) * inv);
+
if (next >= 0 && next < buckets) {
candidate = next;
} else {
@@ -334,7 +230,7 @@ public final class Hashing {
resultBytes[i] = (byte) (resultBytes[i] * 37 ^ nextBytes[i]);
}
}
- return HashCodes.fromBytesNoCopy(resultBytes);
+ return HashCodes.fromBytes(resultBytes);
}
/**
@@ -359,7 +255,7 @@ public final class Hashing {
resultBytes[i] += nextBytes[i];
}
}
- return HashCodes.fromBytesNoCopy(resultBytes);
+ return HashCodes.fromBytes(resultBytes);
}
/**
@@ -370,29 +266,27 @@ public final class Hashing {
return (bits + 31) & ~31;
}
- // TODO(kevinb): Maybe expose this class via a static Hashing method?
- @VisibleForTesting
- static final class ConcatenatedHashFunction extends AbstractCompositeHashFunction {
- private final int bits;
+ // TODO(kevinb): probably expose this via a Hashing method at some point?
+ private static class ConcatenatedHashFunction extends AbstractCompositeHashFunction {
+ final int bits;
- ConcatenatedHashFunction(HashFunction... functions) {
+ ConcatenatedHashFunction(HashFunction[] functions) {
super(functions);
int bitSum = 0;
- for (HashFunction function : functions) {
- bitSum += function.bits();
+ for (HashFunction f : this.functions) {
+ bitSum += f.bits();
}
this.bits = bitSum;
}
@Override
HashCode makeHash(Hasher[] hashers) {
- // TODO(user): Get rid of the ByteBuffer here?
byte[] bytes = new byte[bits / 8];
ByteBuffer buffer = ByteBuffer.wrap(bytes);
for (Hasher hasher : hashers) {
buffer.put(hasher.hash().asBytes());
}
- return HashCodes.fromBytesNoCopy(bytes);
+ return HashCodes.fromBytes(bytes);
}
@Override
@@ -400,21 +294,4 @@ public final class Hashing {
return bits;
}
}
-
- /**
- * Linear CongruentialGenerator to use for consistent hashing.
- * See http://en.wikipedia.org/wiki/Linear_congruential_generator
- */
- private static final class LinearCongruentialGenerator {
- private long state;
-
- public LinearCongruentialGenerator(long seed) {
- this.state = seed;
- }
-
- public double nextDouble() {
- state = 2862933555777941757L * state + 1;
- return ((double) ((int) (state >>> 33) + 1)) / (0x1.0p31);
- }
- }
}
diff --git a/guava/src/com/google/common/hash/MessageDigestHashFunction.java b/guava/src/com/google/common/hash/MessageDigestHashFunction.java
index 029a494..03c6471 100644
--- a/guava/src/com/google/common/hash/MessageDigestHashFunction.java
+++ b/guava/src/com/google/common/hash/MessageDigestHashFunction.java
@@ -14,60 +14,37 @@
package com.google.common.hash;
-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.base.Preconditions.checkPositionIndexes;
-import java.io.Serializable;
+import com.google.common.primitives.Chars;
+import com.google.common.primitives.Ints;
+import com.google.common.primitives.Longs;
+import com.google.common.primitives.Shorts;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
/**
- * {@link HashFunction} adapter for {@link MessageDigest} instances.
+ * {@link HashFunction} adapter for {@link MessageDigest}s.
*
- * @author Kevin Bourrillion
- * @author Dimitris Andreou
+ * @author kevinb@google.com (Kevin Bourrillion)
+ * @author andreou@google.com (Dimitris Andreou)
*/
-final class MessageDigestHashFunction extends AbstractStreamingHashFunction
- implements Serializable {
- private final MessageDigest prototype;
- private final int bytes;
- private final boolean supportsClone;
- private final String toString;
-
- MessageDigestHashFunction(String algorithmName, String toString) {
- this.prototype = getMessageDigest(algorithmName);
- this.bytes = prototype.getDigestLength();
- this.toString = checkNotNull(toString);
- this.supportsClone = supportsClone();
- }
-
- MessageDigestHashFunction(String algorithmName, int bytes, String toString) {
- this.toString = checkNotNull(toString);
- this.prototype = getMessageDigest(algorithmName);
- int maxLength = prototype.getDigestLength();
- checkArgument(bytes >= 4 && bytes <= maxLength,
- "bytes (%s) must be >= 4 and < %s", bytes, maxLength);
- this.bytes = bytes;
- this.supportsClone = supportsClone();
- }
+final class MessageDigestHashFunction extends AbstractStreamingHashFunction {
+ private final String algorithmName;
+ private final int bits;
- private boolean supportsClone() {
- try {
- prototype.clone();
- return true;
- } catch (CloneNotSupportedException e) {
- return false;
- }
+ MessageDigestHashFunction(String algorithmName) {
+ this.algorithmName = algorithmName;
+ this.bits = getMessageDigest(algorithmName).getDigestLength() * 8;
}
- @Override public int bits() {
- return bytes * Byte.SIZE;
- }
-
- @Override public String toString() {
- return toString;
+ public int bits() {
+ return bits;
}
private static MessageDigest getMessageDigest(String algorithmName) {
@@ -79,80 +56,118 @@ final class MessageDigestHashFunction extends AbstractStreamingHashFunction
}
@Override public Hasher newHasher() {
- if (supportsClone) {
- try {
- return new MessageDigestHasher((MessageDigest) prototype.clone(), bytes);
- } catch (CloneNotSupportedException e) {
- // falls through
- }
- }
- return new MessageDigestHasher(getMessageDigest(prototype.getAlgorithm()), bytes);
+ return new MessageDigestHasher(getMessageDigest(algorithmName));
}
- private static final class SerializedForm implements Serializable {
- private final String algorithmName;
- private final int bytes;
- private final String toString;
+ private static class MessageDigestHasher implements Hasher {
+ private final MessageDigest digest;
+ private final ByteBuffer scratch; // lazy convenience
+ private boolean done;
- private SerializedForm(String algorithmName, int bytes, String toString) {
- this.algorithmName = algorithmName;
- this.bytes = bytes;
- this.toString = toString;
+ private MessageDigestHasher(MessageDigest digest) {
+ this.digest = digest;
+ this.scratch = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
}
- private Object readResolve() {
- return new MessageDigestHashFunction(algorithmName, bytes, toString);
+ @Override public Hasher putByte(byte b) {
+ checkNotDone();
+ digest.update(b);
+ return this;
}
- private static final long serialVersionUID = 0;
- }
+ @Override public Hasher putBytes(byte[] bytes) {
+ checkNotDone();
+ digest.update(bytes);
+ return this;
+ }
- Object writeReplace() {
- return new SerializedForm(prototype.getAlgorithm(), bytes, toString);
- }
+ @Override public Hasher putBytes(byte[] bytes, int off, int len) {
+ checkNotDone();
+ checkPositionIndexes(off, off + len, bytes.length);
+ digest.update(bytes, off, len);
+ return this;
+ }
- /**
- * Hasher that updates a message digest.
- */
- private static final class MessageDigestHasher extends AbstractByteHasher {
+ @Override public Hasher putShort(short s) {
+ checkNotDone();
+ scratch.putShort(s);
+ digest.update(scratch.array(), 0, Shorts.BYTES);
+ scratch.clear();
+ return this;
+ }
- private final MessageDigest digest;
- private final int bytes;
- private boolean done;
+ @Override public Hasher putInt(int i) {
+ checkNotDone();
+ scratch.putInt(i);
+ digest.update(scratch.array(), 0, Ints.BYTES);
+ scratch.clear();
+ return this;
+ }
- private MessageDigestHasher(MessageDigest digest, int bytes) {
- this.digest = digest;
- this.bytes = bytes;
+ @Override public Hasher putLong(long l) {
+ checkNotDone();
+ scratch.putLong(l);
+ digest.update(scratch.array(), 0, Longs.BYTES);
+ scratch.clear();
+ return this;
}
- @Override
- protected void update(byte b) {
+ @Override public Hasher putFloat(float f) {
checkNotDone();
- digest.update(b);
+ scratch.putFloat(f);
+ digest.update(scratch.array(), 0, 4);
+ scratch.clear();
+ return this;
}
- @Override
- protected void update(byte[] b) {
+ @Override public Hasher putDouble(double d) {
checkNotDone();
- digest.update(b);
+ scratch.putDouble(d);
+ digest.update(scratch.array(), 0, 8);
+ scratch.clear();
+ return this;
+ }
+
+ @Override public Hasher putBoolean(boolean b) {
+ return putByte(b ? (byte) 1 : (byte) 0);
+ }
+
+ @Override public Hasher putChar(char c) {
+ checkNotDone();
+ scratch.putChar(c);
+ digest.update(scratch.array(), 0, Chars.BYTES);
+ scratch.clear();
+ return this;
+ }
+
+ @Override public Hasher putString(CharSequence charSequence) {
+ for (int i = 0; i < charSequence.length(); i++) {
+ putChar(charSequence.charAt(i));
+ }
+ return this;
+ }
+
+ @Override public Hasher putString(CharSequence charSequence, Charset charset) {
+ try {
+ return putBytes(charSequence.toString().getBytes(charset.name()));
+ } catch (java.io.UnsupportedEncodingException impossible) {
+ throw new AssertionError(impossible);
+ }
}
- @Override
- protected void update(byte[] b, int off, int len) {
+ @Override public <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
checkNotDone();
- digest.update(b, off, len);
+ funnel.funnel(instance, this);
+ return this;
}
private void checkNotDone() {
checkState(!done, "Cannot use Hasher after calling #hash() on it");
}
- @Override
public HashCode hash() {
done = true;
- return (bytes == digest.getDigestLength())
- ? HashCodes.fromBytesNoCopy(digest.digest())
- : HashCodes.fromBytesNoCopy(Arrays.copyOf(digest.digest(), bytes));
+ return HashCodes.fromBytes(digest.digest());
}
}
}
diff --git a/guava/src/com/google/common/hash/Murmur3_128HashFunction.java b/guava/src/com/google/common/hash/Murmur3_128HashFunction.java
index aab08a3..cd49f87 100644
--- a/guava/src/com/google/common/hash/Murmur3_128HashFunction.java
+++ b/guava/src/com/google/common/hash/Murmur3_128HashFunction.java
@@ -12,17 +12,6 @@
* the License.
*/
-/*
- * MurmurHash3 was written by Austin Appleby, and is placed in the public
- * domain. The author hereby disclaims copyright to this source code.
- */
-
-/*
- * Source:
- * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
- * (Modified to adapt to Guava coding conventions and to use the HashFunction interface)
- */
-
package com.google.common.hash;
import static com.google.common.primitives.UnsignedBytes.toInt;
@@ -35,8 +24,8 @@ import java.nio.ByteOrder;
* See http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp
* MurmurHash3_x64_128
*
- * @author Austin Appleby
- * @author Dimitris Andreou
+ * @author aappleby@google.com (Austin Appleby)
+ * @author andreou@google.com (Dimitris Andreou)
*/
final class Murmur3_128HashFunction extends AbstractStreamingHashFunction implements Serializable {
// TODO(user): when the shortcuts are implemented, update BloomFilterStrategies
@@ -54,41 +43,40 @@ final class Murmur3_128HashFunction extends AbstractStreamingHashFunction implem
return new Murmur3_128Hasher(seed);
}
- @Override
- public String toString() {
- return "Hashing.murmur3_128(" + seed + ")";
- }
-
private static final class Murmur3_128Hasher extends AbstractStreamingHasher {
- private static final int CHUNK_SIZE = 16;
- private static final long C1 = 0x87c37b91114253d5L;
- private static final long C2 = 0x4cf5ad432745937fL;
- private long h1;
- private long h2;
- private int length;
+ long h1;
+ long h2;
+ long c1 = 0x87c37b91114253d5L;
+ long c2 = 0x4cf5ad432745937fL;
+ int len;
Murmur3_128Hasher(int seed) {
- super(CHUNK_SIZE);
- this.h1 = seed;
- this.h2 = seed;
- this.length = 0;
+ super(16);
+ h1 = seed;
+ h2 = seed;
}
@Override protected void process(ByteBuffer bb) {
long k1 = bb.getLong();
long k2 = bb.getLong();
+ len += 16;
bmix64(k1, k2);
- length += CHUNK_SIZE;
}
private void bmix64(long k1, long k2) {
- h1 ^= mixK1(k1);
+ k1 *= c1;
+ k1 = Long.rotateLeft(k1, 31);
+ k1 *= c2;
+ h1 ^= k1;
h1 = Long.rotateLeft(h1, 27);
h1 += h2;
h1 = h1 * 5 + 0x52dce729;
- h2 ^= mixK2(k2);
+ k2 *= c2;
+ k2 = Long.rotateLeft(k2, 33);
+ k2 *= c1;
+ h2 ^= k2;
h2 = Long.rotateLeft(h2, 31);
h2 += h1;
@@ -98,7 +86,7 @@ final class Murmur3_128HashFunction extends AbstractStreamingHashFunction implem
@Override protected void processRemaining(ByteBuffer bb) {
long k1 = 0;
long k2 = 0;
- length += bb.remaining();
+ len += bb.remaining();
switch (bb.remaining()) {
case 15:
k2 ^= (long) toInt(bb.get(14)) << 48; // fall through
@@ -113,10 +101,14 @@ final class Murmur3_128HashFunction extends AbstractStreamingHashFunction implem
case 10:
k2 ^= (long) toInt(bb.get(9)) << 8; // fall through
case 9:
- k2 ^= (long) toInt(bb.get(8)); // fall through
+ k2 ^= (long) toInt(bb.get(8)) << 0;
+ k2 *= c2;
+ k2 = Long.rotateLeft(k2, 33);
+ k2 *= c1;
+ h2 ^= k2;
+ // fall through
case 8:
- k1 ^= bb.getLong();
- break;
+ k1 ^= (long) toInt(bb.get(7)) << 56; // fall through
case 7:
k1 ^= (long) toInt(bb.get(6)) << 48; // fall through
case 6:
@@ -130,18 +122,19 @@ final class Murmur3_128HashFunction extends AbstractStreamingHashFunction implem
case 2:
k1 ^= (long) toInt(bb.get(1)) << 8; // fall through
case 1:
- k1 ^= (long) toInt(bb.get(0));
- break;
+ k1 ^= (long) toInt(bb.get(0)) << 0;
+ k1 *= c1;
+ k1 = Long.rotateLeft(k1, 31);
+ k1 *= c2;
+ h1 ^= k1;
+ // fall through
default:
- throw new AssertionError("Should never get here.");
}
- h1 ^= mixK1(k1);
- h2 ^= mixK2(k2);
}
@Override public HashCode makeHash() {
- h1 ^= length;
- h2 ^= length;
+ h1 ^= len;
+ h2 ^= len;
h1 += h2;
h2 += h1;
@@ -152,15 +145,13 @@ final class Murmur3_128HashFunction extends AbstractStreamingHashFunction implem
h1 += h2;
h2 += h1;
- return HashCodes.fromBytesNoCopy(ByteBuffer
- .wrap(new byte[CHUNK_SIZE])
- .order(ByteOrder.LITTLE_ENDIAN)
- .putLong(h1)
- .putLong(h2)
- .array());
+ ByteBuffer bb = ByteBuffer.wrap(new byte[16]).order(ByteOrder.LITTLE_ENDIAN);
+ bb.putLong(h1);
+ bb.putLong(h2);
+ return HashCodes.fromBytes(bb.array());
}
- private static long fmix64(long k) {
+ private long fmix64(long k) {
k ^= k >>> 33;
k *= 0xff51afd7ed558ccdL;
k ^= k >>> 33;
@@ -168,20 +159,6 @@ final class Murmur3_128HashFunction extends AbstractStreamingHashFunction implem
k ^= k >>> 33;
return k;
}
-
- private static long mixK1(long k1) {
- k1 *= C1;
- k1 = Long.rotateLeft(k1, 31);
- k1 *= C2;
- return k1;
- }
-
- private static long mixK2(long k2) {
- k2 *= C2;
- k2 = Long.rotateLeft(k2, 33);
- k2 *= C1;
- return k2;
- }
}
private static final long serialVersionUID = 0L;
diff --git a/guava/src/com/google/common/hash/Murmur3_32HashFunction.java b/guava/src/com/google/common/hash/Murmur3_32HashFunction.java
index c6637de..5c03b92 100644
--- a/guava/src/com/google/common/hash/Murmur3_32HashFunction.java
+++ b/guava/src/com/google/common/hash/Murmur3_32HashFunction.java
@@ -12,42 +12,23 @@
* the License.
*/
-/*
- * MurmurHash3 was written by Austin Appleby, and is placed in the public
- * domain. The author hereby disclaims copyright to this source code.
- */
-
-/*
- * Source:
- * http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
- * (Modified to adapt to Guava coding conventions and to use the HashFunction interface)
- */
-
package com.google.common.hash;
import static com.google.common.primitives.UnsignedBytes.toInt;
-import com.google.common.primitives.Chars;
-import com.google.common.primitives.Ints;
-import com.google.common.primitives.Longs;
-
import java.io.Serializable;
import java.nio.ByteBuffer;
/**
* See http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp
* MurmurHash3_x86_32
- *
- * @author Austin Appleby
- * @author Dimitris Andreou
- * @author Kurt Alfred Kluever
+ *
+ * @author aappleby@google.com (Austin Appleby)
+ * @author andreou@google.com (Dimitris Andreou)
*/
final class Murmur3_32HashFunction extends AbstractStreamingHashFunction implements Serializable {
- private static final int C1 = 0xcc9e2d51;
- private static final int C2 = 0x1b873593;
-
private final int seed;
-
+
Murmur3_32HashFunction(int seed) {
this.seed = seed;
}
@@ -60,107 +41,63 @@ final class Murmur3_32HashFunction extends AbstractStreamingHashFunction impleme
return new Murmur3_32Hasher(seed);
}
- @Override
- public String toString() {
- return "Hashing.murmur3_32(" + seed + ")";
- }
-
- @Override public HashCode hashInt(int input) {
- int k1 = mixK1(input);
- int h1 = mixH1(seed, k1);
-
- return fmix(h1, Ints.BYTES);
- }
-
- @Override public HashCode hashLong(long input) {
- int low = (int) input;
- int high = (int) (input >>> 32);
-
- int k1 = mixK1(low);
- int h1 = mixH1(seed, k1);
-
- k1 = mixK1(high);
- h1 = mixH1(h1, k1);
-
- return fmix(h1, Longs.BYTES);
- }
-
- // TODO(user): Maybe implement #hashBytes instead?
- @Override public HashCode hashString(CharSequence input) {
- int h1 = seed;
-
- // step through the CharSequence 2 chars at a time
- for (int i = 1; i < input.length(); i += 2) {
- int k1 = input.charAt(i - 1) | (input.charAt(i) << 16);
- k1 = mixK1(k1);
- h1 = mixH1(h1, k1);
- }
-
- // deal with any remaining characters
- if ((input.length() & 1) == 1) {
- int k1 = input.charAt(input.length() - 1);
- k1 = mixK1(k1);
- h1 ^= k1;
- }
-
- return fmix(h1, Chars.BYTES * input.length());
- }
-
- private static int mixK1(int k1) {
- k1 *= C1;
- k1 = Integer.rotateLeft(k1, 15);
- k1 *= C2;
- return k1;
- }
-
- private static int mixH1(int h1, int k1) {
- h1 ^= k1;
- h1 = Integer.rotateLeft(h1, 13);
- h1 = h1 * 5 + 0xe6546b64;
- return h1;
- }
-
- // Finalization mix - force all bits of a hash block to avalanche
- private static HashCode fmix(int h1, int length) {
- h1 ^= length;
- h1 ^= h1 >>> 16;
- h1 *= 0x85ebca6b;
- h1 ^= h1 >>> 13;
- h1 *= 0xc2b2ae35;
- h1 ^= h1 >>> 16;
- return HashCodes.fromInt(h1);
- }
-
private static final class Murmur3_32Hasher extends AbstractStreamingHasher {
- private static final int CHUNK_SIZE = 4;
- private int h1;
- private int length;
+ int h1;
+ int c1 = 0xcc9e2d51;
+ int c2 = 0x1b873593;
+ int len;
Murmur3_32Hasher(int seed) {
- super(CHUNK_SIZE);
- this.h1 = seed;
- this.length = 0;
+ super(4);
+ h1 = seed;
}
@Override protected void process(ByteBuffer bb) {
- int k1 = Murmur3_32HashFunction.mixK1(bb.getInt());
- h1 = Murmur3_32HashFunction.mixH1(h1, k1);
- length += CHUNK_SIZE;
+ int k1 = bb.getInt();
+ len += 4;
+
+ k1 *= c1;
+ k1 = Integer.rotateLeft(k1, 15);
+ k1 *= c2;
+
+ h1 ^= k1;
+ h1 = Integer.rotateLeft(h1, 13);
+ h1 = h1 * 5 + 0xe6546b64;
}
-
+
@Override protected void processRemaining(ByteBuffer bb) {
- length += bb.remaining();
+ len += bb.remaining();
int k1 = 0;
- for (int i = 0; bb.hasRemaining(); i += 8) {
- k1 ^= toInt(bb.get()) << i;
+ switch (bb.remaining()) {
+ case 3:
+ k1 ^= toInt(bb.get(2)) << 16;
+ // fall through
+ case 2:
+ k1 ^= toInt(bb.get(1)) << 8;
+ // fall through
+ case 1:
+ k1 ^= toInt(bb.get(0));
+ // fall through
+ default:
+ k1 *= c1;
+ k1 = Integer.rotateLeft(k1, 15);
+ k1 *= c2;
+ h1 ^= k1;
}
- h1 ^= Murmur3_32HashFunction.mixK1(k1);
}
-
+
@Override public HashCode makeHash() {
- return Murmur3_32HashFunction.fmix(h1, length);
+ h1 ^= len;
+
+ h1 ^= h1 >>> 16;
+ h1 *= 0x85ebca6b;
+ h1 ^= h1 >>> 13;
+ h1 *= 0xc2b2ae35;
+ h1 ^= h1 >>> 16;
+
+ return HashCodes.fromInt(h1);
}
}
-
+
private static final long serialVersionUID = 0L;
}
diff --git a/guava/src/com/google/common/hash/PrimitiveSink.java b/guava/src/com/google/common/hash/Sink.java
index c851a1e..37167fc 100644
--- a/guava/src/com/google/common/hash/PrimitiveSink.java
+++ b/guava/src/com/google/common/hash/Sink.java
@@ -22,17 +22,17 @@ import java.nio.charset.Charset;
* An object which can receive a stream of primitive values.
*
* @author Kevin Bourrillion
- * @since 12.0 (in 11.0 as {@code Sink})
+ * @since 11.0
*/
@Beta
-public interface PrimitiveSink {
+public interface Sink {
/**
* Puts a byte into this sink.
*
* @param b a byte
* @return this instance
*/
- PrimitiveSink putByte(byte b);
+ Sink putByte(byte b);
/**
* Puts an array of bytes into this sink.
@@ -40,7 +40,7 @@ public interface PrimitiveSink {
* @param bytes a byte array
* @return this instance
*/
- PrimitiveSink putBytes(byte[] bytes);
+ Sink putBytes(byte[] bytes);
/**
* Puts a chunk of an array of bytes into this sink. {@code bytes[off]} is the first byte written,
@@ -53,50 +53,50 @@ public interface PrimitiveSink {
* @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > bytes.length} or
* {@code len < 0}
*/
- PrimitiveSink putBytes(byte[] bytes, int off, int len);
+ Sink putBytes(byte[] bytes, int off, int len);
/**
* Puts a short into this sink.
*/
- PrimitiveSink putShort(short s);
+ Sink putShort(short s);
/**
* Puts an int into this sink.
*/
- PrimitiveSink putInt(int i);
+ Sink putInt(int i);
/**
* Puts a long into this sink.
*/
- PrimitiveSink putLong(long l);
+ Sink putLong(long l);
/**
* Puts a float into this sink.
*/
- PrimitiveSink putFloat(float f);
+ Sink putFloat(float f);
/**
* Puts a double into this sink.
*/
- PrimitiveSink putDouble(double d);
+ Sink putDouble(double d);
/**
* Puts a boolean into this sink.
*/
- PrimitiveSink putBoolean(boolean b);
+ Sink putBoolean(boolean b);
/**
* Puts a character into this sink.
*/
- PrimitiveSink putChar(char c);
+ Sink putChar(char c);
/**
* Puts a string into this sink.
*/
- PrimitiveSink putString(CharSequence charSequence);
+ Sink putString(CharSequence charSequence);
/**
* Puts a string into this sink using the given charset.
*/
- PrimitiveSink putString(CharSequence charSequence, Charset charset);
+ Sink putString(CharSequence charSequence, Charset charset);
}
diff --git a/guava/src/com/google/common/hash/package-info.java b/guava/src/com/google/common/hash/package-info.java
index 7df4e73..4acc096 100644
--- a/guava/src/com/google/common/hash/package-info.java
+++ b/guava/src/com/google/common/hash/package-info.java
@@ -15,10 +15,6 @@
// TODO(user): when things stabilize, flesh this out
/**
* Hash functions and related structures.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/HashingExplained">
- * hashing</a>.
*/
@ParametersAreNonnullByDefault
package com.google.common.hash;
diff --git a/guava/src/com/google/common/io/AppendableWriter.java b/guava/src/com/google/common/io/AppendableWriter.java
index 7705183..8033e46 100644
--- a/guava/src/com/google/common/io/AppendableWriter.java
+++ b/guava/src/com/google/common/io/AppendableWriter.java
@@ -16,15 +16,11 @@
package com.google.common.io;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.Writer;
-import javax.annotation.Nullable;
-
/**
* Writer that places all output on an {@link Appendable} target. If the target
* is {@link Flushable} or {@link Closeable}, flush()es and close()s will also
@@ -44,7 +40,7 @@ class AppendableWriter extends Writer {
* @param target target to which to append output
*/
AppendableWriter(Appendable target) {
- this.target = checkNotNull(target);
+ this.target = target;
}
/*
@@ -83,12 +79,12 @@ class AppendableWriter extends Writer {
target.append((char) c);
}
- @Override public void write(@Nullable String str) throws IOException {
+ @Override public void write(String str) throws IOException {
checkNotClosed();
target.append(str);
}
- @Override public void write(@Nullable String str, int off, int len) throws IOException {
+ @Override public void write(String str, int off, int len) throws IOException {
checkNotClosed();
// tricky: append takes start, end pair...
target.append(str, off, off + len);
@@ -100,13 +96,13 @@ class AppendableWriter extends Writer {
return this;
}
- @Override public Writer append(@Nullable CharSequence charSeq) throws IOException {
+ @Override public Writer append(CharSequence charSeq) throws IOException {
checkNotClosed();
target.append(charSeq);
return this;
}
- @Override public Writer append(@Nullable CharSequence charSeq, int start, int end)
+ @Override public Writer append(CharSequence charSeq, int start, int end)
throws IOException {
checkNotClosed();
target.append(charSeq, start, end);
diff --git a/guava/src/com/google/common/io/BaseEncoding.java b/guava/src/com/google/common/io/BaseEncoding.java
deleted file mode 100644
index 4af0719..0000000
--- a/guava/src/com/google/common/io/BaseEncoding.java
+++ /dev/null
@@ -1,882 +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.io;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndexes;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.io.GwtWorkarounds.asCharInput;
-import static com.google.common.io.GwtWorkarounds.asCharOutput;
-import static com.google.common.io.GwtWorkarounds.asInputStream;
-import static com.google.common.io.GwtWorkarounds.asOutputStream;
-import static com.google.common.io.GwtWorkarounds.stringBuilderOutput;
-import static com.google.common.math.IntMath.divide;
-import static com.google.common.math.IntMath.log2;
-import static java.math.RoundingMode.CEILING;
-import static java.math.RoundingMode.FLOOR;
-import static java.math.RoundingMode.UNNECESSARY;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-import com.google.common.base.Ascii;
-import com.google.common.base.CharMatcher;
-import com.google.common.io.GwtWorkarounds.ByteInput;
-import com.google.common.io.GwtWorkarounds.ByteOutput;
-import com.google.common.io.GwtWorkarounds.CharInput;
-import com.google.common.io.GwtWorkarounds.CharOutput;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-import java.util.Arrays;
-
-import javax.annotation.CheckReturnValue;
-import javax.annotation.Nullable;
-
-/**
- * A binary encoding scheme for reversibly translating between byte sequences and printable ASCII
- * strings. This class includes several constants for encoding schemes specified by <a
- * href="http://tools.ietf.org/html/rfc4648">RFC 4648</a>. For example, the expression:
- * <pre> {@code
- *
- * BaseEncoding.base32().encode("foo".getBytes(Charsets.US_ASCII))
- * }</pre>
- * returns the string {@code "MZXW6==="}, and <pre> {@code
- *
- * byte[] decoded = BaseEncoding.base32().decode("MZXW6===");
- * }</pre>
- *
- * ...returns the ASCII bytes of the string {@code "foo"}.
- *
- * <p>By default, {@code BaseEncoding}'s behavior is relatively strict and in accordance with
- * RFC 4648. Decoding rejects characters in the wrong case, though padding is optional.
- * To modify encoding and decoding behavior, use configuration methods to obtain a new encoding
- * with modified behavior: <pre> {@code
- *
- * BaseEncoding.base16().lowerCase().decode("deadbeef");
- * }</pre>
- *
- * <p>Warning: BaseEncoding instances are immutable. Invoking a configuration method has no effect
- * on the receiving instance; you must store and use the new encoding instance it returns, instead.
- * <pre> {@code
- *
- * // Do NOT do this
- * BaseEncoding hex = BaseEncoding.base16();
- * hex.lowerCase(); // does nothing!
- * return hex.decode("deadbeef"); // throws an IllegalArgumentException
- * }</pre>
- *
- * <p>It is guaranteed that {@code encoding.decode(encoding.encode(x))} is always equal to
- * {@code x}, but the reverse does not necessarily hold.
- *
- * <p>
- * <table>
- * <tr>
- * <th>Encoding
- * <th>Alphabet
- * <th>{@code char:byte} ratio
- * <th>Default padding
- * <th>Comments
- * <tr>
- * <td>{@link #base16()}
- * <td>0-9 A-F
- * <td>2.00
- * <td>N/A
- * <td>Traditional hexadecimal. Defaults to upper case.
- * <tr>
- * <td>{@link #base32()}
- * <td>A-Z 2-7
- * <td>1.60
- * <td>=
- * <td>Human-readable; no possibility of mixing up 0/O or 1/I. Defaults to upper case.
- * <tr>
- * <td>{@link #base32Hex()}
- * <td>0-9 A-V
- * <td>1.60
- * <td>=
- * <td>"Numerical" base 32; extended from the traditional hex alphabet. Defaults to upper case.
- * <tr>
- * <td>{@link #base64()}
- * <td>A-Z a-z 0-9 + /
- * <td>1.33
- * <td>=
- * <td>
- * <tr>
- * <td>{@link #base64Url()}
- * <td>A-Z a-z 0-9 - _
- * <td>1.33
- * <td>=
- * <td>Safe to use as filenames, or to pass in URLs without escaping
- * </table>
- *
- * <p>
- * All instances of this class are immutable, so they may be stored safely as static constants.
- *
- * @author Louis Wasserman
- * @since 14.0
- */
-@Beta
-@GwtCompatible(emulated = true)
-public abstract class BaseEncoding {
- // TODO(user): consider adding encodeTo(Appendable, byte[], [int, int])
-
- BaseEncoding() {}
-
- /**
- * Encodes the specified byte array, and returns the encoded {@code String}.
- */
- public String encode(byte[] bytes) {
- return encode(checkNotNull(bytes), 0, bytes.length);
- }
-
- /**
- * Encodes the specified range of the specified byte array, and returns the encoded
- * {@code String}.
- */
- public final String encode(byte[] bytes, int off, int len) {
- checkNotNull(bytes);
- checkPositionIndexes(off, off + len, bytes.length);
- CharOutput result = stringBuilderOutput(maxEncodedSize(len));
- ByteOutput byteOutput = encodingStream(result);
- try {
- for (int i = 0; i < len; i++) {
- byteOutput.write(bytes[off + i]);
- }
- byteOutput.close();
- } catch (IOException impossible) {
- throw new AssertionError("impossible");
- }
- return result.toString();
- }
-
- /**
- * Returns an {@code OutputStream} that encodes bytes using this encoding into the specified
- * {@code Writer}. When the returned {@code OutputStream} is closed, so is the backing
- * {@code Writer}.
- */
- @GwtIncompatible("Writer,OutputStream")
- public final OutputStream encodingStream(Writer writer) {
- return asOutputStream(encodingStream(asCharOutput(writer)));
- }
-
- /**
- * Returns an {@code OutputSupplier} that supplies streams that encode bytes using this encoding
- * into writers from the specified {@code OutputSupplier}.
- */
- @GwtIncompatible("Writer,OutputStream")
- public final OutputSupplier<OutputStream> encodingStream(
- final OutputSupplier<? extends Writer> writerSupplier) {
- checkNotNull(writerSupplier);
- return new OutputSupplier<OutputStream>() {
- @Override
- public OutputStream getOutput() throws IOException {
- return encodingStream(writerSupplier.getOutput());
- }
- };
- }
-
- /**
- * Returns a {@code ByteSink} that writes base-encoded bytes to the specified {@code CharSink}.
- */
- @GwtIncompatible("ByteSink,CharSink")
- public final ByteSink encodingSink(final CharSink encodedSink) {
- checkNotNull(encodedSink);
- return new ByteSink() {
- @Override
- public OutputStream openStream() throws IOException {
- return encodingStream(encodedSink.openStream());
- }
- };
- }
-
- // TODO(user): document the extent of leniency, probably after adding ignore(CharMatcher)
-
- private static byte[] extract(byte[] result, int length) {
- if (length == result.length) {
- return result;
- } else {
- byte[] trunc = new byte[length];
- System.arraycopy(result, 0, trunc, 0, length);
- return trunc;
- }
- }
-
- /**
- * Decodes the specified character sequence, and returns the resulting {@code byte[]}.
- * This is the inverse operation to {@link #encode(byte[])}.
- *
- * @throws IllegalArgumentException if the input is not a valid encoded string according to this
- * encoding.
- */
- public final byte[] decode(CharSequence chars) {
- chars = padding().trimTrailingFrom(chars);
- ByteInput decodedInput = decodingStream(asCharInput(chars));
- byte[] tmp = new byte[maxDecodedSize(chars.length())];
- int index = 0;
- try {
- for (int i = decodedInput.read(); i != -1; i = decodedInput.read()) {
- tmp[index++] = (byte) i;
- }
- } catch (IOException badInput) {
- throw new IllegalArgumentException(badInput);
- }
- return extract(tmp, index);
- }
-
- /**
- * Returns an {@code InputStream} that decodes base-encoded input from the specified
- * {@code Reader}.
- */
- @GwtIncompatible("Reader,InputStream")
- public final InputStream decodingStream(Reader reader) {
- return asInputStream(decodingStream(asCharInput(reader)));
- }
-
- /**
- * Returns an {@code InputSupplier} that supplies input streams that decode base-encoded input
- * from readers from the specified supplier.
- */
- @GwtIncompatible("Reader,InputStream")
- public final InputSupplier<InputStream> decodingStream(
- final InputSupplier<? extends Reader> readerSupplier) {
- checkNotNull(readerSupplier);
- return new InputSupplier<InputStream>() {
- @Override
- public InputStream getInput() throws IOException {
- return decodingStream(readerSupplier.getInput());
- }
- };
- }
-
- /**
- * Returns a {@code ByteSource} that reads base-encoded bytes from the specified
- * {@code CharSource}.
- */
- @GwtIncompatible("ByteSource,CharSource")
- public final ByteSource decodingSource(final CharSource encodedSource) {
- checkNotNull(encodedSource);
- return new ByteSource() {
- @Override
- public InputStream openStream() throws IOException {
- return decodingStream(encodedSource.openStream());
- }
- };
- }
-
- // Implementations for encoding/decoding
-
- abstract int maxEncodedSize(int bytes);
-
- abstract ByteOutput encodingStream(CharOutput charOutput);
-
- abstract int maxDecodedSize(int chars);
-
- abstract ByteInput decodingStream(CharInput charInput);
-
- abstract CharMatcher padding();
-
- // Modified encoding generators
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but omits any padding
- * characters as specified by <a href="http://tools.ietf.org/html/rfc4648#section-3.2">RFC 4648
- * section 3.2</a>, Padding of Encoded Data.
- */
- @CheckReturnValue
- public abstract BaseEncoding omitPadding();
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but uses an alternate character
- * for padding.
- *
- * @throws IllegalArgumentException if this padding character is already used in the alphabet or a
- * separator
- */
- @CheckReturnValue
- public abstract BaseEncoding withPadChar(char padChar);
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but adds a separator string
- * after every {@code n} characters. Any occurrences of any characters that occur in the separator
- * are skipped over in decoding.
- *
- * @throws IllegalArgumentException if any alphabet or padding characters appear in the separator
- * string, or if {@code n <= 0}
- * @throws UnsupportedOperationException if this encoding already uses a separator
- */
- @CheckReturnValue
- public abstract BaseEncoding withSeparator(String separator, int n);
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but encodes and decodes with
- * uppercase letters. Padding and separator characters remain in their original case.
- *
- * @throws IllegalStateException if the alphabet used by this encoding contains mixed upper- and
- * lower-case characters
- */
- @CheckReturnValue
- public abstract BaseEncoding upperCase();
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but encodes and decodes with
- * lowercase letters. Padding and separator characters remain in their original case.
- *
- * @throws IllegalStateException if the alphabet used by this encoding contains mixed upper- and
- * lower-case characters
- */
- @CheckReturnValue
- public abstract BaseEncoding lowerCase();
-
- private static final BaseEncoding BASE64 = new StandardBaseEncoding(
- "base64()", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", '=');
-
- /**
- * The "base64" base encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-4">RFC 4648 section 4</a>, Base 64 Encoding.
- * (This is the same as the base 64 encoding from <a
- * href="http://tools.ietf.org/html/rfc3548#section-3">RFC 3548</a>.)
- *
- * <p>The character {@code '='} is used for padding, but can be {@linkplain #omitPadding()
- * omitted} or {@linkplain #withPadChar(char) replaced}.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base64() {
- return BASE64;
- }
-
- private static final BaseEncoding BASE64_URL = new StandardBaseEncoding(
- "base64Url()", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", '=');
-
- /**
- * The "base64url" encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-5">RFC 4648 section 5</a>, Base 64 Encoding
- * with URL and Filename Safe Alphabet, also sometimes referred to as the "web safe Base64."
- * (This is the same as the base 64 encoding with URL and filename safe alphabet from <a
- * href="http://tools.ietf.org/html/rfc3548#section-4">RFC 3548</a>.)
- *
- * <p>The character {@code '='} is used for padding, but can be {@linkplain #omitPadding()
- * omitted} or {@linkplain #withPadChar(char) replaced}.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base64Url() {
- return BASE64_URL;
- }
-
- private static final BaseEncoding BASE32 =
- new StandardBaseEncoding("base32()", "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", '=');
-
- /**
- * The "base32" encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-6">RFC 4648 section 6</a>, Base 32 Encoding.
- * (This is the same as the base 32 encoding from <a
- * href="http://tools.ietf.org/html/rfc3548#section-5">RFC 3548</a>.)
- *
- * <p>The character {@code '='} is used for padding, but can be {@linkplain #omitPadding()
- * omitted} or {@linkplain #withPadChar(char) replaced}.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base32() {
- return BASE32;
- }
-
- private static final BaseEncoding BASE32_HEX =
- new StandardBaseEncoding("base32Hex()", "0123456789ABCDEFGHIJKLMNOPQRSTUV", '=');
-
- /**
- * The "base32hex" encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-7">RFC 4648 section 7</a>, Base 32 Encoding
- * with Extended Hex Alphabet. There is no corresponding encoding in RFC 3548.
- *
- * <p>The character {@code '='} is used for padding, but can be {@linkplain #omitPadding()
- * omitted} or {@linkplain #withPadChar(char) replaced}.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base32Hex() {
- return BASE32_HEX;
- }
-
- private static final BaseEncoding BASE16 =
- new StandardBaseEncoding("base16()", "0123456789ABCDEF", null);
-
- /**
- * The "base16" encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-8">RFC 4648 section 8</a>, Base 16 Encoding.
- * (This is the same as the base 16 encoding from <a
- * href="http://tools.ietf.org/html/rfc3548#section-6">RFC 3548</a>.) This is commonly known as
- * "hexadecimal" format.
- *
- * <p>No padding is necessary in base 16, so {@link #withPadChar(char)} and
- * {@link #omitPadding()} have no effect.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base16() {
- return BASE16;
- }
-
- private static final class Alphabet extends CharMatcher {
- private final String name;
- // this is meant to be immutable -- don't modify it!
- private final char[] chars;
- final int mask;
- final int bitsPerChar;
- final int charsPerChunk;
- final int bytesPerChunk;
- private final byte[] decodabet;
- private final boolean[] validPadding;
-
- Alphabet(String name, char[] chars) {
- this.name = checkNotNull(name);
- this.chars = checkNotNull(chars);
- try {
- this.bitsPerChar = log2(chars.length, UNNECESSARY);
- } catch (ArithmeticException e) {
- throw new IllegalArgumentException("Illegal alphabet length " + chars.length, e);
- }
-
- /*
- * e.g. for base64, bitsPerChar == 6, charsPerChunk == 4, and bytesPerChunk == 3. This makes
- * for the smallest chunk size that still has charsPerChunk * bitsPerChar be a multiple of 8.
- */
- int gcd = Math.min(8, Integer.lowestOneBit(bitsPerChar));
- this.charsPerChunk = 8 / gcd;
- this.bytesPerChunk = bitsPerChar / gcd;
-
- this.mask = chars.length - 1;
-
- byte[] decodabet = new byte[Ascii.MAX + 1];
- Arrays.fill(decodabet, (byte) -1);
- for (int i = 0; i < chars.length; i++) {
- char c = chars[i];
- checkArgument(CharMatcher.ASCII.matches(c), "Non-ASCII character: %s", c);
- checkArgument(decodabet[c] == -1, "Duplicate character: %s", c);
- decodabet[c] = (byte) i;
- }
- this.decodabet = decodabet;
-
- boolean[] validPadding = new boolean[charsPerChunk];
- for (int i = 0; i < bytesPerChunk; i++) {
- validPadding[divide(i * 8, bitsPerChar, CEILING)] = true;
- }
- this.validPadding = validPadding;
- }
-
- char encode(int bits) {
- return chars[bits];
- }
-
- boolean isValidPaddingStartPosition(int index) {
- return validPadding[index % charsPerChunk];
- }
-
- int decode(char ch) throws IOException {
- if (ch > Ascii.MAX || decodabet[ch] == -1) {
- throw new IOException("Unrecognized character: " + ch);
- }
- return decodabet[ch];
- }
-
- private boolean hasLowerCase() {
- for (char c : chars) {
- if (Ascii.isLowerCase(c)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean hasUpperCase() {
- for (char c : chars) {
- if (Ascii.isUpperCase(c)) {
- return true;
- }
- }
- return false;
- }
-
- Alphabet upperCase() {
- if (!hasLowerCase()) {
- return this;
- } else {
- checkState(!hasUpperCase(), "Cannot call upperCase() on a mixed-case alphabet");
- char[] upperCased = new char[chars.length];
- for (int i = 0; i < chars.length; i++) {
- upperCased[i] = Ascii.toUpperCase(chars[i]);
- }
- return new Alphabet(name + ".upperCase()", upperCased);
- }
- }
-
- Alphabet lowerCase() {
- if (!hasUpperCase()) {
- return this;
- } else {
- checkState(!hasLowerCase(), "Cannot call lowerCase() on a mixed-case alphabet");
- char[] lowerCased = new char[chars.length];
- for (int i = 0; i < chars.length; i++) {
- lowerCased[i] = Ascii.toLowerCase(chars[i]);
- }
- return new Alphabet(name + ".lowerCase()", lowerCased);
- }
- }
-
- @Override
- public boolean matches(char c) {
- return CharMatcher.ASCII.matches(c) && decodabet[c] != -1;
- }
-
- @Override
- public String toString() {
- return name;
- }
- }
-
- static final class StandardBaseEncoding extends BaseEncoding {
- // TODO(user): provide a useful toString
- private final Alphabet alphabet;
-
- @Nullable
- private final Character paddingChar;
-
- StandardBaseEncoding(String name, String alphabetChars, @Nullable Character paddingChar) {
- this(new Alphabet(name, alphabetChars.toCharArray()), paddingChar);
- }
-
- StandardBaseEncoding(Alphabet alphabet, Character paddingChar) {
- this.alphabet = checkNotNull(alphabet);
- checkArgument(paddingChar == null || !alphabet.matches(paddingChar),
- "Padding character %s was already in alphabet", paddingChar);
- this.paddingChar = paddingChar;
- }
-
- @Override
- CharMatcher padding() {
- return (paddingChar == null) ? CharMatcher.NONE : CharMatcher.is(paddingChar.charValue());
- }
-
- @Override
- int maxEncodedSize(int bytes) {
- return alphabet.charsPerChunk * divide(bytes, alphabet.bytesPerChunk, CEILING);
- }
-
- @Override
- ByteOutput encodingStream(final CharOutput out) {
- checkNotNull(out);
- return new ByteOutput() {
- int bitBuffer = 0;
- int bitBufferLength = 0;
- int writtenChars = 0;
-
- @Override
- public void write(byte b) throws IOException {
- bitBuffer <<= 8;
- bitBuffer |= b & 0xFF;
- bitBufferLength += 8;
- while (bitBufferLength >= alphabet.bitsPerChar) {
- int charIndex = (bitBuffer >> (bitBufferLength - alphabet.bitsPerChar))
- & alphabet.mask;
- out.write(alphabet.encode(charIndex));
- writtenChars++;
- bitBufferLength -= alphabet.bitsPerChar;
- }
- }
-
- @Override
- public void flush() throws IOException {
- out.flush();
- }
-
- @Override
- public void close() throws IOException {
- if (bitBufferLength > 0) {
- int charIndex = (bitBuffer << (alphabet.bitsPerChar - bitBufferLength))
- & alphabet.mask;
- out.write(alphabet.encode(charIndex));
- writtenChars++;
- if (paddingChar != null) {
- while (writtenChars % alphabet.charsPerChunk != 0) {
- out.write(paddingChar.charValue());
- writtenChars++;
- }
- }
- }
- out.close();
- }
- };
- }
-
- @Override
- int maxDecodedSize(int chars) {
- return (int) ((alphabet.bitsPerChar * (long) chars + 7L) / 8L);
- }
-
- @Override
- ByteInput decodingStream(final CharInput reader) {
- checkNotNull(reader);
- return new ByteInput() {
- int bitBuffer = 0;
- int bitBufferLength = 0;
- int readChars = 0;
- boolean hitPadding = false;
- final CharMatcher paddingMatcher = padding();
-
- @Override
- public int read() throws IOException {
- while (true) {
- int readChar = reader.read();
- if (readChar == -1) {
- if (!hitPadding && !alphabet.isValidPaddingStartPosition(readChars)) {
- throw new IOException("Invalid input length " + readChars);
- }
- return -1;
- }
- readChars++;
- char ch = (char) readChar;
- if (paddingMatcher.matches(ch)) {
- if (!hitPadding
- && (readChars == 1 || !alphabet.isValidPaddingStartPosition(readChars - 1))) {
- throw new IOException("Padding cannot start at index " + readChars);
- }
- hitPadding = true;
- } else if (hitPadding) {
- throw new IOException(
- "Expected padding character but found '" + ch + "' at index " + readChars);
- } else {
- bitBuffer <<= alphabet.bitsPerChar;
- bitBuffer |= alphabet.decode(ch);
- bitBufferLength += alphabet.bitsPerChar;
-
- if (bitBufferLength >= 8) {
- bitBufferLength -= 8;
- return (bitBuffer >> bitBufferLength) & 0xFF;
- }
- }
- }
- }
-
- @Override
- public void close() throws IOException {
- reader.close();
- }
- };
- }
-
- @Override
- public BaseEncoding omitPadding() {
- return (paddingChar == null) ? this : new StandardBaseEncoding(alphabet, null);
- }
-
- @Override
- public BaseEncoding withPadChar(char padChar) {
- if (8 % alphabet.bitsPerChar == 0 ||
- (paddingChar != null && paddingChar.charValue() == padChar)) {
- return this;
- } else {
- return new StandardBaseEncoding(alphabet, padChar);
- }
- }
-
- @Override
- public BaseEncoding withSeparator(String separator, int afterEveryChars) {
- checkNotNull(separator);
- checkArgument(padding().or(alphabet).matchesNoneOf(separator),
- "Separator cannot contain alphabet or padding characters");
- return new SeparatedBaseEncoding(this, separator, afterEveryChars);
- }
-
- private transient BaseEncoding upperCase;
- private transient BaseEncoding lowerCase;
-
- @Override
- public BaseEncoding upperCase() {
- BaseEncoding result = upperCase;
- if (result == null) {
- Alphabet upper = alphabet.upperCase();
- result = upperCase =
- (upper == alphabet) ? this : new StandardBaseEncoding(upper, paddingChar);
- }
- return result;
- }
-
- @Override
- public BaseEncoding lowerCase() {
- BaseEncoding result = lowerCase;
- if (result == null) {
- Alphabet lower = alphabet.lowerCase();
- result = lowerCase =
- (lower == alphabet) ? this : new StandardBaseEncoding(lower, paddingChar);
- }
- return result;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder("BaseEncoding.");
- builder.append(alphabet.toString());
- if (8 % alphabet.bitsPerChar != 0) {
- if (paddingChar == null) {
- builder.append(".omitPadding()");
- } else {
- builder.append(".withPadChar(").append(paddingChar).append(')');
- }
- }
- return builder.toString();
- }
- }
-
- static CharInput ignoringInput(final CharInput delegate, final CharMatcher toIgnore) {
- checkNotNull(delegate);
- checkNotNull(toIgnore);
- return new CharInput() {
- @Override
- public int read() throws IOException {
- int readChar;
- do {
- readChar = delegate.read();
- } while (readChar != -1 && toIgnore.matches((char) readChar));
- return readChar;
- }
-
- @Override
- public void close() throws IOException {
- delegate.close();
- }
- };
- }
-
- static CharOutput separatingOutput(
- final CharOutput delegate, final String separator, final int afterEveryChars) {
- checkNotNull(delegate);
- checkNotNull(separator);
- checkArgument(afterEveryChars > 0);
- return new CharOutput() {
- int charsUntilSeparator = afterEveryChars;
-
- @Override
- public void write(char c) throws IOException {
- if (charsUntilSeparator == 0) {
- for (int i = 0; i < separator.length(); i++) {
- delegate.write(separator.charAt(i));
- }
- charsUntilSeparator = afterEveryChars;
- }
- delegate.write(c);
- charsUntilSeparator--;
- }
-
- @Override
- public void flush() throws IOException {
- delegate.flush();
- }
-
- @Override
- public void close() throws IOException {
- delegate.close();
- }
- };
- }
-
- static final class SeparatedBaseEncoding extends BaseEncoding {
- private final BaseEncoding delegate;
- private final String separator;
- private final int afterEveryChars;
- private final CharMatcher separatorChars;
-
- SeparatedBaseEncoding(BaseEncoding delegate, String separator, int afterEveryChars) {
- this.delegate = checkNotNull(delegate);
- this.separator = checkNotNull(separator);
- this.afterEveryChars = afterEveryChars;
- checkArgument(
- afterEveryChars > 0, "Cannot add a separator after every %s chars", afterEveryChars);
- this.separatorChars = CharMatcher.anyOf(separator).precomputed();
- }
-
- @Override
- CharMatcher padding() {
- return delegate.padding();
- }
-
- @Override
- int maxEncodedSize(int bytes) {
- int unseparatedSize = delegate.maxEncodedSize(bytes);
- return unseparatedSize + separator.length()
- * divide(Math.max(0, unseparatedSize - 1), afterEveryChars, FLOOR);
- }
-
- @Override
- ByteOutput encodingStream(final CharOutput output) {
- return delegate.encodingStream(separatingOutput(output, separator, afterEveryChars));
- }
-
- @Override
- int maxDecodedSize(int chars) {
- return delegate.maxDecodedSize(chars);
- }
-
- @Override
- ByteInput decodingStream(final CharInput input) {
- return delegate.decodingStream(ignoringInput(input, separatorChars));
- }
-
- @Override
- public BaseEncoding omitPadding() {
- return delegate.omitPadding().withSeparator(separator, afterEveryChars);
- }
-
- @Override
- public BaseEncoding withPadChar(char padChar) {
- return delegate.withPadChar(padChar).withSeparator(separator, afterEveryChars);
- }
-
- @Override
- public BaseEncoding withSeparator(String separator, int afterEveryChars) {
- throw new UnsupportedOperationException("Already have a separator");
- }
-
- @Override
- public BaseEncoding upperCase() {
- return delegate.upperCase().withSeparator(separator, afterEveryChars);
- }
-
- @Override
- public BaseEncoding lowerCase() {
- return delegate.lowerCase().withSeparator(separator, afterEveryChars);
- }
-
- @Override
- public String toString() {
- return delegate.toString() +
- ".withSeparator(\"" + separator + "\", " + afterEveryChars + ")";
- }
- }
-}
diff --git a/guava/src/com/google/common/io/ByteArrayDataInput.java b/guava/src/com/google/common/io/ByteArrayDataInput.java
index 3f4a467..f374b4e 100644
--- a/guava/src/com/google/common/io/ByteArrayDataInput.java
+++ b/guava/src/com/google/common/io/ByteArrayDataInput.java
@@ -22,44 +22,26 @@ import java.io.IOException;
/**
* An extension of {@code DataInput} for reading from in-memory byte arrays; its
* methods offer identical functionality but do not throw {@link IOException}.
- *
- * <p><b>Warning:<b> The caller is responsible for not attempting to read past
- * the end of the array. If any method encounters the end of the array
- * prematurely, it throws {@link IllegalStateException} to signify <i>programmer
- * error</i>. This behavior is a technical violation of the supertype's
- * contract, which specifies a checked exception.
+ * If any method encounters the end of the array prematurely, it throws {@link
+ * IllegalStateException}.
*
* @author Kevin Bourrillion
* @since 1.0
*/
public interface ByteArrayDataInput extends DataInput {
@Override void readFully(byte b[]);
-
@Override void readFully(byte b[], int off, int len);
-
@Override int skipBytes(int n);
-
@Override boolean readBoolean();
-
@Override byte readByte();
-
@Override int readUnsignedByte();
-
@Override short readShort();
-
@Override int readUnsignedShort();
-
@Override char readChar();
-
@Override int readInt();
-
@Override long readLong();
-
@Override float readFloat();
-
@Override double readDouble();
-
@Override String readLine();
-
@Override String readUTF();
}
diff --git a/guava/src/com/google/common/io/ByteSink.java b/guava/src/com/google/common/io/ByteSink.java
deleted file mode 100644
index 781b2c3..0000000
--- a/guava/src/com/google/common/io/ByteSink.java
+++ /dev/null
@@ -1,144 +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.io;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.charset.Charset;
-
-/**
- * A destination to which bytes can be written, such as a file. Unlike an {@link OutputStream}, a
- * {@code ByteSink} is not an open, stateful stream that can be written to and closed. Instead, it
- * is an immutable <i>supplier</i> of {@code OutputStream} instances.
- *
- * <p>{@code ByteSink} provides two kinds of methods:
- * <ul>
- * <li><b>Methods that return a stream:</b> These methods should return a <i>new</i>, independent
- * instance each time they are called. The caller is responsible for ensuring that the returned
- * stream is closed.
- * <li><b>Convenience methods:</b> These are implementations of common operations that are
- * typically implemented by opening a stream using one of the methods in the first category, doing
- * something and finally closing the stream or channel that was opened.
- * </ul>
- *
- * @since 14.0
- * @author Colin Decker
- */
-public abstract class ByteSink {
-
- /**
- * Returns a {@link CharSink} view of this {@code ByteSink} that writes characters to this sink
- * as bytes encoded with the given {@link Charset charset}.
- */
- public CharSink asCharSink(Charset charset) {
- return new AsCharSink(charset);
- }
-
- /**
- * Opens a new {@link OutputStream} for writing to this sink. This method should return a new,
- * independent stream each time it is called.
- *
- * <p>The caller is responsible for ensuring that the returned stream is closed.
- *
- * @throws IOException if an I/O error occurs in the process of opening the stream
- */
- public abstract OutputStream openStream() throws IOException;
-
- /**
- * Opens a new {@link BufferedOutputStream} for writing to this sink. This method should return a
- * new, independent stream each time it is called.
- *
- * <p>The caller is responsible for ensuring that the returned stream is closed.
- *
- * @throws IOException if an I/O error occurs in the process of opening the stream
- */
- public BufferedOutputStream openBufferedStream() throws IOException {
- OutputStream out = openStream();
- return (out instanceof BufferedOutputStream)
- ? (BufferedOutputStream) out
- : new BufferedOutputStream(out);
- }
-
- /**
- * Writes all the given bytes to this sink.
- *
- * @throws IOException if an I/O occurs in the process of writing to this sink
- */
- public void write(byte[] bytes) throws IOException {
- checkNotNull(bytes);
-
- Closer closer = Closer.create();
- try {
- OutputStream out = closer.register(openStream());
- out.write(bytes);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Writes all the bytes from the given {@code InputStream} to this sink. Does not close
- * {@code input}.
- *
- * @throws IOException if an I/O occurs in the process of reading from {@code input} or writing to
- * this sink
- */
- public long writeFrom(InputStream input) throws IOException {
- checkNotNull(input);
-
- Closer closer = Closer.create();
- try {
- OutputStream out = closer.register(openStream());
- return ByteStreams.copy(input, out);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * A char sink that encodes written characters with a charset and writes resulting bytes to this
- * byte sink.
- */
- private final class AsCharSink extends CharSink {
-
- private final Charset charset;
-
- private AsCharSink(Charset charset) {
- this.charset = checkNotNull(charset);
- }
-
- @Override
- public Writer openStream() throws IOException {
- return new OutputStreamWriter(ByteSink.this.openStream(), charset);
- }
-
- @Override
- public String toString() {
- return ByteSink.this.toString() + ".asCharSink(" + charset + ")";
- }
- }
-}
diff --git a/guava/src/com/google/common/io/ByteSource.java b/guava/src/com/google/common/io/ByteSource.java
deleted file mode 100644
index 44bb6ff..0000000
--- a/guava/src/com/google/common/io/ByteSource.java
+++ /dev/null
@@ -1,343 +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.io;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.hash.Funnels;
-import com.google.common.hash.HashCode;
-import com.google.common.hash.HashFunction;
-import com.google.common.hash.Hasher;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-
-/**
- * A readable source of bytes, such as a file. Unlike an {@link InputStream}, a
- * {@code ByteSource} is not an open, stateful stream for input that can be read and closed.
- * Instead, it is an immutable <i>supplier</i> of {@code InputStream} instances.
- *
- * <p>{@code ByteSource} provides two kinds of methods:
- * <ul>
- * <li><b>Methods that return a stream:</b> These methods should return a <i>new</i>, independent
- * instance each time they are called. The caller is responsible for ensuring that the returned
- * stream is closed.
- * <li><b>Convenience methods:</b> These are implementations of common operations that are
- * typically implemented by opening a stream using one of the methods in the first category, doing
- * something and finally closing the stream that was opened.
- * </ul>
- *
- * @since 14.0
- * @author Colin Decker
- */
-public abstract class ByteSource {
-
- private static final int BUF_SIZE = 0x1000; // 4K
-
- /**
- * Returns a {@link CharSource} view of this byte source that decodes bytes read from this source
- * as characters using the given {@link Charset}.
- */
- public CharSource asCharSource(Charset charset) {
- return new AsCharSource(charset);
- }
-
- /**
- * Opens a new {@link InputStream} for reading from this source. This method should return a new,
- * independent stream each time it is called.
- *
- * <p>The caller is responsible for ensuring that the returned stream is closed.
- *
- * @throws IOException if an I/O error occurs in the process of opening the stream
- */
- public abstract InputStream openStream() throws IOException;
-
- /**
- * Opens a new {@link BufferedInputStream} for reading from this source. This method should return
- * a new, independent stream each time it is called.
- *
- * <p>The caller is responsible for ensuring that the returned stream is closed.
- *
- * @throws IOException if an I/O error occurs in the process of opening the stream
- */
- public BufferedInputStream openBufferedStream() throws IOException {
- InputStream in = openStream();
- return (in instanceof BufferedInputStream)
- ? (BufferedInputStream) in
- : new BufferedInputStream(in);
- }
-
- /**
- * Returns a view of a slice of this byte source that is at most {@code length} bytes long
- * starting at the given {@code offset}.
- *
- * @throws IllegalArgumentException if {@code offset} or {@code length} is negative
- */
- public ByteSource slice(long offset, long length) {
- return new SlicedByteSource(offset, length);
- }
-
- /**
- * Returns the size of this source in bytes. For most implementations, this is a heavyweight
- * operation that will open a stream, read (or {@link InputStream#skip(long) skip}, if possible)
- * to the end of the stream and return the total number of bytes that were read.
- *
- * <p>For some sources, such as a file, this method may use a more efficient implementation. Note
- * that in such cases, it is <i>possible</i> that this method will return a different number of
- * bytes than would be returned by reading all of the bytes (for example, some special files may
- * return a size of 0 despite actually having content when read).
- *
- * <p>In either case, if this is a mutable source such as a file, the size it returns may not be
- * the same number of bytes a subsequent read would return.
- *
- * @throws IOException if an I/O error occurs in the process of reading the size of this source
- */
- public long size() throws IOException {
- Closer closer = Closer.create();
- try {
- InputStream in = closer.register(openStream());
- return countBySkipping(in);
- } catch (IOException e) {
- // skip may not be supported... at any rate, try reading
- } finally {
- closer.close();
- }
-
- closer = Closer.create();
- try {
- InputStream in = closer.register(openStream());
- return countByReading(in);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Counts the bytes in the given input stream using skip if possible. Returns SKIP_FAILED if the
- * first call to skip threw, in which case skip may just not be supported.
- */
- private long countBySkipping(InputStream in) throws IOException {
- long count = 0;
- while (true) {
- // don't try to skip more than available()
- // things may work really wrong with FileInputStream otherwise
- long skipped = in.skip(Math.min(in.available(), Integer.MAX_VALUE));
- if (skipped <= 0) {
- if (in.read() == -1) {
- return count;
- }
- count++;
- } else {
- count += skipped;
- }
- }
- }
-
- private static final byte[] countBuffer = new byte[BUF_SIZE];
-
- private long countByReading(InputStream in) throws IOException {
- long count = 0;
- long read;
- while ((read = in.read(countBuffer)) != -1) {
- count += read;
- }
- return count;
- }
-
- /**
- * Copies the contents of this byte source to the given {@code OutputStream}. Does not close
- * {@code output}.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source or
- * writing to {@code output}
- */
- public long copyTo(OutputStream output) throws IOException {
- checkNotNull(output);
-
- Closer closer = Closer.create();
- try {
- InputStream in = closer.register(openStream());
- return ByteStreams.copy(in, output);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Copies the contents of this byte source to the given {@code ByteSink}.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source or
- * writing to {@code sink}
- */
- public long copyTo(ByteSink sink) throws IOException {
- checkNotNull(sink);
-
- Closer closer = Closer.create();
- try {
- InputStream in = closer.register(openStream());
- OutputStream out = closer.register(sink.openStream());
- return ByteStreams.copy(in, out);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Reads the full contents of this byte source as a byte array.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source
- */
- public byte[] read() throws IOException {
- Closer closer = Closer.create();
- try {
- InputStream in = closer.register(openStream());
- return ByteStreams.toByteArray(in);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Hashes the contents of this byte source using the given hash function.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source
- */
- public HashCode hash(HashFunction hashFunction) throws IOException {
- Hasher hasher = hashFunction.newHasher();
- copyTo(Funnels.asOutputStream(hasher));
- return hasher.hash();
- }
-
- /**
- * Checks that the contents of this byte source are equal to the contents of the given byte
- * source.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source or
- * {@code other}
- */
- public boolean contentEquals(ByteSource other) throws IOException {
- checkNotNull(other);
-
- byte[] buf1 = new byte[BUF_SIZE];
- byte[] buf2 = new byte[BUF_SIZE];
-
- Closer closer = Closer.create();
- try {
- InputStream in1 = closer.register(openStream());
- InputStream in2 = closer.register(other.openStream());
- while (true) {
- int read1 = ByteStreams.read(in1, buf1, 0, BUF_SIZE);
- int read2 = ByteStreams.read(in2, buf2, 0, BUF_SIZE);
- if (read1 != read2 || !Arrays.equals(buf1, buf2)) {
- return false;
- } else if (read1 != BUF_SIZE) {
- return true;
- }
- }
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * A char source that reads bytes from this source and decodes them as characters using a
- * charset.
- */
- private final class AsCharSource extends CharSource {
-
- private final Charset charset;
-
- private AsCharSource(Charset charset) {
- this.charset = checkNotNull(charset);
- }
-
- @Override
- public Reader openStream() throws IOException {
- return new InputStreamReader(ByteSource.this.openStream(), charset);
- }
-
- @Override
- public String toString() {
- return ByteSource.this.toString() + ".asCharSource(" + charset + ")";
- }
- }
-
- /**
- * A view of a subsection of the containing byte source.
- */
- private final class SlicedByteSource extends ByteSource {
-
- private final long offset;
- private final long length;
-
- private SlicedByteSource(long offset, long length) {
- checkArgument(offset >= 0, "offset (%s) may not be negative", offset);
- checkArgument(length >= 0, "length (%s) may not be negative", length);
- this.offset = offset;
- this.length = length;
- }
-
- @Override
- public InputStream openStream() throws IOException {
- InputStream in = ByteSource.this.openStream();
- if (offset > 0) {
- try {
- ByteStreams.skipFully(in, offset);
- } catch (Throwable e) {
- Closer closer = Closer.create();
- closer.register(in);
- try {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
- }
- return ByteStreams.limit(in, length);
- }
-
- @Override
- public ByteSource slice(long offset, long length) {
- checkArgument(offset >= 0, "offset (%s) may not be negative", offset);
- checkArgument(length >= 0, "length (%s) may not be negative", length);
- long maxLength = this.length - offset;
- return ByteSource.this.slice(this.offset + offset, Math.min(length, maxLength));
- }
-
- @Override
- public String toString() {
- return ByteSource.this.toString() + ".slice(" + offset + ", " + length + ")";
- }
- }
-}
diff --git a/guava/src/com/google/common/io/ByteStreams.java b/guava/src/com/google/common/io/ByteStreams.java
index 4259d2b..78e63c5 100644
--- a/guava/src/com/google/common/io/ByteStreams.java
+++ b/guava/src/com/google/common/io/ByteStreams.java
@@ -16,13 +16,8 @@
package com.google.common.io;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndex;
-
import com.google.common.annotations.Beta;
-import com.google.common.hash.HashCode;
-import com.google.common.hash.HashFunction;
+import com.google.common.base.Preconditions;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -31,21 +26,22 @@ import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.EOFException;
-import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
+import java.security.MessageDigest;
import java.util.Arrays;
import java.util.zip.Checksum;
/**
* Provides utility methods for working with byte arrays and I/O streams.
*
+ * <p>All method parameters must be non-null unless documented otherwise.
+ *
* @author Chris Nokleberg
- * @author Colin Decker
* @since 1.0
*/
@Beta
@@ -63,7 +59,7 @@ public final class ByteStreams {
*/
public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
byte[] b) {
- return ByteStreams.asInputSupplier(asByteSource(b));
+ return newInputStreamSupplier(b, 0, b.length);
}
/**
@@ -77,58 +73,12 @@ public final class ByteStreams {
*/
public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
final byte[] b, final int off, final int len) {
- return ByteStreams.asInputSupplier(asByteSource(b).slice(off, len));
- }
-
- /**
- * Returns a new {@link ByteSource} that reads bytes from the given byte array.
- *
- * @since 14.0
- */
- public static ByteSource asByteSource(byte[] b) {
- return new ByteArrayByteSource(b);
- }
-
- private static final class ByteArrayByteSource extends ByteSource {
-
- private final byte[] bytes;
-
- private ByteArrayByteSource(byte[] bytes) {
- this.bytes = checkNotNull(bytes);
- }
-
- @Override
- public InputStream openStream() throws IOException {
- return new ByteArrayInputStream(bytes);
- }
-
- @Override
- public long size() throws IOException {
- return bytes.length;
- }
-
- @Override
- public byte[] read() throws IOException {
- return bytes.clone();
- }
-
- @Override
- public long copyTo(OutputStream output) throws IOException {
- output.write(bytes);
- return bytes.length;
- }
-
- @Override
- public HashCode hash(HashFunction hashFunction) throws IOException {
- return hashFunction.hashBytes(bytes);
- }
-
- // TODO(user): Possibly override slice()
-
- @Override
- public String toString() {
- return "ByteStreams.asByteSource(" + BaseEncoding.base16().encode(bytes) + ")";
- }
+ return new InputSupplier<ByteArrayInputStream>() {
+ @Override
+ public ByteArrayInputStream getInput() {
+ return new ByteArrayInputStream(b, off, len);
+ }
+ };
}
/**
@@ -140,7 +90,15 @@ public final class ByteStreams {
*/
public static void write(byte[] from,
OutputSupplier<? extends OutputStream> to) throws IOException {
- asByteSink(to).write(from);
+ Preconditions.checkNotNull(from);
+ boolean threw = true;
+ OutputStream out = to.getOutput();
+ try {
+ out.write(from);
+ threw = false;
+ } finally {
+ Closeables.close(out, threw);
+ }
}
/**
@@ -154,7 +112,21 @@ public final class ByteStreams {
*/
public static long copy(InputSupplier<? extends InputStream> from,
OutputSupplier<? extends OutputStream> to) throws IOException {
- return asByteSource(from).copyTo(asByteSink(to));
+ int successfulOps = 0;
+ InputStream in = from.getInput();
+ try {
+ OutputStream out = to.getOutput();
+ try {
+ long count = copy(in, out);
+ successfulOps++;
+ return count;
+ } finally {
+ Closeables.close(out, successfulOps < 1);
+ successfulOps++;
+ }
+ } finally {
+ Closeables.close(in, successfulOps < 2);
+ }
}
/**
@@ -169,13 +141,21 @@ public final class ByteStreams {
*/
public static long copy(InputSupplier<? extends InputStream> from,
OutputStream to) throws IOException {
- return asByteSource(from).copyTo(to);
+ boolean threw = true;
+ InputStream in = from.getInput();
+ try {
+ long count = copy(in, to);
+ threw = false;
+ return count;
+ } finally {
+ Closeables.close(in, threw);
+ }
}
/**
* Opens an output stream from the supplier, copies all bytes from the input
* to the output, and closes the output stream. Does not close or flush the
- * input stream.
+ * output stream.
*
* @param from the input stream to read from
* @param to the output factory
@@ -185,7 +165,15 @@ public final class ByteStreams {
*/
public static long copy(InputStream from,
OutputSupplier<? extends OutputStream> to) throws IOException {
- return asByteSink(to).writeFrom(from);
+ boolean threw = true;
+ OutputStream out = to.getOutput();
+ try {
+ long count = copy(from, out);
+ threw = false;
+ return count;
+ } finally {
+ Closeables.close(out, threw);
+ }
}
/**
@@ -199,8 +187,6 @@ public final class ByteStreams {
*/
public static long copy(InputStream from, OutputStream to)
throws IOException {
- checkNotNull(from);
- checkNotNull(to);
byte[] buf = new byte[BUF_SIZE];
long total = 0;
while (true) {
@@ -225,8 +211,6 @@ public final class ByteStreams {
*/
public static long copy(ReadableByteChannel from,
WritableByteChannel to) throws IOException {
- checkNotNull(from);
- checkNotNull(to);
ByteBuffer buf = ByteBuffer.allocate(BUF_SIZE);
long total = 0;
while (from.read(buf) != -1) {
@@ -261,7 +245,15 @@ public final class ByteStreams {
*/
public static byte[] toByteArray(
InputSupplier<? extends InputStream> supplier) throws IOException {
- return asByteSource(supplier).read();
+ boolean threw = true;
+ InputStream in = supplier.getInput();
+ try {
+ byte[] result = toByteArray(in);
+ threw = false;
+ return result;
+ } finally {
+ Closeables.close(in, threw);
+ }
}
/**
@@ -280,7 +272,7 @@ public final class ByteStreams {
* than the length of the array
*/
public static ByteArrayDataInput newDataInput(byte[] bytes, int start) {
- checkPositionIndex(start, bytes.length);
+ Preconditions.checkPositionIndex(start, bytes.length);
return new ByteArrayDataInputStream(bytes, start);
}
@@ -433,7 +425,7 @@ public final class ByteStreams {
* @throws IllegalArgumentException if {@code size} is negative
*/
public static ByteArrayDataOutput newDataOutput(int size) {
- checkArgument(size >= 0, "Invalid size: %s", size);
+ Preconditions.checkArgument(size >= 0, "Invalid size: %s", size);
return new ByteArrayDataOutputStream(size);
}
@@ -572,123 +564,35 @@ public final class ByteStreams {
@Override public byte[] toByteArray() {
return byteArrayOutputSteam.toByteArray();
}
- }
-
- private static final OutputStream NULL_OUTPUT_STREAM =
- new OutputStream() {
- /** Discards the specified byte. */
- @Override public void write(int b) {
- }
- /** Discards the specified byte array. */
- @Override public void write(byte[] b) {
- checkNotNull(b);
- }
- /** Discards the specified byte array. */
- @Override public void write(byte[] b, int off, int len) {
- checkNotNull(b);
- }
-
- @Override
- public String toString() {
- return "ByteStreams.nullOutputStream()";
- }
- };
-
- /**
- * Returns an {@link OutputStream} that simply discards written bytes.
- *
- * @since 14.0 (since 1.0 as com.google.common.io.NullOutputStream)
- */
- public static OutputStream nullOutputStream() {
- return NULL_OUTPUT_STREAM;
- }
- /**
- * Wraps a {@link InputStream}, limiting the number of bytes which can be
- * read.
- *
- * @param in the input stream to be wrapped
- * @param limit the maximum number of bytes to be read
- * @return a length-limited {@link InputStream}
- * @since 14.0 (since 1.0 as com.google.common.io.LimitInputStream)
- */
- public static InputStream limit(InputStream in, long limit) {
- return new LimitedInputStream(in, limit);
}
- private static final class LimitedInputStream extends FilterInputStream {
-
- private long left;
- private long mark = -1;
-
- LimitedInputStream(InputStream in, long limit) {
- super(in);
- checkNotNull(in);
- checkArgument(limit >= 0, "limit must be non-negative");
- left = limit;
- }
-
- @Override public int available() throws IOException {
- return (int) Math.min(in.available(), left);
- }
-
- // it's okay to mark even if mark isn't supported, as reset won't work
- @Override public synchronized void mark(int readLimit) {
- in.mark(readLimit);
- mark = left;
- }
-
- @Override public int read() throws IOException {
- if (left == 0) {
- return -1;
- }
-
- int result = in.read();
- if (result != -1) {
- --left;
- }
- return result;
- }
-
- @Override public int read(byte[] b, int off, int len) throws IOException {
- if (left == 0) {
- return -1;
- }
-
- len = (int) Math.min(len, left);
- int result = in.read(b, off, len);
- if (result != -1) {
- left -= result;
- }
- return result;
- }
-
- @Override public synchronized void reset() throws IOException {
- if (!in.markSupported()) {
- throw new IOException("Mark not supported");
- }
- if (mark == -1) {
- throw new IOException("Mark not set");
+ // TODO(chrisn): Not all streams support skipping.
+ /** Returns the length of a supplied input stream, in bytes. */
+ public static long length(InputSupplier<? extends InputStream> supplier)
+ throws IOException {
+ long count = 0;
+ boolean threw = true;
+ InputStream in = supplier.getInput();
+ try {
+ while (true) {
+ // We skip only Integer.MAX_VALUE due to JDK overflow bugs.
+ long amt = in.skip(Integer.MAX_VALUE);
+ if (amt == 0) {
+ if (in.read() == -1) {
+ threw = false;
+ return count;
+ }
+ count++;
+ } else {
+ count += amt;
+ }
}
-
- in.reset();
- left = mark;
- }
-
- @Override public long skip(long n) throws IOException {
- n = Math.min(n, left);
- long skipped = in.skip(n);
- left -= skipped;
- return skipped;
+ } finally {
+ Closeables.close(in, threw);
}
}
- /** Returns the length of a supplied input stream, in bytes. */
- public static long length(
- InputSupplier<? extends InputStream> supplier) throws IOException {
- return asByteSource(supplier).size();
- }
-
/**
* Returns true if the supplied input streams contain the same bytes.
*
@@ -696,7 +600,31 @@ public final class ByteStreams {
*/
public static boolean equal(InputSupplier<? extends InputStream> supplier1,
InputSupplier<? extends InputStream> supplier2) throws IOException {
- return asByteSource(supplier1).contentEquals(asByteSource(supplier2));
+ byte[] buf1 = new byte[BUF_SIZE];
+ byte[] buf2 = new byte[BUF_SIZE];
+
+ boolean threw = true;
+ InputStream in1 = supplier1.getInput();
+ try {
+ InputStream in2 = supplier2.getInput();
+ try {
+ while (true) {
+ int read1 = read(in1, buf1, 0, BUF_SIZE);
+ int read2 = read(in2, buf2, 0, BUF_SIZE);
+ if (read1 != read2 || !Arrays.equals(buf1, buf2)) {
+ threw = false;
+ return false;
+ } else if (read1 != BUF_SIZE) {
+ threw = false;
+ return true;
+ }
+ }
+ } finally {
+ Closeables.close(in2, threw);
+ }
+ } finally {
+ Closeables.close(in1, threw);
+ }
}
/**
@@ -728,12 +656,10 @@ public final class ByteStreams {
* the bytes.
* @throws IOException if an I/O error occurs.
*/
- public static void readFully(
- InputStream in, byte[] b, int off, int len) throws IOException {
- int read = read(in, b, off, len);
- if (read != len) {
- throw new EOFException("reached end of stream after reading "
- + read + " bytes; " + len + " bytes expected");
+ public static void readFully(InputStream in, byte[] b, int off, int len)
+ throws IOException {
+ if (read(in, b, off, len) != len) {
+ throw new EOFException();
}
}
@@ -750,15 +676,12 @@ public final class ByteStreams {
* support skipping
*/
public static void skipFully(InputStream in, long n) throws IOException {
- long toSkip = n;
while (n > 0) {
long amt = in.skip(n);
if (amt == 0) {
// Force a blocking read to avoid infinite loop
if (in.read() == -1) {
- long skipped = toSkip - n;
- throw new EOFException("reached end of stream after skipping "
- + skipped + " bytes; " + toSkip + " bytes expected");
+ throw new EOFException();
}
n--;
} else {
@@ -775,46 +698,27 @@ public final class ByteStreams {
* @return the result of the byte processor
* @throws IOException if an I/O error occurs
*/
- public static <T> T readBytes(
- InputSupplier<? extends InputStream> supplier,
+ public static <T> T readBytes(InputSupplier<? extends InputStream> supplier,
ByteProcessor<T> processor) throws IOException {
- checkNotNull(supplier);
- checkNotNull(processor);
-
- Closer closer = Closer.create();
+ byte[] buf = new byte[BUF_SIZE];
+ boolean threw = true;
+ InputStream in = supplier.getInput();
try {
- InputStream in = closer.register(supplier.getInput());
- return readBytes(in, processor);
- } catch (Throwable e) {
- throw closer.rethrow(e);
+ int amt;
+ do {
+ amt = in.read(buf);
+ if (amt == -1) {
+ threw = false;
+ break;
+ }
+ } while (processor.processBytes(buf, 0, amt));
+ return processor.getResult();
} finally {
- closer.close();
+ Closeables.close(in, threw);
}
}
/**
- * Process the bytes of the given input stream using the given processor.
- *
- * @param input the input stream to process
- * @param processor the object to which to pass the bytes of the stream
- * @return the result of the byte processor
- * @throws IOException if an I/O error occurs
- * @since 14.0
- */
- public static <T> T readBytes(
- InputStream input, ByteProcessor<T> processor) throws IOException {
- checkNotNull(input);
- checkNotNull(processor);
-
- byte[] buf = new byte[BUF_SIZE];
- int read;
- do {
- read = input.read(buf);
- } while (read != -1 && processor.processBytes(buf, 0, read));
- return processor.getResult();
- }
-
- /**
* Computes and returns the checksum value for a supplied input stream.
* The checksum object is reset when this method returns successfully.
*
@@ -823,21 +727,16 @@ public final class ByteStreams {
* @return the result of {@link Checksum#getValue} after updating the
* checksum object with all of the bytes in the stream
* @throws IOException if an I/O error occurs
- * @deprecated Use {@code hash} with the {@code Hashing.crc32()} or
- * {@code Hashing.adler32()} hash functions instead. This method is
- * scheduled to be removed in Guava 15.0.
*/
- @Deprecated
- public static long getChecksum(
- InputSupplier<? extends InputStream> supplier, final Checksum checksum)
- throws IOException {
- checkNotNull(checksum);
+ public static long getChecksum(InputSupplier<? extends InputStream> supplier,
+ final Checksum checksum) throws IOException {
return readBytes(supplier, new ByteProcessor<Long>() {
@Override
public boolean processBytes(byte[] buf, int off, int len) {
checksum.update(buf, off, len);
return true;
}
+
@Override
public Long getResult() {
long result = checksum.getValue();
@@ -848,19 +747,29 @@ public final class ByteStreams {
}
/**
- * Computes the hash code of the data supplied by {@code supplier} using {@code
- * hashFunction}.
+ * Computes and returns the digest value for a supplied input stream.
+ * The digest object is reset when this method returns successfully.
*
* @param supplier the input stream factory
- * @param hashFunction the hash function to use to hash the data
- * @return the {@link HashCode} of all of the bytes in the input stream
+ * @param md the digest object
+ * @return the result of {@link MessageDigest#digest()} after updating the
+ * digest object with all of the bytes in the stream
* @throws IOException if an I/O error occurs
- * @since 12.0
*/
- public static HashCode hash(
- InputSupplier<? extends InputStream> supplier, HashFunction hashFunction)
- throws IOException {
- return asByteSource(supplier).hash(hashFunction);
+ public static byte[] getDigest(InputSupplier<? extends InputStream> supplier,
+ final MessageDigest md) throws IOException {
+ return readBytes(supplier, new ByteProcessor<byte[]>() {
+ @Override
+ public boolean processBytes(byte[] buf, int off, int len) {
+ md.update(buf, off, len);
+ return true;
+ }
+
+ @Override
+ public byte[] getResult() {
+ return md.digest();
+ }
+ });
}
/**
@@ -889,8 +798,6 @@ public final class ByteStreams {
*/
public static int read(InputStream in, byte[] b, int off, int len)
throws IOException {
- checkNotNull(in);
- checkNotNull(b);
if (len < 0) {
throw new IndexOutOfBoundsException("len is negative");
}
@@ -920,7 +827,23 @@ public final class ByteStreams {
final InputSupplier<? extends InputStream> supplier,
final long offset,
final long length) {
- return asInputSupplier(asByteSource(supplier).slice(offset, length));
+ Preconditions.checkNotNull(supplier);
+ Preconditions.checkArgument(offset >= 0, "offset is negative");
+ Preconditions.checkArgument(length >= 0, "length is negative");
+ return new InputSupplier<InputStream>() {
+ @Override public InputStream getInput() throws IOException {
+ InputStream in = supplier.getInput();
+ if (offset > 0) {
+ try {
+ skipFully(in, offset);
+ } catch (IOException e) {
+ Closeables.closeQuietly(in);
+ throw e;
+ }
+ }
+ return new LimitInputStream(in, length);
+ }
+ };
}
/**
@@ -940,7 +863,6 @@ public final class ByteStreams {
*/
public static InputSupplier<InputStream> join(
final Iterable<? extends InputSupplier<? extends InputStream>> suppliers) {
- checkNotNull(suppliers);
return new InputSupplier<InputStream>() {
@Override public InputStream getInput() throws IOException {
return new MultiInputStream(suppliers.iterator());
@@ -953,52 +875,4 @@ public final class ByteStreams {
InputSupplier<? extends InputStream>... suppliers) {
return join(Arrays.asList(suppliers));
}
-
- // TODO(user): Remove these once Input/OutputSupplier methods are removed
-
- static <S extends InputStream> InputSupplier<S> asInputSupplier(
- final ByteSource source) {
- checkNotNull(source);
- return new InputSupplier<S>() {
- @SuppressWarnings("unchecked") // used internally where known to be safe
- @Override
- public S getInput() throws IOException {
- return (S) source.openStream();
- }
- };
- }
-
- static <S extends OutputStream> OutputSupplier<S> asOutputSupplier(
- final ByteSink sink) {
- checkNotNull(sink);
- return new OutputSupplier<S>() {
- @SuppressWarnings("unchecked") // used internally where known to be safe
- @Override
- public S getOutput() throws IOException {
- return (S) sink.openStream();
- }
- };
- }
-
- static ByteSource asByteSource(
- final InputSupplier<? extends InputStream> supplier) {
- checkNotNull(supplier);
- return new ByteSource() {
- @Override
- public InputStream openStream() throws IOException {
- return supplier.getInput();
- }
- };
- }
-
- static ByteSink asByteSink(
- final OutputSupplier<? extends OutputStream> supplier) {
- checkNotNull(supplier);
- return new ByteSink() {
- @Override
- public OutputStream openStream() throws IOException {
- return supplier.getOutput();
- }
- };
- }
}
diff --git a/guava/src/com/google/common/io/CharSink.java b/guava/src/com/google/common/io/CharSink.java
deleted file mode 100644
index 064adcd..0000000
--- a/guava/src/com/google/common/io/CharSink.java
+++ /dev/null
@@ -1,150 +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.io;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.nio.charset.Charset;
-
-/**
- * A destination to which characters can be written, such as a text file. Unlike a {@link Writer}, a
- * {@code CharSink} is not an open, stateful stream that can be written to and closed. Instead, it
- * is an immutable <i>supplier</i> of {@code Writer} instances.
- *
- * <p>{@code CharSink} provides two kinds of methods:
- * <ul>
- * <li><b>Methods that return a writer:</b> These methods should return a <i>new</i>,
- * independent instance each time they are called. The caller is responsible for ensuring that the
- * returned writer is closed.
- * <li><b>Convenience methods:</b> These are implementations of common operations that are
- * typically implemented by opening a writer using one of the methods in the first category,
- * doing something and finally closing the writer that was opened.
- * </ul>
- *
- * <p>Any {@link ByteSink} may be viewed as a {@code CharSink} with a specific {@linkplain Charset
- * character encoding} using {@link ByteSink#asCharSink(Charset)}. Characters written to the
- * resulting {@code CharSink} will written to the {@code ByteSink} as encoded bytes.
- *
- * @since 14.0
- * @author Colin Decker
- */
-public abstract class CharSink {
-
- /**
- * Opens a new {@link Writer} for writing to this sink. This method should return a new,
- * independent writer each time it is called.
- *
- * <p>The caller is responsible for ensuring that the returned writer is closed.
- *
- * @throws IOException if an I/O error occurs in the process of opening the writer
- */
- public abstract Writer openStream() throws IOException;
-
- /**
- * Opens a new {@link BufferedWriter} for writing to this sink. This method should return a new,
- * independent writer each time it is called.
- *
- * <p>The caller is responsible for ensuring that the returned writer is closed.
- *
- * @throws IOException if an I/O error occurs in the process of opening the writer
- */
- public BufferedWriter openBufferedStream() throws IOException {
- Writer writer = openStream();
- return (writer instanceof BufferedWriter)
- ? (BufferedWriter) writer
- : new BufferedWriter(writer);
- }
-
- /**
- * Writes the given character sequence to this sink.
- *
- * @throws IOException if an I/O error in the process of writing to this sink
- */
- public void write(CharSequence charSequence) throws IOException {
- checkNotNull(charSequence);
-
- Closer closer = Closer.create();
- try {
- Writer out = closer.register(openStream());
- out.append(charSequence);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Writes the given lines of text to this sink with each line (including the last) terminated with
- * the operating system's default line separator. This method is equivalent to
- * {@code writeLines(lines, System.getProperty("line.separator"))}.
- *
- * @throws IOException if an I/O error occurs in the process of writing to this sink
- */
- public void writeLines(Iterable<? extends CharSequence> lines) throws IOException {
- writeLines(lines, System.getProperty("line.separator"));
- }
-
- /**
- * Writes the given lines of text to this sink with each line (including the last) terminated with
- * the given line separator.
- *
- * @throws IOException if an I/O error occurs in the process of writing to this sink
- */
- public void writeLines(Iterable<? extends CharSequence> lines, String lineSeparator)
- throws IOException {
- checkNotNull(lines);
- checkNotNull(lineSeparator);
-
- Closer closer = Closer.create();
- try {
- BufferedWriter out = closer.register(openBufferedStream());
- for (CharSequence line : lines) {
- out.append(line).append(lineSeparator);
- }
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Writes all the text from the given {@link Readable} (such as a {@link Reader}) to this sink.
- * Does not close {@code readable} if it is {@code Closeable}.
- *
- * @throws IOException if an I/O error occurs in the process of reading from {@code readable} or
- * writing to this sink
- */
- public long writeFrom(Readable readable) throws IOException {
- checkNotNull(readable);
-
- Closer closer = Closer.create();
- try {
- Writer out = closer.register(openStream());
- return CharStreams.copy(readable, out);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-}
diff --git a/guava/src/com/google/common/io/CharSource.java b/guava/src/com/google/common/io/CharSource.java
deleted file mode 100644
index 057deaf..0000000
--- a/guava/src/com/google/common/io/CharSource.java
+++ /dev/null
@@ -1,192 +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.io;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-/**
- * A readable source of characters, such as a text file. Unlike a {@link Reader}, a
- * {@code CharSource} is not an open, stateful stream of characters that can be read and closed.
- * Instead, it is an immutable <i>supplier</i> of {@code InputStream} instances.
- *
- * <p>{@code CharSource} provides two kinds of methods:
- * <ul>
- * <li><b>Methods that return a reader:</b> These methods should return a <i>new</i>, independent
- * instance each time they are called. The caller is responsible for ensuring that the returned
- * reader is closed.
- * <li><b>Convenience methods:</b> These are implementations of common operations that are
- * typically implemented by opening a reader using one of the methods in the first category,
- * doing something and finally closing the reader that was opened.
- * </ul>
- *
- * <p>Several methods in this class, such as {@link #readLines()}, break the contents of the
- * source into lines. Like {@link BufferedReader}, these methods break lines on any of {@code \n},
- * {@code \r} or {@code \r\n}, do not include the line separator in each line and do not consider
- * there to be an empty line at the end if the contents are terminated with a line separator.
- *
- * <p>Any {@link ByteSource} containing text encoded with a specific {@linkplain Charset character
- * encoding} may be viewed as a {@code CharSource} using {@link ByteSource#asCharSource(Charset)}.
- *
- * @since 14.0
- * @author Colin Decker
- */
-public abstract class CharSource {
-
- /**
- * Opens a new {@link Reader} for reading from this source. This method should return a new,
- * independent reader each time it is called.
- *
- * <p>The caller is responsible for ensuring that the returned reader is closed.
- *
- * @throws IOException if an I/O error occurs in the process of opening the reader
- */
- public abstract Reader openStream() throws IOException;
-
- /**
- * Opens a new {@link BufferedReader} for reading from this source. This method should return a
- * new, independent reader each time it is called.
- *
- * <p>The caller is responsible for ensuring that the returned reader is closed.
- *
- * @throws IOException if an I/O error occurs in the process of opening the reader
- */
- public BufferedReader openBufferedStream() throws IOException {
- Reader reader = openStream();
- return (reader instanceof BufferedReader)
- ? (BufferedReader) reader
- : new BufferedReader(reader);
- }
-
- /**
- * Appends the contents of this source to the given {@link Appendable} (such as a {@link Writer}).
- * Does not close {@code appendable} if it is {@code Closeable}.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source or
- * writing to {@code appendable}
- */
- public long copyTo(Appendable appendable) throws IOException {
- checkNotNull(appendable);
-
- Closer closer = Closer.create();
- try {
- Reader reader = closer.register(openStream());
- return CharStreams.copy(reader, appendable);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Copies the contents of this source to the given sink.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source or
- * writing to {@code sink}
- */
- public long copyTo(CharSink sink) throws IOException {
- checkNotNull(sink);
-
- Closer closer = Closer.create();
- try {
- Reader reader = closer.register(openStream());
- Writer writer = closer.register(sink.openStream());
- return CharStreams.copy(reader, writer);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Reads the contents of this source as a string.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source
- */
- public String read() throws IOException {
- Closer closer = Closer.create();
- try {
- Reader reader = closer.register(openStream());
- return CharStreams.toString(reader);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Reads the first link of this source as a string. Returns {@code null} if this source is empty.
- *
- * <p>Like {@link BufferedReader}, this method breaks lines on any of {@code \n}, {@code \r} or
- * {@code \r\n}, does not include the line separator in the returned line and does not consider
- * there to be an extra empty line at the end if the content is terminated with a line separator.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source
- */
- public @Nullable String readFirstLine() throws IOException {
- Closer closer = Closer.create();
- try {
- BufferedReader reader = closer.register(openBufferedStream());
- return reader.readLine();
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- /**
- * Reads all the lines of this source as a list of strings. The returned list will be empty if
- * this source is empty.
- *
- * <p>Like {@link BufferedReader}, this method breaks lines on any of {@code \n}, {@code \r} or
- * {@code \r\n}, does not include the line separator in the returned lines and does not consider
- * there to be an extra empty line at the end if the content is terminated with a line separator.
- *
- * @throws IOException if an I/O error occurs in the process of reading from this source
- */
- public ImmutableList<String> readLines() throws IOException {
- Closer closer = Closer.create();
- try {
- BufferedReader reader = closer.register(openBufferedStream());
- List<String> result = Lists.newArrayList();
- String line;
- while ((line = reader.readLine()) != null) {
- result.add(line);
- }
- return ImmutableList.copyOf(result);
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-}
diff --git a/guava/src/com/google/common/io/CharStreams.java b/guava/src/com/google/common/io/CharStreams.java
index 6d9999d..0d53d90 100644
--- a/guava/src/com/google/common/io/CharStreams.java
+++ b/guava/src/com/google/common/io/CharStreams.java
@@ -16,13 +16,8 @@
package com.google.common.io;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.Beta;
-import com.google.common.base.Charsets;
-import com.google.common.base.Splitter;
-import com.google.common.collect.AbstractIterator;
-import com.google.common.collect.ImmutableList;
+import com.google.common.base.Preconditions;
import java.io.Closeable;
import java.io.EOFException;
@@ -38,9 +33,7 @@ import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Iterator;
import java.util.List;
-import java.util.regex.Pattern;
/**
* Provides utility methods for working with character streams.
@@ -54,7 +47,6 @@ import java.util.regex.Pattern;
*
* @author Chris Nokleberg
* @author Bin Zhu
- * @author Colin Decker
* @since 1.0
*/
@Beta
@@ -72,85 +64,13 @@ public final class CharStreams {
*/
public static InputSupplier<StringReader> newReaderSupplier(
final String value) {
- return CharStreams.asInputSupplier(asCharSource(value));
- }
-
- /**
- * Returns a {@link CharSource} that reads the given string value.
- *
- * @since 14.0
- */
- public static CharSource asCharSource(String string) {
- return new StringCharSource(string);
- }
-
- private static final class StringCharSource extends CharSource {
-
- private static final Splitter LINE_SPLITTER
- = Splitter.on(Pattern.compile("\r\n|\n|\r"));
-
- private final String string;
-
- private StringCharSource(String string) {
- this.string = checkNotNull(string);
- }
-
- @Override
- public Reader openStream() {
- return new StringReader(string);
- }
-
- @Override
- public String read() {
- return string;
- }
-
- /**
- * Returns an iterable over the lines in the string. If the string ends in
- * a newline, a final empty string is not included to match the behavior of
- * BufferedReader/LineReader.readLine().
- */
- private Iterable<String> lines() {
- return new Iterable<String>() {
- @Override
- public Iterator<String> iterator() {
- return new AbstractIterator<String>() {
- Iterator<String> lines = LINE_SPLITTER.split(string).iterator();
-
- @Override
- protected String computeNext() {
- if (lines.hasNext()) {
- String next = lines.next();
- // skip last line if it's empty
- if (lines.hasNext() || !next.isEmpty()) {
- return next;
- }
- }
- return endOfData();
- }
- };
- }
- };
- }
-
- @Override
- public String readFirstLine() {
- Iterator<String> lines = lines().iterator();
- return lines.hasNext() ? lines.next() : null;
- }
-
- @Override
- public ImmutableList<String> readLines() {
- return ImmutableList.copyOf(lines());
- }
-
- @Override
- public String toString() {
- String limited = (string.length() <= 15)
- ? string
- : string.substring(0, 12) + "...";
- return "CharStreams.asCharSource(" + limited + ")";
- }
+ Preconditions.checkNotNull(value);
+ return new InputSupplier<StringReader>() {
+ @Override
+ public StringReader getInput() {
+ return new StringReader(value);
+ }
+ };
}
/**
@@ -158,14 +78,19 @@ public final class CharStreams {
* using the given {@link InputStream} factory and character set.
*
* @param in the factory that will be used to open input streams
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used to decode the input stream
* @return the factory
*/
public static InputSupplier<InputStreamReader> newReaderSupplier(
final InputSupplier<? extends InputStream> in, final Charset charset) {
- return CharStreams.asInputSupplier(
- ByteStreams.asByteSource(in).asCharSource(charset));
+ Preconditions.checkNotNull(in);
+ Preconditions.checkNotNull(charset);
+ return new InputSupplier<InputStreamReader>() {
+ @Override
+ public InputStreamReader getInput() throws IOException {
+ return new InputStreamReader(in.getInput(), charset);
+ }
+ };
}
/**
@@ -173,14 +98,19 @@ public final class CharStreams {
* using the given {@link OutputStream} factory and character set.
*
* @param out the factory that will be used to open output streams
- * @param charset the charset used to encode the output stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used to encode the output stream
* @return the factory
*/
public static OutputSupplier<OutputStreamWriter> newWriterSupplier(
final OutputSupplier<? extends OutputStream> out, final Charset charset) {
- return CharStreams.asOutputSupplier(
- ByteStreams.asByteSink(out).asCharSink(charset));
+ Preconditions.checkNotNull(out);
+ Preconditions.checkNotNull(charset);
+ return new OutputSupplier<OutputStreamWriter>() {
+ @Override
+ public OutputStreamWriter getOutput() throws IOException {
+ return new OutputStreamWriter(out.getOutput(), charset);
+ }
+ };
}
/**
@@ -193,7 +123,15 @@ public final class CharStreams {
*/
public static <W extends Appendable & Closeable> void write(CharSequence from,
OutputSupplier<W> to) throws IOException {
- asCharSink(to).write(from);
+ Preconditions.checkNotNull(from);
+ boolean threw = true;
+ W out = to.getOutput();
+ try {
+ out.append(from);
+ threw = false;
+ } finally {
+ Closeables.close(out, threw);
+ }
}
/**
@@ -209,7 +147,21 @@ public final class CharStreams {
public static <R extends Readable & Closeable,
W extends Appendable & Closeable> long copy(InputSupplier<R> from,
OutputSupplier<W> to) throws IOException {
- return asCharSource(from).copyTo(asCharSink(to));
+ int successfulOps = 0;
+ R in = from.getInput();
+ try {
+ W out = to.getOutput();
+ try {
+ long count = copy(in, out);
+ successfulOps++;
+ return count;
+ } finally {
+ Closeables.close(out, successfulOps < 1);
+ successfulOps++;
+ }
+ } finally {
+ Closeables.close(in, successfulOps < 2);
+ }
}
/**
@@ -224,7 +176,15 @@ public final class CharStreams {
*/
public static <R extends Readable & Closeable> long copy(
InputSupplier<R> from, Appendable to) throws IOException {
- return asCharSource(from).copyTo(to);
+ boolean threw = true;
+ R in = from.getInput();
+ try {
+ long count = copy(in, to);
+ threw = false;
+ return count;
+ } finally {
+ Closeables.close(in, threw);
+ }
}
/**
@@ -237,15 +197,16 @@ public final class CharStreams {
* @throws IOException if an I/O error occurs
*/
public static long copy(Readable from, Appendable to) throws IOException {
- checkNotNull(from);
- checkNotNull(to);
CharBuffer buf = CharBuffer.allocate(BUF_SIZE);
long total = 0;
- while (from.read(buf) != -1) {
+ while (true) {
+ int r = from.read(buf);
+ if (r == -1) {
+ break;
+ }
buf.flip();
- to.append(buf);
- total += buf.remaining();
- buf.clear();
+ to.append(buf, 0, r);
+ total += r;
}
return total;
}
@@ -272,7 +233,7 @@ public final class CharStreams {
*/
public static <R extends Readable & Closeable> String toString(
InputSupplier<R> supplier) throws IOException {
- return asCharSource(supplier).read();
+ return toStringBuilder(supplier).toString();
}
/**
@@ -290,6 +251,26 @@ public final class CharStreams {
}
/**
+ * Returns the characters from a {@link Readable} & {@link Closeable} object
+ * supplied by a factory as a new {@link StringBuilder} instance.
+ *
+ * @param supplier the factory to read from
+ * @throws IOException if an I/O error occurs
+ */
+ private static <R extends Readable & Closeable> StringBuilder toStringBuilder(
+ InputSupplier<R> supplier) throws IOException {
+ boolean threw = true;
+ R r = supplier.getInput();
+ try {
+ StringBuilder result = toStringBuilder(r);
+ threw = false;
+ return result;
+ } finally {
+ Closeables.close(r, threw);
+ }
+ }
+
+ /**
* Reads the first line from a {@link Readable} & {@link Closeable} object
* supplied by a factory. The line does not include line-termination
* characters, but does include other leading and trailing whitespace.
@@ -300,7 +281,15 @@ public final class CharStreams {
*/
public static <R extends Readable & Closeable> String readFirstLine(
InputSupplier<R> supplier) throws IOException {
- return asCharSource(supplier).readFirstLine();
+ boolean threw = true;
+ R r = supplier.getInput();
+ try {
+ String line = new LineReader(r).readLine();
+ threw = false;
+ return line;
+ } finally {
+ Closeables.close(r, threw);
+ }
}
/**
@@ -314,14 +303,14 @@ public final class CharStreams {
*/
public static <R extends Readable & Closeable> List<String> readLines(
InputSupplier<R> supplier) throws IOException {
- Closer closer = Closer.create();
+ boolean threw = true;
+ R r = supplier.getInput();
try {
- R r = closer.register(supplier.getInput());
- return readLines(r);
- } catch (Throwable e) {
- throw closer.rethrow(e);
+ List<String> result = readLines(r);
+ threw = false;
+ return result;
} finally {
- closer.close();
+ Closeables.close(r, threw);
}
}
@@ -349,31 +338,6 @@ public final class CharStreams {
}
/**
- * Streams lines from a {@link Readable} object, stopping when the processor
- * returns {@code false} or all lines have been read and returning the result
- * produced by the processor. Does not close {@code readable}. Note that this
- * method may not fully consume the contents of {@code readable} if the
- * processor stops processing early.
- *
- * @throws IOException if an I/O error occurs
- * @since 14.0
- */
- public static <T> T readLines(
- Readable readable, LineProcessor<T> processor) throws IOException {
- checkNotNull(readable);
- checkNotNull(processor);
-
- LineReader lineReader = new LineReader(readable);
- String line;
- while ((line = lineReader.readLine()) != null) {
- if (!processor.processLine(line)) {
- break;
- }
- }
- return processor.getResult();
- }
-
- /**
* Streams lines from a {@link Readable} and {@link Closeable} object
* supplied by a factory, stopping when our callback returns false, or we
* have read all of the lines.
@@ -385,18 +349,21 @@ public final class CharStreams {
*/
public static <R extends Readable & Closeable, T> T readLines(
InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException {
- checkNotNull(supplier);
- checkNotNull(callback);
-
- Closer closer = Closer.create();
+ boolean threw = true;
+ R r = supplier.getInput();
try {
- R r = closer.register(supplier.getInput());
- return readLines(r, callback);
- } catch (Throwable e) {
- throw closer.rethrow(e);
+ LineReader lineReader = new LineReader(r);
+ String line;
+ while ((line = lineReader.readLine()) != null) {
+ if (!callback.processLine(line)) {
+ break;
+ }
+ }
+ threw = false;
} finally {
- closer.close();
+ Closeables.close(r, threw);
}
+ return callback.getResult();
}
/**
@@ -416,7 +383,6 @@ public final class CharStreams {
*/
public static InputSupplier<Reader> join(
final Iterable<? extends InputSupplier<? extends Reader>> suppliers) {
- checkNotNull(suppliers);
return new InputSupplier<Reader>() {
@Override public Reader getInput() throws IOException {
return new MultiReader(suppliers.iterator());
@@ -442,7 +408,6 @@ public final class CharStreams {
* @throws IOException if an I/O error occurs
*/
public static void skipFully(Reader reader, long n) throws IOException {
- checkNotNull(reader);
while (n > 0) {
long amt = reader.skip(n);
if (amt == 0) {
@@ -473,73 +438,4 @@ public final class CharStreams {
}
return new AppendableWriter(target);
}
-
- // TODO(user): Remove these once Input/OutputSupplier methods are removed
-
- static <R extends Readable & Closeable> Reader asReader(final R readable) {
- checkNotNull(readable);
- if (readable instanceof Reader) {
- return (Reader) readable;
- }
- return new Reader() {
- @Override
- public int read(char[] cbuf, int off, int len) throws IOException {
- return read(CharBuffer.wrap(cbuf, off, len));
- }
-
- @Override
- public int read(CharBuffer target) throws IOException {
- return readable.read(target);
- }
-
- @Override
- public void close() throws IOException {
- readable.close();
- }
- };
- }
-
- static <R extends Reader> InputSupplier<R> asInputSupplier(
- final CharSource source) {
- checkNotNull(source);
- return new InputSupplier<R>() {
- @Override
- public R getInput() throws IOException {
- return (R) source.openStream();
- }
- };
- }
-
- static <W extends Writer> OutputSupplier<W> asOutputSupplier(
- final CharSink sink) {
- checkNotNull(sink);
- return new OutputSupplier<W>() {
- @Override
- public W getOutput() throws IOException {
- return (W) sink.openStream();
- }
- };
- }
-
- static <R extends Readable & Closeable> CharSource asCharSource(
- final InputSupplier<R> supplier) {
- checkNotNull(supplier);
- return new CharSource() {
- @Override
- public Reader openStream() throws IOException {
- return asReader(supplier.getInput());
- }
- };
- }
-
- static <W extends Appendable & Closeable> CharSink asCharSink(
- final OutputSupplier<W> supplier) {
- checkNotNull(supplier);
- return new CharSink() {
- @Override
- public Writer openStream() throws IOException {
- return asWriter(supplier.getOutput());
- }
- };
- }
}
diff --git a/guava/src/com/google/common/io/Closeables.java b/guava/src/com/google/common/io/Closeables.java
index d312184..e619887 100644
--- a/guava/src/com/google/common/io/Closeables.java
+++ b/guava/src/com/google/common/io/Closeables.java
@@ -40,33 +40,36 @@ public final class Closeables {
private Closeables() {}
/**
- * Closes a {@link Closeable}, with control over whether an {@code IOException} may be thrown.
- * This is primarily useful in a finally block, where a thrown exception needs to be logged but
- * not propagated (otherwise the original exception will be lost).
+ * Closes a {@link Closeable}, with control over whether an
+ * {@code IOException} may be thrown. This is primarily useful in a
+ * finally block, where a thrown exception needs to be logged but not
+ * propagated (otherwise the original exception will be lost).
*
- * <p>If {@code swallowIOException} is true then we never throw {@code IOException} but merely log
- * it.
+ * <p>If {@code swallowIOException} is true then we never throw
+ * {@code IOException} but merely log it.
*
- * <p>Example: <pre> {@code
+ * <p>Example:
*
- * public void useStreamNicely() throws IOException {
- * SomeStream stream = new SomeStream("foo");
- * boolean threw = true;
- * try {
- * // ... code which does something with the stream ...
- * threw = false;
- * } finally {
- * // If an exception occurs, rethrow it only if threw==false:
- * Closeables.close(stream, threw);
- * }
- * }}</pre>
+ * <p><pre>public void useStreamNicely() throws IOException {
+ * SomeStream stream = new SomeStream("foo");
+ * boolean threw = true;
+ * try {
+ * // Some code which does something with the Stream. May throw a
+ * // Throwable.
+ * threw = false; // No throwable thrown.
+ * } finally {
+ * // Close the stream.
+ * // If an exception occurs, only rethrow it if (threw==false).
+ * Closeables.close(stream, threw);
+ * }
+ * </pre>
*
- * @param closeable the {@code Closeable} object to be closed, or null, in which case this method
- * does nothing
- * @param swallowIOException if true, don't propagate IO exceptions thrown by the {@code close}
- * methods
- * @throws IOException if {@code swallowIOException} is false and {@code close} throws an
- * {@code IOException}.
+ * @param closeable the {@code Closeable} object to be closed, or null,
+ * in which case this method does nothing
+ * @param swallowIOException if true, don't propagate IO exceptions
+ * thrown by the {@code close} methods
+ * @throws IOException if {@code swallowIOException} is false and
+ * {@code close} throws an {@code IOException}.
*/
public static void close(@Nullable Closeable closeable,
boolean swallowIOException) throws IOException {
@@ -86,23 +89,11 @@ public final class Closeables {
}
/**
- * Equivalent to calling {@code close(closeable, true)}, but with no IOException in the signature.
- *
- * @param closeable the {@code Closeable} object to be closed, or null, in which case this method
- * does nothing
- * @deprecated Where possible, use the
- * <a href="http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html">
- * try-with-resources</a> statement if using JDK7 or {@link Closer} on JDK6 to close one or
- * more {@code Closeable} objects. This method is deprecated because it is easy to misuse and
- * may swallow IO exceptions that really should be thrown and handled. See
- * <a href="https://code.google.com/p/guava-libraries/issues/detail?id=1118">Guava issue
- * 1118</a> for a more detailed explanation of the reasons for deprecation and see
- * <a href="https://code.google.com/p/guava-libraries/wiki/ClosingResourcesExplained">
- * Closing Resources</a> for more information on the problems with closing {@code Closeable}
- * objects and some of the preferred solutions for handling it correctly. This method is
- * scheduled to be removed in Guava 16.0.
+ * Equivalent to calling {@code close(closeable, true)}, but with no
+ * IOException in the signature.
+ * @param closeable the {@code Closeable} object to be closed, or null, in
+ * which case this method does nothing
*/
- @Deprecated
public static void closeQuietly(@Nullable Closeable closeable) {
try {
close(closeable, true);
diff --git a/guava/src/com/google/common/io/Closer.java b/guava/src/com/google/common/io/Closer.java
deleted file mode 100644
index 49141c2..0000000
--- a/guava/src/com/google/common/io/Closer.java
+++ /dev/null
@@ -1,285 +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.io;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Throwables;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.logging.Level;
-
-/**
- * A {@link Closeable} that collects {@code Closeable} resources and closes them all when it is
- * {@linkplain #close closed}. This is intended to approximately emulate the behavior of Java 7's
- * <a href="http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html">
- * try-with-resources</a> statement in JDK6-compatible code. Running on Java 7, code using this
- * should be approximately equivalent in behavior to the same code written with try-with-resources.
- * Running on Java 6, exceptions that cannot be thrown must be logged rather than being added to the
- * thrown exception as a suppressed exception.
- *
- * <p>This class is intended to to be used in the following pattern:
- *
- * <pre>{@code
- * Closer closer = Closer.create();
- * try {
- * InputStream in = closer.register(openInputStream());
- * OutputStream out = closer.register(openOutputStream());
- * // do stuff
- * } catch (Throwable e) {
- * // ensure that any checked exception types other than IOException that could be thrown are
- * // provided here, e.g. throw closer.rethrow(e, CheckedException.class);
- * throw closer.rethrow(e);
- * } finally {
- * closer.close();
- * }
- * }</pre>
- *
- * <p>Note that this try-catch-finally block is not equivalent to a try-catch-finally block using
- * try-with-resources. To get the equivalent of that, you must wrap the above code in <i>another</i>
- * try block in order to catch any exception that may be thrown (including from the call to
- * {@code close()}).
- *
- * <p>This pattern ensures the following:
- * <ul>
- * <li>Each {@code Closeable} resource that is successfully registered will be closed later.</li>
- * <li>If a {@code Throwable} is thrown in the try block, no exceptions that occur when attempting
- * to close resources will be thrown from the finally block. The throwable from the try block will
- * be thrown.</li>
- * <li>If no exceptions or errors were thrown in the try block, the <i>first</i> exception thrown
- * by an attempt to close a resource will be thrown.</li>
- * <li>Any exception caught when attempting to close a resource that is <i>not</i> thrown
- * (because another exception is already being thrown) is <i>suppressed</i>.</li>
- * </ul>
- *
- * An exception that is suppressed is not thrown. The method of suppression used depends on the
- * version of Java the code is running on:
- *
- * <ul>
- * <li><b>Java 7+:</b> Exceptions are suppressed by adding them to the exception that <i>will</i>
- * be thrown using {@code Throwable.addSuppressed(Throwable)}.</li>
- * <li><b>Java 6:</b> Exceptions are suppressed by logging them instead.</li>
- * </ul>
- *
- * @author Colin Decker
- * @since 14.0
- */
-// Coffee's for {@link Closer closers} only.
-@Beta
-public final class Closer implements Closeable {
-
- /**
- * The suppressor implementation to use for the current Java version.
- */
- private static final Suppressor SUPPRESSOR = SuppressingSuppressor.isAvailable()
- ? SuppressingSuppressor.INSTANCE
- : LoggingSuppressor.INSTANCE;
-
- /**
- * Creates a new {@link Closer}.
- */
- public static Closer create() {
- return new Closer(SUPPRESSOR);
- }
-
- @VisibleForTesting final Suppressor suppressor;
-
- // only need space for 2 elements in most cases, so try to use the smallest array possible
- private final Deque<Closeable> stack = new ArrayDeque<Closeable>(4);
- private Throwable thrown;
-
- @VisibleForTesting Closer(Suppressor suppressor) {
- this.suppressor = checkNotNull(suppressor); // checkNotNull to satisfy null tests
- }
-
- /**
- * Registers the given {@code closeable} to be closed when this {@code Closer} is
- * {@linkplain #close closed}.
- *
- * @return the given {@code closeable}
- */
- // close. this word no longer has any meaning to me.
- public <C extends Closeable> C register(C closeable) {
- stack.push(closeable);
- return closeable;
- }
-
- /**
- * Stores the given throwable and rethrows it. It will be rethrown as is if it is an
- * {@code IOException}, {@code RuntimeException} or {@code Error}. Otherwise, it will be rethrown
- * wrapped in a {@code RuntimeException}. <b>Note:</b> Be sure to declare all of the checked
- * exception types your try block can throw when calling an overload of this method so as to avoid
- * losing the original exception type.
- *
- * <p>This method always throws, and as such should be called as
- * {@code throw closer.rethrow(e);} to ensure the compiler knows that it will throw.
- *
- * @return this method does not return; it always throws
- * @throws IOException when the given throwable is an IOException
- */
- public RuntimeException rethrow(Throwable e) throws IOException {
- thrown = e;
- Throwables.propagateIfPossible(e, IOException.class);
- throw Throwables.propagate(e);
- }
-
- /**
- * Stores the given throwable and rethrows it. It will be rethrown as is if it is an
- * {@code IOException}, {@code RuntimeException}, {@code Error} or a checked exception of the
- * given type. Otherwise, it will be rethrown wrapped in a {@code RuntimeException}. <b>Note:</b>
- * Be sure to declare all of the checked exception types your try block can throw when calling an
- * overload of this method so as to avoid losing the original exception type.
- *
- * <p>This method always throws, and as such should be called as
- * {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw.
- *
- * @return this method does not return; it always throws
- * @throws IOException when the given throwable is an IOException
- * @throws X when the given throwable is of the declared type X
- */
- public <X extends Exception> RuntimeException rethrow(Throwable e,
- Class<X> declaredType) throws IOException, X {
- thrown = e;
- Throwables.propagateIfPossible(e, IOException.class);
- Throwables.propagateIfPossible(e, declaredType);
- throw Throwables.propagate(e);
- }
-
- /**
- * Stores the given throwable and rethrows it. It will be rethrown as is if it is an
- * {@code IOException}, {@code RuntimeException}, {@code Error} or a checked exception of either
- * of the given types. Otherwise, it will be rethrown wrapped in a {@code RuntimeException}.
- * <b>Note:</b> Be sure to declare all of the checked exception types your try block can throw
- * when calling an overload of this method so as to avoid losing the original exception type.
- *
- * <p>This method always throws, and as such should be called as
- * {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw.
- *
- * @return this method does not return; it always throws
- * @throws IOException when the given throwable is an IOException
- * @throws X1 when the given throwable is of the declared type X1
- * @throws X2 when the given throwable is of the declared type X2
- */
- public <X1 extends Exception, X2 extends Exception> RuntimeException rethrow(
- Throwable e, Class<X1> declaredType1, Class<X2> declaredType2) throws IOException, X1, X2 {
- thrown = e;
- Throwables.propagateIfPossible(e, IOException.class);
- Throwables.propagateIfPossible(e, declaredType1, declaredType2);
- throw Throwables.propagate(e);
- }
-
- /**
- * Closes all {@code Closeable} instances that have been added to this {@code Closer}. If an
- * exception was thrown in the try block and passed to one of the {@code exceptionThrown} methods,
- * any exceptions thrown when attempting to close a closeable will be suppressed. Otherwise, the
- * <i>first</i> exception to be thrown from an attempt to close a closeable will be thrown and any
- * additional exceptions that are thrown after that will be suppressed.
- */
- @Override
- public void close() throws IOException {
- Throwable throwable = thrown;
-
- // close closeables in LIFO order
- while (!stack.isEmpty()) {
- Closeable closeable = stack.pop();
- try {
- closeable.close();
- } catch (Throwable e) {
- if (throwable == null) {
- throwable = e;
- } else {
- suppressor.suppress(closeable, throwable, e);
- }
- }
- }
-
- if (thrown == null && throwable != null) {
- Throwables.propagateIfPossible(throwable, IOException.class);
- throw new AssertionError(throwable); // not possible
- }
- }
-
- /**
- * Suppression strategy interface.
- */
- @VisibleForTesting interface Suppressor {
- /**
- * Suppresses the given exception ({@code suppressed}) which was thrown when attempting to close
- * the given closeable. {@code thrown} is the exception that is actually being thrown from the
- * method. Implementations of this method should not throw under any circumstances.
- */
- void suppress(Closeable closeable, Throwable thrown, Throwable suppressed);
- }
-
- /**
- * Suppresses exceptions by logging them.
- */
- @VisibleForTesting static final class LoggingSuppressor implements Suppressor {
-
- static final LoggingSuppressor INSTANCE = new LoggingSuppressor();
-
- @Override
- public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) {
- // log to the same place as Closeables
- Closeables.logger.log(Level.WARNING,
- "Suppressing exception thrown when closing " + closeable, suppressed);
- }
- }
-
- /**
- * Suppresses exceptions by adding them to the exception that will be thrown using JDK7's
- * addSuppressed(Throwable) mechanism.
- */
- @VisibleForTesting static final class SuppressingSuppressor implements Suppressor {
-
- static final SuppressingSuppressor INSTANCE = new SuppressingSuppressor();
-
- static boolean isAvailable() {
- return addSuppressed != null;
- }
-
- static final Method addSuppressed = getAddSuppressed();
-
- private static Method getAddSuppressed() {
- try {
- return Throwable.class.getMethod("addSuppressed", Throwable.class);
- } catch (Throwable e) {
- return null;
- }
- }
-
- @Override
- public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) {
- // ensure no exceptions from addSuppressed
- if (thrown == suppressed) {
- return;
- }
- try {
- addSuppressed.invoke(thrown, suppressed);
- } catch (Throwable e) {
- // if, somehow, IllegalAccessException or another exception is thrown, fall back to logging
- LoggingSuppressor.INSTANCE.suppress(closeable, thrown, suppressed);
- }
- }
- }
-}
diff --git a/guava/src/com/google/common/io/CountingInputStream.java b/guava/src/com/google/common/io/CountingInputStream.java
index 573099a..d11c8ec 100644
--- a/guava/src/com/google/common/io/CountingInputStream.java
+++ b/guava/src/com/google/common/io/CountingInputStream.java
@@ -22,8 +22,6 @@ import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
-import javax.annotation.Nullable;
-
/**
* An {@link InputStream} that counts the number of bytes read.
*
@@ -41,7 +39,7 @@ public final class CountingInputStream extends FilterInputStream {
*
* @param in the input stream to be wrapped
*/
- public CountingInputStream(@Nullable InputStream in) {
+ public CountingInputStream(InputStream in) {
super(in);
}
diff --git a/guava/src/com/google/common/io/CountingOutputStream.java b/guava/src/com/google/common/io/CountingOutputStream.java
index 4013f9c..5f57714 100644
--- a/guava/src/com/google/common/io/CountingOutputStream.java
+++ b/guava/src/com/google/common/io/CountingOutputStream.java
@@ -22,8 +22,6 @@ import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
-import javax.annotation.Nullable;
-
/**
* An OutputStream that counts the number of bytes written.
*
@@ -40,7 +38,7 @@ public final class CountingOutputStream extends FilterOutputStream {
*
* @param out the output stream to be wrapped
*/
- public CountingOutputStream(@Nullable OutputStream out) {
+ public CountingOutputStream(OutputStream out) {
super(out);
}
diff --git a/guava/src/com/google/common/io/FileWriteMode.java b/guava/src/com/google/common/io/FileWriteMode.java
deleted file mode 100644
index d246740..0000000
--- a/guava/src/com/google/common/io/FileWriteMode.java
+++ /dev/null
@@ -1,28 +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.io;
-
-/**
- * Modes for opening a file for writing. The default when mode when none is specified is to
- * truncate the file before writing.
- *
- * @author Colin Decker
- */
-public enum FileWriteMode {
- /** Specifies that writes to the opened file should append to the end of the file. */
- APPEND
-}
diff --git a/guava/src/com/google/common/io/Files.java b/guava/src/com/google/common/io/Files.java
index c3dd506..1d3ce1a 100644
--- a/guava/src/com/google/common/io/Files.java
+++ b/guava/src/com/google/common/io/Files.java
@@ -16,21 +16,15 @@
package com.google.common.io;
-import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.io.FileWriteMode.APPEND;
import com.google.common.annotations.Beta;
-import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.hash.HashCode;
-import com.google.common.hash.HashFunction;
import java.io.BufferedReader;
import java.io.BufferedWriter;
-import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
@@ -46,8 +40,8 @@ import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.Charset;
+import java.security.MessageDigest;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.zip.Checksum;
@@ -57,7 +51,6 @@ import java.util.zip.Checksum;
* <p>All method parameters must be non-null unless documented otherwise.
*
* @author Chris Nokleberg
- * @author Colin Decker
* @since 1.0
*/
@Beta
@@ -73,14 +66,11 @@ public final class Files {
* character set.
*
* @param file the file to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @return the buffered reader
*/
public static BufferedReader newReader(File file, Charset charset)
throws FileNotFoundException {
- checkNotNull(file);
- checkNotNull(charset);
return new BufferedReader(
new InputStreamReader(new FileInputStream(file), charset));
}
@@ -90,171 +80,16 @@ public final class Files {
* character set.
*
* @param file the file to write to
- * @param charset the charset used to encode the output stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @return the buffered writer
*/
public static BufferedWriter newWriter(File file, Charset charset)
throws FileNotFoundException {
- checkNotNull(file);
- checkNotNull(charset);
return new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(file), charset));
}
/**
- * Returns a new {@link ByteSource} for reading bytes from the given file.
- *
- * @since 14.0
- */
- public static ByteSource asByteSource(File file) {
- return new FileByteSource(file);
- }
-
- private static final class FileByteSource extends ByteSource {
-
- private final File file;
-
- private FileByteSource(File file) {
- this.file = checkNotNull(file);
- }
-
- @Override
- public FileInputStream openStream() throws IOException {
- return new FileInputStream(file);
- }
-
- @Override
- public long size() throws IOException {
- if (!file.isFile()) {
- throw new FileNotFoundException(file.toString());
- }
- return file.length();
- }
-
- @Override
- public byte[] read() throws IOException {
- long size = file.length();
- // some special files may return size 0 but have content
- // read normally to be sure
- if (size == 0) {
- return super.read();
- }
-
- // can't initialize a large enough array
- // technically, this could probably be Integer.MAX_VALUE - 5
- if (size > Integer.MAX_VALUE) {
- // OOME is what would be thrown if we tried to initialize the array
- throw new OutOfMemoryError("file is too large to fit in a byte array: "
- + size + " bytes");
- }
-
- // initialize the array to the current size of the file
- byte[] bytes = new byte[(int) size];
-
- Closer closer = Closer.create();
- try {
- InputStream in = closer.register(openStream());
- int off = 0;
- int read = 0;
-
- // read until we've read size bytes or reached EOF
- while (off < size
- && ((read = in.read(bytes, off, (int) size - off)) != -1)) {
- off += read;
- }
-
- byte[] result = bytes;
-
- if (off < size) {
- // encountered EOF early; truncate the result
- result = Arrays.copyOf(bytes, off);
- } else if (read != -1) {
- // we read size bytes... if the last read didn't return -1, the file got larger
- // so we just read the rest normally and then create a new array
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ByteStreams.copy(in, out);
- byte[] moreBytes = out.toByteArray();
- result = new byte[bytes.length + moreBytes.length];
- System.arraycopy(bytes, 0, result, 0, bytes.length);
- System.arraycopy(moreBytes, 0, result, bytes.length, moreBytes.length);
- }
- // normally, off should == size and read should == -1
- // in that case, the array is just returned as is
- return result;
- } catch (Throwable e) {
- throw closer.rethrow(e);
- } finally {
- closer.close();
- }
- }
-
- @Override
- public String toString() {
- return "Files.asByteSource(" + file + ")";
- }
- }
-
- /**
- * Returns a new {@link ByteSink} for writing bytes to the given file. The
- * given {@code modes} control how the file is opened for writing. When no
- * mode is provided, the file will be truncated before writing. When the
- * {@link FileWriteMode#APPEND APPEND} mode is provided, writes will
- * append to the end of the file without truncating it.
- *
- * @since 14.0
- */
- public static ByteSink asByteSink(File file, FileWriteMode... modes) {
- return new FileByteSink(file, modes);
- }
-
- private static final class FileByteSink extends ByteSink {
-
- private final File file;
- private final ImmutableSet<FileWriteMode> modes;
-
- private FileByteSink(File file, FileWriteMode... modes) {
- this.file = checkNotNull(file);
- this.modes = ImmutableSet.copyOf(modes);
- }
-
- @Override
- public FileOutputStream openStream() throws IOException {
- return new FileOutputStream(file, modes.contains(APPEND));
- }
-
- @Override
- public String toString() {
- return "Files.asByteSink(" + file + ", " + modes + ")";
- }
- }
-
- /**
- * Returns a new {@link CharSource} for reading character data from the given
- * file using the given character set.
- *
- * @since 14.0
- */
- public static CharSource asCharSource(File file, Charset charset) {
- return asByteSource(file).asCharSource(charset);
- }
-
- /**
- * Returns a new {@link CharSink} for writing character data to the given
- * file using the given character set. The given {@code modes} control how
- * the file is opened for writing. When no mode is provided, the file
- * will be truncated before writing. When the
- * {@link FileWriteMode#APPEND APPEND} mode is provided, writes will
- * append to the end of the file without truncating it.
- *
- * @since 14.0
- */
- public static CharSink asCharSink(File file, Charset charset,
- FileWriteMode... modes) {
- return asByteSink(file, modes).asCharSink(charset);
- }
-
- /**
* Returns a factory that will supply instances of {@link FileInputStream}
* that read from a file.
*
@@ -263,7 +98,13 @@ public final class Files {
*/
public static InputSupplier<FileInputStream> newInputStreamSupplier(
final File file) {
- return ByteStreams.asInputSupplier(asByteSource(file));
+ Preconditions.checkNotNull(file);
+ return new InputSupplier<FileInputStream>() {
+ @Override
+ public FileInputStream getInput() throws IOException {
+ return new FileInputStream(file);
+ }
+ };
}
/**
@@ -289,13 +130,13 @@ public final class Files {
*/
public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
final File file, final boolean append) {
- return ByteStreams.asOutputSupplier(asByteSink(file, modes(append)));
- }
-
- private static FileWriteMode[] modes(boolean append) {
- return append
- ? new FileWriteMode[]{ FileWriteMode.APPEND }
- : new FileWriteMode[0];
+ Preconditions.checkNotNull(file);
+ return new OutputSupplier<FileOutputStream>() {
+ @Override
+ public FileOutputStream getOutput() throws IOException {
+ return new FileOutputStream(file, append);
+ }
+ };
}
/**
@@ -303,13 +144,12 @@ public final class Files {
* {@link InputStreamReader} that read a file using the given character set.
*
* @param file the file to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when reading the file
* @return the factory
*/
public static InputSupplier<InputStreamReader> newReaderSupplier(File file,
Charset charset) {
- return CharStreams.asInputSupplier(asCharSource(file, charset));
+ return CharStreams.newReaderSupplier(newInputStreamSupplier(file), charset);
}
/**
@@ -317,8 +157,7 @@ public final class Files {
* that write to a file using the given character set.
*
* @param file the file to write to
- * @param charset the charset used to encode the output stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @return the factory
*/
public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
@@ -331,15 +170,15 @@ public final class Files {
* that write to or append to a file using the given character set.
*
* @param file the file to write to
- * @param charset the charset used to encode the output stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @param append if true, the encoded characters will be appended to the file;
* otherwise the file is overwritten
* @return the factory
*/
public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
Charset charset, boolean append) {
- return CharStreams.asOutputSupplier(asCharSink(file, charset, modes(append)));
+ return CharStreams.newWriterSupplier(newOutputStreamSupplier(file, append),
+ charset);
}
/**
@@ -352,7 +191,23 @@ public final class Files {
* @throws IOException if an I/O error occurs
*/
public static byte[] toByteArray(File file) throws IOException {
- return asByteSource(file).read();
+ Preconditions.checkArgument(file.length() <= Integer.MAX_VALUE);
+ if (file.length() == 0) {
+ // Some special files are length 0 but have content nonetheless.
+ return ByteStreams.toByteArray(newInputStreamSupplier(file));
+ } else {
+ // Avoid an extra allocation and copy.
+ byte[] b = new byte[(int) file.length()];
+ boolean threw = true;
+ InputStream in = new FileInputStream(file);
+ try {
+ ByteStreams.readFully(in, b);
+ threw = false;
+ } finally {
+ Closeables.close(in, threw);
+ }
+ return b;
+ }
}
/**
@@ -360,13 +215,12 @@ public final class Files {
* character set.
*
* @param file the file to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when reading the file
* @return a string containing all the characters from the file
* @throws IOException if an I/O error occurs
*/
public static String toString(File file, Charset charset) throws IOException {
- return asCharSource(file, charset).read();
+ return new String(toByteArray(file), charset.name());
}
/**
@@ -379,7 +233,7 @@ public final class Files {
*/
public static void copy(InputSupplier<? extends InputStream> from, File to)
throws IOException {
- ByteStreams.asByteSource(from).copyTo(asByteSink(to));
+ ByteStreams.copy(from, newOutputStreamSupplier(to));
}
/**
@@ -390,7 +244,7 @@ public final class Files {
* @throws IOException if an I/O error occurs
*/
public static void write(byte[] from, File to) throws IOException {
- asByteSink(to).write(from);
+ ByteStreams.write(from, newOutputStreamSupplier(to));
}
/**
@@ -403,7 +257,7 @@ public final class Files {
*/
public static void copy(File from, OutputSupplier<? extends OutputStream> to)
throws IOException {
- asByteSource(from).copyTo(ByteStreams.asByteSink(to));
+ ByteStreams.copy(newInputStreamSupplier(from), to);
}
/**
@@ -414,26 +268,21 @@ public final class Files {
* @throws IOException if an I/O error occurs
*/
public static void copy(File from, OutputStream to) throws IOException {
- asByteSource(from).copyTo(to);
+ ByteStreams.copy(newInputStreamSupplier(from), to);
}
/**
* Copies all the bytes from one file to another.
- *
- * <p><b>Warning:</b> If {@code to} represents an existing file, that file
- * will be overwritten with the contents of {@code from}. If {@code to} and
- * {@code from} refer to the <i>same</i> file, the contents of that file
- * will be deleted.
- *
+ *.
* @param from the source file
* @param to the destination file
* @throws IOException if an I/O error occurs
* @throws IllegalArgumentException if {@code from.equals(to)}
*/
public static void copy(File from, File to) throws IOException {
- checkArgument(!from.equals(to),
+ Preconditions.checkArgument(!from.equals(to),
"Source %s and destination %s must be different", from, to);
- asByteSource(from).copyTo(asByteSink(to));
+ copy(newInputStreamSupplier(from), to);
}
/**
@@ -443,13 +292,12 @@ public final class Files {
*
* @param from the readable supplier
* @param to the destination file
- * @param charset the charset used to encode the output stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @throws IOException if an I/O error occurs
*/
public static <R extends Readable & Closeable> void copy(
InputSupplier<R> from, File to, Charset charset) throws IOException {
- CharStreams.asCharSource(from).copyTo(asCharSink(to, charset));
+ CharStreams.copy(from, newWriterSupplier(to, charset));
}
/**
@@ -458,13 +306,12 @@ public final class Files {
*
* @param from the character sequence to write
* @param to the destination file
- * @param charset the charset used to encode the output stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @throws IOException if an I/O error occurs
*/
public static void write(CharSequence from, File to, Charset charset)
throws IOException {
- asCharSink(to, charset).write(from);
+ write(from, to, charset, false);
}
/**
@@ -473,8 +320,7 @@ public final class Files {
*
* @param from the character sequence to append
* @param to the destination file
- * @param charset the charset used to encode the output stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @throws IOException if an I/O error occurs
*/
public static void append(CharSequence from, File to, Charset charset)
@@ -488,14 +334,13 @@ public final class Files {
*
* @param from the character sequence to append
* @param to the destination file
- * @param charset the charset used to encode the output stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @param append true to append, false to overwrite
* @throws IOException if an I/O error occurs
*/
private static void write(CharSequence from, File to, Charset charset,
boolean append) throws IOException {
- asCharSink(to, charset, modes(append)).write(from);
+ CharStreams.write(from, newWriterSupplier(to, charset, append));
}
/**
@@ -504,14 +349,13 @@ public final class Files {
* character set.
*
* @param from the source file
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when reading the file
* @param to the appendable supplier
* @throws IOException if an I/O error occurs
*/
public static <W extends Appendable & Closeable> void copy(File from,
Charset charset, OutputSupplier<W> to) throws IOException {
- asCharSource(from, charset).copyTo(CharStreams.asCharSink(to));
+ CharStreams.copy(newReaderSupplier(from, charset), to);
}
/**
@@ -519,14 +363,13 @@ public final class Files {
* using the given character set.
*
* @param from the source file
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when reading the file
* @param to the appendable object
* @throws IOException if an I/O error occurs
*/
public static void copy(File from, Charset charset, Appendable to)
throws IOException {
- asCharSource(from, charset).copyTo(to);
+ CharStreams.copy(newReaderSupplier(from, charset), to);
}
/**
@@ -535,8 +378,6 @@ public final class Files {
* @throws IOException if an I/O error occurs
*/
public static boolean equal(File file1, File file2) throws IOException {
- checkNotNull(file1);
- checkNotNull(file2);
if (file1 == file2 || file1.equals(file2)) {
return true;
}
@@ -551,7 +392,8 @@ public final class Files {
if (len1 != 0 && len2 != 0 && len1 != len2) {
return false;
}
- return asByteSource(file1).contentEquals(asByteSource(file2));
+ return ByteStreams.equal(newInputStreamSupplier(file1),
+ newInputStreamSupplier(file2));
}
/**
@@ -596,7 +438,6 @@ public final class Files {
* @throws IOException if an I/O error occurs
*/
public static void touch(File file) throws IOException {
- checkNotNull(file);
if (!file.createNewFile()
&& !file.setLastModified(System.currentTimeMillis())) {
throw new IOException("Unable to update modification time of " + file);
@@ -614,7 +455,6 @@ public final class Files {
* @since 4.0
*/
public static void createParentDirs(File file) throws IOException {
- checkNotNull(file);
File parent = file.getCanonicalFile().getParentFile();
if (parent == null) {
/*
@@ -642,9 +482,8 @@ public final class Files {
* @throws IllegalArgumentException if {@code from.equals(to)}
*/
public static void move(File from, File to) throws IOException {
- checkNotNull(from);
- checkNotNull(to);
- checkArgument(!from.equals(to),
+ Preconditions.checkNotNull(to);
+ Preconditions.checkArgument(!from.equals(to),
"Source %s and destination %s must be different", from, to);
if (!from.renameTo(to)) {
@@ -664,14 +503,13 @@ public final class Files {
* trailing whitespace.
*
* @param file the file to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @return the first line, or null if the file is empty
* @throws IOException if an I/O error occurs
*/
public static String readFirstLine(File file, Charset charset)
throws IOException {
- return asCharSource(file, charset).readFirstLine();
+ return CharStreams.readFirstLine(Files.newReaderSupplier(file, charset));
}
/**
@@ -680,8 +518,7 @@ public final class Files {
* trailing whitespace.
*
* @param file the file to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @return a mutable {@link List} containing all the lines
* @throws IOException if an I/O error occurs
*/
@@ -695,15 +532,15 @@ public final class Files {
* false, or we have read all of the lines.
*
* @param file the file to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @param callback the {@link LineProcessor} to use to handle the lines
* @return the output of processing the lines
* @throws IOException if an I/O error occurs
*/
public static <T> T readLines(File file, Charset charset,
LineProcessor<T> callback) throws IOException {
- return CharStreams.readLines(newReaderSupplier(file, charset), callback);
+ return CharStreams.readLines(Files.newReaderSupplier(file, charset),
+ callback);
}
/**
@@ -731,28 +568,25 @@ public final class Files {
* @return the result of {@link Checksum#getValue} after updating the
* checksum object with all of the bytes in the file
* @throws IOException if an I/O error occurs
- * @deprecated Use {@code hash} with the {@code Hashing.crc32()} or
- * {@code Hashing.adler32()} hash functions. This method is scheduled
- * to be removed in Guava 15.0.
*/
- @Deprecated
public static long getChecksum(File file, Checksum checksum)
throws IOException {
return ByteStreams.getChecksum(newInputStreamSupplier(file), checksum);
}
/**
- * Computes the hash code of the {@code file} using {@code hashFunction}.
+ * Computes and returns the digest value for a file.
+ * The digest object is reset when this method returns successfully.
*
* @param file the file to read
- * @param hashFunction the hash function to use to hash the data
- * @return the {@link HashCode} of all of the bytes in the file
+ * @param md the digest object
+ * @return the result of {@link MessageDigest#digest()} after updating the
+ * digest object with all of the bytes in this file
* @throws IOException if an I/O error occurs
- * @since 12.0
*/
- public static HashCode hash(File file, HashFunction hashFunction)
+ public static byte[] getDigest(File file, MessageDigest md)
throws IOException {
- return asByteSource(file).hash(hashFunction);
+ return ByteStreams.getDigest(newInputStreamSupplier(file), md);
}
/**
@@ -772,7 +606,6 @@ public final class Files {
* @since 2.0
*/
public static MappedByteBuffer map(File file) throws IOException {
- checkNotNull(file);
return map(file, MapMode.READ_ONLY);
}
@@ -796,8 +629,6 @@ public final class Files {
*/
public static MappedByteBuffer map(File file, MapMode mode)
throws IOException {
- checkNotNull(file);
- checkNotNull(mode);
if (!file.exists()) {
throw new FileNotFoundException(file.toString());
}
@@ -827,31 +658,30 @@ public final class Files {
*/
public static MappedByteBuffer map(File file, MapMode mode, long size)
throws FileNotFoundException, IOException {
- checkNotNull(file);
- checkNotNull(mode);
+ RandomAccessFile raf =
+ new RandomAccessFile(file, mode == MapMode.READ_ONLY ? "r" : "rw");
- Closer closer = Closer.create();
+ boolean threw = true;
try {
- RandomAccessFile raf = closer.register(
- new RandomAccessFile(file, mode == MapMode.READ_ONLY ? "r" : "rw"));
- return map(raf, mode, size);
- } catch (Throwable e) {
- throw closer.rethrow(e);
+ MappedByteBuffer mbb = map(raf, mode, size);
+ threw = false;
+ return mbb;
} finally {
- closer.close();
+ Closeables.close(raf, threw);
}
}
private static MappedByteBuffer map(RandomAccessFile raf, MapMode mode,
long size) throws IOException {
- Closer closer = Closer.create();
+ FileChannel channel = raf.getChannel();
+
+ boolean threw = true;
try {
- FileChannel channel = closer.register(raf.getChannel());
- return channel.map(mode, 0, size);
- } catch (Throwable e) {
- throw closer.rethrow(e);
+ MappedByteBuffer mbb = channel.map(mode, 0, size);
+ threw = false;
+ return mbb;
} finally {
- closer.close();
+ Closeables.close(channel, threw);
}
}
@@ -877,7 +707,6 @@ public final class Files {
* @since 11.0
*/
public static String simplifyPath(String pathname) {
- checkNotNull(pathname);
if (pathname.length() == 0) {
return ".";
}
@@ -927,27 +756,9 @@ public final class Files {
*
* @since 11.0
*/
- public static String getFileExtension(String fullName) {
- checkNotNull(fullName);
- String fileName = new File(fullName).getName();
+ public static String getFileExtension(String fileName) {
+ checkNotNull(fileName);
int dotIndex = fileName.lastIndexOf('.');
return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
}
-
- /**
- * Returns the file name without its
- * <a href="http://en.wikipedia.org/wiki/Filename_extension">file extension</a> or path. This is
- * similar to the {@code basename} unix command. The result does not include the '{@code .}'.
- *
- * @param file The name of the file to trim the extension from. This can be either a fully
- * qualified file name (including a path) or just a file name.
- * @return The file name without its path or extension.
- * @since 14.0
- */
- public static String getNameWithoutExtension(String file) {
- checkNotNull(file);
- String fileName = new File(file).getName();
- int dotIndex = fileName.lastIndexOf('.');
- return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
- }
}
diff --git a/guava/src/com/google/common/io/GwtWorkarounds.java b/guava/src/com/google/common/io/GwtWorkarounds.java
deleted file mode 100644
index 285df59..0000000
--- a/guava/src/com/google/common/io/GwtWorkarounds.java
+++ /dev/null
@@ -1,231 +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.io;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndexes;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-
-/**
- * Provides simple GWT-compatible substitutes for {@code InputStream}, {@code OutputStream},
- * {@code Reader}, and {@code Writer} so that {@code BaseEncoding} can use streaming implementations
- * while remaining GWT-compatible.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-final class GwtWorkarounds {
- private GwtWorkarounds() {}
-
- /**
- * A GWT-compatible substitute for a {@code Reader}.
- */
- interface CharInput {
- int read() throws IOException;
- void close() throws IOException;
- }
-
- /**
- * Views a {@code Reader} as a {@code CharInput}.
- */
- @GwtIncompatible("Reader")
- static CharInput asCharInput(final Reader reader) {
- checkNotNull(reader);
- return new CharInput() {
- @Override
- public int read() throws IOException {
- return reader.read();
- }
-
- @Override
- public void close() throws IOException {
- reader.close();
- }
- };
- }
-
- /**
- * Views a {@code CharSequence} as a {@code CharInput}.
- */
- static CharInput asCharInput(final CharSequence chars) {
- checkNotNull(chars);
- return new CharInput() {
- int index = 0;
-
- @Override
- public int read() {
- if (index < chars.length()) {
- return chars.charAt(index++);
- } else {
- return -1;
- }
- }
-
- @Override
- public void close() {
- index = chars.length();
- }
- };
- }
-
- /**
- * A GWT-compatible substitute for an {@code InputStream}.
- */
- interface ByteInput {
- int read() throws IOException;
- void close() throws IOException;
- }
-
- /**
- * Views a {@code ByteInput} as an {@code InputStream}.
- */
- @GwtIncompatible("InputStream")
- static InputStream asInputStream(final ByteInput input) {
- checkNotNull(input);
- return new InputStream() {
- @Override
- public int read() throws IOException {
- return input.read();
- }
-
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- checkNotNull(b);
- checkPositionIndexes(off, off + len, b.length);
- if (len == 0) {
- return 0;
- }
- int firstByte = read();
- if (firstByte == -1) {
- return -1;
- }
- b[off] = (byte) firstByte;
- for (int dst = 1; dst < len; dst++) {
- int readByte = read();
- if (readByte == -1) {
- return dst;
- }
- b[off + dst] = (byte) readByte;
- }
- return len;
- }
-
- @Override
- public void close() throws IOException {
- input.close();
- }
- };
- }
-
- /**
- * A GWT-compatible substitute for an {@code OutputStream}.
- */
- interface ByteOutput {
- void write(byte b) throws IOException;
- void flush() throws IOException;
- void close() throws IOException;
- }
-
- /**
- * Views a {@code ByteOutput} as an {@code OutputStream}.
- */
- @GwtIncompatible("OutputStream")
- static OutputStream asOutputStream(final ByteOutput output) {
- checkNotNull(output);
- return new OutputStream() {
- @Override
- public void write(int b) throws IOException {
- output.write((byte) b);
- }
-
- @Override
- public void flush() throws IOException {
- output.flush();
- }
-
- @Override
- public void close() throws IOException {
- output.close();
- }
- };
- }
-
- /**
- * A GWT-compatible substitute for a {@code Writer}.
- */
- interface CharOutput {
- void write(char c) throws IOException;
- void flush() throws IOException;
- void close() throws IOException;
- }
-
- /**
- * Views a {@code Writer} as a {@code CharOutput}.
- */
- @GwtIncompatible("Writer")
- static CharOutput asCharOutput(final Writer writer) {
- checkNotNull(writer);
- return new CharOutput() {
- @Override
- public void write(char c) throws IOException {
- writer.append(c);
- }
-
- @Override
- public void flush() throws IOException {
- writer.flush();
- }
-
- @Override
- public void close() throws IOException {
- writer.close();
- }
- };
- }
-
- /**
- * Returns a {@code CharOutput} whose {@code toString()} method can be used
- * to get the combined output.
- */
- static CharOutput stringBuilderOutput(int initialSize) {
- final StringBuilder builder = new StringBuilder(initialSize);
- return new CharOutput() {
-
- @Override
- public void write(char c) {
- builder.append(c);
- }
-
- @Override
- public void flush() {}
-
- @Override
- public void close() {}
-
- @Override
- public String toString() {
- return builder.toString();
- }
- };
- }
-}
diff --git a/guava/src/com/google/common/io/LimitInputStream.java b/guava/src/com/google/common/io/LimitInputStream.java
index c8bd6cf..e9d963d 100644
--- a/guava/src/com/google/common/io/LimitInputStream.java
+++ b/guava/src/com/google/common/io/LimitInputStream.java
@@ -28,11 +28,8 @@ import java.io.InputStream;
*
* @author Charles Fry
* @since 1.0
- * @deprecated Use {@link ByteStreams#limit} instead. This class is scheduled
- * to be removed in Guava release 15.0.
*/
@Beta
-@Deprecated
public final class LimitInputStream extends FilterInputStream {
private long left;
diff --git a/guava/src/com/google/common/io/LineBuffer.java b/guava/src/com/google/common/io/LineBuffer.java
index 119516b..1f1c8dc 100644
--- a/guava/src/com/google/common/io/LineBuffer.java
+++ b/guava/src/com/google/common/io/LineBuffer.java
@@ -75,9 +75,6 @@ abstract class LineBuffer {
finishLine(true);
start = pos + 1;
break;
-
- default:
- // do nothing
}
}
line.append(cbuf, start, off + len - start);
diff --git a/guava/src/com/google/common/io/MultiInputStream.java b/guava/src/com/google/common/io/MultiInputStream.java
index 1902baf..f8f1a0b 100644
--- a/guava/src/com/google/common/io/MultiInputStream.java
+++ b/guava/src/com/google/common/io/MultiInputStream.java
@@ -16,14 +16,10 @@
package com.google.common.io;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
-import javax.annotation.Nullable;
-
/**
* An {@link InputStream} that concatenates multiple substreams. At most
* one stream will be open at a time.
@@ -44,7 +40,7 @@ final class MultiInputStream extends InputStream {
public MultiInputStream(
Iterator<? extends InputSupplier<? extends InputStream>> it)
throws IOException {
- this.it = checkNotNull(it);
+ this.it = it;
advance();
}
@@ -91,7 +87,7 @@ final class MultiInputStream extends InputStream {
return result;
}
- @Override public int read(@Nullable byte[] b, int off, int len) throws IOException {
+ @Override public int read(byte[] b, int off, int len) throws IOException {
if (in == null) {
return -1;
}
diff --git a/guava/src/com/google/common/io/MultiReader.java b/guava/src/com/google/common/io/MultiReader.java
index fc0e7fb..6757a26 100644
--- a/guava/src/com/google/common/io/MultiReader.java
+++ b/guava/src/com/google/common/io/MultiReader.java
@@ -22,8 +22,6 @@ import java.io.IOException;
import java.io.Reader;
import java.util.Iterator;
-import javax.annotation.Nullable;
-
/**
* A {@link Reader} that concatenates multiple readers.
*
@@ -50,7 +48,7 @@ class MultiReader extends Reader {
}
}
- @Override public int read(@Nullable char cbuf[], int off, int len) throws IOException {
+ @Override public int read(char cbuf[], int off, int len) throws IOException {
if (current == null) {
return -1;
}
diff --git a/guava/src/com/google/common/io/NullOutputStream.java b/guava/src/com/google/common/io/NullOutputStream.java
index d1dda67..1c1e98e 100644
--- a/guava/src/com/google/common/io/NullOutputStream.java
+++ b/guava/src/com/google/common/io/NullOutputStream.java
@@ -16,8 +16,6 @@
package com.google.common.io;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.Beta;
import java.io.OutputStream;
@@ -27,11 +25,8 @@ import java.io.OutputStream;
*
* @author Spencer Kimball
* @since 1.0
- * @deprecated Use {@link ByteStreams#nullOutputStream} instead. This class is
- * scheduled to be removed in Guava release 15.0.
*/
@Beta
-@Deprecated
public final class NullOutputStream extends OutputStream {
/** Discards the specified byte. */
@Override public void write(int b) {
@@ -39,6 +34,5 @@ public final class NullOutputStream extends OutputStream {
/** Discards the specified byte array. */
@Override public void write(byte[] b, int off, int len) {
- checkNotNull(b);
}
}
diff --git a/guava/src/com/google/common/io/PatternFilenameFilter.java b/guava/src/com/google/common/io/PatternFilenameFilter.java
index 2859277..065566f 100644
--- a/guava/src/com/google/common/io/PatternFilenameFilter.java
+++ b/guava/src/com/google/common/io/PatternFilenameFilter.java
@@ -27,8 +27,8 @@ import java.util.regex.PatternSyntaxException;
import javax.annotation.Nullable;
/**
- * File name filter that only accepts files matching a regular expression. This
- * class is thread-safe and immutable.
+ * File name filter that only accepts files matching a regular expression. This class is thread-safe
+ * and immutable.
*
* @author Apple Chow
* @since 1.0
diff --git a/guava/src/com/google/common/io/Resources.java b/guava/src/com/google/common/io/Resources.java
index 3d81491..c57a95f 100644
--- a/guava/src/com/google/common/io/Resources.java
+++ b/guava/src/com/google/common/io/Resources.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.Beta;
-import com.google.common.base.Charsets;
import java.io.IOException;
import java.io.InputStream;
@@ -39,7 +38,6 @@ import java.util.List;
*
* @author Chris Nokleberg
* @author Ben Yu
- * @author Colin Decker
* @since 1.0
*/
@Beta
@@ -53,39 +51,15 @@ public final class Resources {
* @param url the URL to read from
* @return the factory
*/
- public static InputSupplier<InputStream> newInputStreamSupplier(URL url) {
- return ByteStreams.asInputSupplier(asByteSource(url));
- }
-
- /**
- * Returns a {@link ByteSource} that reads from the given URL.
- *
- * @since 14.0
- */
- public static ByteSource asByteSource(URL url) {
- return new UrlByteSource(url);
- }
-
- /**
- * A byte source that reads from a URL using {@link URL#openStream()}.
- */
- private static final class UrlByteSource extends ByteSource {
-
- private final URL url;
-
- private UrlByteSource(URL url) {
- this.url = checkNotNull(url);
- }
-
- @Override
- public InputStream openStream() throws IOException {
- return url.openStream();
- }
-
- @Override
- public String toString() {
- return "Resources.newByteSource(" + url + ")";
- }
+ public static InputSupplier<InputStream> newInputStreamSupplier(
+ final URL url) {
+ checkNotNull(url);
+ return new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return url.openStream();
+ }
+ };
}
/**
@@ -93,22 +67,12 @@ public final class Resources {
* {@link InputStreamReader} that read a URL using the given character set.
*
* @param url the URL to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when reading the URL contents
* @return the factory
*/
public static InputSupplier<InputStreamReader> newReaderSupplier(
URL url, Charset charset) {
- return CharStreams.asInputSupplier(asCharSource(url, charset));
- }
-
- /**
- * Returns a {@link CharSource} that reads from the given URL using the given character set.
- *
- * @since 14.0
- */
- public static CharSource asCharSource(URL url, Charset charset) {
- return asByteSource(url).asCharSource(charset);
+ return CharStreams.newReaderSupplier(newInputStreamSupplier(url), charset);
}
/**
@@ -119,7 +83,7 @@ public final class Resources {
* @throws IOException if an I/O error occurs
*/
public static byte[] toByteArray(URL url) throws IOException {
- return asByteSource(url).read();
+ return ByteStreams.toByteArray(newInputStreamSupplier(url));
}
/**
@@ -127,13 +91,12 @@ public final class Resources {
* character set.
*
* @param url the URL to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when reading the URL
* @return a string containing all the characters from the URL
* @throws IOException if an I/O error occurs.
*/
public static String toString(URL url, Charset charset) throws IOException {
- return asCharSource(url, charset).read();
+ return CharStreams.toString(newReaderSupplier(url, charset));
}
/**
@@ -141,8 +104,7 @@ public final class Resources {
* have read all of the lines.
*
* @param url the URL to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when reading the URL
* @param callback the LineProcessor to use to handle the lines
* @return the output of processing the lines
* @throws IOException if an I/O error occurs
@@ -158,8 +120,7 @@ public final class Resources {
* whitespace.
*
* @param url the URL to read from
- * @param charset the charset used to decode the input stream; see {@link
- * Charsets} for helpful predefined constants
+ * @param charset the character set used when writing the file
* @return a mutable {@link List} containing all the lines
* @throws IOException if an I/O error occurs
*/
@@ -176,7 +137,7 @@ public final class Resources {
* @throws IOException if an I/O error occurs
*/
public static void copy(URL from, OutputStream to) throws IOException {
- asByteSource(from).copyTo(to);
+ ByteStreams.copy(newInputStreamSupplier(from), to);
}
/**
diff --git a/guava/src/com/google/common/io/package-info.java b/guava/src/com/google/common/io/package-info.java
index f5f83ad..9f08e64 100644
--- a/guava/src/com/google/common/io/package-info.java
+++ b/guava/src/com/google/common/io/package-info.java
@@ -38,4 +38,3 @@
package com.google.common.io;
import javax.annotation.ParametersAreNonnullByDefault;
-
diff --git a/guava/src/com/google/common/math/BigIntegerMath.java b/guava/src/com/google/common/math/BigIntegerMath.java
index 6b40b6b..99e69fe 100644
--- a/guava/src/com/google/common/math/BigIntegerMath.java
+++ b/guava/src/com/google/common/math/BigIntegerMath.java
@@ -25,8 +25,7 @@ import static java.math.RoundingMode.CEILING;
import static java.math.RoundingMode.FLOOR;
import static java.math.RoundingMode.HALF_EVEN;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
import java.math.BigDecimal;
@@ -47,7 +46,7 @@ import java.util.List;
* @author Louis Wasserman
* @since 11.0
*/
-@GwtCompatible(emulated = true)
+@Beta
public final class BigIntegerMath {
/**
* Returns {@code true} if {@code x} represents a power of two.
@@ -65,7 +64,6 @@ public final class BigIntegerMath {
* is not a power of two
*/
@SuppressWarnings("fallthrough")
- // TODO(kevinb): remove after this warning is disabled globally
public static int log2(BigInteger x, RoundingMode mode) {
checkPositive("x", checkNotNull(x));
int logFloor = x.bitLength() - 1;
@@ -124,7 +122,6 @@ public final class BigIntegerMath {
* @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
* is not a power of ten
*/
- @GwtIncompatible("TODO")
@SuppressWarnings("fallthrough")
public static int log10(BigInteger x, RoundingMode mode) {
checkPositive("x", x);
@@ -132,45 +129,27 @@ public final class BigIntegerMath {
return LongMath.log10(x.longValue(), mode);
}
- int approxLog10 = (int) (log2(x, FLOOR) * LN_2 / LN_10);
- BigInteger approxPow = BigInteger.TEN.pow(approxLog10);
- int approxCmp = approxPow.compareTo(x);
-
- /*
- * We adjust approxLog10 and approxPow until they're equal to floor(log10(x)) and
- * 10^floor(log10(x)).
- */
-
- if (approxCmp > 0) {
- /*
- * The code is written so that even completely incorrect approximations will still yield the
- * correct answer eventually, but in practice this branch should almost never be entered,
- * and even then the loop should not run more than once.
- */
- do {
- approxLog10--;
- approxPow = approxPow.divide(BigInteger.TEN);
- approxCmp = approxPow.compareTo(x);
- } while (approxCmp > 0);
- } else {
- BigInteger nextPow = BigInteger.TEN.multiply(approxPow);
- int nextCmp = nextPow.compareTo(x);
- while (nextCmp <= 0) {
- approxLog10++;
- approxPow = nextPow;
- approxCmp = nextCmp;
- nextPow = BigInteger.TEN.multiply(approxPow);
- nextCmp = nextPow.compareTo(x);
+ // capacity of 10 suffices for all x <= 10^(2^10).
+ List<BigInteger> powersOf10 = new ArrayList<BigInteger>(10);
+ BigInteger powerOf10 = BigInteger.TEN;
+ while (x.compareTo(powerOf10) >= 0) {
+ powersOf10.add(powerOf10);
+ powerOf10 = powerOf10.pow(2);
+ }
+ BigInteger floorPow = BigInteger.ONE;
+ int floorLog = 0;
+ for (int i = powersOf10.size() - 1; i >= 0; i--) {
+ BigInteger powOf10 = powersOf10.get(i);
+ floorLog *= 2;
+ BigInteger tenPow = powOf10.multiply(floorPow);
+ if (x.compareTo(tenPow) >= 0) {
+ floorPow = tenPow;
+ floorLog++;
}
}
-
- int floorLog = approxLog10;
- BigInteger floorPow = approxPow;
- int floorCmp = approxCmp;
-
switch (mode) {
case UNNECESSARY:
- checkRoundingUnnecessary(floorCmp == 0);
+ checkRoundingUnnecessary(floorPow.equals(x));
// fall through
case FLOOR:
case DOWN:
@@ -192,9 +171,6 @@ public final class BigIntegerMath {
}
}
- private static final double LN_10 = Math.log(10);
- private static final double LN_2 = Math.log(2);
-
/**
* Returns the square root of {@code x}, rounded with the specified rounding mode.
*
@@ -202,7 +178,6 @@ public final class BigIntegerMath {
* @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and
* {@code sqrt(x)} is not an integer
*/
- @GwtIncompatible("TODO")
@SuppressWarnings("fallthrough")
public static BigInteger sqrt(BigInteger x, RoundingMode mode) {
checkNonNegative("x", x);
@@ -234,7 +209,6 @@ public final class BigIntegerMath {
}
}
- @GwtIncompatible("TODO")
private static BigInteger sqrtFloor(BigInteger x) {
/*
* Adapted from Hacker's Delight, Figure 11-1.
@@ -257,7 +231,7 @@ public final class BigIntegerMath {
*/
BigInteger sqrt0;
int log2 = log2(x, FLOOR);
- if(log2 < Double.MAX_EXPONENT) {
+ if(log2 < DoubleUtils.MAX_DOUBLE_EXPONENT) {
sqrt0 = sqrtApproxWithDoubles(x);
} else {
int shift = (log2 - DoubleUtils.SIGNIFICAND_BITS) & ~1; // even!
@@ -278,7 +252,6 @@ public final class BigIntegerMath {
return sqrt0;
}
- @GwtIncompatible("TODO")
private static BigInteger sqrtApproxWithDoubles(BigInteger x) {
return DoubleMath.roundToBigInteger(Math.sqrt(DoubleUtils.bigToDouble(x)), HALF_EVEN);
}
@@ -290,7 +263,6 @@ public final class BigIntegerMath {
* @throws ArithmeticException if {@code q == 0}, or if {@code mode == UNNECESSARY} and {@code a}
* is not an integer multiple of {@code b}
*/
- @GwtIncompatible("TODO")
public static BigInteger divide(BigInteger p, BigInteger q, RoundingMode mode){
BigDecimal pDec = new BigDecimal(p);
BigDecimal qDec = new BigDecimal(q);
@@ -313,8 +285,8 @@ public final class BigIntegerMath {
checkNonNegative("n", n);
// If the factorial is small enough, just use LongMath to do it.
- if (n < LongMath.factorials.length) {
- return BigInteger.valueOf(LongMath.factorials[n]);
+ if (n < LongMath.FACTORIALS.length) {
+ return BigInteger.valueOf(LongMath.FACTORIALS[n]);
}
// Pre-allocate space for our list of intermediate BigIntegers.
@@ -322,8 +294,8 @@ public final class BigIntegerMath {
ArrayList<BigInteger> bignums = new ArrayList<BigInteger>(approxSize);
// Start from the pre-computed maximum long factorial.
- int startingNumber = LongMath.factorials.length;
- long product = LongMath.factorials[startingNumber - 1];
+ int startingNumber = LongMath.FACTORIALS.length;
+ long product = LongMath.FACTORIALS[startingNumber - 1];
// Strip off 2s from this value.
int shift = Long.numberOfTrailingZeros(product);
product >>= shift;
@@ -400,48 +372,18 @@ public final class BigIntegerMath {
if (k > (n >> 1)) {
k = n - k;
}
- if (k < LongMath.biggestBinomials.length && n <= LongMath.biggestBinomials[k]) {
+ if (k < LongMath.BIGGEST_BINOMIALS.length && n <= LongMath.BIGGEST_BINOMIALS[k]) {
return BigInteger.valueOf(LongMath.binomial(n, k));
}
-
- BigInteger accum = BigInteger.ONE;
-
- long numeratorAccum = n;
- long denominatorAccum = 1;
-
- int bits = LongMath.log2(n, RoundingMode.CEILING);
-
- int numeratorBits = bits;
-
- for (int i = 1; i < k; i++) {
- int p = n - i;
- int q = i + 1;
-
- // log2(p) >= bits - 1, because p >= n/2
-
- if (numeratorBits + bits >= Long.SIZE - 1) {
- // The numerator is as big as it can get without risking overflow.
- // Multiply numeratorAccum / denominatorAccum into accum.
- accum = accum
- .multiply(BigInteger.valueOf(numeratorAccum))
- .divide(BigInteger.valueOf(denominatorAccum));
- numeratorAccum = p;
- denominatorAccum = q;
- numeratorBits = bits;
- } else {
- // We can definitely multiply into the long accumulators without overflowing them.
- numeratorAccum *= p;
- denominatorAccum *= q;
- numeratorBits += bits;
- }
+ BigInteger result = BigInteger.ONE;
+ for (int i = 0; i < k; i++) {
+ result = result.multiply(BigInteger.valueOf(n - i));
+ result = result.divide(BigInteger.valueOf(i + 1));
}
- return accum
- .multiply(BigInteger.valueOf(numeratorAccum))
- .divide(BigInteger.valueOf(denominatorAccum));
+ return result;
}
// Returns true if BigInteger.valueOf(x.longValue()).equals(x).
- @GwtIncompatible("TODO")
static boolean fitsInLong(BigInteger x) {
return x.bitLength() <= Long.SIZE - 1;
}
diff --git a/guava/src/com/google/common/math/DoubleMath.java b/guava/src/com/google/common/math/DoubleMath.java
index ded38b2..35365a7 100644
--- a/guava/src/com/google/common/math/DoubleMath.java
+++ b/guava/src/com/google/common/math/DoubleMath.java
@@ -19,31 +19,29 @@ package com.google.common.math;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.math.DoubleUtils.IMPLICIT_BIT;
import static com.google.common.math.DoubleUtils.SIGNIFICAND_BITS;
+import static com.google.common.math.DoubleUtils.getExponent;
import static com.google.common.math.DoubleUtils.getSignificand;
import static com.google.common.math.DoubleUtils.isFinite;
import static com.google.common.math.DoubleUtils.isNormal;
+import static com.google.common.math.DoubleUtils.next;
import static com.google.common.math.DoubleUtils.scaleNormalize;
import static com.google.common.math.MathPreconditions.checkInRange;
import static com.google.common.math.MathPreconditions.checkNonNegative;
import static com.google.common.math.MathPreconditions.checkRoundingUnnecessary;
-import static java.lang.Math.abs;
-import static java.lang.Math.copySign;
-import static java.lang.Math.getExponent;
-import static java.lang.Math.log;
-import static java.lang.Math.rint;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.primitives.Booleans;
import java.math.BigInteger;
import java.math.RoundingMode;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.annotations.Beta;
+
/**
* A class for arithmetic on doubles that is not covered by {@link java.lang.Math}.
*
* @author Louis Wasserman
* @since 11.0
*/
+@Beta
public final class DoubleMath {
/*
* This method returns a value y such that rounding y DOWN (towards zero) gives the same result
@@ -59,55 +57,43 @@ public final class DoubleMath {
return x;
case FLOOR:
- if (x >= 0.0 || isMathematicalInteger(x)) {
- return x;
- } else {
- return x - 1.0;
- }
+ return (x >= 0.0) ? x : Math.floor(x);
case CEILING:
- if (x <= 0.0 || isMathematicalInteger(x)) {
- return x;
- } else {
- return x + 1.0;
- }
+ return (x >= 0.0) ? Math.ceil(x) : x;
case DOWN:
return x;
case UP:
- if (isMathematicalInteger(x)) {
- return x;
- } else {
- return x + Math.copySign(1.0, x);
- }
+ return (x >= 0.0) ? Math.ceil(x) : Math.floor(x);
case HALF_EVEN:
- return rint(x);
+ return Math.rint(x);
- case HALF_UP: {
- double z = rint(x);
- if (abs(x - z) == 0.5) {
- return x + copySign(0.5, x);
+ case HALF_UP:
+ if (isMathematicalInteger(x)) {
+ return x;
} else {
- return z;
+ return (x >= 0.0) ? x + 0.5 : x - 0.5;
}
- }
- case HALF_DOWN: {
- double z = rint(x);
- if (abs(x - z) == 0.5) {
+ case HALF_DOWN:
+ if (isMathematicalInteger(x)) {
return x;
+ } else if (x >= 0.0) {
+ double z = x + 0.5;
+ return (z == x) ? x : next(z, false); // x + 0.5 - epsilon
} else {
- return z;
+ double z = x - 0.5;
+ return (z == x) ? x : next(z, true); // x - 0.5 + epsilon
}
- }
default:
throw new AssertionError();
}
}
-
+
/**
* Returns the {@code int} value that is equal to {@code x} rounded with the specified rounding
* mode, if possible.
@@ -175,6 +161,9 @@ public final class DoubleMath {
return BigInteger.valueOf((long) x);
}
int exponent = getExponent(x);
+ if (exponent < 0) {
+ return BigInteger.ZERO;
+ }
long significand = getSignificand(x);
BigInteger result = BigInteger.valueOf(significand).shiftLeft(exponent - SIGNIFICAND_BITS);
return (x < 0) ? result.negate() : result;
@@ -198,16 +187,16 @@ public final class DoubleMath {
* <li>If {@code x} is positive or negative zero, the result is negative infinity.
* </ul>
*
- * <p>The computed result is within 1 ulp of the exact result.
+ * <p>The computed result must be within 1 ulp of the exact result.
*
* <p>If the result of this method will be immediately rounded to an {@code int},
* {@link #log2(double, RoundingMode)} is faster.
*/
public static double log2(double x) {
- return log(x) / LN_2; // surprisingly within 1 ulp according to tests
+ return Math.log(x) / LN_2; // surprisingly within 1 ulp according to tests
}
- private static final double LN_2 = log(2);
+ private static final double LN_2 = Math.log(2);
/**
* Returns the base 2 logarithm of a double value, rounded with the specified rounding mode to an
@@ -260,14 +249,14 @@ public final class DoubleMath {
/**
* Returns {@code true} if {@code x} represents a mathematical integer.
- *
+ *
* <p>This is equivalent to, but not necessarily implemented as, the expression {@code
* !Double.isNaN(x) && !Double.isInfinite(x) && x == Math.rint(x)}.
*/
public static boolean isMathematicalInteger(double x) {
return isFinite(x)
- && (x == 0.0 ||
- SIGNIFICAND_BITS - Long.numberOfTrailingZeros(getSignificand(x)) <= getExponent(x));
+ && (x == 0.0 || SIGNIFICAND_BITS
+ - Long.numberOfTrailingZeros(getSignificand(x)) <= getExponent(x));
}
/**
@@ -285,12 +274,12 @@ public final class DoubleMath {
return Double.POSITIVE_INFINITY;
} else {
// Multiplying the last (n & 0xf) values into their own accumulator gives a more accurate
- // result than multiplying by everySixteenthFactorial[n >> 4] directly.
+ // result than multiplying by EVERY_SIXTEENTH_FACTORIAL[n >> 4] directly.
double accum = 1.0;
for (int i = 1 + (n & ~0xf); i <= n; i++) {
accum *= i;
}
- return accum * everySixteenthFactorial[n >> 4];
+ return accum * EVERY_SIXTEENTH_FACTORIAL[n >> 4];
}
}
@@ -298,7 +287,7 @@ public final class DoubleMath {
static final int MAX_FACTORIAL = 170;
@VisibleForTesting
- static final double[] everySixteenthFactorial = {
+ static final double[] EVERY_SIXTEENTH_FACTORIAL = {
0x1.0p0,
0x1.30777758p44,
0x1.956ad0aae33a4p117,
@@ -310,66 +299,4 @@ public final class DoubleMath {
0x1.1e5dfc140e1e5p716,
0x1.8ce85fadb707ep829,
0x1.95d5f3d928edep945};
-
- /**
- * Returns {@code true} if {@code a} and {@code b} are within {@code tolerance} of each other.
- *
- * <p>Technically speaking, this is equivalent to
- * {@code Math.abs(a - b) <= tolerance || Double.valueOf(a).equals(Double.valueOf(b))}.
- *
- * <p>Notable special cases include:
- * <ul>
- * <li>All NaNs are fuzzily equal.
- * <li>If {@code a == b}, then {@code a} and {@code b} are always fuzzily equal.
- * <li>Positive and negative zero are always fuzzily equal.
- * <li>If {@code tolerance} is zero, and neither {@code a} nor {@code b} is NaN, then
- * {@code a} and {@code b} are fuzzily equal if and only if {@code a == b}.
- * <li>With {@link Double#POSITIVE_INFINITY} tolerance, all non-NaN values are fuzzily equal.
- * <li>With finite tolerance, {@code Double.POSITIVE_INFINITY} and {@code
- * Double.NEGATIVE_INFINITY} are fuzzily equal only to themselves.
- * </li>
- *
- * <p>This is reflexive and symmetric, but <em>not</em> transitive, so it is <em>not</em> an
- * equivalence relation and <em>not</em> suitable for use in {@link Object#equals}
- * implementations.
- *
- * @throws IllegalArgumentException if {@code tolerance} is {@code < 0} or NaN
- * @since 13.0
- */
- public static boolean fuzzyEquals(double a, double b, double tolerance) {
- MathPreconditions.checkNonNegative("tolerance", tolerance);
- return
- Math.copySign(a - b, 1.0) <= tolerance
- // copySign(x, 1.0) is a branch-free version of abs(x), but with different NaN semantics
- || (a == b) // needed to ensure that infinities equal themselves
- || ((a != a) && (b != b)); // x != x is equivalent to Double.isNaN(x), but faster
- }
-
- /**
- * Compares {@code a} and {@code b} "fuzzily," with a tolerance for nearly-equal values.
- *
- * <p>This method is equivalent to
- * {@code fuzzyEquals(a, b, tolerance) ? 0 : Double.compare(a, b)}. In particular, like
- * {@link Double#compare(double, double)}, it treats all NaN values as equal and greater than all
- * other values (including {@link Double#POSITIVE_INFINITY}).
- *
- * <p>This is <em>not</em> a total ordering and is <em>not</em> suitable for use in
- * {@link Comparable#compareTo} implementations. In particular, it is not transitive.
- *
- * @throws IllegalArgumentException if {@code tolerance} is {@code < 0} or NaN
- * @since 13.0
- */
- public static int fuzzyCompare(double a, double b, double tolerance) {
- if (fuzzyEquals(a, b, tolerance)) {
- return 0;
- } else if (a < b) {
- return -1;
- } else if (a > b) {
- return 1;
- } else {
- return Booleans.compare(Double.isNaN(a), Double.isNaN(b));
- }
- }
-
- private DoubleMath() {}
}
diff --git a/guava/src/com/google/common/math/DoubleUtils.java b/guava/src/com/google/common/math/DoubleUtils.java
index 6cd94e3..5a6fb3e 100644
--- a/guava/src/com/google/common/math/DoubleUtils.java
+++ b/guava/src/com/google/common/math/DoubleUtils.java
@@ -17,27 +17,35 @@
package com.google.common.math;
import static com.google.common.base.Preconditions.checkArgument;
-import static java.lang.Double.MAX_EXPONENT;
-import static java.lang.Double.MIN_EXPONENT;
-import static java.lang.Double.POSITIVE_INFINITY;
-import static java.lang.Double.doubleToRawLongBits;
-import static java.lang.Double.isNaN;
-import static java.lang.Double.longBitsToDouble;
-import static java.lang.Math.getExponent;
import java.math.BigInteger;
+import com.google.common.annotations.VisibleForTesting;
+
/**
- * Utilities for {@code double} primitives.
+ * Utilities for {@code double} primitives. Some of these are exposed in JDK 6,
+ * but we can't depend on them there.
*
* @author Louis Wasserman
*/
final class DoubleUtils {
+ // TODO(user): replace with appropriate calls when we move to JDK 6
+
private DoubleUtils() {
}
- static double nextDown(double d) {
- return -Math.nextUp(-d);
+ static double next(double x, boolean up) {
+ // Math.nextAfter is JDK 6.
+ if (x == 0.0) {
+ return up ? Double.MIN_VALUE : -Double.MIN_VALUE;
+ }
+ long bits = Double.doubleToRawLongBits(x);
+ if ((x < 0.0) == up) {
+ bits--;
+ } else {
+ bits++;
+ }
+ return Double.longBitsToDouble(bits);
}
// The mask for the significand, according to the {@link
@@ -56,27 +64,64 @@ final class DoubleUtils {
static final int EXPONENT_BIAS = 1023;
+ static final int MIN_DOUBLE_EXPONENT = -1022;
+
+ static final int MAX_DOUBLE_EXPONENT = 1023;
+
/**
* The implicit 1 bit that is omitted in significands of normal doubles.
*/
static final long IMPLICIT_BIT = SIGNIFICAND_MASK + 1;
+ @VisibleForTesting
+ static int getExponent(double d) {
+ // TODO: replace with Math.getExponent in JDK 6
+ long bits = Double.doubleToRawLongBits(d);
+ int exponent = (int) ((bits & EXPONENT_MASK) >> SIGNIFICAND_BITS);
+ exponent -= EXPONENT_BIAS;
+ return exponent;
+ }
+
+ /**
+ * Returns {@code d * 2^scale}.
+ */
+ static strictfp double scalb(double d, int scale) {
+ // TODO: replace with Math.scalb in JDK 6
+ int exponent = getExponent(d);
+ switch (exponent) {
+ case MAX_DOUBLE_EXPONENT + 1: // NaN, infinity
+ return d;
+ case MIN_DOUBLE_EXPONENT - 1:
+ return d * StrictMath.pow(2.0, scale);
+ default:
+ int newExponent = exponent + scale;
+ if (MIN_DOUBLE_EXPONENT <= newExponent
+ & newExponent <= MAX_DOUBLE_EXPONENT) {
+ long bits = Double.doubleToRawLongBits(d);
+ bits &= ~EXPONENT_MASK;
+ bits |= ((long) (newExponent + EXPONENT_BIAS)) << SIGNIFICAND_BITS;
+ return Double.longBitsToDouble(bits);
+ }
+ return d * StrictMath.pow(2.0, scale);
+ }
+ }
+
static long getSignificand(double d) {
checkArgument(isFinite(d), "not a normal value");
int exponent = getExponent(d);
- long bits = doubleToRawLongBits(d);
+ long bits = Double.doubleToRawLongBits(d);
bits &= SIGNIFICAND_MASK;
- return (exponent == MIN_EXPONENT - 1)
+ return (exponent == MIN_DOUBLE_EXPONENT - 1)
? bits << 1
: bits | IMPLICIT_BIT;
}
static boolean isFinite(double d) {
- return getExponent(d) <= MAX_EXPONENT;
+ return getExponent(d) <= MAX_DOUBLE_EXPONENT;
}
static boolean isNormal(double d) {
- return getExponent(d) >= MIN_EXPONENT;
+ return getExponent(d) >= MIN_DOUBLE_EXPONENT;
}
/*
@@ -84,8 +129,8 @@ final class DoubleUtils {
* normal, and finite.
*/
static double scaleNormalize(double x) {
- long significand = doubleToRawLongBits(x) & SIGNIFICAND_MASK;
- return longBitsToDouble(significand | ONE_BITS);
+ long significand = Double.doubleToRawLongBits(x) & SIGNIFICAND_MASK;
+ return Double.longBitsToDouble(significand | ONE_BITS);
}
static double bigToDouble(BigInteger x) {
@@ -95,8 +140,8 @@ final class DoubleUtils {
// exponent == floor(log2(abs(x)))
if (exponent < Long.SIZE - 1) {
return x.longValue();
- } else if (exponent > MAX_EXPONENT) {
- return x.signum() * POSITIVE_INFINITY;
+ } else if (exponent > MAX_DOUBLE_EXPONENT) {
+ return x.signum() * Double.POSITIVE_INFINITY;
}
/*
@@ -129,20 +174,8 @@ final class DoubleUtils {
* Double.POSITIVE_INFINITY.
*/
bits |= x.signum() & SIGN_MASK;
- return longBitsToDouble(bits);
- }
-
- /**
- * Returns its argument if it is non-negative, zero if it is negative.
- */
- static double ensureNonNegative(double value) {
- checkArgument(!isNaN(value));
- if (value > 0.0) {
- return value;
- } else {
- return 0.0;
- }
+ return Double.longBitsToDouble(bits);
}
- private static final long ONE_BITS = doubleToRawLongBits(1.0);
+ private static final long ONE_BITS = Double.doubleToRawLongBits(1.0);
}
diff --git a/guava/src/com/google/common/math/IntMath.java b/guava/src/com/google/common/math/IntMath.java
index 33ed400..8fc7cd8 100644
--- a/guava/src/com/google/common/math/IntMath.java
+++ b/guava/src/com/google/common/math/IntMath.java
@@ -23,10 +23,10 @@ import static com.google.common.math.MathPreconditions.checkNonNegative;
import static com.google.common.math.MathPreconditions.checkPositive;
import static com.google.common.math.MathPreconditions.checkRoundingUnnecessary;
import static java.lang.Math.abs;
-import static java.lang.Math.min;
import static java.math.RoundingMode.HALF_EVEN;
import static java.math.RoundingMode.HALF_UP;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
@@ -48,6 +48,7 @@ import java.math.RoundingMode;
* @author Louis Wasserman
* @since 11.0
*/
+@Beta
@GwtCompatible(emulated = true)
public final class IntMath {
// NOTE: Whenever both tests are cheap and functional, it's faster to use &, | instead of &&, ||
@@ -70,8 +71,8 @@ public final class IntMath {
* @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
* is not a power of two
*/
+ @GwtIncompatible("need BigIntegerMath to adequately test")
@SuppressWarnings("fallthrough")
- // TODO(kevinb): remove after this warning is disabled globally
public static int log2(int x, RoundingMode mode) {
checkPositive("x", x);
switch (mode) {
@@ -116,7 +117,7 @@ public final class IntMath {
public static int log10(int x, RoundingMode mode) {
checkPositive("x", x);
int logFloor = log10Floor(x);
- int floorPow = powersOf10[logFloor];
+ int floorPow = POWERS_OF_10[logFloor];
switch (mode) {
case UNNECESSARY:
checkRoundingUnnecessary(x == floorPow);
@@ -131,40 +132,26 @@ public final class IntMath {
case HALF_UP:
case HALF_EVEN:
// sqrt(10) is irrational, so log10(x) - logFloor is never exactly 0.5
- return (x <= halfPowersOf10[logFloor]) ? logFloor : logFloor + 1;
+ return (x <= HALF_POWERS_OF_10[logFloor]) ? logFloor : logFloor + 1;
default:
throw new AssertionError();
}
}
private static int log10Floor(int x) {
- /*
- * Based on Hacker's Delight Fig. 11-5, the two-table-lookup, branch-free implementation.
- *
- * The key idea is that based on the number of leading zeros (equivalently, floor(log2(x))),
- * we can narrow the possible floor(log10(x)) values to two. For example, if floor(log2(x))
- * is 6, then 64 <= x < 128, so floor(log10(x)) is either 1 or 2.
- */
- int y = maxLog10ForLeadingZeros[Integer.numberOfLeadingZeros(x)];
- // y is the higher of the two possible values of floor(log10(x))
-
- int sgn = (x - powersOf10[y]) >>> (Integer.SIZE - 1);
- /*
- * sgn is the sign bit of x - 10^y; it is 1 if x < 10^y, and 0 otherwise. If x < 10^y, then we
- * want the lower of the two possible values, or y - 1, otherwise, we want y.
- */
- return y - sgn;
+ for (int i = 1; i < POWERS_OF_10.length; i++) {
+ if (x < POWERS_OF_10[i]) {
+ return i - 1;
+ }
+ }
+ return POWERS_OF_10.length - 1;
}
- // maxLog10ForLeadingZeros[i] == floor(log10(2^(Long.SIZE - i)))
- @VisibleForTesting static final byte[] maxLog10ForLeadingZeros = {9, 9, 9, 8, 8, 8,
- 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0};
+ @VisibleForTesting static final int[] POWERS_OF_10 =
+ {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
- @VisibleForTesting static final int[] powersOf10 = {1, 10, 100, 1000, 10000,
- 100000, 1000000, 10000000, 100000000, 1000000000};
-
- // halfPowersOf10[i] = largest int less than 10^(i + 0.5)
- @VisibleForTesting static final int[] halfPowersOf10 =
+ // HALF_POWERS_OF_10[i] = largest int less than 10^(i + 0.5)
+ @VisibleForTesting static final int[] HALF_POWERS_OF_10 =
{3, 31, 316, 3162, 31622, 316227, 3162277, 31622776, 316227766, Integer.MAX_VALUE};
/**
@@ -194,8 +181,6 @@ public final class IntMath {
} else {
return 0;
}
- default:
- // continue below to handle the general case
}
for (int accum = 1;; k >>= 1) {
switch (k) {
@@ -259,6 +244,7 @@ public final class IntMath {
* @throws ArithmeticException if {@code q == 0}, or if {@code mode == UNNECESSARY} and {@code a}
* is not an integer multiple of {@code b}
*/
+ @GwtIncompatible("failing tests")
@SuppressWarnings("fallthrough")
public static int divide(int p, int q, RoundingMode mode) {
checkNotNull(mode);
@@ -352,41 +338,13 @@ public final class IntMath {
*/
checkNonNegative("a", a);
checkNonNegative("b", b);
- if (a == 0) {
- // 0 % b == 0, so b divides a, but the converse doesn't hold.
- // BigInteger.gcd is consistent with this decision.
- return b;
- } else if (b == 0) {
- return a; // similar logic
- }
- /*
- * Uses the binary GCD algorithm; see http://en.wikipedia.org/wiki/Binary_GCD_algorithm.
- * This is >40% faster than the Euclidean algorithm in benchmarks.
- */
- int aTwos = Integer.numberOfTrailingZeros(a);
- a >>= aTwos; // divide out all 2s
- int bTwos = Integer.numberOfTrailingZeros(b);
- b >>= bTwos; // divide out all 2s
- while (a != b) { // both a, b are odd
- // The key to the binary GCD algorithm is as follows:
- // Both a and b are odd. Assume a > b; then gcd(a - b, b) = gcd(a, b).
- // But in gcd(a - b, b), a - b is even and b is odd, so we can divide out powers of two.
-
- // We bend over backwards to avoid branching, adapting a technique from
- // http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
-
- int delta = a - b; // can't overflow, since a and b are nonnegative
-
- int minDeltaOrZero = delta & (delta >> (Integer.SIZE - 1));
- // equivalent to Math.min(delta, 0)
-
- a = delta - minDeltaOrZero - minDeltaOrZero; // sets a to Math.abs(a - b)
- // a is now nonnegative and even
-
- b += minDeltaOrZero; // sets b to min(old a, b)
- a >>= Integer.numberOfTrailingZeros(a); // divide out all 2s, since 2 doesn't divide b
+ // The simple Euclidean algorithm is the fastest for ints, and is easily the most readable.
+ while (b != 0) {
+ int t = b;
+ b = a % b;
+ a = t;
}
- return a << min(aTwos, bTwos);
+ return a;
}
/**
@@ -430,6 +388,7 @@ public final class IntMath {
* @throws ArithmeticException if {@code b} to the {@code k}th power overflows in signed
* {@code int} arithmetic
*/
+ @GwtIncompatible("failing tests")
public static int checkedPow(int b, int k) {
checkNonNegative("exponent", k);
switch (b) {
@@ -445,8 +404,6 @@ public final class IntMath {
case (-2):
checkNoOverflow(k < Integer.SIZE);
return ((k & 1) == 0) ? 1 << k : -1 << k;
- default:
- // continue below to handle the general case
}
int accum = 1;
while (true) {
@@ -477,12 +434,13 @@ public final class IntMath {
*
* @throws IllegalArgumentException if {@code n < 0}
*/
+ @GwtIncompatible("need BigIntegerMath to adequately test")
public static int factorial(int n) {
checkNonNegative("n", n);
- return (n < factorials.length) ? factorials[n] : Integer.MAX_VALUE;
+ return (n < FACTORIALS.length) ? FACTORIALS[n] : Integer.MAX_VALUE;
}
- private static final int[] factorials = {
+ static final int[] FACTORIALS = {
1,
1,
1 * 2,
@@ -511,7 +469,7 @@ public final class IntMath {
if (k > (n >> 1)) {
k = n - k;
}
- if (k >= biggestBinomials.length || n > biggestBinomials[k]) {
+ if (k >= BIGGEST_BINOMIALS.length || n > BIGGEST_BINOMIALS[k]) {
return Integer.MAX_VALUE;
}
switch (k) {
@@ -529,8 +487,8 @@ public final class IntMath {
}
}
- // binomial(biggestBinomials[k], k) fits in an int, but not binomial(biggestBinomials[k]+1,k).
- @VisibleForTesting static int[] biggestBinomials = {
+ // binomial(BIGGEST_BINOMIALS[k], k) fits in an int, but not binomial(BIGGEST_BINOMIALS[k]+1,k).
+ @VisibleForTesting static int[] BIGGEST_BINOMIALS = {
Integer.MAX_VALUE,
Integer.MAX_VALUE,
65536,
@@ -550,18 +508,5 @@ public final class IntMath {
33
};
- /**
- * Returns the arithmetic mean of {@code x} and {@code y}, rounded towards
- * negative infinity. This method is overflow resilient.
- *
- * @since 14.0
- */
- public static int mean(int x, int y) {
- // Efficient method for computing the arithmetic mean.
- // The alternative (x + y) / 2 fails for large values.
- // The alternative (x + y) >>> 1 fails for negative values.
- return (x & y) + ((x ^ y) >> 1);
- }
-
private IntMath() {}
}
diff --git a/guava/src/com/google/common/math/LongMath.java b/guava/src/com/google/common/math/LongMath.java
index 6e00e61..07bd534 100644
--- a/guava/src/com/google/common/math/LongMath.java
+++ b/guava/src/com/google/common/math/LongMath.java
@@ -27,8 +27,7 @@ import static java.lang.Math.min;
import static java.math.RoundingMode.HALF_EVEN;
import static java.math.RoundingMode.HALF_UP;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
import java.math.BigInteger;
@@ -48,7 +47,7 @@ import java.math.RoundingMode;
* @author Louis Wasserman
* @since 11.0
*/
-@GwtCompatible(emulated = true)
+@Beta
public final class LongMath {
// NOTE: Whenever both tests are cheap and functional, it's faster to use &, | instead of &&, ||
@@ -70,7 +69,6 @@ public final class LongMath {
* is not a power of two
*/
@SuppressWarnings("fallthrough")
- // TODO(kevinb): remove after this warning is disabled globally
public static int log2(long x, RoundingMode mode) {
checkPositive("x", x);
switch (mode) {
@@ -110,16 +108,14 @@ public final class LongMath {
* @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
* is not a power of ten
*/
- @GwtIncompatible("TODO")
@SuppressWarnings("fallthrough")
- // TODO(kevinb): remove after this warning is disabled globally
public static int log10(long x, RoundingMode mode) {
checkPositive("x", x);
if (fitsInInt(x)) {
return IntMath.log10((int) x, mode);
}
int logFloor = log10Floor(x);
- long floorPow = powersOf10[logFloor];
+ long floorPow = POWERS_OF_10[logFloor];
switch (mode) {
case UNNECESSARY:
checkRoundingUnnecessary(x == floorPow);
@@ -134,41 +130,23 @@ public final class LongMath {
case HALF_UP:
case HALF_EVEN:
// sqrt(10) is irrational, so log10(x)-logFloor is never exactly 0.5
- return (x <= halfPowersOf10[logFloor]) ? logFloor : logFloor + 1;
+ return (x <= HALF_POWERS_OF_10[logFloor]) ? logFloor : logFloor + 1;
default:
throw new AssertionError();
}
}
- @GwtIncompatible("TODO")
static int log10Floor(long x) {
- /*
- * Based on Hacker's Delight Fig. 11-5, the two-table-lookup, branch-free implementation.
- *
- * The key idea is that based on the number of leading zeros (equivalently, floor(log2(x))),
- * we can narrow the possible floor(log10(x)) values to two. For example, if floor(log2(x))
- * is 6, then 64 <= x < 128, so floor(log10(x)) is either 1 or 2.
- */
- int y = maxLog10ForLeadingZeros[Long.numberOfLeadingZeros(x)];
- // y is the higher of the two possible values of floor(log10(x))
-
- long sgn = (x - powersOf10[y]) >>> (Long.SIZE - 1);
- /*
- * sgn is the sign bit of x - 10^y; it is 1 if x < 10^y, and 0 otherwise. If x < 10^y, then we
- * want the lower of the two possible values, or y - 1, otherwise, we want y.
- */
- return y - (int) sgn;
+ for (int i = 1; i < POWERS_OF_10.length; i++) {
+ if (x < POWERS_OF_10[i]) {
+ return i - 1;
+ }
+ }
+ return POWERS_OF_10.length - 1;
}
- // maxLog10ForLeadingZeros[i] == floor(log10(2^(Long.SIZE - i)))
- @VisibleForTesting static final byte[] maxLog10ForLeadingZeros = {
- 19, 18, 18, 18, 18, 17, 17, 17, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 13, 13, 13, 12, 12,
- 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 4, 4,
- 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0 };
-
- @GwtIncompatible("TODO")
@VisibleForTesting
- static final long[] powersOf10 = {
+ static final long[] POWERS_OF_10 = {
1L,
10L,
100L,
@@ -190,10 +168,9 @@ public final class LongMath {
1000000000000000000L
};
- // halfPowersOf10[i] = largest long less than 10^(i + 0.5)
- @GwtIncompatible("TODO")
+ // HALF_POWERS_OF_10[i] = largest long less than 10^(i + 0.5)
@VisibleForTesting
- static final long[] halfPowersOf10 = {
+ static final long[] HALF_POWERS_OF_10 = {
3L,
31L,
316L,
@@ -222,7 +199,6 @@ public final class LongMath {
*
* @throws IllegalArgumentException if {@code k < 0}
*/
- @GwtIncompatible("TODO")
public static long pow(long b, int k) {
checkNonNegative("exponent", k);
if (-2 <= b && b <= 2) {
@@ -241,8 +217,6 @@ public final class LongMath {
} else {
return 0;
}
- default:
- throw new AssertionError();
}
}
for (long accum = 1;; k >>= 1) {
@@ -265,7 +239,6 @@ public final class LongMath {
* @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and
* {@code sqrt(x)} is not an integer
*/
- @GwtIncompatible("TODO")
@SuppressWarnings("fallthrough")
public static long sqrt(long x, RoundingMode mode) {
checkNonNegative("x", x);
@@ -297,60 +270,19 @@ public final class LongMath {
}
}
- @GwtIncompatible("TODO")
private static long sqrtFloor(long x) {
- long guess = (long) Math.sqrt(x);
- /*
- * Lemma: For all a, b, if |a - b| <= 1, then |floor(a) - floor(b)| <= 1.
- *
- * Proof:
- * -1 <= a - b <= 1
- * b - 1 <= a <= b + 1
- * floor(b - 1) <= floor(a) <= floor(b + 1)
- * floor(b) - 1 <= floor(a) <= floor(b) + 1
- * -1 <= floor(a) - floor(b) <= 1
- *
- * Theorem: |floor(sqrt(x)) - guess| <= 1.
- *
- * Proof: By the lemma, it suffices to show that |sqrt(x) - Math.sqrt(x)| <= 1.
- * We consider two cases: x <= 2^53 and x > 2^53.
- *
- * If x <= 2^53, then x is exactly representable as a double, so the only error is in rounding
- * sqrt(x) to a double, which introduces at most 2^-52 relative error. Since sqrt(x) < 2^27,
- * the absolute error is at most 2^(27-52) = 2^-25 < 1.
- *
- * Otherwise, x > 2^53. The rounding error introduced by casting x to a double is at most
- * 2^63 * 2^-52 = 2^11. Noting that sqrt(x) > 2^26,
- *
- * sqrt(x) - 0.5 = sqrt((sqrt(x) - 0.5)^2)
- * = sqrt(x - sqrt(x) + 0.25)
- * < sqrt(x - 2^26 + 0.25)
- * < sqrt(x - 2^11)
- * <= sqrt((double) x)
- * sqrt(x) + 0.5 = sqrt((sqrt(x) + 0.5)^2)
- * = sqrt(x + sqrt(x) + 0.25)
- * > sqrt(x + 2^26 + 0.25)
- * > sqrt(x + 2^11)
- * >= sqrt((double) x)
- * sqrt(x) - 0.5 < sqrt((double) x) < sqrt(x) + 0.5
- *
- * Math.sqrt((double) x) is obtained by rounding sqrt((double) x) to a double, increasing the
- * error by at most 2^-52 * sqrt(x) <= 2^(32 - 52) <= 2^-20, so clearly
- *
- * sqrt(x) - 0.5 - 2^-20 <= Math.sqrt((double) x) <= sqrt(x) + 0.5 + 2^-20
- *
- * Therefore, |sqrt(x) - Math.sqrt((double) x)| <= 1, so
- * |floor(sqrt(x)) - (long) Math.sqrt((double) x)| <= 1
- * as desired.
- */
- long guessSquared = guess * guess;
- if (x - guessSquared >= guess + guess + 1) {
- // The condition is equivalent to x >= (guess + 1) * (guess + 1), but doesn't overflow.
- guess++;
- } else if (x < guessSquared) {
- guess--;
+ // Hackers's Delight, Figure 11-1
+ long sqrt0 = (long) Math.sqrt(x);
+ // Precision can be lost in the cast to double, so we use this as a starting estimate.
+ long sqrt1 = (sqrt0 + (x / sqrt0)) >> 1;
+ if (sqrt1 == sqrt0) {
+ return sqrt0;
}
- return guess;
+ do {
+ sqrt0 = sqrt1;
+ sqrt1 = (sqrt0 + (x / sqrt0)) >> 1;
+ } while (sqrt1 < sqrt0);
+ return sqrt0;
}
/**
@@ -360,7 +292,6 @@ public final class LongMath {
* @throws ArithmeticException if {@code q == 0}, or if {@code mode == UNNECESSARY} and {@code a}
* is not an integer multiple of {@code b}
*/
- @GwtIncompatible("TODO")
@SuppressWarnings("fallthrough")
public static long divide(long p, long q, RoundingMode mode) {
checkNotNull(mode);
@@ -431,7 +362,6 @@ public final class LongMath {
*
* @throws ArithmeticException if {@code m <= 0}
*/
- @GwtIncompatible("TODO")
public static int mod(long x, int m) {
// Cast is safe because the result is guaranteed in the range [0, m)
return (int) mod(x, (long) m);
@@ -453,7 +383,6 @@ public final class LongMath {
*
* @throws ArithmeticException if {@code m <= 0}
*/
- @GwtIncompatible("TODO")
public static long mod(long x, long m) {
if (m <= 0) {
throw new ArithmeticException("Modulus " + m + " must be > 0");
@@ -476,38 +405,24 @@ public final class LongMath {
*/
checkNonNegative("a", a);
checkNonNegative("b", b);
- if (a == 0) {
- // 0 % b == 0, so b divides a, but the converse doesn't hold.
- // BigInteger.gcd is consistent with this decision.
- return b;
- } else if (b == 0) {
- return a; // similar logic
+ if (a == 0 | b == 0) {
+ return a | b;
}
/*
* Uses the binary GCD algorithm; see http://en.wikipedia.org/wiki/Binary_GCD_algorithm.
- * This is >60% faster than the Euclidean algorithm in benchmarks.
+ * This is over 40% faster than the Euclidean algorithm in benchmarks.
*/
int aTwos = Long.numberOfTrailingZeros(a);
a >>= aTwos; // divide out all 2s
int bTwos = Long.numberOfTrailingZeros(b);
b >>= bTwos; // divide out all 2s
while (a != b) { // both a, b are odd
- // The key to the binary GCD algorithm is as follows:
- // Both a and b are odd. Assume a > b; then gcd(a - b, b) = gcd(a, b).
- // But in gcd(a - b, b), a - b is even and b is odd, so we can divide out powers of two.
-
- // We bend over backwards to avoid branching, adapting a technique from
- // http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
-
- long delta = a - b; // can't overflow, since a and b are nonnegative
-
- long minDeltaOrZero = delta & (delta >> (Long.SIZE - 1));
- // equivalent to Math.min(delta, 0)
-
- a = delta - minDeltaOrZero - minDeltaOrZero; // sets a to Math.abs(a - b)
- // a is now nonnegative and even
-
- b += minDeltaOrZero; // sets b to min(old a, b)
+ if (a < b) { // swap a, b
+ long t = b;
+ b = a;
+ a = t;
+ }
+ a -= b; // a is now positive and even
a >>= Long.numberOfTrailingZeros(a); // divide out all 2s, since 2 doesn't divide b
}
return a << min(aTwos, bTwos);
@@ -518,7 +433,6 @@ public final class LongMath {
*
* @throws ArithmeticException if {@code a + b} overflows in signed {@code long} arithmetic
*/
- @GwtIncompatible("TODO")
public static long checkedAdd(long a, long b) {
long result = a + b;
checkNoOverflow((a ^ b) < 0 | (a ^ result) >= 0);
@@ -530,7 +444,6 @@ public final class LongMath {
*
* @throws ArithmeticException if {@code a - b} overflows in signed {@code long} arithmetic
*/
- @GwtIncompatible("TODO")
public static long checkedSubtract(long a, long b) {
long result = a - b;
checkNoOverflow((a ^ b) >= 0 | (a ^ result) >= 0);
@@ -542,7 +455,6 @@ public final class LongMath {
*
* @throws ArithmeticException if {@code a * b} overflows in signed {@code long} arithmetic
*/
- @GwtIncompatible("TODO")
public static long checkedMultiply(long a, long b) {
// Hacker's Delight, Section 2-12
int leadingZeros = Long.numberOfLeadingZeros(a) + Long.numberOfLeadingZeros(~a)
@@ -573,7 +485,6 @@ public final class LongMath {
* @throws ArithmeticException if {@code b} to the {@code k}th power overflows in signed
* {@code long} arithmetic
*/
- @GwtIncompatible("TODO")
public static long checkedPow(long b, int k) {
checkNonNegative("exponent", k);
if (b >= -2 & b <= 2) {
@@ -590,8 +501,6 @@ public final class LongMath {
case (-2):
checkNoOverflow(k < Long.SIZE);
return ((k & 1) == 0) ? (1L << k) : (-1L << k);
- default:
- throw new AssertionError();
}
}
long accum = 1;
@@ -614,7 +523,6 @@ public final class LongMath {
}
}
- @GwtIncompatible("TODO")
@VisibleForTesting static final long FLOOR_SQRT_MAX_LONG = 3037000499L;
/**
@@ -624,13 +532,12 @@ public final class LongMath {
*
* @throws IllegalArgumentException if {@code n < 0}
*/
- @GwtIncompatible("TODO")
public static long factorial(int n) {
checkNonNegative("n", n);
- return (n < factorials.length) ? factorials[n] : Long.MAX_VALUE;
+ return (n < FACTORIALS.length) ? FACTORIALS[n] : Long.MAX_VALUE;
}
- static final long[] factorials = {
+ static final long[] FACTORIALS = {
1L,
1L,
1L * 2,
@@ -667,111 +574,51 @@ public final class LongMath {
if (k > (n >> 1)) {
k = n - k;
}
- switch (k) {
- case 0:
- return 1;
- case 1:
- return n;
- default:
- if (n < factorials.length) {
- return factorials[n] / (factorials[k] * factorials[n - k]);
- } else if (k >= biggestBinomials.length || n > biggestBinomials[k]) {
- return Long.MAX_VALUE;
- } else if (k < biggestSimpleBinomials.length && n <= biggestSimpleBinomials[k]) {
- // guaranteed not to overflow
- long result = n--;
- for (int i = 2; i <= k; n--, i++) {
- result *= n;
- result /= i;
- }
- return result;
- } else {
- int nBits = LongMath.log2(n, RoundingMode.CEILING);
-
- long result = 1;
- long numerator = n--;
- long denominator = 1;
-
- int numeratorBits = nBits;
- // This is an upper bound on log2(numerator, ceiling).
-
- /*
- * We want to do this in long math for speed, but want to avoid overflow. We adapt the
- * technique previously used by BigIntegerMath: maintain separate numerator and
- * denominator accumulators, multiplying the fraction into result when near overflow.
- */
- for (int i = 2; i <= k; i++, n--) {
- if (numeratorBits + nBits < Long.SIZE - 1) {
- // It's definitely safe to multiply into numerator and denominator.
- numerator *= n;
- denominator *= i;
- numeratorBits += nBits;
- } else {
- // It might not be safe to multiply into numerator and denominator,
- // so multiply (numerator / denominator) into result.
- result = multiplyFraction(result, numerator, denominator);
- numerator = n;
- denominator = i;
- numeratorBits = nBits;
- }
- }
- return multiplyFraction(result, numerator, denominator);
- }
+ if (k >= BIGGEST_BINOMIALS.length || n > BIGGEST_BINOMIALS[k]) {
+ return Long.MAX_VALUE;
}
- }
-
- /**
- * Returns (x * numerator / denominator), which is assumed to come out to an integral value.
- */
- static long multiplyFraction(long x, long numerator, long denominator) {
- if (x == 1) {
- return numerator / denominator;
+ long result = 1;
+ if (k < BIGGEST_SIMPLE_BINOMIALS.length && n <= BIGGEST_SIMPLE_BINOMIALS[k]) {
+ // guaranteed not to overflow
+ for (int i = 0; i < k; i++) {
+ result *= n - i;
+ result /= i + 1;
+ }
+ } else {
+ // We want to do this in long math for speed, but want to avoid overflow.
+ // Dividing by the GCD suffices to avoid overflow in all the remaining cases.
+ for (int i = 1; i <= k; i++, n--) {
+ int d = IntMath.gcd(n, i);
+ result /= i / d; // (i/d) is guaranteed to divide result
+ result *= n / d;
+ }
}
- long commonDivisor = gcd(x, denominator);
- x /= commonDivisor;
- denominator /= commonDivisor;
- // We know gcd(x, denominator) = 1, and x * numerator / denominator is exact,
- // so denominator must be a divisor of numerator.
- return x * (numerator / denominator);
+ return result;
}
/*
- * binomial(biggestBinomials[k], k) fits in a long, but not
- * binomial(biggestBinomials[k] + 1, k).
+ * binomial(BIGGEST_BINOMIALS[k], k) fits in a long, but not
+ * binomial(BIGGEST_BINOMIALS[k] + 1, k).
*/
- static final int[] biggestBinomials =
+ static final int[] BIGGEST_BINOMIALS =
{Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 3810779, 121977, 16175, 4337, 1733,
887, 534, 361, 265, 206, 169, 143, 125, 111, 101, 94, 88, 83, 79, 76, 74, 72, 70, 69, 68,
67, 67, 66, 66, 66, 66};
/*
- * binomial(biggestSimpleBinomials[k], k) doesn't need to use the slower GCD-based impl,
- * but binomial(biggestSimpleBinomials[k] + 1, k) does.
+ * binomial(BIGGEST_SIMPLE_BINOMIALS[k], k) doesn't need to use the slower GCD-based impl,
+ * but binomial(BIGGEST_SIMPLE_BINOMIALS[k] + 1, k) does.
*/
- @VisibleForTesting static final int[] biggestSimpleBinomials =
+ @VisibleForTesting static final int[] BIGGEST_SIMPLE_BINOMIALS =
{Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 2642246, 86251, 11724, 3218, 1313,
684, 419, 287, 214, 169, 139, 119, 105, 95, 87, 81, 76, 73, 70, 68, 66, 64, 63, 62, 62,
61, 61, 61};
// These values were generated by using checkedMultiply to see when the simple multiply/divide
// algorithm would lead to an overflow.
- @GwtIncompatible("TODO")
static boolean fitsInInt(long x) {
return (int) x == x;
}
- /**
- * Returns the arithmetic mean of {@code x} and {@code y}, rounded toward
- * negative infinity. This method is resilient to overflow.
- *
- * @since 14.0
- */
- public static long mean(long x, long y) {
- // Efficient method for computing the arithmetic mean.
- // The alternative (x + y) / 2 fails for large values.
- // The alternative (x + y) >>> 1 fails for negative values.
- return (x & y) + ((x ^ y) >> 1);
- }
-
private LongMath() {}
}
diff --git a/guava/src/com/google/common/math/MathPreconditions.java b/guava/src/com/google/common/math/MathPreconditions.java
index afaee3b..98a6d38 100644
--- a/guava/src/com/google/common/math/MathPreconditions.java
+++ b/guava/src/com/google/common/math/MathPreconditions.java
@@ -1,76 +1,71 @@
/*
* 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
+ * 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.math;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.annotations.GwtCompatible;
import java.math.BigInteger;
-import javax.annotation.Nullable;
-
/**
* A collection of preconditions for math functions.
- *
+ *
* @author Louis Wasserman
*/
@GwtCompatible
final class MathPreconditions {
- static int checkPositive(@Nullable String role, int x) {
+ static int checkPositive(String role, int x) {
if (x <= 0) {
throw new IllegalArgumentException(role + " (" + x + ") must be > 0");
}
return x;
}
- static long checkPositive(@Nullable String role, long x) {
+ static long checkPositive(String role, long x) {
if (x <= 0) {
throw new IllegalArgumentException(role + " (" + x + ") must be > 0");
}
return x;
}
- static BigInteger checkPositive(@Nullable String role, BigInteger x) {
+ static BigInteger checkPositive(String role, BigInteger x) {
if (x.signum() <= 0) {
throw new IllegalArgumentException(role + " (" + x + ") must be > 0");
}
return x;
}
- static int checkNonNegative(@Nullable String role, int x) {
+ static int checkNonNegative(String role, int x) {
if (x < 0) {
throw new IllegalArgumentException(role + " (" + x + ") must be >= 0");
}
return x;
}
- static long checkNonNegative(@Nullable String role, long x) {
+ static long checkNonNegative(String role, long x) {
if (x < 0) {
throw new IllegalArgumentException(role + " (" + x + ") must be >= 0");
}
return x;
}
- static BigInteger checkNonNegative(@Nullable String role, BigInteger x) {
- if (x.signum() < 0) {
- throw new IllegalArgumentException(role + " (" + x + ") must be >= 0");
- }
- return x;
- }
-
- static double checkNonNegative(@Nullable String role, double x) {
- if (!(x >= 0)) { // not x < 0, to work with NaN.
+ static BigInteger checkNonNegative(String role, BigInteger x) {
+ if (checkNotNull(x).signum() < 0) {
throw new IllegalArgumentException(role + " (" + x + ") must be >= 0");
}
return x;
diff --git a/guava/src/com/google/common/math/package-info.java b/guava/src/com/google/common/math/package-info.java
index bd17e52..6bbd4f2 100644
--- a/guava/src/com/google/common/math/package-info.java
+++ b/guava/src/com/google/common/math/package-info.java
@@ -19,13 +19,8 @@
*
* <p>This package is a part of the open-source
* <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/MathExplained">
- * math utilities</a>.
*/
@ParametersAreNonnullByDefault
package com.google.common.math;
import javax.annotation.ParametersAreNonnullByDefault;
-
diff --git a/guava/src/com/google/common/net/HostAndPort.java b/guava/src/com/google/common/net/HostAndPort.java
index a0cd3bf..eacc858 100644
--- a/guava/src/com/google/common/net/HostAndPort.java
+++ b/guava/src/com/google/common/net/HostAndPort.java
@@ -22,13 +22,10 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.Beta;
import com.google.common.base.Objects;
-import com.google.common.base.Strings;
-import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
@@ -63,7 +60,7 @@ import javax.annotation.concurrent.Immutable;
* @since 10.0
*/
@Beta @Immutable
-public final class HostAndPort implements Serializable {
+public final class HostAndPort {
/** Magic value indicating the absence of a port number. */
private static final int NO_PORT = -1;
@@ -86,7 +83,7 @@ public final class HostAndPort implements Serializable {
* Returns the portion of this {@code HostAndPort} instance that should
* represent the hostname or IPv4/IPv6 literal.
*
- * <p>A successful parse does not imply any degree of sanity in this field.
+ * A successful parse does not imply any degree of sanity in this field.
* For additional validation, see the {@link HostSpecifier} class.
*/
public String getHostText() {
@@ -174,7 +171,7 @@ public final class HostAndPort implements Serializable {
}
int port = NO_PORT;
- if (!Strings.isNullOrEmpty(portString)) {
+ if (portString != null) {
// Try to parse the whole port string as a number.
// JDK7 accepts leading plus signs. We don't want to.
checkArgument(!portString.startsWith("+"), "Unparseable port number: %s", hostPortString);
@@ -228,7 +225,7 @@ public final class HostAndPort implements Serializable {
}
@Override
- public boolean equals(@Nullable Object other) {
+ public boolean equals(Object other) {
if (this == other) {
return true;
}
@@ -265,6 +262,4 @@ public final class HostAndPort implements Serializable {
private static boolean isValidPort(int port) {
return port >= 0 && port <= 65535;
}
-
- private static final long serialVersionUID = 0;
}
diff --git a/guava/src/com/google/common/net/HttpHeaders.java b/guava/src/com/google/common/net/HttpHeaders.java
index ace1773..4bb6f9f 100644
--- a/guava/src/com/google/common/net/HttpHeaders.java
+++ b/guava/src/com/google/common/net/HttpHeaders.java
@@ -16,6 +16,7 @@
package com.google.common.net;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
/**
@@ -31,6 +32,7 @@ import com.google.common.annotations.GwtCompatible;
* @author Kurt Alfred Kluever
* @since 11.0
*/
+@Beta
@GwtCompatible
public final class HttpHeaders {
private HttpHeaders() {}
diff --git a/guava/src/com/google/common/net/InetAddresses.java b/guava/src/com/google/common/net/InetAddresses.java
index 8eddd0d..2cd9472 100644
--- a/guava/src/com/google/common/net/InetAddresses.java
+++ b/guava/src/com/google/common/net/InetAddresses.java
@@ -17,9 +17,8 @@
package com.google.common.net;
import com.google.common.annotations.Beta;
-import com.google.common.base.Objects;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
-import com.google.common.hash.Hashing;
import com.google.common.io.ByteStreams;
import com.google.common.primitives.Ints;
@@ -42,6 +41,12 @@ import javax.annotation.Nullable;
* IP address string literals -- there is no blocking DNS penalty for a
* malformed string.
*
+ * <p>This class hooks into the {@code sun.net.util.IPAddressUtil} class
+ * to make use of the {@code textToNumericFormatV4} and
+ * {@code textToNumericFormatV6} methods directly as a means to avoid
+ * accidentally traversing all nameservices (it can be vitally important
+ * to avoid, say, blocking on DNS at times).
+ *
* <p>When dealing with {@link Inet4Address} and {@link Inet6Address}
* objects as byte arrays (vis. {@code InetAddress.getAddress()}) they
* are 4 and 16 bytes in length, respectively, and represent the address
@@ -114,36 +119,68 @@ import javax.annotation.Nullable;
public final class InetAddresses {
private static final int IPV4_PART_COUNT = 4;
private static final int IPV6_PART_COUNT = 8;
- private static final Inet4Address LOOPBACK4 = (Inet4Address) forString("127.0.0.1");
- private static final Inet4Address ANY4 = (Inet4Address) forString("0.0.0.0");
+ private static final Inet4Address LOOPBACK4 =
+ (Inet4Address) forString("127.0.0.1");
+ private static final Inet4Address ANY4 =
+ (Inet4Address) forString("0.0.0.0");
private InetAddresses() {}
/**
- * Returns an {@link Inet4Address}, given a byte array representation of the IPv4 address.
+ * Returns an {@link Inet4Address}, given a byte array representation
+ * of the IPv4 address.
*
- * @param bytes byte array representing an IPv4 address (should be of length 4)
- * @return {@link Inet4Address} corresponding to the supplied byte array
- * @throws IllegalArgumentException if a valid {@link Inet4Address} can not be created
+ * @param bytes byte array representing an IPv4 address (should be
+ * of length 4).
+ * @return {@link Inet4Address} corresponding to the supplied byte
+ * array.
+ * @throws IllegalArgumentException if a valid {@link Inet4Address}
+ * can not be created.
*/
private static Inet4Address getInet4Address(byte[] bytes) {
Preconditions.checkArgument(bytes.length == 4,
"Byte array has invalid length for an IPv4 address: %s != 4.",
bytes.length);
- // Given a 4-byte array, this cast should always succeed.
- return (Inet4Address) bytesToInetAddress(bytes);
+ try {
+ InetAddress ipv4 = InetAddress.getByAddress(bytes);
+ if (!(ipv4 instanceof Inet4Address)) {
+ throw new UnknownHostException(
+ String.format("'%s' is not an IPv4 address.",
+ ipv4.getHostAddress()));
+ }
+
+ return (Inet4Address) ipv4;
+ } catch (UnknownHostException e) {
+
+ /*
+ * This really shouldn't happen in practice since all our byte
+ * sequences should be valid IP addresses.
+ *
+ * However {@link InetAddress#getByAddress} is documented as
+ * potentially throwing this "if IP address is of illegal length".
+ *
+ * This is mapped to IllegalArgumentException since, presumably,
+ * the argument triggered some bizarre processing bug.
+ */
+ throw new IllegalArgumentException(
+ String.format("Host address '%s' is not a valid IPv4 address.",
+ Arrays.toString(bytes)),
+ e);
+ }
}
/**
- * Returns the {@link InetAddress} having the given string representation.
+ * Returns the {@link InetAddress} having the given string
+ * representation.
*
* <p>This deliberately avoids all nameservice lookups (e.g. no DNS).
*
- * @param ipString {@code String} containing an IPv4 or IPv6 string literal, e.g.
- * {@code "192.168.0.1"} or {@code "2001:db8::1"}
+ * @param ipString {@code String} containing an IPv4 or IPv6 string literal,
+ * e.g. {@code "192.168.0.1"} or {@code "2001:db8::1"}
* @return {@link InetAddress} representing the argument
- * @throws IllegalArgumentException if the argument is not a valid IP string literal
+ * @throws IllegalArgumentException if the argument is not a valid
+ * IP string literal
*/
public static InetAddress forString(String ipString) {
byte[] addr = ipStringToBytes(ipString);
@@ -154,7 +191,25 @@ public final class InetAddresses {
String.format("'%s' is not an IP string literal.", ipString));
}
- return bytesToInetAddress(addr);
+ try {
+ return InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {
+
+ /*
+ * This really shouldn't happen in practice since all our byte
+ * sequences should be valid IP addresses.
+ *
+ * However {@link InetAddress#getByAddress} is documented as
+ * potentially throwing this "if IP address is of illegal length".
+ *
+ * This is mapped to IllegalArgumentException since, presumably,
+ * the argument triggered some processing bug in either
+ * {@link IPAddressUtil#textToNumericFormatV4} or
+ * {@link IPAddressUtil#textToNumericFormatV6}.
+ */
+ throw new IllegalArgumentException(
+ String.format("'%s' is extremely broken.", ipString), e);
+ }
}
/**
@@ -316,25 +371,6 @@ public final class InetAddresses {
}
/**
- * Convert a byte array into an InetAddress.
- *
- * {@link InetAddress#getByAddress} is documented as throwing a checked
- * exception "if IP address if of illegal length." We replace it with
- * an unchecked exception, for use by callers who already know that addr
- * is an array of length 4 or 16.
- *
- * @param addr the raw 4-byte or 16-byte IP address in big-endian order
- * @return an InetAddress object created from the raw IP address
- */
- private static InetAddress bytesToInetAddress(byte[] addr) {
- try {
- return InetAddress.getByAddress(addr);
- } catch (UnknownHostException e) {
- throw new AssertionError(e);
- }
- }
-
- /**
* Returns the string representation of an {@link InetAddress}.
*
* <p>For IPv4 addresses, this is identical to
@@ -375,7 +411,7 @@ public final class InetAddresses {
* leftmost run wins. If a qualifying run is found, its hextets are replaced
* by the sentinel value -1.
*
- * @param hextets {@code int[]} mutable array of eight 16-bit hextets
+ * @param hextets {@code int[]} mutable array of eight 16-bit hextets.
*/
private static void compressLongestRunOfZeroes(int[] hextets) {
int bestRunStart = -1;
@@ -400,13 +436,13 @@ public final class InetAddresses {
}
}
- /**
+ /**
* Convert a list of hextets into a human-readable IPv6 address.
*
* <p>In order for "::" compression to work, the input should contain negative
* sentinel values in place of the elided zeroes.
*
- * @param hextets {@code int[]} array of eight 16-bit hextets, or -1s
+ * @param hextets {@code int[]} array of eight 16-bit hextets, or -1s.
*/
private static String hextetsToIPv6String(int[] hextets) {
/*
@@ -483,26 +519,30 @@ public final class InetAddresses {
*/
public static InetAddress forUriString(String hostAddr) {
Preconditions.checkNotNull(hostAddr);
+ Preconditions.checkArgument(hostAddr.length() > 0, "host string is empty");
+ InetAddress retval = null;
- // Decide if this should be an IPv6 or IPv4 address.
- String ipString;
- int expectBytes;
- if (hostAddr.startsWith("[") && hostAddr.endsWith("]")) {
- ipString = hostAddr.substring(1, hostAddr.length() - 1);
- expectBytes = 16;
- } else {
- ipString = hostAddr;
- expectBytes = 4;
+ // IPv4 address?
+ try {
+ retval = forString(hostAddr);
+ if (retval instanceof Inet4Address) {
+ return retval;
+ }
+ } catch (IllegalArgumentException e) {
+ // Not a valid IP address, fall through.
}
- // Parse the address, and make sure the length/version is correct.
- byte[] addr = ipStringToBytes(ipString);
- if (addr == null || addr.length != expectBytes) {
- throw new IllegalArgumentException(
- String.format("Not a valid URI IP literal: '%s'", hostAddr));
+ // IPv6 address
+ if (!(hostAddr.startsWith("[") && hostAddr.endsWith("]"))) {
+ throw new IllegalArgumentException("Not a valid address: \"" + hostAddr + '"');
+ }
+
+ retval = forString(hostAddr.substring(1, hostAddr.length() - 1));
+ if (retval instanceof Inet6Address) {
+ return retval;
}
- return bytesToInetAddress(addr);
+ throw new IllegalArgumentException("Not a valid address: \"" + hostAddr + '"');
}
/**
@@ -542,7 +582,8 @@ public final class InetAddresses {
* proper IPv6 addresses (which they are), NOT IPv4 compatible
* addresses (which they are generally NOT considered to be).
*
- * @param ip {@link Inet6Address} to be examined for embedded IPv4 compatible address format
+ * @param ip {@link Inet6Address} to be examined for embedded IPv4
+ * compatible address format
* @return {@code true} if the argument is a valid "compat" address
*/
public static boolean isCompatIPv4Address(Inet6Address ip) {
@@ -552,7 +593,7 @@ public final class InetAddresses {
byte[] bytes = ip.getAddress();
if ((bytes[12] == 0) && (bytes[13] == 0) && (bytes[14] == 0)
- && ((bytes[15] == 0) || (bytes[15] == 1))) {
+ && ((bytes[15] == 0) || (bytes[15] == 1))) {
return false;
}
@@ -562,15 +603,17 @@ public final class InetAddresses {
/**
* Returns the IPv4 address embedded in an IPv4 compatible address.
*
- * @param ip {@link Inet6Address} to be examined for an embedded IPv4 address
+ * @param ip {@link Inet6Address} to be examined for an embedded
+ * IPv4 address
* @return {@link Inet4Address} of the embedded IPv4 address
- * @throws IllegalArgumentException if the argument is not a valid IPv4 compatible address
+ * @throws IllegalArgumentException if the argument is not a valid
+ * IPv4 compatible address
*/
public static Inet4Address getCompatIPv4Address(Inet6Address ip) {
Preconditions.checkArgument(isCompatIPv4Address(ip),
"Address '%s' is not IPv4-compatible.", toAddrString(ip));
- return getInet4Address(Arrays.copyOfRange(ip.getAddress(), 12, 16));
+ return getInet4Address(copyOfRange(ip.getAddress(), 12, 16));
}
/**
@@ -584,7 +627,8 @@ public final class InetAddresses {
* <a target="_parent" href="http://tools.ietf.org/html/rfc3056#section-2"
* >http://tools.ietf.org/html/rfc3056</a>
*
- * @param ip {@link Inet6Address} to be examined for 6to4 address format
+ * @param ip {@link Inet6Address} to be examined for 6to4 address
+ * format
* @return {@code true} if the argument is a 6to4 address
*/
public static boolean is6to4Address(Inet6Address ip) {
@@ -595,19 +639,21 @@ public final class InetAddresses {
/**
* Returns the IPv4 address embedded in a 6to4 address.
*
- * @param ip {@link Inet6Address} to be examined for embedded IPv4 in 6to4 address
- * @return {@link Inet4Address} of embedded IPv4 in 6to4 address
- * @throws IllegalArgumentException if the argument is not a valid IPv6 6to4 address
+ * @param ip {@link Inet6Address} to be examined for embedded IPv4
+ * in 6to4 address.
+ * @return {@link Inet4Address} of embedded IPv4 in 6to4 address.
+ * @throws IllegalArgumentException if the argument is not a valid
+ * IPv6 6to4 address.
*/
public static Inet4Address get6to4IPv4Address(Inet6Address ip) {
Preconditions.checkArgument(is6to4Address(ip),
"Address '%s' is not a 6to4 address.", toAddrString(ip));
- return getInet4Address(Arrays.copyOfRange(ip.getAddress(), 2, 6));
+ return getInet4Address(copyOfRange(ip.getAddress(), 2, 6));
}
/**
- * A simple immutable data class to encapsulate the information to be found in a
+ * A simple data class to encapsulate the information to be found in a
* Teredo address.
*
* <p>All of the fields in this class are encoded in various portions
@@ -635,19 +681,31 @@ public final class InetAddresses {
* <p>Both server and client can be {@code null}, in which case the
* value {@code "0.0.0.0"} will be assumed.
*
- * @throws IllegalArgumentException if either of the {@code port} or the {@code flags}
- * arguments are out of range of an unsigned short
+ * @throws IllegalArgumentException if either of the {@code port}
+ * or the {@code flags} arguments are out of range of an
+ * unsigned short
*/
// TODO: why is this public?
- public TeredoInfo(
- @Nullable Inet4Address server, @Nullable Inet4Address client, int port, int flags) {
+ public TeredoInfo(@Nullable Inet4Address server,
+ @Nullable Inet4Address client,
+ int port, int flags) {
Preconditions.checkArgument((port >= 0) && (port <= 0xffff),
"port '%s' is out of range (0 <= port <= 0xffff)", port);
Preconditions.checkArgument((flags >= 0) && (flags <= 0xffff),
"flags '%s' is out of range (0 <= flags <= 0xffff)", flags);
-
- this.server = Objects.firstNonNull(server, ANY4);
- this.client = Objects.firstNonNull(client, ANY4);
+
+ if (server != null) {
+ this.server = server;
+ } else {
+ this.server = ANY4;
+ }
+
+ if (client != null) {
+ this.client = client;
+ } else {
+ this.client = ANY4;
+ }
+
this.port = port;
this.flags = flags;
}
@@ -674,7 +732,8 @@ public final class InetAddresses {
*
* <p>Teredo addresses begin with the {@code "2001::/32"} prefix.
*
- * @param ip {@link Inet6Address} to be examined for Teredo address format
+ * @param ip {@link Inet6Address} to be examined for Teredo address
+ * format.
* @return {@code true} if the argument is a Teredo address
*/
public static boolean isTeredoAddress(Inet6Address ip) {
@@ -686,23 +745,25 @@ public final class InetAddresses {
/**
* Returns the Teredo information embedded in a Teredo address.
*
- * @param ip {@link Inet6Address} to be examined for embedded Teredo information
+ * @param ip {@link Inet6Address} to be examined for embedded Teredo
+ * information
* @return extracted {@code TeredoInfo}
- * @throws IllegalArgumentException if the argument is not a valid IPv6 Teredo address
+ * @throws IllegalArgumentException if the argument is not a valid
+ * IPv6 Teredo address
*/
public static TeredoInfo getTeredoInfo(Inet6Address ip) {
Preconditions.checkArgument(isTeredoAddress(ip),
"Address '%s' is not a Teredo address.", toAddrString(ip));
byte[] bytes = ip.getAddress();
- Inet4Address server = getInet4Address(Arrays.copyOfRange(bytes, 4, 8));
+ Inet4Address server = getInet4Address(copyOfRange(bytes, 4, 8));
int flags = ByteStreams.newDataInput(bytes, 8).readShort() & 0xffff;
// Teredo obfuscates the mapped client port, per section 4 of the RFC.
int port = ~ByteStreams.newDataInput(bytes, 10).readShort() & 0xffff;
- byte[] clientBytes = Arrays.copyOfRange(bytes, 12, 16);
+ byte[] clientBytes = copyOfRange(bytes, 12, 16);
for (int i = 0; i < clientBytes.length; i++) {
// Teredo obfuscates the mapped client IP, per section 4 of the RFC.
clientBytes[i] = (byte) ~clientBytes[i];
@@ -724,7 +785,8 @@ public final class InetAddresses {
* <a target="_parent" href="http://tools.ietf.org/html/rfc5214#section-6.1"
* >http://tools.ietf.org/html/rfc5214</a>
*
- * @param ip {@link Inet6Address} to be examined for ISATAP address format
+ * @param ip {@link Inet6Address} to be examined for ISATAP address
+ * format.
* @return {@code true} if the argument is an ISATAP address
*/
public static boolean isIsatapAddress(Inet6Address ip) {
@@ -751,15 +813,17 @@ public final class InetAddresses {
/**
* Returns the IPv4 address embedded in an ISATAP address.
*
- * @param ip {@link Inet6Address} to be examined for embedded IPv4 in ISATAP address
+ * @param ip {@link Inet6Address} to be examined for embedded IPv4
+ * in ISATAP address
* @return {@link Inet4Address} of embedded IPv4 in an ISATAP address
- * @throws IllegalArgumentException if the argument is not a valid IPv6 ISATAP address
+ * @throws IllegalArgumentException if the argument is not a valid
+ * IPv6 ISATAP address
*/
public static Inet4Address getIsatapIPv4Address(Inet6Address ip) {
Preconditions.checkArgument(isIsatapAddress(ip),
"Address '%s' is not an ISATAP address.", toAddrString(ip));
- return getInet4Address(Arrays.copyOfRange(ip.getAddress(), 12, 16));
+ return getInet4Address(copyOfRange(ip.getAddress(), 12, 16));
}
/**
@@ -770,12 +834,14 @@ public final class InetAddresses {
* due to their trivial spoofability. With other transition addresses
* spoofing involves (at least) infection of one's BGP routing table.
*
- * @param ip {@link Inet6Address} to be examined for embedded IPv4 client address
- * @return {@code true} if there is an embedded IPv4 client address
+ * @param ip {@link Inet6Address} to be examined for embedded IPv4
+ * client address.
+ * @return {@code true} if there is an embedded IPv4 client address.
* @since 7.0
*/
public static boolean hasEmbeddedIPv4ClientAddress(Inet6Address ip) {
- return isCompatIPv4Address(ip) || is6to4Address(ip) || isTeredoAddress(ip);
+ return isCompatIPv4Address(ip) || is6to4Address(ip) ||
+ isTeredoAddress(ip);
}
/**
@@ -787,9 +853,11 @@ public final class InetAddresses {
* due to their trivial spoofability. With other transition addresses
* spoofing involves (at least) infection of one's BGP routing table.
*
- * @param ip {@link Inet6Address} to be examined for embedded IPv4 client address
- * @return {@link Inet4Address} of embedded IPv4 client address
- * @throws IllegalArgumentException if the argument does not have a valid embedded IPv4 address
+ * @param ip {@link Inet6Address} to be examined for embedded IPv4
+ * client address.
+ * @return {@link Inet4Address} of embedded IPv4 client address.
+ * @throws IllegalArgumentException if the argument does not have a valid
+ * embedded IPv4 address.
*/
public static Inet4Address getEmbeddedIPv4ClientAddress(Inet6Address ip) {
if (isCompatIPv4Address(ip)) {
@@ -805,7 +873,8 @@ public final class InetAddresses {
}
throw new IllegalArgumentException(
- String.format("'%s' has no embedded IPv4 address.", toAddrString(ip)));
+ String.format("'%s' has no embedded IPv4 address.",
+ toAddrString(ip)));
}
/**
@@ -826,7 +895,8 @@ public final class InetAddresses {
* {@link Inet6Address} methods, but it would be unwise to depend on such
* a poorly-documented feature.)
*
- * @param ipString {@code String} to be examined for embedded IPv4-mapped IPv6 address format
+ * @param ipString {@code String} to be examined for embedded IPv4-mapped
+ * IPv6 address format
* @return {@code true} if the argument is a valid "mapped" address
* @since 10.0
*/
@@ -899,7 +969,7 @@ public final class InetAddresses {
}
// Many strategies for hashing are possible. This might suffice for now.
- int coercedHash = Hashing.murmur3_32().hashLong(addressAsLong).asInt();
+ int coercedHash = hash64To32(addressAsLong);
// Squash into 224/4 Multicast and 240/4 Reserved space (i.e. 224/3).
coercedHash |= 0xe0000000;
@@ -914,6 +984,27 @@ public final class InetAddresses {
}
/**
+ * Returns an {@code int} hash of a 64-bit long.
+ *
+ * This comes from http://www.concentric.net/~ttwang/tech/inthash.htm
+ *
+ * This hash gives no guarantees on the cryptographic suitability nor the
+ * quality of randomness produced, and the mapping may change in the future.
+ *
+ * @param key A 64-bit number to hash
+ * @return {@code int} the input hashed into 32 bits
+ */
+ @VisibleForTesting static int hash64To32(long key) {
+ key = (~key) + (key << 18);
+ key = key ^ (key >>> 31);
+ key = key * 21;
+ key = key ^ (key >>> 11);
+ key = key + (key << 6);
+ key = key ^ (key >>> 22);
+ return (int) key;
+ }
+
+ /**
* Returns an integer representing an IPv4 address regardless of
* whether the supplied argument is an IPv4 address or not.
*
@@ -960,7 +1051,8 @@ public final class InetAddresses {
* @return an InetAddress object created from the raw IP address
* @throws UnknownHostException if IP address is of illegal length
*/
- public static InetAddress fromLittleEndianByteArray(byte[] addr) throws UnknownHostException {
+ public static InetAddress fromLittleEndianByteArray(byte[] addr)
+ throws UnknownHostException {
byte[] reversed = new byte[addr.length];
for (int i = 0; i < addr.length; i++) {
reversed[i] = addr[addr.length - i - 1];
@@ -973,8 +1065,9 @@ public final class InetAddresses {
* This method works for both IPv4 and IPv6 addresses.
*
* @param address the InetAddress to increment
- * @return a new InetAddress that is one more than the passed in address
- * @throws IllegalArgumentException if InetAddress is at the end of its range
+ * @return a new InetAddress that is one more than the passed in address.
+ * @throws IllegalArgumentException if InetAddress is at the end of its
+ * range.
* @since 10.0
*/
public static InetAddress increment(InetAddress address) {
@@ -988,7 +1081,11 @@ public final class InetAddresses {
Preconditions.checkArgument(i >= 0, "Incrementing %s would wrap.", address);
addr[i]++;
- return bytesToInetAddress(addr);
+ try {
+ return InetAddress.getByAddress(addr);
+ } catch (UnknownHostException e) {
+ throw new AssertionError(e);
+ }
}
/**
@@ -996,7 +1093,7 @@ public final class InetAddresses {
* ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff for IPv6.
*
* @return true if the InetAddress is either 255.255.255.255 for IPv4 or
- * ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff for IPv6
+ * ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff for IPv6.
* @since 10.0
*/
public static boolean isMaximum(InetAddress address) {
@@ -1008,4 +1105,19 @@ public final class InetAddresses {
}
return true;
}
+
+ /**
+ * This method emulates the Java 6 method
+ * {@code Arrays.copyOfRange(byte, int, int)}, which is not available in
+ * Java 5, and thus cannot be used in Guava code.
+ */
+ private static byte[] copyOfRange(byte[] original, int from, int to) {
+ Preconditions.checkNotNull(original);
+
+ int end = Math.min(to, original.length);
+ byte[] result = new byte[to - from];
+
+ System.arraycopy(original, from, result, 0, end - from);
+ return result;
+ }
}
diff --git a/guava/src/com/google/common/net/InternetDomainName.java b/guava/src/com/google/common/net/InternetDomainName.java
index 4ca6581..7537271 100644
--- a/guava/src/com/google/common/net/InternetDomainName.java
+++ b/guava/src/com/google/common/net/InternetDomainName.java
@@ -73,7 +73,7 @@ import javax.annotation.Nullable;
* @since 5.0
*/
@Beta
-@GwtCompatible
+@GwtCompatible(emulated = true)
public final class InternetDomainName {
private static final CharMatcher DOTS_MATCHER =
@@ -146,13 +146,11 @@ public final class InternetDomainName {
name = name.substring(0, name.length() - 1);
}
- checkArgument(name.length() <= MAX_LENGTH,
- "Domain name too long: '%s':", name);
+ checkArgument(name.length() <= MAX_LENGTH, "Domain name too long: '%s':", name);
this.name = name;
this.parts = ImmutableList.copyOf(DOT_SPLITTER.split(name));
- checkArgument(parts.size() <= MAX_PARTS,
- "Domain has too many parts: '%s'", name);
+ checkArgument(parts.size() <= MAX_PARTS, "Domain has too many parts: '%s'", name);
checkArgument(validateSyntax(parts), "Not a valid domain name: '%s'", name);
this.publicSuffixIndex = findPublicSuffix();
@@ -194,7 +192,7 @@ public final class InternetDomainName {
*
* @param domain A domain name (not IP address)
* @throws IllegalArgumentException if {@code name} is not syntactically valid
- * according to {@link #isValid}
+ * according to {@link #isValidLenient}
* @since 8.0 (previously named {@code from})
* @deprecated Use {@link #from(String)}
*/
diff --git a/guava/src/com/google/common/net/MediaType.java b/guava/src/com/google/common/net/MediaType.java
deleted file mode 100644
index bef306c..0000000
--- a/guava/src/com/google/common/net/MediaType.java
+++ /dev/null
@@ -1,703 +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.net;
-
-import static com.google.common.base.CharMatcher.ASCII;
-import static com.google.common.base.CharMatcher.JAVA_ISO_CONTROL;
-import static com.google.common.base.Charsets.UTF_8;
-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.base.Ascii;
-import com.google.common.base.CharMatcher;
-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.Optional;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultiset;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Multimaps;
-
-import java.nio.charset.Charset;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-
-/**
- * Represents an <a href="http://en.wikipedia.org/wiki/Internet_media_type">Internet Media Type</a>
- * (also known as a MIME Type or Content Type). This class also supports the concept of media ranges
- * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">defined by HTTP/1.1</a>.
- * As such, the {@code *} character is treated as a wildcard and is used to represent any acceptable
- * type or subtype value. A media type may not have wildcard type with a declared subtype. The
- * {@code *} character has no special meaning as part of a parameter. All values for type, subtype,
- * parameter attributes or parameter values must be valid according to RFCs
- * <a href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and
- * <a href="http://www.ietf.org/rfc/rfc2046.txt">2046</a>.
- *
- * <p>All portions of the media type that are case-insensitive (type, subtype, parameter attributes)
- * are normalized to lowercase. The value of the {@code charset} parameter is normalized to
- * lowercase, but all others are left as-is.
- *
- * <p>Note that this specifically does <strong>not</strong> represent the value of the MIME
- * {@code Content-Type} header and as such has no support for header-specific considerations such as
- * line folding and comments.
- *
- * <p>For media types that take a charset the predefined constants default to UTF-8 and have a
- * "_UTF_8" suffix. To get a version without a character set, use {@link #withoutParameters}.
- *
- * @since 12.0
- *
- * @author Gregory Kick
- */
-@Beta
-@GwtCompatible
-@Immutable
-public final class MediaType {
- private static final String CHARSET_ATTRIBUTE = "charset";
- private static final ImmutableListMultimap<String, String> UTF_8_CONSTANT_PARAMETERS =
- ImmutableListMultimap.of(CHARSET_ATTRIBUTE, Ascii.toLowerCase(UTF_8.name()));
-
- /** Matcher for type, subtype and attributes. */
- private static final CharMatcher TOKEN_MATCHER = ASCII.and(JAVA_ISO_CONTROL.negate())
- .and(CharMatcher.isNot(' '))
- .and(CharMatcher.noneOf("()<>@,;:\\\"/[]?="));
- private static final CharMatcher QUOTED_TEXT_MATCHER = ASCII
- .and(CharMatcher.noneOf("\"\\\r"));
- /*
- * This matches the same characters as linear-white-space from RFC 822, but we make no effort to
- * enforce any particular rules with regards to line folding as stated in the class docs.
- */
- private static final CharMatcher LINEAR_WHITE_SPACE = CharMatcher.anyOf(" \t\r\n");
-
- // TODO(gak): make these public?
- private static final String APPLICATION_TYPE = "application";
- private static final String AUDIO_TYPE = "audio";
- private static final String IMAGE_TYPE = "image";
- private static final String TEXT_TYPE = "text";
- private static final String VIDEO_TYPE = "video";
-
- private static final String WILDCARD = "*";
-
- /*
- * The following constants are grouped by their type and ordered alphabetically by the constant
- * name within that type. The constant name should be a sensible identifier that is closest to the
- * "common name" of the media. This is often, but not necessarily the same as the subtype.
- *
- * Be sure to declare all constants with the type and subtype in all lowercase.
- *
- * When adding constants, be sure to add an entry into the KNOWN_TYPES map. For types that
- * take a charset (e.g. all text/* types), default to UTF-8 and suffix with "_UTF_8".
- */
-
- public static final MediaType ANY_TYPE = createConstant(WILDCARD, WILDCARD);
- public static final MediaType ANY_TEXT_TYPE = createConstant(TEXT_TYPE, WILDCARD);
- public static final MediaType ANY_IMAGE_TYPE = createConstant(IMAGE_TYPE, WILDCARD);
- public static final MediaType ANY_AUDIO_TYPE = createConstant(AUDIO_TYPE, WILDCARD);
- public static final MediaType ANY_VIDEO_TYPE = createConstant(VIDEO_TYPE, WILDCARD);
- public static final MediaType ANY_APPLICATION_TYPE = createConstant(APPLICATION_TYPE, WILDCARD);
-
- /* text types */
- public static final MediaType CACHE_MANIFEST_UTF_8 =
- createConstantUtf8(TEXT_TYPE, "cache-manifest");
- public static final MediaType CSS_UTF_8 = createConstantUtf8(TEXT_TYPE, "css");
- public static final MediaType CSV_UTF_8 = createConstantUtf8(TEXT_TYPE, "csv");
- public static final MediaType HTML_UTF_8 = createConstantUtf8(TEXT_TYPE, "html");
- public static final MediaType I_CALENDAR_UTF_8 = createConstantUtf8(TEXT_TYPE, "calendar");
- public static final MediaType PLAIN_TEXT_UTF_8 = createConstantUtf8(TEXT_TYPE, "plain");
- /**
- * <a href="http://www.rfc-editor.org/rfc/rfc4329.txt">RFC 4329</a> declares
- * {@link #JAVASCRIPT_UTF_8 application/javascript} to be the correct media type for JavaScript,
- * but this may be necessary in certain situations for compatibility.
- */
- public static final MediaType TEXT_JAVASCRIPT_UTF_8 = createConstantUtf8(TEXT_TYPE, "javascript");
- public static final MediaType VCARD_UTF_8 = createConstantUtf8(TEXT_TYPE, "vcard");
- public static final MediaType WML_UTF_8 = createConstantUtf8(TEXT_TYPE, "vnd.wap.wml");
- /**
- * As described in <a href="http://www.ietf.org/rfc/rfc3023.txt">RFC 3023</a>, this constant
- * ({@code text/xml}) is used for XML documents that are "readable by casual users."
- * {@link #APPLICATION_XML_UTF_8} is provided for documents that are intended for applications.
- */
- public static final MediaType XML_UTF_8 = createConstantUtf8(TEXT_TYPE, "xml");
-
- /* image types */
- public static final MediaType BMP = createConstant(IMAGE_TYPE, "bmp");
- public static final MediaType GIF = createConstant(IMAGE_TYPE, "gif");
- public static final MediaType ICO = createConstant(IMAGE_TYPE, "vnd.microsoft.icon");
- public static final MediaType JPEG = createConstant(IMAGE_TYPE, "jpeg");
- public static final MediaType PNG = createConstant(IMAGE_TYPE, "png");
- public static final MediaType SVG_UTF_8 = createConstantUtf8(IMAGE_TYPE, "svg+xml");
- public static final MediaType TIFF = createConstant(IMAGE_TYPE, "tiff");
- public static final MediaType WEBP = createConstant(IMAGE_TYPE, "webp");
-
- /* audio types */
- public static final MediaType MP4_AUDIO = createConstant(AUDIO_TYPE, "mp4");
- public static final MediaType MPEG_AUDIO = createConstant(AUDIO_TYPE, "mpeg");
- public static final MediaType OGG_AUDIO = createConstant(AUDIO_TYPE, "ogg");
- public static final MediaType WEBM_AUDIO = createConstant(AUDIO_TYPE, "webm");
-
- /* video types */
- public static final MediaType MP4_VIDEO = createConstant(VIDEO_TYPE, "mp4");
- public static final MediaType MPEG_VIDEO = createConstant(VIDEO_TYPE, "mpeg");
- public static final MediaType OGG_VIDEO = createConstant(VIDEO_TYPE, "ogg");
- public static final MediaType QUICKTIME = createConstant(VIDEO_TYPE, "quicktime");
- public static final MediaType WEBM_VIDEO = createConstant(VIDEO_TYPE, "webm");
- public static final MediaType WMV = createConstant(VIDEO_TYPE, "x-ms-wmv");
-
- /* application types */
- /**
- * As described in <a href="http://www.ietf.org/rfc/rfc3023.txt">RFC 3023</a>, this constant
- * ({@code application/xml}) is used for XML documents that are "unreadable by casual users."
- * {@link #XML_UTF_8} is provided for documents that may be read by users.
- */
- public static final MediaType APPLICATION_XML_UTF_8 = createConstantUtf8(APPLICATION_TYPE, "xml");
- public static final MediaType ATOM_UTF_8 = createConstantUtf8(APPLICATION_TYPE, "atom+xml");
- public static final MediaType BZIP2 = createConstant(APPLICATION_TYPE, "x-bzip2");
- public static final MediaType FORM_DATA = createConstant(APPLICATION_TYPE,
- "x-www-form-urlencoded");
- /**
- * This is a non-standard media type, but is commonly used in serving hosted binary files as it is
- * <a href="http://code.google.com/p/browsersec/wiki/Part2#Survey_of_content_sniffing_behaviors">
- * known not to trigger content sniffing in current browsers</a>. It <i>should not</i> be used in
- * other situations as it is not specified by any RFC and does not appear in the <a href=
- * "http://www.iana.org/assignments/media-types">/IANA MIME Media Types</a> list. Consider
- * {@link #OCTET_STREAM} for binary data that is not being served to a browser.
- *
- *
- * @since 14.0
- */
- public static final MediaType APPLICATION_BINARY = createConstant(APPLICATION_TYPE, "binary");
- public static final MediaType GZIP = createConstant(APPLICATION_TYPE, "x-gzip");
- /**
- * <a href="http://www.rfc-editor.org/rfc/rfc4329.txt">RFC 4329</a> declares this to be the
- * correct media type for JavaScript, but {@link #TEXT_JAVASCRIPT_UTF_8 text/javascript} may be
- * necessary in certain situations for compatibility.
- */
- public static final MediaType JAVASCRIPT_UTF_8 =
- createConstantUtf8(APPLICATION_TYPE, "javascript");
- public static final MediaType JSON_UTF_8 = createConstantUtf8(APPLICATION_TYPE, "json");
- public static final MediaType KML = createConstant(APPLICATION_TYPE, "vnd.google-earth.kml+xml");
- public static final MediaType KMZ = createConstant(APPLICATION_TYPE, "vnd.google-earth.kmz");
- public static final MediaType MBOX = createConstant(APPLICATION_TYPE, "mbox");
- public static final MediaType MICROSOFT_EXCEL = createConstant(APPLICATION_TYPE, "vnd.ms-excel");
- public static final MediaType MICROSOFT_POWERPOINT =
- createConstant(APPLICATION_TYPE, "vnd.ms-powerpoint");
- public static final MediaType MICROSOFT_WORD = createConstant(APPLICATION_TYPE, "msword");
- public static final MediaType OCTET_STREAM = createConstant(APPLICATION_TYPE, "octet-stream");
- public static final MediaType OGG_CONTAINER = createConstant(APPLICATION_TYPE, "ogg");
- public static final MediaType OOXML_DOCUMENT = createConstant(APPLICATION_TYPE,
- "vnd.openxmlformats-officedocument.wordprocessingml.document");
- public static final MediaType OOXML_PRESENTATION = createConstant(APPLICATION_TYPE,
- "vnd.openxmlformats-officedocument.presentationml.presentation");
- public static final MediaType OOXML_SHEET =
- createConstant(APPLICATION_TYPE, "vnd.openxmlformats-officedocument.spreadsheetml.sheet");
- public static final MediaType OPENDOCUMENT_GRAPHICS =
- createConstant(APPLICATION_TYPE, "vnd.oasis.opendocument.graphics");
- public static final MediaType OPENDOCUMENT_PRESENTATION =
- createConstant(APPLICATION_TYPE, "vnd.oasis.opendocument.presentation");
- public static final MediaType OPENDOCUMENT_SPREADSHEET =
- createConstant(APPLICATION_TYPE, "vnd.oasis.opendocument.spreadsheet");
- public static final MediaType OPENDOCUMENT_TEXT =
- createConstant(APPLICATION_TYPE, "vnd.oasis.opendocument.text");
- public static final MediaType PDF = createConstant(APPLICATION_TYPE, "pdf");
- public static final MediaType POSTSCRIPT = createConstant(APPLICATION_TYPE, "postscript");
- public static final MediaType RDF_XML_UTF_8 = createConstantUtf8(APPLICATION_TYPE, "rdf+xml");
- public static final MediaType RTF_UTF_8 = createConstantUtf8(APPLICATION_TYPE, "rtf");
- public static final MediaType SHOCKWAVE_FLASH = createConstant(APPLICATION_TYPE,
- "x-shockwave-flash");
- public static final MediaType SKETCHUP = createConstant(APPLICATION_TYPE, "vnd.sketchup.skp");
- public static final MediaType TAR = createConstant(APPLICATION_TYPE, "x-tar");
- public static final MediaType XHTML_UTF_8 = createConstantUtf8(APPLICATION_TYPE, "xhtml+xml");
- /**
- * Media type for Extensible Resource Descriptors. This is not yet registered with the IANA, but
- * it is specified by OASIS in the
- * <a href="http://docs.oasis-open.org/xri/xrd/v1.0/cd02/xrd-1.0-cd02.html"> XRD definition</a>
- * and implemented in projects such as
- * <a href="http://code.google.com/p/webfinger/">WebFinger</a>.
- */
- public static final MediaType XRD_UTF_8 = createConstantUtf8(APPLICATION_TYPE, "xrd+xml");
- public static final MediaType ZIP = createConstant(APPLICATION_TYPE, "zip");
-
- private static final ImmutableMap<MediaType, MediaType> KNOWN_TYPES =
- new ImmutableMap.Builder<MediaType, MediaType>()
- .put(ANY_TYPE, ANY_TYPE)
- .put(ANY_TEXT_TYPE, ANY_TEXT_TYPE)
- .put(ANY_IMAGE_TYPE, ANY_IMAGE_TYPE)
- .put(ANY_AUDIO_TYPE, ANY_AUDIO_TYPE)
- .put(ANY_VIDEO_TYPE, ANY_VIDEO_TYPE)
- .put(ANY_APPLICATION_TYPE, ANY_APPLICATION_TYPE)
- /* text types */
- .put(CACHE_MANIFEST_UTF_8, CACHE_MANIFEST_UTF_8)
- .put(CSS_UTF_8, CSS_UTF_8)
- .put(CSV_UTF_8, CSV_UTF_8)
- .put(HTML_UTF_8, HTML_UTF_8)
- .put(I_CALENDAR_UTF_8, I_CALENDAR_UTF_8)
- .put(PLAIN_TEXT_UTF_8, PLAIN_TEXT_UTF_8)
- .put(TEXT_JAVASCRIPT_UTF_8, TEXT_JAVASCRIPT_UTF_8)
- .put(VCARD_UTF_8, VCARD_UTF_8)
- .put(WML_UTF_8, WML_UTF_8)
- .put(XML_UTF_8, XML_UTF_8)
- /* image types */
- .put(BMP, BMP)
- .put(GIF, GIF)
- .put(ICO, ICO)
- .put(JPEG, JPEG)
- .put(PNG, PNG)
- .put(SVG_UTF_8, SVG_UTF_8)
- .put(TIFF, TIFF)
- .put(WEBP, WEBP)
- /* audio types */
- .put(MP4_AUDIO, MP4_AUDIO)
- .put(MPEG_AUDIO, MPEG_AUDIO)
- .put(OGG_AUDIO, OGG_AUDIO)
- .put(WEBM_AUDIO, WEBM_AUDIO)
- /* video types */
- .put(MP4_VIDEO, MP4_VIDEO)
- .put(MPEG_VIDEO, MPEG_VIDEO)
- .put(OGG_VIDEO, OGG_VIDEO)
- .put(QUICKTIME, QUICKTIME)
- .put(WEBM_VIDEO, WEBM_VIDEO)
- .put(WMV, WMV)
- /* application types */
- .put(APPLICATION_XML_UTF_8, APPLICATION_XML_UTF_8)
- .put(ATOM_UTF_8, ATOM_UTF_8)
- .put(BZIP2, BZIP2)
- .put(FORM_DATA, FORM_DATA)
- .put(APPLICATION_BINARY, APPLICATION_BINARY)
- .put(GZIP, GZIP)
- .put(JAVASCRIPT_UTF_8, JAVASCRIPT_UTF_8)
- .put(JSON_UTF_8, JSON_UTF_8)
- .put(KML, KML)
- .put(KMZ, KMZ)
- .put(MBOX, MBOX)
- .put(MICROSOFT_EXCEL, MICROSOFT_EXCEL)
- .put(MICROSOFT_POWERPOINT, MICROSOFT_POWERPOINT)
- .put(MICROSOFT_WORD, MICROSOFT_WORD)
- .put(OCTET_STREAM, OCTET_STREAM)
- .put(OGG_CONTAINER, OGG_CONTAINER)
- .put(OOXML_DOCUMENT, OOXML_DOCUMENT)
- .put(OOXML_PRESENTATION, OOXML_PRESENTATION)
- .put(OOXML_SHEET, OOXML_SHEET)
- .put(OPENDOCUMENT_GRAPHICS, OPENDOCUMENT_GRAPHICS)
- .put(OPENDOCUMENT_PRESENTATION, OPENDOCUMENT_PRESENTATION)
- .put(OPENDOCUMENT_SPREADSHEET, OPENDOCUMENT_SPREADSHEET)
- .put(OPENDOCUMENT_TEXT, OPENDOCUMENT_TEXT)
- .put(PDF, PDF)
- .put(POSTSCRIPT, POSTSCRIPT)
- .put(RDF_XML_UTF_8, RDF_XML_UTF_8)
- .put(RTF_UTF_8, RTF_UTF_8)
- .put(SHOCKWAVE_FLASH, SHOCKWAVE_FLASH)
- .put(SKETCHUP, SKETCHUP)
- .put(TAR, TAR)
- .put(XHTML_UTF_8, XHTML_UTF_8)
- .put(XRD_UTF_8, XRD_UTF_8)
- .put(ZIP, ZIP)
- .build();
-
- private final String type;
- private final String subtype;
- private final ImmutableListMultimap<String, String> parameters;
-
- private MediaType(String type, String subtype,
- ImmutableListMultimap<String, String> parameters) {
- this.type = type;
- this.subtype = subtype;
- this.parameters = parameters;
- }
-
- private static MediaType createConstant(String type, String subtype) {
- return new MediaType(type, subtype, ImmutableListMultimap.<String, String>of());
- }
-
- private static MediaType createConstantUtf8(String type, String subtype) {
- return new MediaType(type, subtype, UTF_8_CONSTANT_PARAMETERS);
- }
-
- /** Returns the top-level media type. For example, {@code "text"} in {@code "text/plain"}. */
- public String type() {
- return type;
- }
-
- /** Returns the media subtype. For example, {@code "plain"} in {@code "text/plain"}. */
- public String subtype() {
- return subtype;
- }
-
- /** Returns a multimap containing the parameters of this media type. */
- public ImmutableListMultimap<String, String> parameters() {
- return parameters;
- }
-
- private Map<String, ImmutableMultiset<String>> parametersAsMap() {
- return Maps.transformValues(parameters.asMap(),
- new Function<Collection<String>, ImmutableMultiset<String>>() {
- @Override public ImmutableMultiset<String> apply(Collection<String> input) {
- return ImmutableMultiset.copyOf(input);
- }
- });
- }
-
- /**
- * Returns an optional charset for the value of the charset parameter if it is specified.
- *
- * @throws IllegalStateException if multiple charset values have been set for this media type
- * @throws IllegalCharsetNameException if a charset value is present, but illegal
- * @throws UnsupportedCharsetException if a charset value is present, but no support is available
- * in this instance of the Java virtual machine
- */
- public Optional<Charset> charset() {
- ImmutableSet<String> charsetValues = ImmutableSet.copyOf(parameters.get(CHARSET_ATTRIBUTE));
- switch (charsetValues.size()) {
- case 0:
- return Optional.absent();
- case 1:
- return Optional.of(Charset.forName(Iterables.getOnlyElement(charsetValues)));
- default:
- throw new IllegalStateException("Multiple charset values defined: " + charsetValues);
- }
- }
-
- /**
- * Returns a new instance with the same type and subtype as this instance, but without any
- * parameters.
- */
- public MediaType withoutParameters() {
- return parameters.isEmpty() ? this : create(type, subtype);
- }
-
- /**
- * <em>Replaces</em> all parameters with the given parameters.
- *
- * @throws IllegalArgumentException if any parameter or value is invalid
- */
- public MediaType withParameters(Multimap<String, String> parameters) {
- return create(type, subtype, parameters);
- }
-
- /**
- * <em>Replaces</em> all parameters with the given attribute with a single parameter with the
- * given value. If multiple parameters with the same attributes are necessary use
- * {@link #withParameters}. Prefer {@link #withCharset} for setting the {@code charset} parameter
- * when using a {@link Charset} object.
- *
- * @throws IllegalArgumentException if either {@code attribute} or {@code value} is invalid
- */
- public MediaType withParameter(String attribute, String value) {
- checkNotNull(attribute);
- checkNotNull(value);
- String normalizedAttribute = normalizeToken(attribute);
- ImmutableListMultimap.Builder<String, String> builder = ImmutableListMultimap.builder();
- for (Entry<String, String> entry : parameters.entries()) {
- String key = entry.getKey();
- if (!normalizedAttribute.equals(key)) {
- builder.put(key, entry.getValue());
- }
- }
- builder.put(normalizedAttribute, normalizeParameterValue(normalizedAttribute, value));
- MediaType mediaType = new MediaType(type, subtype, builder.build());
- // Return one of the constants if the media type is a known type.
- return Objects.firstNonNull(KNOWN_TYPES.get(mediaType), mediaType);
- }
-
- /**
- * Returns a new instance with the same type and subtype as this instance, with the
- * {@code charset} parameter set to the {@link Charset#name name} of the given charset. Only one
- * {@code charset} parameter will be present on the new instance regardless of the number set on
- * this one.
- *
- * <p>If a charset must be specified that is not supported on this JVM (and thus is not
- * representable as a {@link Charset} instance, use {@link #withParameter}.
- */
- public MediaType withCharset(Charset charset) {
- checkNotNull(charset);
- return withParameter(CHARSET_ATTRIBUTE, charset.name());
- }
-
- /** Returns true if either the type or subtype is the wildcard. */
- public boolean hasWildcard() {
- return WILDCARD.equals(type) || WILDCARD.equals(subtype);
- }
-
- /**
- * Returns {@code true} if this instance falls within the range (as defined by
- * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">the HTTP Accept header</a>)
- * given by the argument according to three criteria:
- *
- * <ol>
- * <li>The type of the argument is the wildcard or equal to the type of this instance.
- * <li>The subtype of the argument is the wildcard or equal to the subtype of this instance.
- * <li>All of the parameters present in the argument are present in this instance.
- * </ol>
- *
- * For example: <pre> {@code
- * PLAIN_TEXT_UTF_8.is(PLAIN_TEXT_UTF_8) // true
- * PLAIN_TEXT_UTF_8.is(HTML_UTF_8) // false
- * PLAIN_TEXT_UTF_8.is(ANY_TYPE) // true
- * PLAIN_TEXT_UTF_8.is(ANY_TEXT_TYPE) // true
- * PLAIN_TEXT_UTF_8.is(ANY_IMAGE_TYPE) // false
- * PLAIN_TEXT_UTF_8.is(ANY_TEXT_TYPE.withCharset(UTF_8)) // true
- * PLAIN_TEXT_UTF_8.withoutParameters().is(ANY_TEXT_TYPE.withCharset(UTF_8)) // false
- * PLAIN_TEXT_UTF_8.is(ANY_TEXT_TYPE.withCharset(UTF_16)) // false}</pre>
- *
- * <p>Note that while it is possible to have the same parameter declared multiple times within a
- * media type this method does not consider the number of occurrences of a parameter. For
- * example, {@code "text/plain; charset=UTF-8"} satisfies
- * {@code "text/plain; charset=UTF-8; charset=UTF-8"}.
- */
- public boolean is(MediaType mediaTypeRange) {
- return (mediaTypeRange.type.equals(WILDCARD) || mediaTypeRange.type.equals(this.type))
- && (mediaTypeRange.subtype.equals(WILDCARD) || mediaTypeRange.subtype.equals(this.subtype))
- && this.parameters.entries().containsAll(mediaTypeRange.parameters.entries());
- }
-
- /**
- * Creates a new media type with the given type and subtype.
- *
- * @throws IllegalArgumentException if type or subtype is invalid or if a wildcard is used for the
- * type, but not the subtype.
- */
- public static MediaType create(String type, String subtype) {
- return create(type, subtype, ImmutableListMultimap.<String, String>of());
- }
-
- /**
- * Creates a media type with the "application" type and the given subtype.
- *
- * @throws IllegalArgumentException if subtype is invalid
- */
- static MediaType createApplicationType(String subtype) {
- return create(APPLICATION_TYPE, subtype);
- }
-
- /**
- * Creates a media type with the "audio" type and the given subtype.
- *
- * @throws IllegalArgumentException if subtype is invalid
- */
- static MediaType createAudioType(String subtype) {
- return create(AUDIO_TYPE, subtype);
- }
-
- /**
- * Creates a media type with the "image" type and the given subtype.
- *
- * @throws IllegalArgumentException if subtype is invalid
- */
- static MediaType createImageType(String subtype) {
- return create(IMAGE_TYPE, subtype);
- }
-
- /**
- * Creates a media type with the "text" type and the given subtype.
- *
- * @throws IllegalArgumentException if subtype is invalid
- */
- static MediaType createTextType(String subtype) {
- return create(TEXT_TYPE, subtype);
- }
-
- /**
- * Creates a media type with the "video" type and the given subtype.
- *
- * @throws IllegalArgumentException if subtype is invalid
- */
- static MediaType createVideoType(String subtype) {
- return create(VIDEO_TYPE, subtype);
- }
-
- private static MediaType create(String type, String subtype,
- Multimap<String, String> parameters) {
- checkNotNull(type);
- checkNotNull(subtype);
- checkNotNull(parameters);
- String normalizedType = normalizeToken(type);
- String normalizedSubtype = normalizeToken(subtype);
- checkArgument(!WILDCARD.equals(normalizedType) || WILDCARD.equals(normalizedSubtype),
- "A wildcard type cannot be used with a non-wildcard subtype");
- ImmutableListMultimap.Builder<String, String> builder = ImmutableListMultimap.builder();
- for (Entry<String, String> entry : parameters.entries()) {
- String attribute = normalizeToken(entry.getKey());
- builder.put(attribute, normalizeParameterValue(attribute, entry.getValue()));
- }
- MediaType mediaType = new MediaType(normalizedType, normalizedSubtype, builder.build());
- // Return one of the constants if the media type is a known type.
- return Objects.firstNonNull(KNOWN_TYPES.get(mediaType), mediaType);
- }
-
- private static String normalizeToken(String token) {
- checkArgument(TOKEN_MATCHER.matchesAllOf(token));
- return Ascii.toLowerCase(token);
- }
-
- private static String normalizeParameterValue(String attribute, String value) {
- return CHARSET_ATTRIBUTE.equals(attribute) ? Ascii.toLowerCase(value) : value;
- }
-
- /**
- * Parses a media type from its string representation.
- *
- * @throws IllegalArgumentException if the input is not parsable
- */
- public static MediaType parse(String input) {
- checkNotNull(input);
- Tokenizer tokenizer = new Tokenizer(input);
- try {
- String type = tokenizer.consumeToken(TOKEN_MATCHER);
- tokenizer.consumeCharacter('/');
- String subtype = tokenizer.consumeToken(TOKEN_MATCHER);
- ImmutableListMultimap.Builder<String, String> parameters = ImmutableListMultimap.builder();
- while (tokenizer.hasMore()) {
- tokenizer.consumeCharacter(';');
- tokenizer.consumeTokenIfPresent(LINEAR_WHITE_SPACE);
- String attribute = tokenizer.consumeToken(TOKEN_MATCHER);
- tokenizer.consumeCharacter('=');
- final String value;
- if ('"' == tokenizer.previewChar()) {
- tokenizer.consumeCharacter('"');
- StringBuilder valueBuilder = new StringBuilder();
- while ('"' != tokenizer.previewChar()) {
- if ('\\' == tokenizer.previewChar()) {
- tokenizer.consumeCharacter('\\');
- valueBuilder.append(tokenizer.consumeCharacter(ASCII));
- } else {
- valueBuilder.append(tokenizer.consumeToken(QUOTED_TEXT_MATCHER));
- }
- }
- value = valueBuilder.toString();
- tokenizer.consumeCharacter('"');
- } else {
- value = tokenizer.consumeToken(TOKEN_MATCHER);
- }
- parameters.put(attribute, value);
- }
- return create(type, subtype, parameters.build());
- } catch (IllegalStateException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- private static final class Tokenizer {
- final String input;
- int position = 0;
-
- Tokenizer(String input) {
- this.input = input;
- }
-
- String consumeTokenIfPresent(CharMatcher matcher) {
- checkState(hasMore());
- int startPosition = position;
- position = matcher.negate().indexIn(input, startPosition);
- return hasMore() ? input.substring(startPosition, position) : input.substring(startPosition);
- }
-
- String consumeToken(CharMatcher matcher) {
- int startPosition = position;
- String token = consumeTokenIfPresent(matcher);
- checkState(position != startPosition);
- return token;
- }
-
- char consumeCharacter(CharMatcher matcher) {
- checkState(hasMore());
- char c = previewChar();
- checkState(matcher.matches(c));
- position++;
- return c;
- }
-
- char consumeCharacter(char c) {
- checkState(hasMore());
- checkState(previewChar() == c);
- position++;
- return c;
- }
-
- char previewChar() {
- checkState(hasMore());
- return input.charAt(position);
- }
-
- boolean hasMore() {
- return (position >= 0) && (position < input.length());
- }
- }
-
- @Override public boolean equals(@Nullable Object obj) {
- if (obj == this) {
- return true;
- } else if (obj instanceof MediaType) {
- MediaType that = (MediaType) obj;
- return this.type.equals(that.type)
- && this.subtype.equals(that.subtype)
- // compare parameters regardless of order
- && this.parametersAsMap().equals(that.parametersAsMap());
- } else {
- return false;
- }
- }
-
- @Override public int hashCode() {
- return Objects.hashCode(type, subtype, parametersAsMap());
- }
-
- private static final MapJoiner PARAMETER_JOINER = Joiner.on("; ").withKeyValueSeparator("=");
-
- /**
- * Returns the string representation of this media type in the format described in <a
- * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
- */
- @Override public String toString() {
- StringBuilder builder = new StringBuilder().append(type).append('/').append(subtype);
- if (!parameters.isEmpty()) {
- builder.append("; ");
- Multimap<String, String> quotedParameters = Multimaps.transformValues(parameters,
- new Function<String, String>() {
- @Override public String apply(String value) {
- return TOKEN_MATCHER.matchesAllOf(value) ? value : escapeAndQuote(value);
- }
- });
- PARAMETER_JOINER.appendTo(builder, quotedParameters.entries());
- }
- return builder.toString();
- }
-
- private static String escapeAndQuote(String value) {
- StringBuilder escaped = new StringBuilder(value.length() + 16).append('"');
- for (char ch : value.toCharArray()) {
- if (ch == '\r' || ch == '\\' || ch == '"') {
- escaped.append('\\');
- }
- escaped.append(ch);
- }
- return escaped.append('"').toString();
- }
-
-}
diff --git a/guava/src/com/google/common/net/TldPatterns.java b/guava/src/com/google/common/net/TldPatterns.java
index 6bc5bb2..879b34d 100644
--- a/guava/src/com/google/common/net/TldPatterns.java
+++ b/guava/src/com/google/common/net/TldPatterns.java
@@ -1,26 +1,11 @@
// GENERATED FILE - DO NOT EDIT
-/*
- * 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.net;
import com.google.common.annotations.GwtCompatible;
import com.google.common.collect.ImmutableSet;
+import java.util.Set;
/**
* A generated static class containing public members which provide domain
@@ -28,13 +13,15 @@ import com.google.common.collect.ImmutableSet;
* effective top-level domain (TLD).
*/
@GwtCompatible
-final class TldPatterns {
- private TldPatterns() {}
+class TldPatterns {
+ private TldPatterns() {
+ // Prevent instantiation.
+ }
/**
* If a hostname is contained in this set, it is a TLD.
*/
- static final ImmutableSet<String> EXACT = ImmutableSet.of(
+ static final Set<String> EXACT = ImmutableSet.of(
"ac",
"com.ac",
"edu.ac",
@@ -194,25 +181,9 @@ final class TldPatterns {
"co.at",
"gv.at",
"or.at",
- "com.au",
- "net.au",
- "org.au",
- "edu.au",
- "gov.au",
- "csiro.au",
- "asn.au",
- "id.au",
- "info.au",
- "conf.au",
- "oz.au",
- "act.au",
- "nsw.au",
- "nt.au",
- "qld.au",
- "sa.au",
- "tas.au",
- "vic.au",
- "wa.au",
+ "biz.at",
+ "info.at",
+ "priv.at",
"act.edu.au",
"nsw.edu.au",
"nt.edu.au",
@@ -228,6 +199,14 @@ final class TldPatterns {
"tas.gov.au",
"vic.gov.au",
"wa.gov.au",
+ "act.au",
+ "nsw.au",
+ "nt.au",
+ "qld.au",
+ "sa.au",
+ "tas.au",
+ "vic.au",
+ "wa.au",
"aw",
"com.aw",
"ax",
@@ -350,13 +329,13 @@ final class TldPatterns {
"bio.br",
"blog.br",
"bmd.br",
+ "can.br",
"cim.br",
"cng.br",
"cnt.br",
"com.br",
"coop.br",
"ecn.br",
- "eco.br",
"edu.br",
"emp.br",
"eng.br",
@@ -377,7 +356,6 @@ final class TldPatterns {
"inf.br",
"jor.br",
"jus.br",
- "leg.br",
"lel.br",
"mat.br",
"med.br",
@@ -477,8 +455,6 @@ final class TldPatterns {
"cl",
"gov.cl",
"gob.cl",
- "co.cl",
- "mil.cl",
"cm",
"gov.cm",
"cn",
@@ -544,6 +520,26 @@ final class TldPatterns {
"rec.co",
"web.co",
"com",
+ "ar.com",
+ "br.com",
+ "cn.com",
+ "de.com",
+ "eu.com",
+ "gb.com",
+ "hu.com",
+ "jpn.com",
+ "kr.com",
+ "no.com",
+ "qc.com",
+ "ru.com",
+ "sa.com",
+ "se.com",
+ "uk.com",
+ "us.com",
+ "uy.com",
+ "za.com",
+ "operaunite.com",
+ "appspot.com",
"coop",
"cr",
"ac.cr",
@@ -637,6 +633,7 @@ final class TldPatterns {
"eu",
"fi",
"aland.fi",
+ "iki.fi",
"fm",
"fo",
"fr",
@@ -1190,1732 +1187,6 @@ final class TldPatterns {
"lg.jp",
"ne.jp",
"or.jp",
- "aichi.jp",
- "akita.jp",
- "aomori.jp",
- "chiba.jp",
- "ehime.jp",
- "fukui.jp",
- "fukuoka.jp",
- "fukushima.jp",
- "gifu.jp",
- "gunma.jp",
- "hiroshima.jp",
- "hokkaido.jp",
- "hyogo.jp",
- "ibaraki.jp",
- "ishikawa.jp",
- "iwate.jp",
- "kagawa.jp",
- "kagoshima.jp",
- "kanagawa.jp",
- "kochi.jp",
- "kumamoto.jp",
- "kyoto.jp",
- "mie.jp",
- "miyagi.jp",
- "miyazaki.jp",
- "nagano.jp",
- "nagasaki.jp",
- "nara.jp",
- "niigata.jp",
- "oita.jp",
- "okayama.jp",
- "okinawa.jp",
- "osaka.jp",
- "saga.jp",
- "saitama.jp",
- "shiga.jp",
- "shimane.jp",
- "shizuoka.jp",
- "tochigi.jp",
- "tokushima.jp",
- "tokyo.jp",
- "tottori.jp",
- "toyama.jp",
- "wakayama.jp",
- "yamagata.jp",
- "yamaguchi.jp",
- "yamanashi.jp",
- "aisai.aichi.jp",
- "ama.aichi.jp",
- "anjo.aichi.jp",
- "asuke.aichi.jp",
- "chiryu.aichi.jp",
- "chita.aichi.jp",
- "fuso.aichi.jp",
- "gamagori.aichi.jp",
- "handa.aichi.jp",
- "hazu.aichi.jp",
- "hekinan.aichi.jp",
- "higashiura.aichi.jp",
- "ichinomiya.aichi.jp",
- "inazawa.aichi.jp",
- "inuyama.aichi.jp",
- "isshiki.aichi.jp",
- "iwakura.aichi.jp",
- "kanie.aichi.jp",
- "kariya.aichi.jp",
- "kasugai.aichi.jp",
- "kira.aichi.jp",
- "kiyosu.aichi.jp",
- "komaki.aichi.jp",
- "konan.aichi.jp",
- "kota.aichi.jp",
- "mihama.aichi.jp",
- "miyoshi.aichi.jp",
- "nagakute.aichi.jp",
- "nishio.aichi.jp",
- "nisshin.aichi.jp",
- "obu.aichi.jp",
- "oguchi.aichi.jp",
- "oharu.aichi.jp",
- "okazaki.aichi.jp",
- "owariasahi.aichi.jp",
- "seto.aichi.jp",
- "shikatsu.aichi.jp",
- "shinshiro.aichi.jp",
- "shitara.aichi.jp",
- "tahara.aichi.jp",
- "takahama.aichi.jp",
- "tobishima.aichi.jp",
- "toei.aichi.jp",
- "togo.aichi.jp",
- "tokai.aichi.jp",
- "tokoname.aichi.jp",
- "toyoake.aichi.jp",
- "toyohashi.aichi.jp",
- "toyokawa.aichi.jp",
- "toyone.aichi.jp",
- "toyota.aichi.jp",
- "tsushima.aichi.jp",
- "yatomi.aichi.jp",
- "akita.akita.jp",
- "daisen.akita.jp",
- "fujisato.akita.jp",
- "gojome.akita.jp",
- "hachirogata.akita.jp",
- "happou.akita.jp",
- "higashinaruse.akita.jp",
- "honjo.akita.jp",
- "honjyo.akita.jp",
- "ikawa.akita.jp",
- "kamikoani.akita.jp",
- "kamioka.akita.jp",
- "katagami.akita.jp",
- "kazuno.akita.jp",
- "kitaakita.akita.jp",
- "kosaka.akita.jp",
- "kyowa.akita.jp",
- "misato.akita.jp",
- "mitane.akita.jp",
- "moriyoshi.akita.jp",
- "nikaho.akita.jp",
- "noshiro.akita.jp",
- "odate.akita.jp",
- "oga.akita.jp",
- "ogata.akita.jp",
- "semboku.akita.jp",
- "yokote.akita.jp",
- "yurihonjo.akita.jp",
- "aomori.aomori.jp",
- "gonohe.aomori.jp",
- "hachinohe.aomori.jp",
- "hashikami.aomori.jp",
- "hiranai.aomori.jp",
- "hirosaki.aomori.jp",
- "itayanagi.aomori.jp",
- "kuroishi.aomori.jp",
- "misawa.aomori.jp",
- "mutsu.aomori.jp",
- "nakadomari.aomori.jp",
- "noheji.aomori.jp",
- "oirase.aomori.jp",
- "owani.aomori.jp",
- "rokunohe.aomori.jp",
- "sannohe.aomori.jp",
- "shichinohe.aomori.jp",
- "shingo.aomori.jp",
- "takko.aomori.jp",
- "towada.aomori.jp",
- "tsugaru.aomori.jp",
- "tsuruta.aomori.jp",
- "abiko.chiba.jp",
- "asahi.chiba.jp",
- "chonan.chiba.jp",
- "chosei.chiba.jp",
- "choshi.chiba.jp",
- "chuo.chiba.jp",
- "funabashi.chiba.jp",
- "futtsu.chiba.jp",
- "hanamigawa.chiba.jp",
- "ichihara.chiba.jp",
- "ichikawa.chiba.jp",
- "ichinomiya.chiba.jp",
- "inzai.chiba.jp",
- "isumi.chiba.jp",
- "kamagaya.chiba.jp",
- "kamogawa.chiba.jp",
- "kashiwa.chiba.jp",
- "katori.chiba.jp",
- "katsuura.chiba.jp",
- "kimitsu.chiba.jp",
- "kisarazu.chiba.jp",
- "kozaki.chiba.jp",
- "kujukuri.chiba.jp",
- "kyonan.chiba.jp",
- "matsudo.chiba.jp",
- "midori.chiba.jp",
- "mihama.chiba.jp",
- "minamiboso.chiba.jp",
- "mobara.chiba.jp",
- "mutsuzawa.chiba.jp",
- "nagara.chiba.jp",
- "nagareyama.chiba.jp",
- "narashino.chiba.jp",
- "narita.chiba.jp",
- "noda.chiba.jp",
- "oamishirasato.chiba.jp",
- "omigawa.chiba.jp",
- "onjuku.chiba.jp",
- "otaki.chiba.jp",
- "sakae.chiba.jp",
- "sakura.chiba.jp",
- "shimofusa.chiba.jp",
- "shirako.chiba.jp",
- "shiroi.chiba.jp",
- "shisui.chiba.jp",
- "sodegaura.chiba.jp",
- "sosa.chiba.jp",
- "tako.chiba.jp",
- "tateyama.chiba.jp",
- "togane.chiba.jp",
- "tohnosho.chiba.jp",
- "tomisato.chiba.jp",
- "urayasu.chiba.jp",
- "yachimata.chiba.jp",
- "yachiyo.chiba.jp",
- "yokaichiba.chiba.jp",
- "yokoshibahikari.chiba.jp",
- "yotsukaido.chiba.jp",
- "ainan.ehime.jp",
- "honai.ehime.jp",
- "ikata.ehime.jp",
- "imabari.ehime.jp",
- "iyo.ehime.jp",
- "kamijima.ehime.jp",
- "kihoku.ehime.jp",
- "kumakogen.ehime.jp",
- "masaki.ehime.jp",
- "matsuno.ehime.jp",
- "matsuyama.ehime.jp",
- "namikata.ehime.jp",
- "niihama.ehime.jp",
- "ozu.ehime.jp",
- "saijo.ehime.jp",
- "seiyo.ehime.jp",
- "shikokuchuo.ehime.jp",
- "tobe.ehime.jp",
- "toon.ehime.jp",
- "uchiko.ehime.jp",
- "uwajima.ehime.jp",
- "yawatahama.ehime.jp",
- "echizen.fukui.jp",
- "eiheiji.fukui.jp",
- "fukui.fukui.jp",
- "ikeda.fukui.jp",
- "katsuyama.fukui.jp",
- "mihama.fukui.jp",
- "minamiechizen.fukui.jp",
- "obama.fukui.jp",
- "ohi.fukui.jp",
- "ono.fukui.jp",
- "sabae.fukui.jp",
- "sakai.fukui.jp",
- "takahama.fukui.jp",
- "tsuruga.fukui.jp",
- "wakasa.fukui.jp",
- "ashiya.fukuoka.jp",
- "buzen.fukuoka.jp",
- "chikugo.fukuoka.jp",
- "chikuho.fukuoka.jp",
- "chikujo.fukuoka.jp",
- "chikushino.fukuoka.jp",
- "chikuzen.fukuoka.jp",
- "chuo.fukuoka.jp",
- "dazaifu.fukuoka.jp",
- "fukuchi.fukuoka.jp",
- "hakata.fukuoka.jp",
- "higashi.fukuoka.jp",
- "hirokawa.fukuoka.jp",
- "hisayama.fukuoka.jp",
- "iizuka.fukuoka.jp",
- "inatsuki.fukuoka.jp",
- "kaho.fukuoka.jp",
- "kasuga.fukuoka.jp",
- "kasuya.fukuoka.jp",
- "kawara.fukuoka.jp",
- "keisen.fukuoka.jp",
- "koga.fukuoka.jp",
- "kurate.fukuoka.jp",
- "kurogi.fukuoka.jp",
- "kurume.fukuoka.jp",
- "minami.fukuoka.jp",
- "miyako.fukuoka.jp",
- "miyama.fukuoka.jp",
- "miyawaka.fukuoka.jp",
- "mizumaki.fukuoka.jp",
- "munakata.fukuoka.jp",
- "nakagawa.fukuoka.jp",
- "nakama.fukuoka.jp",
- "nishi.fukuoka.jp",
- "nogata.fukuoka.jp",
- "ogori.fukuoka.jp",
- "okagaki.fukuoka.jp",
- "okawa.fukuoka.jp",
- "oki.fukuoka.jp",
- "omuta.fukuoka.jp",
- "onga.fukuoka.jp",
- "onojo.fukuoka.jp",
- "oto.fukuoka.jp",
- "saigawa.fukuoka.jp",
- "sasaguri.fukuoka.jp",
- "shingu.fukuoka.jp",
- "shinyoshitomi.fukuoka.jp",
- "shonai.fukuoka.jp",
- "soeda.fukuoka.jp",
- "sue.fukuoka.jp",
- "tachiarai.fukuoka.jp",
- "tagawa.fukuoka.jp",
- "takata.fukuoka.jp",
- "toho.fukuoka.jp",
- "toyotsu.fukuoka.jp",
- "tsuiki.fukuoka.jp",
- "ukiha.fukuoka.jp",
- "umi.fukuoka.jp",
- "usui.fukuoka.jp",
- "yamada.fukuoka.jp",
- "yame.fukuoka.jp",
- "yanagawa.fukuoka.jp",
- "yukuhashi.fukuoka.jp",
- "aizubange.fukushima.jp",
- "aizumisato.fukushima.jp",
- "aizuwakamatsu.fukushima.jp",
- "asakawa.fukushima.jp",
- "bandai.fukushima.jp",
- "date.fukushima.jp",
- "fukushima.fukushima.jp",
- "furudono.fukushima.jp",
- "futaba.fukushima.jp",
- "hanawa.fukushima.jp",
- "higashi.fukushima.jp",
- "hirata.fukushima.jp",
- "hirono.fukushima.jp",
- "iitate.fukushima.jp",
- "inawashiro.fukushima.jp",
- "ishikawa.fukushima.jp",
- "iwaki.fukushima.jp",
- "izumizaki.fukushima.jp",
- "kagamiishi.fukushima.jp",
- "kaneyama.fukushima.jp",
- "kawamata.fukushima.jp",
- "kitakata.fukushima.jp",
- "kitashiobara.fukushima.jp",
- "koori.fukushima.jp",
- "koriyama.fukushima.jp",
- "kunimi.fukushima.jp",
- "miharu.fukushima.jp",
- "mishima.fukushima.jp",
- "namie.fukushima.jp",
- "nango.fukushima.jp",
- "nishiaizu.fukushima.jp",
- "nishigo.fukushima.jp",
- "okuma.fukushima.jp",
- "omotego.fukushima.jp",
- "ono.fukushima.jp",
- "otama.fukushima.jp",
- "samegawa.fukushima.jp",
- "shimogo.fukushima.jp",
- "shirakawa.fukushima.jp",
- "showa.fukushima.jp",
- "soma.fukushima.jp",
- "sukagawa.fukushima.jp",
- "taishin.fukushima.jp",
- "tamakawa.fukushima.jp",
- "tanagura.fukushima.jp",
- "tenei.fukushima.jp",
- "yabuki.fukushima.jp",
- "yamato.fukushima.jp",
- "yamatsuri.fukushima.jp",
- "yanaizu.fukushima.jp",
- "yugawa.fukushima.jp",
- "anpachi.gifu.jp",
- "ena.gifu.jp",
- "gifu.gifu.jp",
- "ginan.gifu.jp",
- "godo.gifu.jp",
- "gujo.gifu.jp",
- "hashima.gifu.jp",
- "hichiso.gifu.jp",
- "hida.gifu.jp",
- "higashishirakawa.gifu.jp",
- "ibigawa.gifu.jp",
- "ikeda.gifu.jp",
- "kakamigahara.gifu.jp",
- "kani.gifu.jp",
- "kasahara.gifu.jp",
- "kasamatsu.gifu.jp",
- "kawaue.gifu.jp",
- "kitagata.gifu.jp",
- "mino.gifu.jp",
- "minokamo.gifu.jp",
- "mitake.gifu.jp",
- "mizunami.gifu.jp",
- "motosu.gifu.jp",
- "nakatsugawa.gifu.jp",
- "ogaki.gifu.jp",
- "sakahogi.gifu.jp",
- "seki.gifu.jp",
- "sekigahara.gifu.jp",
- "shirakawa.gifu.jp",
- "tajimi.gifu.jp",
- "takayama.gifu.jp",
- "tarui.gifu.jp",
- "toki.gifu.jp",
- "tomika.gifu.jp",
- "wanouchi.gifu.jp",
- "yamagata.gifu.jp",
- "yaotsu.gifu.jp",
- "yoro.gifu.jp",
- "annaka.gunma.jp",
- "chiyoda.gunma.jp",
- "fujioka.gunma.jp",
- "higashiagatsuma.gunma.jp",
- "isesaki.gunma.jp",
- "itakura.gunma.jp",
- "kanna.gunma.jp",
- "kanra.gunma.jp",
- "katashina.gunma.jp",
- "kawaba.gunma.jp",
- "kiryu.gunma.jp",
- "kusatsu.gunma.jp",
- "maebashi.gunma.jp",
- "meiwa.gunma.jp",
- "midori.gunma.jp",
- "minakami.gunma.jp",
- "naganohara.gunma.jp",
- "nakanojo.gunma.jp",
- "nanmoku.gunma.jp",
- "numata.gunma.jp",
- "oizumi.gunma.jp",
- "ora.gunma.jp",
- "ota.gunma.jp",
- "shibukawa.gunma.jp",
- "shimonita.gunma.jp",
- "shinto.gunma.jp",
- "showa.gunma.jp",
- "takasaki.gunma.jp",
- "takayama.gunma.jp",
- "tamamura.gunma.jp",
- "tatebayashi.gunma.jp",
- "tomioka.gunma.jp",
- "tsukiyono.gunma.jp",
- "tsumagoi.gunma.jp",
- "ueno.gunma.jp",
- "yoshioka.gunma.jp",
- "asaminami.hiroshima.jp",
- "daiwa.hiroshima.jp",
- "etajima.hiroshima.jp",
- "fuchu.hiroshima.jp",
- "fukuyama.hiroshima.jp",
- "hatsukaichi.hiroshima.jp",
- "higashihiroshima.hiroshima.jp",
- "hongo.hiroshima.jp",
- "jinsekikogen.hiroshima.jp",
- "kaita.hiroshima.jp",
- "kui.hiroshima.jp",
- "kumano.hiroshima.jp",
- "kure.hiroshima.jp",
- "mihara.hiroshima.jp",
- "miyoshi.hiroshima.jp",
- "naka.hiroshima.jp",
- "onomichi.hiroshima.jp",
- "osakikamijima.hiroshima.jp",
- "otake.hiroshima.jp",
- "saka.hiroshima.jp",
- "sera.hiroshima.jp",
- "seranishi.hiroshima.jp",
- "shinichi.hiroshima.jp",
- "shobara.hiroshima.jp",
- "takehara.hiroshima.jp",
- "abashiri.hokkaido.jp",
- "abira.hokkaido.jp",
- "aibetsu.hokkaido.jp",
- "akabira.hokkaido.jp",
- "akkeshi.hokkaido.jp",
- "asahikawa.hokkaido.jp",
- "ashibetsu.hokkaido.jp",
- "ashoro.hokkaido.jp",
- "assabu.hokkaido.jp",
- "atsuma.hokkaido.jp",
- "bibai.hokkaido.jp",
- "biei.hokkaido.jp",
- "bifuka.hokkaido.jp",
- "bihoro.hokkaido.jp",
- "biratori.hokkaido.jp",
- "chippubetsu.hokkaido.jp",
- "chitose.hokkaido.jp",
- "date.hokkaido.jp",
- "ebetsu.hokkaido.jp",
- "embetsu.hokkaido.jp",
- "eniwa.hokkaido.jp",
- "erimo.hokkaido.jp",
- "esan.hokkaido.jp",
- "esashi.hokkaido.jp",
- "fukagawa.hokkaido.jp",
- "fukushima.hokkaido.jp",
- "furano.hokkaido.jp",
- "furubira.hokkaido.jp",
- "haboro.hokkaido.jp",
- "hakodate.hokkaido.jp",
- "hamatonbetsu.hokkaido.jp",
- "hidaka.hokkaido.jp",
- "higashikagura.hokkaido.jp",
- "higashikawa.hokkaido.jp",
- "hiroo.hokkaido.jp",
- "hokuryu.hokkaido.jp",
- "hokuto.hokkaido.jp",
- "honbetsu.hokkaido.jp",
- "horokanai.hokkaido.jp",
- "horonobe.hokkaido.jp",
- "ikeda.hokkaido.jp",
- "imakane.hokkaido.jp",
- "ishikari.hokkaido.jp",
- "iwamizawa.hokkaido.jp",
- "iwanai.hokkaido.jp",
- "kamifurano.hokkaido.jp",
- "kamikawa.hokkaido.jp",
- "kamishihoro.hokkaido.jp",
- "kamisunagawa.hokkaido.jp",
- "kamoenai.hokkaido.jp",
- "kayabe.hokkaido.jp",
- "kembuchi.hokkaido.jp",
- "kikonai.hokkaido.jp",
- "kimobetsu.hokkaido.jp",
- "kitahiroshima.hokkaido.jp",
- "kitami.hokkaido.jp",
- "kiyosato.hokkaido.jp",
- "koshimizu.hokkaido.jp",
- "kunneppu.hokkaido.jp",
- "kuriyama.hokkaido.jp",
- "kuromatsunai.hokkaido.jp",
- "kushiro.hokkaido.jp",
- "kutchan.hokkaido.jp",
- "kyowa.hokkaido.jp",
- "mashike.hokkaido.jp",
- "matsumae.hokkaido.jp",
- "mikasa.hokkaido.jp",
- "minamifurano.hokkaido.jp",
- "mombetsu.hokkaido.jp",
- "moseushi.hokkaido.jp",
- "mukawa.hokkaido.jp",
- "muroran.hokkaido.jp",
- "naie.hokkaido.jp",
- "nakagawa.hokkaido.jp",
- "nakasatsunai.hokkaido.jp",
- "nakatombetsu.hokkaido.jp",
- "nanae.hokkaido.jp",
- "nanporo.hokkaido.jp",
- "nayoro.hokkaido.jp",
- "nemuro.hokkaido.jp",
- "niikappu.hokkaido.jp",
- "niki.hokkaido.jp",
- "nishiokoppe.hokkaido.jp",
- "noboribetsu.hokkaido.jp",
- "numata.hokkaido.jp",
- "obihiro.hokkaido.jp",
- "obira.hokkaido.jp",
- "oketo.hokkaido.jp",
- "okoppe.hokkaido.jp",
- "otaru.hokkaido.jp",
- "otobe.hokkaido.jp",
- "otofuke.hokkaido.jp",
- "otoineppu.hokkaido.jp",
- "oumu.hokkaido.jp",
- "ozora.hokkaido.jp",
- "pippu.hokkaido.jp",
- "rankoshi.hokkaido.jp",
- "rebun.hokkaido.jp",
- "rikubetsu.hokkaido.jp",
- "rishiri.hokkaido.jp",
- "rishirifuji.hokkaido.jp",
- "saroma.hokkaido.jp",
- "sarufutsu.hokkaido.jp",
- "shakotan.hokkaido.jp",
- "shari.hokkaido.jp",
- "shibecha.hokkaido.jp",
- "shibetsu.hokkaido.jp",
- "shikabe.hokkaido.jp",
- "shikaoi.hokkaido.jp",
- "shimamaki.hokkaido.jp",
- "shimizu.hokkaido.jp",
- "shimokawa.hokkaido.jp",
- "shinshinotsu.hokkaido.jp",
- "shintoku.hokkaido.jp",
- "shiranuka.hokkaido.jp",
- "shiraoi.hokkaido.jp",
- "shiriuchi.hokkaido.jp",
- "sobetsu.hokkaido.jp",
- "sunagawa.hokkaido.jp",
- "taiki.hokkaido.jp",
- "takasu.hokkaido.jp",
- "takikawa.hokkaido.jp",
- "takinoue.hokkaido.jp",
- "teshikaga.hokkaido.jp",
- "tobetsu.hokkaido.jp",
- "tohma.hokkaido.jp",
- "tomakomai.hokkaido.jp",
- "tomari.hokkaido.jp",
- "toya.hokkaido.jp",
- "toyako.hokkaido.jp",
- "toyotomi.hokkaido.jp",
- "toyoura.hokkaido.jp",
- "tsubetsu.hokkaido.jp",
- "tsukigata.hokkaido.jp",
- "urakawa.hokkaido.jp",
- "urausu.hokkaido.jp",
- "uryu.hokkaido.jp",
- "utashinai.hokkaido.jp",
- "wakkanai.hokkaido.jp",
- "wassamu.hokkaido.jp",
- "yakumo.hokkaido.jp",
- "yoichi.hokkaido.jp",
- "aioi.hyogo.jp",
- "akashi.hyogo.jp",
- "ako.hyogo.jp",
- "amagasaki.hyogo.jp",
- "aogaki.hyogo.jp",
- "asago.hyogo.jp",
- "ashiya.hyogo.jp",
- "awaji.hyogo.jp",
- "fukusaki.hyogo.jp",
- "goshiki.hyogo.jp",
- "harima.hyogo.jp",
- "himeji.hyogo.jp",
- "ichikawa.hyogo.jp",
- "inagawa.hyogo.jp",
- "itami.hyogo.jp",
- "kakogawa.hyogo.jp",
- "kamigori.hyogo.jp",
- "kamikawa.hyogo.jp",
- "kasai.hyogo.jp",
- "kasuga.hyogo.jp",
- "kawanishi.hyogo.jp",
- "miki.hyogo.jp",
- "minamiawaji.hyogo.jp",
- "nishinomiya.hyogo.jp",
- "nishiwaki.hyogo.jp",
- "ono.hyogo.jp",
- "sanda.hyogo.jp",
- "sannan.hyogo.jp",
- "sasayama.hyogo.jp",
- "sayo.hyogo.jp",
- "shingu.hyogo.jp",
- "shinonsen.hyogo.jp",
- "shiso.hyogo.jp",
- "sumoto.hyogo.jp",
- "taishi.hyogo.jp",
- "taka.hyogo.jp",
- "takarazuka.hyogo.jp",
- "takasago.hyogo.jp",
- "takino.hyogo.jp",
- "tamba.hyogo.jp",
- "tatsuno.hyogo.jp",
- "toyooka.hyogo.jp",
- "yabu.hyogo.jp",
- "yashiro.hyogo.jp",
- "yoka.hyogo.jp",
- "yokawa.hyogo.jp",
- "ami.ibaraki.jp",
- "asahi.ibaraki.jp",
- "bando.ibaraki.jp",
- "chikusei.ibaraki.jp",
- "daigo.ibaraki.jp",
- "fujishiro.ibaraki.jp",
- "hitachi.ibaraki.jp",
- "hitachinaka.ibaraki.jp",
- "hitachiomiya.ibaraki.jp",
- "hitachiota.ibaraki.jp",
- "ibaraki.ibaraki.jp",
- "ina.ibaraki.jp",
- "inashiki.ibaraki.jp",
- "itako.ibaraki.jp",
- "iwama.ibaraki.jp",
- "joso.ibaraki.jp",
- "kamisu.ibaraki.jp",
- "kasama.ibaraki.jp",
- "kashima.ibaraki.jp",
- "kasumigaura.ibaraki.jp",
- "koga.ibaraki.jp",
- "miho.ibaraki.jp",
- "mito.ibaraki.jp",
- "moriya.ibaraki.jp",
- "naka.ibaraki.jp",
- "namegata.ibaraki.jp",
- "oarai.ibaraki.jp",
- "ogawa.ibaraki.jp",
- "omitama.ibaraki.jp",
- "ryugasaki.ibaraki.jp",
- "sakai.ibaraki.jp",
- "sakuragawa.ibaraki.jp",
- "shimodate.ibaraki.jp",
- "shimotsuma.ibaraki.jp",
- "shirosato.ibaraki.jp",
- "sowa.ibaraki.jp",
- "suifu.ibaraki.jp",
- "takahagi.ibaraki.jp",
- "tamatsukuri.ibaraki.jp",
- "tokai.ibaraki.jp",
- "tomobe.ibaraki.jp",
- "tone.ibaraki.jp",
- "toride.ibaraki.jp",
- "tsuchiura.ibaraki.jp",
- "tsukuba.ibaraki.jp",
- "uchihara.ibaraki.jp",
- "ushiku.ibaraki.jp",
- "yachiyo.ibaraki.jp",
- "yamagata.ibaraki.jp",
- "yawara.ibaraki.jp",
- "yuki.ibaraki.jp",
- "anamizu.ishikawa.jp",
- "hakui.ishikawa.jp",
- "hakusan.ishikawa.jp",
- "kaga.ishikawa.jp",
- "kahoku.ishikawa.jp",
- "kanazawa.ishikawa.jp",
- "kawakita.ishikawa.jp",
- "komatsu.ishikawa.jp",
- "nakanoto.ishikawa.jp",
- "nanao.ishikawa.jp",
- "nomi.ishikawa.jp",
- "nonoichi.ishikawa.jp",
- "noto.ishikawa.jp",
- "shika.ishikawa.jp",
- "suzu.ishikawa.jp",
- "tsubata.ishikawa.jp",
- "tsurugi.ishikawa.jp",
- "uchinada.ishikawa.jp",
- "wajima.ishikawa.jp",
- "fudai.iwate.jp",
- "fujisawa.iwate.jp",
- "hanamaki.iwate.jp",
- "hiraizumi.iwate.jp",
- "hirono.iwate.jp",
- "ichinohe.iwate.jp",
- "ichinoseki.iwate.jp",
- "iwaizumi.iwate.jp",
- "iwate.iwate.jp",
- "joboji.iwate.jp",
- "kamaishi.iwate.jp",
- "kanegasaki.iwate.jp",
- "karumai.iwate.jp",
- "kawai.iwate.jp",
- "kitakami.iwate.jp",
- "kuji.iwate.jp",
- "kunohe.iwate.jp",
- "kuzumaki.iwate.jp",
- "miyako.iwate.jp",
- "mizusawa.iwate.jp",
- "morioka.iwate.jp",
- "ninohe.iwate.jp",
- "noda.iwate.jp",
- "ofunato.iwate.jp",
- "oshu.iwate.jp",
- "otsuchi.iwate.jp",
- "rikuzentakata.iwate.jp",
- "shiwa.iwate.jp",
- "shizukuishi.iwate.jp",
- "sumita.iwate.jp",
- "takizawa.iwate.jp",
- "tanohata.iwate.jp",
- "tono.iwate.jp",
- "yahaba.iwate.jp",
- "yamada.iwate.jp",
- "ayagawa.kagawa.jp",
- "higashikagawa.kagawa.jp",
- "kanonji.kagawa.jp",
- "kotohira.kagawa.jp",
- "manno.kagawa.jp",
- "marugame.kagawa.jp",
- "mitoyo.kagawa.jp",
- "naoshima.kagawa.jp",
- "sanuki.kagawa.jp",
- "tadotsu.kagawa.jp",
- "takamatsu.kagawa.jp",
- "tonosho.kagawa.jp",
- "uchinomi.kagawa.jp",
- "utazu.kagawa.jp",
- "zentsuji.kagawa.jp",
- "akune.kagoshima.jp",
- "amami.kagoshima.jp",
- "hioki.kagoshima.jp",
- "isa.kagoshima.jp",
- "isen.kagoshima.jp",
- "izumi.kagoshima.jp",
- "kagoshima.kagoshima.jp",
- "kanoya.kagoshima.jp",
- "kawanabe.kagoshima.jp",
- "kinko.kagoshima.jp",
- "kouyama.kagoshima.jp",
- "makurazaki.kagoshima.jp",
- "matsumoto.kagoshima.jp",
- "minamitane.kagoshima.jp",
- "nakatane.kagoshima.jp",
- "nishinoomote.kagoshima.jp",
- "satsumasendai.kagoshima.jp",
- "soo.kagoshima.jp",
- "tarumizu.kagoshima.jp",
- "yusui.kagoshima.jp",
- "aikawa.kanagawa.jp",
- "atsugi.kanagawa.jp",
- "ayase.kanagawa.jp",
- "chigasaki.kanagawa.jp",
- "ebina.kanagawa.jp",
- "fujisawa.kanagawa.jp",
- "hadano.kanagawa.jp",
- "hakone.kanagawa.jp",
- "hiratsuka.kanagawa.jp",
- "isehara.kanagawa.jp",
- "kaisei.kanagawa.jp",
- "kamakura.kanagawa.jp",
- "kiyokawa.kanagawa.jp",
- "matsuda.kanagawa.jp",
- "minamiashigara.kanagawa.jp",
- "miura.kanagawa.jp",
- "nakai.kanagawa.jp",
- "ninomiya.kanagawa.jp",
- "odawara.kanagawa.jp",
- "oi.kanagawa.jp",
- "oiso.kanagawa.jp",
- "sagamihara.kanagawa.jp",
- "samukawa.kanagawa.jp",
- "tsukui.kanagawa.jp",
- "yamakita.kanagawa.jp",
- "yamato.kanagawa.jp",
- "yokosuka.kanagawa.jp",
- "yugawara.kanagawa.jp",
- "zama.kanagawa.jp",
- "zushi.kanagawa.jp",
- "aki.kochi.jp",
- "geisei.kochi.jp",
- "hidaka.kochi.jp",
- "higashitsuno.kochi.jp",
- "ino.kochi.jp",
- "kagami.kochi.jp",
- "kami.kochi.jp",
- "kitagawa.kochi.jp",
- "kochi.kochi.jp",
- "mihara.kochi.jp",
- "motoyama.kochi.jp",
- "muroto.kochi.jp",
- "nahari.kochi.jp",
- "nakamura.kochi.jp",
- "nankoku.kochi.jp",
- "nishitosa.kochi.jp",
- "niyodogawa.kochi.jp",
- "ochi.kochi.jp",
- "okawa.kochi.jp",
- "otoyo.kochi.jp",
- "otsuki.kochi.jp",
- "sakawa.kochi.jp",
- "sukumo.kochi.jp",
- "susaki.kochi.jp",
- "tosa.kochi.jp",
- "tosashimizu.kochi.jp",
- "toyo.kochi.jp",
- "tsuno.kochi.jp",
- "umaji.kochi.jp",
- "yasuda.kochi.jp",
- "yusuhara.kochi.jp",
- "amakusa.kumamoto.jp",
- "arao.kumamoto.jp",
- "aso.kumamoto.jp",
- "choyo.kumamoto.jp",
- "gyokuto.kumamoto.jp",
- "hitoyoshi.kumamoto.jp",
- "kamiamakusa.kumamoto.jp",
- "kashima.kumamoto.jp",
- "kikuchi.kumamoto.jp",
- "kosa.kumamoto.jp",
- "kumamoto.kumamoto.jp",
- "mashiki.kumamoto.jp",
- "mifune.kumamoto.jp",
- "minamata.kumamoto.jp",
- "minamioguni.kumamoto.jp",
- "nagasu.kumamoto.jp",
- "nishihara.kumamoto.jp",
- "oguni.kumamoto.jp",
- "ozu.kumamoto.jp",
- "sumoto.kumamoto.jp",
- "takamori.kumamoto.jp",
- "uki.kumamoto.jp",
- "uto.kumamoto.jp",
- "yamaga.kumamoto.jp",
- "yamato.kumamoto.jp",
- "yatsushiro.kumamoto.jp",
- "ayabe.kyoto.jp",
- "fukuchiyama.kyoto.jp",
- "higashiyama.kyoto.jp",
- "ide.kyoto.jp",
- "ine.kyoto.jp",
- "joyo.kyoto.jp",
- "kameoka.kyoto.jp",
- "kamo.kyoto.jp",
- "kita.kyoto.jp",
- "kizu.kyoto.jp",
- "kumiyama.kyoto.jp",
- "kyotamba.kyoto.jp",
- "kyotanabe.kyoto.jp",
- "kyotango.kyoto.jp",
- "maizuru.kyoto.jp",
- "minami.kyoto.jp",
- "minamiyamashiro.kyoto.jp",
- "miyazu.kyoto.jp",
- "muko.kyoto.jp",
- "nagaokakyo.kyoto.jp",
- "nakagyo.kyoto.jp",
- "nantan.kyoto.jp",
- "oyamazaki.kyoto.jp",
- "sakyo.kyoto.jp",
- "seika.kyoto.jp",
- "tanabe.kyoto.jp",
- "uji.kyoto.jp",
- "ujitawara.kyoto.jp",
- "wazuka.kyoto.jp",
- "yamashina.kyoto.jp",
- "yawata.kyoto.jp",
- "asahi.mie.jp",
- "inabe.mie.jp",
- "ise.mie.jp",
- "kameyama.mie.jp",
- "kawagoe.mie.jp",
- "kiho.mie.jp",
- "kisosaki.mie.jp",
- "kiwa.mie.jp",
- "komono.mie.jp",
- "kumano.mie.jp",
- "kuwana.mie.jp",
- "matsusaka.mie.jp",
- "meiwa.mie.jp",
- "mihama.mie.jp",
- "minamiise.mie.jp",
- "misugi.mie.jp",
- "miyama.mie.jp",
- "nabari.mie.jp",
- "shima.mie.jp",
- "suzuka.mie.jp",
- "tado.mie.jp",
- "taiki.mie.jp",
- "taki.mie.jp",
- "tamaki.mie.jp",
- "toba.mie.jp",
- "tsu.mie.jp",
- "udono.mie.jp",
- "ureshino.mie.jp",
- "watarai.mie.jp",
- "yokkaichi.mie.jp",
- "furukawa.miyagi.jp",
- "higashimatsushima.miyagi.jp",
- "ishinomaki.miyagi.jp",
- "iwanuma.miyagi.jp",
- "kakuda.miyagi.jp",
- "kami.miyagi.jp",
- "kawasaki.miyagi.jp",
- "kesennuma.miyagi.jp",
- "marumori.miyagi.jp",
- "matsushima.miyagi.jp",
- "minamisanriku.miyagi.jp",
- "misato.miyagi.jp",
- "murata.miyagi.jp",
- "natori.miyagi.jp",
- "ogawara.miyagi.jp",
- "ohira.miyagi.jp",
- "onagawa.miyagi.jp",
- "osaki.miyagi.jp",
- "rifu.miyagi.jp",
- "semine.miyagi.jp",
- "shibata.miyagi.jp",
- "shichikashuku.miyagi.jp",
- "shikama.miyagi.jp",
- "shiogama.miyagi.jp",
- "shiroishi.miyagi.jp",
- "tagajo.miyagi.jp",
- "taiwa.miyagi.jp",
- "tome.miyagi.jp",
- "tomiya.miyagi.jp",
- "wakuya.miyagi.jp",
- "watari.miyagi.jp",
- "yamamoto.miyagi.jp",
- "zao.miyagi.jp",
- "aya.miyazaki.jp",
- "ebino.miyazaki.jp",
- "gokase.miyazaki.jp",
- "hyuga.miyazaki.jp",
- "kadogawa.miyazaki.jp",
- "kawaminami.miyazaki.jp",
- "kijo.miyazaki.jp",
- "kitagawa.miyazaki.jp",
- "kitakata.miyazaki.jp",
- "kitaura.miyazaki.jp",
- "kobayashi.miyazaki.jp",
- "kunitomi.miyazaki.jp",
- "kushima.miyazaki.jp",
- "mimata.miyazaki.jp",
- "miyakonojo.miyazaki.jp",
- "miyazaki.miyazaki.jp",
- "morotsuka.miyazaki.jp",
- "nichinan.miyazaki.jp",
- "nishimera.miyazaki.jp",
- "nobeoka.miyazaki.jp",
- "saito.miyazaki.jp",
- "shiiba.miyazaki.jp",
- "shintomi.miyazaki.jp",
- "takaharu.miyazaki.jp",
- "takanabe.miyazaki.jp",
- "takazaki.miyazaki.jp",
- "tsuno.miyazaki.jp",
- "achi.nagano.jp",
- "agematsu.nagano.jp",
- "anan.nagano.jp",
- "aoki.nagano.jp",
- "asahi.nagano.jp",
- "azumino.nagano.jp",
- "chikuhoku.nagano.jp",
- "chikuma.nagano.jp",
- "chino.nagano.jp",
- "fujimi.nagano.jp",
- "hakuba.nagano.jp",
- "hara.nagano.jp",
- "hiraya.nagano.jp",
- "iida.nagano.jp",
- "iijima.nagano.jp",
- "iiyama.nagano.jp",
- "iizuna.nagano.jp",
- "ikeda.nagano.jp",
- "ikusaka.nagano.jp",
- "ina.nagano.jp",
- "karuizawa.nagano.jp",
- "kawakami.nagano.jp",
- "kiso.nagano.jp",
- "kisofukushima.nagano.jp",
- "kitaaiki.nagano.jp",
- "komagane.nagano.jp",
- "komoro.nagano.jp",
- "matsukawa.nagano.jp",
- "matsumoto.nagano.jp",
- "miasa.nagano.jp",
- "minamiaiki.nagano.jp",
- "minamimaki.nagano.jp",
- "minamiminowa.nagano.jp",
- "minowa.nagano.jp",
- "miyada.nagano.jp",
- "miyota.nagano.jp",
- "mochizuki.nagano.jp",
- "nagano.nagano.jp",
- "nagawa.nagano.jp",
- "nagiso.nagano.jp",
- "nakagawa.nagano.jp",
- "nakano.nagano.jp",
- "nozawaonsen.nagano.jp",
- "obuse.nagano.jp",
- "ogawa.nagano.jp",
- "okaya.nagano.jp",
- "omachi.nagano.jp",
- "omi.nagano.jp",
- "ookuwa.nagano.jp",
- "ooshika.nagano.jp",
- "otaki.nagano.jp",
- "otari.nagano.jp",
- "sakae.nagano.jp",
- "sakaki.nagano.jp",
- "saku.nagano.jp",
- "sakuho.nagano.jp",
- "shimosuwa.nagano.jp",
- "shinanomachi.nagano.jp",
- "shiojiri.nagano.jp",
- "suwa.nagano.jp",
- "suzaka.nagano.jp",
- "takagi.nagano.jp",
- "takamori.nagano.jp",
- "takayama.nagano.jp",
- "tateshina.nagano.jp",
- "tatsuno.nagano.jp",
- "togakushi.nagano.jp",
- "togura.nagano.jp",
- "tomi.nagano.jp",
- "ueda.nagano.jp",
- "wada.nagano.jp",
- "yamagata.nagano.jp",
- "yamanouchi.nagano.jp",
- "yasaka.nagano.jp",
- "yasuoka.nagano.jp",
- "chijiwa.nagasaki.jp",
- "futsu.nagasaki.jp",
- "goto.nagasaki.jp",
- "hasami.nagasaki.jp",
- "hirado.nagasaki.jp",
- "iki.nagasaki.jp",
- "isahaya.nagasaki.jp",
- "kawatana.nagasaki.jp",
- "kuchinotsu.nagasaki.jp",
- "matsuura.nagasaki.jp",
- "nagasaki.nagasaki.jp",
- "obama.nagasaki.jp",
- "omura.nagasaki.jp",
- "oseto.nagasaki.jp",
- "saikai.nagasaki.jp",
- "sasebo.nagasaki.jp",
- "seihi.nagasaki.jp",
- "shimabara.nagasaki.jp",
- "shinkamigoto.nagasaki.jp",
- "togitsu.nagasaki.jp",
- "tsushima.nagasaki.jp",
- "unzen.nagasaki.jp",
- "ando.nara.jp",
- "gose.nara.jp",
- "heguri.nara.jp",
- "higashiyoshino.nara.jp",
- "ikaruga.nara.jp",
- "ikoma.nara.jp",
- "kamikitayama.nara.jp",
- "kanmaki.nara.jp",
- "kashiba.nara.jp",
- "kashihara.nara.jp",
- "katsuragi.nara.jp",
- "kawai.nara.jp",
- "kawakami.nara.jp",
- "kawanishi.nara.jp",
- "koryo.nara.jp",
- "kurotaki.nara.jp",
- "mitsue.nara.jp",
- "miyake.nara.jp",
- "nara.nara.jp",
- "nosegawa.nara.jp",
- "oji.nara.jp",
- "ouda.nara.jp",
- "oyodo.nara.jp",
- "sakurai.nara.jp",
- "sango.nara.jp",
- "shimoichi.nara.jp",
- "shimokitayama.nara.jp",
- "shinjo.nara.jp",
- "soni.nara.jp",
- "takatori.nara.jp",
- "tawaramoto.nara.jp",
- "tenkawa.nara.jp",
- "tenri.nara.jp",
- "uda.nara.jp",
- "yamatokoriyama.nara.jp",
- "yamatotakada.nara.jp",
- "yamazoe.nara.jp",
- "yoshino.nara.jp",
- "aga.niigata.jp",
- "agano.niigata.jp",
- "gosen.niigata.jp",
- "itoigawa.niigata.jp",
- "izumozaki.niigata.jp",
- "joetsu.niigata.jp",
- "kamo.niigata.jp",
- "kariwa.niigata.jp",
- "kashiwazaki.niigata.jp",
- "minamiuonuma.niigata.jp",
- "mitsuke.niigata.jp",
- "muika.niigata.jp",
- "murakami.niigata.jp",
- "myoko.niigata.jp",
- "nagaoka.niigata.jp",
- "niigata.niigata.jp",
- "ojiya.niigata.jp",
- "omi.niigata.jp",
- "sado.niigata.jp",
- "sanjo.niigata.jp",
- "seiro.niigata.jp",
- "seirou.niigata.jp",
- "sekikawa.niigata.jp",
- "shibata.niigata.jp",
- "tagami.niigata.jp",
- "tainai.niigata.jp",
- "tochio.niigata.jp",
- "tokamachi.niigata.jp",
- "tsubame.niigata.jp",
- "tsunan.niigata.jp",
- "uonuma.niigata.jp",
- "yahiko.niigata.jp",
- "yoita.niigata.jp",
- "yuzawa.niigata.jp",
- "beppu.oita.jp",
- "bungoono.oita.jp",
- "bungotakada.oita.jp",
- "hasama.oita.jp",
- "hiji.oita.jp",
- "himeshima.oita.jp",
- "hita.oita.jp",
- "kamitsue.oita.jp",
- "kokonoe.oita.jp",
- "kuju.oita.jp",
- "kunisaki.oita.jp",
- "kusu.oita.jp",
- "oita.oita.jp",
- "saiki.oita.jp",
- "taketa.oita.jp",
- "tsukumi.oita.jp",
- "usa.oita.jp",
- "usuki.oita.jp",
- "yufu.oita.jp",
- "akaiwa.okayama.jp",
- "asakuchi.okayama.jp",
- "bizen.okayama.jp",
- "hayashima.okayama.jp",
- "ibara.okayama.jp",
- "kagamino.okayama.jp",
- "kasaoka.okayama.jp",
- "kibichuo.okayama.jp",
- "kumenan.okayama.jp",
- "kurashiki.okayama.jp",
- "maniwa.okayama.jp",
- "misaki.okayama.jp",
- "nagi.okayama.jp",
- "niimi.okayama.jp",
- "nishiawakura.okayama.jp",
- "okayama.okayama.jp",
- "satosho.okayama.jp",
- "setouchi.okayama.jp",
- "shinjo.okayama.jp",
- "shoo.okayama.jp",
- "soja.okayama.jp",
- "takahashi.okayama.jp",
- "tamano.okayama.jp",
- "tsuyama.okayama.jp",
- "wake.okayama.jp",
- "yakage.okayama.jp",
- "aguni.okinawa.jp",
- "ginowan.okinawa.jp",
- "ginoza.okinawa.jp",
- "gushikami.okinawa.jp",
- "haebaru.okinawa.jp",
- "higashi.okinawa.jp",
- "hirara.okinawa.jp",
- "iheya.okinawa.jp",
- "ishigaki.okinawa.jp",
- "ishikawa.okinawa.jp",
- "itoman.okinawa.jp",
- "izena.okinawa.jp",
- "kadena.okinawa.jp",
- "kin.okinawa.jp",
- "kitadaito.okinawa.jp",
- "kitanakagusuku.okinawa.jp",
- "kumejima.okinawa.jp",
- "kunigami.okinawa.jp",
- "minamidaito.okinawa.jp",
- "motobu.okinawa.jp",
- "nago.okinawa.jp",
- "naha.okinawa.jp",
- "nakagusuku.okinawa.jp",
- "nakijin.okinawa.jp",
- "nanjo.okinawa.jp",
- "nishihara.okinawa.jp",
- "ogimi.okinawa.jp",
- "okinawa.okinawa.jp",
- "onna.okinawa.jp",
- "shimoji.okinawa.jp",
- "taketomi.okinawa.jp",
- "tarama.okinawa.jp",
- "tokashiki.okinawa.jp",
- "tomigusuku.okinawa.jp",
- "tonaki.okinawa.jp",
- "urasoe.okinawa.jp",
- "uruma.okinawa.jp",
- "yaese.okinawa.jp",
- "yomitan.okinawa.jp",
- "yonabaru.okinawa.jp",
- "yonaguni.okinawa.jp",
- "zamami.okinawa.jp",
- "abeno.osaka.jp",
- "chihayaakasaka.osaka.jp",
- "chuo.osaka.jp",
- "daito.osaka.jp",
- "fujiidera.osaka.jp",
- "habikino.osaka.jp",
- "hannan.osaka.jp",
- "higashiosaka.osaka.jp",
- "higashisumiyoshi.osaka.jp",
- "higashiyodogawa.osaka.jp",
- "hirakata.osaka.jp",
- "ibaraki.osaka.jp",
- "ikeda.osaka.jp",
- "izumi.osaka.jp",
- "izumiotsu.osaka.jp",
- "izumisano.osaka.jp",
- "kadoma.osaka.jp",
- "kaizuka.osaka.jp",
- "kanan.osaka.jp",
- "kashiwara.osaka.jp",
- "katano.osaka.jp",
- "kawachinagano.osaka.jp",
- "kishiwada.osaka.jp",
- "kita.osaka.jp",
- "kumatori.osaka.jp",
- "matsubara.osaka.jp",
- "minato.osaka.jp",
- "minoh.osaka.jp",
- "misaki.osaka.jp",
- "moriguchi.osaka.jp",
- "neyagawa.osaka.jp",
- "nishi.osaka.jp",
- "nose.osaka.jp",
- "osakasayama.osaka.jp",
- "sakai.osaka.jp",
- "sayama.osaka.jp",
- "sennan.osaka.jp",
- "settsu.osaka.jp",
- "shijonawate.osaka.jp",
- "shimamoto.osaka.jp",
- "suita.osaka.jp",
- "tadaoka.osaka.jp",
- "taishi.osaka.jp",
- "tajiri.osaka.jp",
- "takaishi.osaka.jp",
- "takatsuki.osaka.jp",
- "tondabayashi.osaka.jp",
- "toyonaka.osaka.jp",
- "toyono.osaka.jp",
- "yao.osaka.jp",
- "ariake.saga.jp",
- "arita.saga.jp",
- "fukudomi.saga.jp",
- "genkai.saga.jp",
- "hamatama.saga.jp",
- "hizen.saga.jp",
- "imari.saga.jp",
- "kamimine.saga.jp",
- "kanzaki.saga.jp",
- "karatsu.saga.jp",
- "kashima.saga.jp",
- "kitagata.saga.jp",
- "kitahata.saga.jp",
- "kiyama.saga.jp",
- "kouhoku.saga.jp",
- "kyuragi.saga.jp",
- "nishiarita.saga.jp",
- "ogi.saga.jp",
- "omachi.saga.jp",
- "ouchi.saga.jp",
- "saga.saga.jp",
- "shiroishi.saga.jp",
- "taku.saga.jp",
- "tara.saga.jp",
- "tosu.saga.jp",
- "yoshinogari.saga.jp",
- "arakawa.saitama.jp",
- "asaka.saitama.jp",
- "chichibu.saitama.jp",
- "fujimi.saitama.jp",
- "fujimino.saitama.jp",
- "fukaya.saitama.jp",
- "hanno.saitama.jp",
- "hanyu.saitama.jp",
- "hasuda.saitama.jp",
- "hatogaya.saitama.jp",
- "hatoyama.saitama.jp",
- "hidaka.saitama.jp",
- "higashichichibu.saitama.jp",
- "higashimatsuyama.saitama.jp",
- "honjo.saitama.jp",
- "ina.saitama.jp",
- "iruma.saitama.jp",
- "iwatsuki.saitama.jp",
- "kamiizumi.saitama.jp",
- "kamikawa.saitama.jp",
- "kamisato.saitama.jp",
- "kasukabe.saitama.jp",
- "kawagoe.saitama.jp",
- "kawaguchi.saitama.jp",
- "kawajima.saitama.jp",
- "kazo.saitama.jp",
- "kitamoto.saitama.jp",
- "koshigaya.saitama.jp",
- "kounosu.saitama.jp",
- "kuki.saitama.jp",
- "kumagaya.saitama.jp",
- "matsubushi.saitama.jp",
- "minano.saitama.jp",
- "misato.saitama.jp",
- "miyashiro.saitama.jp",
- "miyoshi.saitama.jp",
- "moroyama.saitama.jp",
- "nagatoro.saitama.jp",
- "namegawa.saitama.jp",
- "niiza.saitama.jp",
- "ogano.saitama.jp",
- "ogawa.saitama.jp",
- "ogose.saitama.jp",
- "okegawa.saitama.jp",
- "omiya.saitama.jp",
- "otaki.saitama.jp",
- "ranzan.saitama.jp",
- "ryokami.saitama.jp",
- "saitama.saitama.jp",
- "sakado.saitama.jp",
- "satte.saitama.jp",
- "sayama.saitama.jp",
- "shiki.saitama.jp",
- "shiraoka.saitama.jp",
- "soka.saitama.jp",
- "sugito.saitama.jp",
- "toda.saitama.jp",
- "tokigawa.saitama.jp",
- "tokorozawa.saitama.jp",
- "tsurugashima.saitama.jp",
- "urawa.saitama.jp",
- "warabi.saitama.jp",
- "yashio.saitama.jp",
- "yokoze.saitama.jp",
- "yono.saitama.jp",
- "yorii.saitama.jp",
- "yoshida.saitama.jp",
- "yoshikawa.saitama.jp",
- "yoshimi.saitama.jp",
- "aisho.shiga.jp",
- "gamo.shiga.jp",
- "higashiomi.shiga.jp",
- "hikone.shiga.jp",
- "koka.shiga.jp",
- "konan.shiga.jp",
- "kosei.shiga.jp",
- "koto.shiga.jp",
- "kusatsu.shiga.jp",
- "maibara.shiga.jp",
- "moriyama.shiga.jp",
- "nagahama.shiga.jp",
- "nishiazai.shiga.jp",
- "notogawa.shiga.jp",
- "omihachiman.shiga.jp",
- "otsu.shiga.jp",
- "ritto.shiga.jp",
- "ryuoh.shiga.jp",
- "takashima.shiga.jp",
- "takatsuki.shiga.jp",
- "torahime.shiga.jp",
- "toyosato.shiga.jp",
- "yasu.shiga.jp",
- "akagi.shimane.jp",
- "ama.shimane.jp",
- "gotsu.shimane.jp",
- "hamada.shimane.jp",
- "higashiizumo.shimane.jp",
- "hikawa.shimane.jp",
- "hikimi.shimane.jp",
- "izumo.shimane.jp",
- "kakinoki.shimane.jp",
- "masuda.shimane.jp",
- "matsue.shimane.jp",
- "misato.shimane.jp",
- "nishinoshima.shimane.jp",
- "ohda.shimane.jp",
- "okinoshima.shimane.jp",
- "okuizumo.shimane.jp",
- "shimane.shimane.jp",
- "tamayu.shimane.jp",
- "tsuwano.shimane.jp",
- "unnan.shimane.jp",
- "yakumo.shimane.jp",
- "yasugi.shimane.jp",
- "yatsuka.shimane.jp",
- "arai.shizuoka.jp",
- "atami.shizuoka.jp",
- "fuji.shizuoka.jp",
- "fujieda.shizuoka.jp",
- "fujikawa.shizuoka.jp",
- "fujinomiya.shizuoka.jp",
- "fukuroi.shizuoka.jp",
- "gotemba.shizuoka.jp",
- "haibara.shizuoka.jp",
- "hamamatsu.shizuoka.jp",
- "higashiizu.shizuoka.jp",
- "ito.shizuoka.jp",
- "iwata.shizuoka.jp",
- "izu.shizuoka.jp",
- "izunokuni.shizuoka.jp",
- "kakegawa.shizuoka.jp",
- "kannami.shizuoka.jp",
- "kawanehon.shizuoka.jp",
- "kawazu.shizuoka.jp",
- "kikugawa.shizuoka.jp",
- "kosai.shizuoka.jp",
- "makinohara.shizuoka.jp",
- "matsuzaki.shizuoka.jp",
- "minamiizu.shizuoka.jp",
- "mishima.shizuoka.jp",
- "morimachi.shizuoka.jp",
- "nishiizu.shizuoka.jp",
- "numazu.shizuoka.jp",
- "omaezaki.shizuoka.jp",
- "shimada.shizuoka.jp",
- "shimizu.shizuoka.jp",
- "shimoda.shizuoka.jp",
- "shizuoka.shizuoka.jp",
- "susono.shizuoka.jp",
- "yaizu.shizuoka.jp",
- "yoshida.shizuoka.jp",
- "ashikaga.tochigi.jp",
- "bato.tochigi.jp",
- "haga.tochigi.jp",
- "ichikai.tochigi.jp",
- "iwafune.tochigi.jp",
- "kaminokawa.tochigi.jp",
- "kanuma.tochigi.jp",
- "karasuyama.tochigi.jp",
- "kuroiso.tochigi.jp",
- "mashiko.tochigi.jp",
- "mibu.tochigi.jp",
- "moka.tochigi.jp",
- "motegi.tochigi.jp",
- "nasu.tochigi.jp",
- "nasushiobara.tochigi.jp",
- "nikko.tochigi.jp",
- "nishikata.tochigi.jp",
- "nogi.tochigi.jp",
- "ohira.tochigi.jp",
- "ohtawara.tochigi.jp",
- "oyama.tochigi.jp",
- "sakura.tochigi.jp",
- "sano.tochigi.jp",
- "shimotsuke.tochigi.jp",
- "shioya.tochigi.jp",
- "takanezawa.tochigi.jp",
- "tochigi.tochigi.jp",
- "tsuga.tochigi.jp",
- "ujiie.tochigi.jp",
- "utsunomiya.tochigi.jp",
- "yaita.tochigi.jp",
- "aizumi.tokushima.jp",
- "anan.tokushima.jp",
- "ichiba.tokushima.jp",
- "itano.tokushima.jp",
- "kainan.tokushima.jp",
- "komatsushima.tokushima.jp",
- "matsushige.tokushima.jp",
- "mima.tokushima.jp",
- "minami.tokushima.jp",
- "miyoshi.tokushima.jp",
- "mugi.tokushima.jp",
- "nakagawa.tokushima.jp",
- "naruto.tokushima.jp",
- "sanagochi.tokushima.jp",
- "shishikui.tokushima.jp",
- "tokushima.tokushima.jp",
- "wajiki.tokushima.jp",
- "adachi.tokyo.jp",
- "akiruno.tokyo.jp",
- "akishima.tokyo.jp",
- "aogashima.tokyo.jp",
- "arakawa.tokyo.jp",
- "bunkyo.tokyo.jp",
- "chiyoda.tokyo.jp",
- "chofu.tokyo.jp",
- "chuo.tokyo.jp",
- "edogawa.tokyo.jp",
- "fuchu.tokyo.jp",
- "fussa.tokyo.jp",
- "hachijo.tokyo.jp",
- "hachioji.tokyo.jp",
- "hamura.tokyo.jp",
- "higashikurume.tokyo.jp",
- "higashimurayama.tokyo.jp",
- "higashiyamato.tokyo.jp",
- "hino.tokyo.jp",
- "hinode.tokyo.jp",
- "hinohara.tokyo.jp",
- "inagi.tokyo.jp",
- "itabashi.tokyo.jp",
- "katsushika.tokyo.jp",
- "kita.tokyo.jp",
- "kiyose.tokyo.jp",
- "kodaira.tokyo.jp",
- "koganei.tokyo.jp",
- "kokubunji.tokyo.jp",
- "komae.tokyo.jp",
- "koto.tokyo.jp",
- "kouzushima.tokyo.jp",
- "kunitachi.tokyo.jp",
- "machida.tokyo.jp",
- "meguro.tokyo.jp",
- "minato.tokyo.jp",
- "mitaka.tokyo.jp",
- "mizuho.tokyo.jp",
- "musashimurayama.tokyo.jp",
- "musashino.tokyo.jp",
- "nakano.tokyo.jp",
- "nerima.tokyo.jp",
- "ogasawara.tokyo.jp",
- "okutama.tokyo.jp",
- "ome.tokyo.jp",
- "oshima.tokyo.jp",
- "ota.tokyo.jp",
- "setagaya.tokyo.jp",
- "shibuya.tokyo.jp",
- "shinagawa.tokyo.jp",
- "shinjuku.tokyo.jp",
- "suginami.tokyo.jp",
- "sumida.tokyo.jp",
- "tachikawa.tokyo.jp",
- "taito.tokyo.jp",
- "tama.tokyo.jp",
- "toshima.tokyo.jp",
- "chizu.tottori.jp",
- "hino.tottori.jp",
- "kawahara.tottori.jp",
- "koge.tottori.jp",
- "kotoura.tottori.jp",
- "misasa.tottori.jp",
- "nanbu.tottori.jp",
- "nichinan.tottori.jp",
- "sakaiminato.tottori.jp",
- "tottori.tottori.jp",
- "wakasa.tottori.jp",
- "yazu.tottori.jp",
- "yonago.tottori.jp",
- "asahi.toyama.jp",
- "fuchu.toyama.jp",
- "fukumitsu.toyama.jp",
- "funahashi.toyama.jp",
- "himi.toyama.jp",
- "imizu.toyama.jp",
- "inami.toyama.jp",
- "johana.toyama.jp",
- "kamiichi.toyama.jp",
- "kurobe.toyama.jp",
- "nakaniikawa.toyama.jp",
- "namerikawa.toyama.jp",
- "nanto.toyama.jp",
- "nyuzen.toyama.jp",
- "oyabe.toyama.jp",
- "taira.toyama.jp",
- "takaoka.toyama.jp",
- "tateyama.toyama.jp",
- "toga.toyama.jp",
- "tonami.toyama.jp",
- "toyama.toyama.jp",
- "unazuki.toyama.jp",
- "uozu.toyama.jp",
- "yamada.toyama.jp",
- "arida.wakayama.jp",
- "aridagawa.wakayama.jp",
- "gobo.wakayama.jp",
- "hashimoto.wakayama.jp",
- "hidaka.wakayama.jp",
- "hirogawa.wakayama.jp",
- "inami.wakayama.jp",
- "iwade.wakayama.jp",
- "kainan.wakayama.jp",
- "kamitonda.wakayama.jp",
- "katsuragi.wakayama.jp",
- "kimino.wakayama.jp",
- "kinokawa.wakayama.jp",
- "kitayama.wakayama.jp",
- "koya.wakayama.jp",
- "koza.wakayama.jp",
- "kozagawa.wakayama.jp",
- "kudoyama.wakayama.jp",
- "kushimoto.wakayama.jp",
- "mihama.wakayama.jp",
- "misato.wakayama.jp",
- "nachikatsuura.wakayama.jp",
- "shingu.wakayama.jp",
- "shirahama.wakayama.jp",
- "taiji.wakayama.jp",
- "tanabe.wakayama.jp",
- "wakayama.wakayama.jp",
- "yuasa.wakayama.jp",
- "yura.wakayama.jp",
- "asahi.yamagata.jp",
- "funagata.yamagata.jp",
- "higashine.yamagata.jp",
- "iide.yamagata.jp",
- "kahoku.yamagata.jp",
- "kaminoyama.yamagata.jp",
- "kaneyama.yamagata.jp",
- "kawanishi.yamagata.jp",
- "mamurogawa.yamagata.jp",
- "mikawa.yamagata.jp",
- "murayama.yamagata.jp",
- "nagai.yamagata.jp",
- "nakayama.yamagata.jp",
- "nanyo.yamagata.jp",
- "nishikawa.yamagata.jp",
- "obanazawa.yamagata.jp",
- "oe.yamagata.jp",
- "oguni.yamagata.jp",
- "ohkura.yamagata.jp",
- "oishida.yamagata.jp",
- "sagae.yamagata.jp",
- "sakata.yamagata.jp",
- "sakegawa.yamagata.jp",
- "shinjo.yamagata.jp",
- "shirataka.yamagata.jp",
- "shonai.yamagata.jp",
- "takahata.yamagata.jp",
- "tendo.yamagata.jp",
- "tozawa.yamagata.jp",
- "tsuruoka.yamagata.jp",
- "yamagata.yamagata.jp",
- "yamanobe.yamagata.jp",
- "yonezawa.yamagata.jp",
- "yuza.yamagata.jp",
- "abu.yamaguchi.jp",
- "hagi.yamaguchi.jp",
- "hikari.yamaguchi.jp",
- "hofu.yamaguchi.jp",
- "iwakuni.yamaguchi.jp",
- "kudamatsu.yamaguchi.jp",
- "mitou.yamaguchi.jp",
- "nagato.yamaguchi.jp",
- "oshima.yamaguchi.jp",
- "shimonoseki.yamaguchi.jp",
- "shunan.yamaguchi.jp",
- "tabuse.yamaguchi.jp",
- "tokuyama.yamaguchi.jp",
- "toyota.yamaguchi.jp",
- "ube.yamaguchi.jp",
- "yuu.yamaguchi.jp",
- "chuo.yamanashi.jp",
- "doshi.yamanashi.jp",
- "fuefuki.yamanashi.jp",
- "fujikawa.yamanashi.jp",
- "fujikawaguchiko.yamanashi.jp",
- "fujiyoshida.yamanashi.jp",
- "hayakawa.yamanashi.jp",
- "hokuto.yamanashi.jp",
- "ichikawamisato.yamanashi.jp",
- "kai.yamanashi.jp",
- "kofu.yamanashi.jp",
- "koshu.yamanashi.jp",
- "kosuge.yamanashi.jp",
- "minami-alps.yamanashi.jp",
- "minobu.yamanashi.jp",
- "nakamichi.yamanashi.jp",
- "nanbu.yamanashi.jp",
- "narusawa.yamanashi.jp",
- "nirasaki.yamanashi.jp",
- "nishikatsura.yamanashi.jp",
- "oshino.yamanashi.jp",
- "otsuki.yamanashi.jp",
- "showa.yamanashi.jp",
- "tabayama.yamanashi.jp",
- "tsuru.yamanashi.jp",
- "uenohara.yamanashi.jp",
- "yamanakako.yamanashi.jp",
- "yamanashi.yamanashi.jp",
"kg",
"org.kg",
"net.kg",
@@ -3012,6 +1283,7 @@ final class TldPatterns {
"per.la",
"com.la",
"org.la",
+ "c.la",
"com.lb",
"edu.lb",
"gov.lb",
@@ -3040,6 +1312,7 @@ final class TldPatterns {
"assn.lk",
"grp.lk",
"hotel.lk",
+ "local",
"com.lr",
"edu.lr",
"gov.lr",
@@ -3760,6 +2033,10 @@ final class TldPatterns {
"asso.nc",
"ne",
"net",
+ "gb.net",
+ "se.net",
+ "uk.net",
+ "za.net",
"nf",
"com.nf",
"net.nf",
@@ -4716,6 +2993,8 @@ final class TldPatterns {
"com.nr",
"nu",
"org",
+ "ae.org",
+ "za.org",
"pa",
"ac.pa",
"gob.pa",
@@ -4944,7 +3223,7 @@ final class TldPatterns {
"poznan.pl",
"wroc.pl",
"zakopane.pl",
- "pm",
+ "co.pl",
"pn",
"gov.pn",
"co.pn",
@@ -4997,15 +3276,6 @@ final class TldPatterns {
"ed.pw",
"go.pw",
"belau.pw",
- "qa",
- "com.qa",
- "edu.qa",
- "gov.qa",
- "mil.qa",
- "name.qa",
- "net.qa",
- "org.qa",
- "sch.qa",
"re",
"com.re",
"asso.re",
@@ -5200,7 +3470,6 @@ final class TldPatterns {
"org.sd",
"edu.sd",
"med.sd",
- "tv.sd",
"gov.sd",
"info.sd",
"se",
@@ -5252,11 +3521,6 @@ final class TldPatterns {
"edu.sg",
"per.sg",
"sh",
- "com.sh",
- "net.sh",
- "gov.sh",
- "org.sh",
- "mil.sh",
"si",
"sk",
"sl",
@@ -5293,8 +3557,6 @@ final class TldPatterns {
"saotome.st",
"store.st",
"su",
- "sx",
- "gov.sx",
"sy",
"edu.sy",
"gov.sy",
@@ -5339,14 +3601,6 @@ final class TldPatterns {
"tl",
"gov.tl",
"tm",
- "com.tm",
- "co.tm",
- "org.tm",
- "net.tm",
- "nom.tm",
- "gov.tm",
- "mil.tm",
- "edu.tm",
"tn",
"com.tn",
"ens.tn",
@@ -5428,86 +3682,58 @@ final class TldPatterns {
"net.ua",
"org.ua",
"cherkassy.ua",
- "cherkasy.ua",
"chernigov.ua",
- "chernihiv.ua",
- "chernivtsi.ua",
"chernovtsy.ua",
"ck.ua",
"cn.ua",
- "cr.ua",
"crimea.ua",
"cv.ua",
"dn.ua",
"dnepropetrovsk.ua",
- "dnipropetrovsk.ua",
- "dominic.ua",
"donetsk.ua",
"dp.ua",
"if.ua",
"ivano-frankivsk.ua",
"kh.ua",
- "kharkiv.ua",
"kharkov.ua",
"kherson.ua",
"khmelnitskiy.ua",
- "khmelnytskyi.ua",
"kiev.ua",
"kirovograd.ua",
"km.ua",
"kr.ua",
- "krym.ua",
"ks.ua",
"kv.ua",
- "kyiv.ua",
"lg.ua",
- "lt.ua",
"lugansk.ua",
"lutsk.ua",
- "lv.ua",
"lviv.ua",
"mk.ua",
- "mykolaiv.ua",
"nikolaev.ua",
"od.ua",
- "odesa.ua",
"odessa.ua",
"pl.ua",
"poltava.ua",
- "rivne.ua",
"rovno.ua",
"rv.ua",
- "sb.ua",
"sebastopol.ua",
- "sevastopol.ua",
- "sm.ua",
"sumy.ua",
"te.ua",
"ternopil.ua",
- "uz.ua",
"uzhgorod.ua",
"vinnica.ua",
- "vinnytsia.ua",
"vn.ua",
- "volyn.ua",
- "yalta.ua",
"zaporizhzhe.ua",
- "zaporizhzhia.ua",
- "zhitomir.ua",
- "zhytomyr.ua",
"zp.ua",
+ "zhitomir.ua",
"zt.ua",
- "co.ua",
- "pp.ua",
"ug",
"co.ug",
- "or.ug",
"ac.ug",
"sc.ug",
"go.ug",
"ne.ug",
- "com.ug",
- "org.ug",
+ "or.ug",
"us",
"dni.us",
"fed.us",
@@ -5736,18 +3962,9 @@ final class TldPatterns {
"pvt.k12.ma.us",
"chtr.k12.ma.us",
"paroch.k12.ma.us",
- "uy",
- "com.uy",
- "edu.uy",
- "gub.uy",
- "mil.uy",
- "net.uy",
- "org.uy",
"uz",
- "co.uz",
"com.uz",
- "net.uz",
- "org.uz",
+ "co.uz",
"va",
"vc",
"com.vc",
@@ -5756,17 +3973,6 @@ final class TldPatterns {
"gov.vc",
"mil.vc",
"edu.vc",
- "ve",
- "co.ve",
- "com.ve",
- "e12.ve",
- "edu.ve",
- "gov.ve",
- "info.ve",
- "mil.ve",
- "net.ve",
- "org.ve",
- "web.ve",
"vg",
"vi",
"co.vi",
@@ -5788,14 +3994,12 @@ final class TldPatterns {
"pro.vn",
"health.vn",
"vu",
- "wf",
"ws",
"com.ws",
"net.ws",
"org.ws",
"gov.ws",
"edu.ws",
- "yt",
"\u0627\u0645\u0627\u0631\u0627\u062a",
"xn--mgbaam7a8h",
"\u09ac\u09be\u0982\u09b2\u09be",
@@ -5881,330 +4085,9 @@ final class TldPatterns {
"\u0627\u0644\u064a\u0645\u0646",
"xn--mgb2ddes",
"xxx",
- "biz.at",
- "info.at",
- "priv.at",
- "co.ca",
- "ae.org",
- "ar.com",
- "br.com",
- "cn.com",
- "com.de",
- "de.com",
- "eu.com",
- "gb.com",
- "gb.net",
- "gr.com",
- "hu.com",
- "hu.net",
- "jp.net",
- "jpn.com",
- "kr.com",
- "no.com",
- "qc.com",
- "ru.com",
- "sa.com",
- "se.com",
- "se.net",
- "uk.com",
- "uk.net",
- "us.com",
- "us.org",
- "uy.com",
- "za.com",
- "operaunite.com",
- "appspot.com",
- "dreamhosters.com",
- "iki.fi",
- "c.la",
- "za.net",
- "za.org",
- "co.nl",
- "co.no",
- "co.pl",
- "dyndns-at-home.com",
- "dyndns-at-work.com",
- "dyndns-blog.com",
- "dyndns-free.com",
- "dyndns-home.com",
- "dyndns-ip.com",
- "dyndns-mail.com",
- "dyndns-office.com",
- "dyndns-pics.com",
- "dyndns-remote.com",
- "dyndns-server.com",
- "dyndns-web.com",
- "dyndns-wiki.com",
- "dyndns-work.com",
- "dyndns.biz",
- "dyndns.info",
- "dyndns.org",
- "dyndns.tv",
- "at-band-camp.net",
- "ath.cx",
- "barrel-of-knowledge.info",
- "barrell-of-knowledge.info",
- "better-than.tv",
- "blogdns.com",
- "blogdns.net",
- "blogdns.org",
- "blogsite.org",
- "boldlygoingnowhere.org",
- "broke-it.net",
- "buyshouses.net",
- "cechire.com",
- "dnsalias.com",
- "dnsalias.net",
- "dnsalias.org",
- "dnsdojo.com",
- "dnsdojo.net",
- "dnsdojo.org",
- "does-it.net",
- "doesntexist.com",
- "doesntexist.org",
- "dontexist.com",
- "dontexist.net",
- "dontexist.org",
- "doomdns.com",
- "doomdns.org",
- "dvrdns.org",
- "dyn-o-saur.com",
- "dynalias.com",
- "dynalias.net",
- "dynalias.org",
- "dynathome.net",
- "dyndns.ws",
- "endofinternet.net",
- "endofinternet.org",
- "endoftheinternet.org",
- "est-a-la-maison.com",
- "est-a-la-masion.com",
- "est-le-patron.com",
- "est-mon-blogueur.com",
- "for-better.biz",
- "for-more.biz",
- "for-our.info",
- "for-some.biz",
- "for-the.biz",
- "forgot.her.name",
- "forgot.his.name",
- "from-ak.com",
- "from-al.com",
- "from-ar.com",
- "from-az.net",
- "from-ca.com",
- "from-co.net",
- "from-ct.com",
- "from-dc.com",
- "from-de.com",
- "from-fl.com",
- "from-ga.com",
- "from-hi.com",
- "from-ia.com",
- "from-id.com",
- "from-il.com",
- "from-in.com",
- "from-ks.com",
- "from-ky.com",
- "from-la.net",
- "from-ma.com",
- "from-md.com",
- "from-me.org",
- "from-mi.com",
- "from-mn.com",
- "from-mo.com",
- "from-ms.com",
- "from-mt.com",
- "from-nc.com",
- "from-nd.com",
- "from-ne.com",
- "from-nh.com",
- "from-nj.com",
- "from-nm.com",
- "from-nv.com",
- "from-ny.net",
- "from-oh.com",
- "from-ok.com",
- "from-or.com",
- "from-pa.com",
- "from-pr.com",
- "from-ri.com",
- "from-sc.com",
- "from-sd.com",
- "from-tn.com",
- "from-tx.com",
- "from-ut.com",
- "from-va.com",
- "from-vt.com",
- "from-wa.com",
- "from-wi.com",
- "from-wv.com",
- "from-wy.com",
- "ftpaccess.cc",
- "fuettertdasnetz.de",
- "game-host.org",
- "game-server.cc",
- "getmyip.com",
- "gets-it.net",
- "go.dyndns.org",
- "gotdns.com",
- "gotdns.org",
- "groks-the.info",
- "groks-this.info",
- "ham-radio-op.net",
- "here-for-more.info",
- "hobby-site.com",
- "hobby-site.org",
- "home.dyndns.org",
- "homedns.org",
- "homeftp.net",
- "homeftp.org",
- "homeip.net",
- "homelinux.com",
- "homelinux.net",
- "homelinux.org",
- "homeunix.com",
- "homeunix.net",
- "homeunix.org",
- "iamallama.com",
- "in-the-band.net",
- "is-a-anarchist.com",
- "is-a-blogger.com",
- "is-a-bookkeeper.com",
- "is-a-bruinsfan.org",
- "is-a-bulls-fan.com",
- "is-a-candidate.org",
- "is-a-caterer.com",
- "is-a-celticsfan.org",
- "is-a-chef.com",
- "is-a-chef.net",
- "is-a-chef.org",
- "is-a-conservative.com",
- "is-a-cpa.com",
- "is-a-cubicle-slave.com",
- "is-a-democrat.com",
- "is-a-designer.com",
- "is-a-doctor.com",
- "is-a-financialadvisor.com",
- "is-a-geek.com",
- "is-a-geek.net",
- "is-a-geek.org",
- "is-a-green.com",
- "is-a-guru.com",
- "is-a-hard-worker.com",
- "is-a-hunter.com",
- "is-a-knight.org",
- "is-a-landscaper.com",
- "is-a-lawyer.com",
- "is-a-liberal.com",
- "is-a-libertarian.com",
- "is-a-linux-user.org",
- "is-a-llama.com",
- "is-a-musician.com",
- "is-a-nascarfan.com",
- "is-a-nurse.com",
- "is-a-painter.com",
- "is-a-patsfan.org",
- "is-a-personaltrainer.com",
- "is-a-photographer.com",
- "is-a-player.com",
- "is-a-republican.com",
- "is-a-rockstar.com",
- "is-a-socialist.com",
- "is-a-soxfan.org",
- "is-a-student.com",
- "is-a-teacher.com",
- "is-a-techie.com",
- "is-a-therapist.com",
- "is-an-accountant.com",
- "is-an-actor.com",
- "is-an-actress.com",
- "is-an-anarchist.com",
- "is-an-artist.com",
- "is-an-engineer.com",
- "is-an-entertainer.com",
- "is-by.us",
- "is-certified.com",
- "is-found.org",
- "is-gone.com",
- "is-into-anime.com",
- "is-into-cars.com",
- "is-into-cartoons.com",
- "is-into-games.com",
- "is-leet.com",
- "is-lost.org",
- "is-not-certified.com",
- "is-saved.org",
- "is-slick.com",
- "is-uberleet.com",
- "is-very-bad.org",
- "is-very-evil.org",
- "is-very-good.org",
- "is-very-nice.org",
- "is-very-sweet.org",
- "is-with-theband.com",
- "isa-geek.com",
- "isa-geek.net",
- "isa-geek.org",
- "isa-hockeynut.com",
- "issmarterthanyou.com",
- "isteingeek.de",
- "istmein.de",
- "kicks-ass.net",
- "kicks-ass.org",
- "knowsitall.info",
- "land-4-sale.us",
- "lebtimnetz.de",
- "leitungsen.de",
- "likes-pie.com",
- "likescandy.com",
- "merseine.nu",
- "mine.nu",
- "misconfused.org",
- "mypets.ws",
- "myphotos.cc",
- "neat-url.com",
- "office-on-the.net",
- "on-the-web.tv",
- "podzone.net",
- "podzone.org",
- "readmyblog.org",
- "saves-the-whales.com",
- "scrapper-site.net",
- "scrapping.cc",
- "selfip.biz",
- "selfip.com",
- "selfip.info",
- "selfip.net",
- "selfip.org",
- "sells-for-less.com",
- "sells-for-u.com",
- "sells-it.net",
- "sellsyourhome.org",
- "servebbs.com",
- "servebbs.net",
- "servebbs.org",
- "serveftp.net",
- "serveftp.org",
- "servegame.org",
- "shacknet.nu",
- "simple-url.com",
- "space-to-rent.com",
- "stuff-4-sale.org",
- "stuff-4-sale.us",
- "teaches-yoga.com",
- "thruhere.net",
- "traeumtgerade.de",
- "webhop.biz",
- "webhop.info",
- "webhop.net",
- "webhop.org",
- "worse-than.tv",
- "writesthisblog.com",
"tp",
- "ng",
- "\u049b\u0430\u0437",
- "xn--80ao21a"
+ "yt",
+ "ng"
);
/**
@@ -6212,8 +4095,9 @@ final class TldPatterns {
* leftmost component results in a name which is contained in this
* set, it is a TLD.
*/
- static final ImmutableSet<String> UNDER = ImmutableSet.of(
+ static final Set<String> UNDER = ImmutableSet.of(
"ar",
+ "au",
"bd",
"bn",
"ck",
@@ -6226,12 +4110,59 @@ final class TldPatterns {
"gu",
"il",
"jm",
+ "aichi.jp",
+ "akita.jp",
+ "aomori.jp",
+ "chiba.jp",
+ "ehime.jp",
+ "fukui.jp",
+ "fukuoka.jp",
+ "fukushima.jp",
+ "gifu.jp",
+ "gunma.jp",
+ "hiroshima.jp",
+ "hokkaido.jp",
+ "hyogo.jp",
+ "ibaraki.jp",
+ "ishikawa.jp",
+ "iwate.jp",
+ "kagawa.jp",
+ "kagoshima.jp",
+ "kanagawa.jp",
"kawasaki.jp",
"kitakyushu.jp",
"kobe.jp",
+ "kochi.jp",
+ "kumamoto.jp",
+ "kyoto.jp",
+ "mie.jp",
+ "miyagi.jp",
+ "miyazaki.jp",
+ "nagano.jp",
+ "nagasaki.jp",
"nagoya.jp",
+ "nara.jp",
+ "niigata.jp",
+ "oita.jp",
+ "okayama.jp",
+ "okinawa.jp",
+ "osaka.jp",
+ "saga.jp",
+ "saitama.jp",
"sapporo.jp",
"sendai.jp",
+ "shiga.jp",
+ "shimane.jp",
+ "shizuoka.jp",
+ "tochigi.jp",
+ "tokushima.jp",
+ "tokyo.jp",
+ "tottori.jp",
+ "toyama.jp",
+ "wakayama.jp",
+ "yamagata.jp",
+ "yamaguchi.jp",
+ "yamanashi.jp",
"yokohama.jp",
"ke",
"kh",
@@ -6245,13 +4176,15 @@ final class TldPatterns {
"om",
"pg",
"py",
+ "qa",
"sv",
"tr",
"uk",
- "nhs.uk",
- "police.uk",
"sch.uk",
+ "uy",
+ "ve",
"ye",
+ "yu",
"za",
"zm",
"zw"
@@ -6261,7 +4194,7 @@ final class TldPatterns {
* The elements in this set would pass the UNDER test, but are
* known not to be TLDs and are thus excluded from consideration.
*/
- static final ImmutableSet<String> EXCLUDED = ImmutableSet.of(
+ static final Set<String> EXCLUDED = ImmutableSet.of(
"congresodelalengua3.ar",
"educ.ar",
"gobiernoelectronico.ar",
@@ -6271,14 +4204,68 @@ final class TldPatterns {
"promocion.ar",
"retina.ar",
"uba.ar",
- "www.ck",
- "www.gt",
+ "metro.tokyo.jp",
+ "pref.aichi.jp",
+ "pref.akita.jp",
+ "pref.aomori.jp",
+ "pref.chiba.jp",
+ "pref.ehime.jp",
+ "pref.fukui.jp",
+ "pref.fukuoka.jp",
+ "pref.fukushima.jp",
+ "pref.gifu.jp",
+ "pref.gunma.jp",
+ "pref.hiroshima.jp",
+ "pref.hokkaido.jp",
+ "pref.hyogo.jp",
+ "pref.ibaraki.jp",
+ "pref.ishikawa.jp",
+ "pref.iwate.jp",
+ "pref.kagawa.jp",
+ "pref.kagoshima.jp",
+ "pref.kanagawa.jp",
+ "pref.kochi.jp",
+ "pref.kumamoto.jp",
+ "pref.kyoto.jp",
+ "pref.mie.jp",
+ "pref.miyagi.jp",
+ "pref.miyazaki.jp",
+ "pref.nagano.jp",
+ "pref.nagasaki.jp",
+ "pref.nara.jp",
+ "pref.niigata.jp",
+ "pref.oita.jp",
+ "pref.okayama.jp",
+ "pref.okinawa.jp",
+ "pref.osaka.jp",
+ "pref.saga.jp",
+ "pref.saitama.jp",
+ "pref.shiga.jp",
+ "pref.shimane.jp",
+ "pref.shizuoka.jp",
+ "pref.tochigi.jp",
+ "pref.tokushima.jp",
+ "pref.tottori.jp",
+ "pref.toyama.jp",
+ "pref.wakayama.jp",
+ "pref.yamagata.jp",
+ "pref.yamaguchi.jp",
+ "pref.yamanashi.jp",
+ "city.chiba.jp",
+ "city.fukuoka.jp",
+ "city.hiroshima.jp",
"city.kawasaki.jp",
"city.kitakyushu.jp",
"city.kobe.jp",
+ "city.kyoto.jp",
"city.nagoya.jp",
+ "city.niigata.jp",
+ "city.okayama.jp",
+ "city.osaka.jp",
+ "city.saitama.jp",
"city.sapporo.jp",
"city.sendai.jp",
+ "city.shizuoka.jp",
"city.yokohama.jp",
"mediaphone.om",
"nawrastelecom.om",
@@ -6291,15 +4278,17 @@ final class TldPatterns {
"songfest.om",
"statecouncil.om",
"nic.tr",
+ "tsk.tr",
"bl.uk",
"british-library.uk",
+ "icnet.uk",
"jet.uk",
- "mod.uk",
- "national-library-scotland.uk",
"nel.uk",
- "nic.uk",
+ "nhs.uk",
"nls.uk",
- "parliament.uk"
+ "national-library-scotland.uk",
+ "parliament.uk",
+ "police.uk"
);
}
diff --git a/guava/src/com/google/common/net/package-info.java b/guava/src/com/google/common/net/package-info.java
index 090a231..1cb9958 100644
--- a/guava/src/com/google/common/net/package-info.java
+++ b/guava/src/com/google/common/net/package-info.java
@@ -27,4 +27,3 @@
package com.google.common.net;
import javax.annotation.ParametersAreNonnullByDefault;
-
diff --git a/guava/src/com/google/common/primitives/Booleans.java b/guava/src/com/google/common/primitives/Booleans.java
index 3601a8a..ab333f1 100644
--- a/guava/src/com/google/common/primitives/Booleans.java
+++ b/guava/src/com/google/common/primitives/Booleans.java
@@ -37,10 +37,6 @@ import java.util.RandomAccess;
* Static utility methods pertaining to {@code boolean} primitives, that are not
* already found in either {@link Boolean} or {@link Arrays}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
@@ -407,8 +403,7 @@ public final class Booleans {
@Override public Boolean set(int index, Boolean element) {
checkElementIndex(index, size());
boolean oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -459,7 +454,7 @@ public final class Booleans {
}
boolean[] toBooleanArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
boolean[] result = new boolean[size];
System.arraycopy(array, start, result, 0, size);
diff --git a/guava/src/com/google/common/primitives/Bytes.java b/guava/src/com/google/common/primitives/Bytes.java
index d9c5e1f..92f7805 100644
--- a/guava/src/com/google/common/primitives/Bytes.java
+++ b/guava/src/com/google/common/primitives/Bytes.java
@@ -38,10 +38,6 @@ import java.util.RandomAccess;
* treat bytes as signed or unsigned are found in {@link SignedBytes} and {@link
* UnsignedBytes}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
@@ -214,21 +210,20 @@ public final class Bytes {
}
/**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code byte} value in the manner of {@link Number#byteValue}.
+ * Copies a collection of {@code Byte} instances into a new array of
+ * primitive {@code byte} values.
*
* <p>Elements are copied from the argument collection as if by {@code
* collection.toArray()}. Calling this method is as thread-safe as calling
* that method.
*
- * @param collection a collection of {@code Number} instances
+ * @param collection a collection of {@code Byte} objects
* @return an array containing the same values as {@code collection}, in the
* same order, converted to primitives
* @throws NullPointerException if {@code collection} or any of its elements
* is null
- * @since 1.0 (parameter was {@code Collection<Byte>} before 12.0)
*/
- public static byte[] toArray(Collection<? extends Number> collection) {
+ public static byte[] toArray(Collection<Byte> collection) {
if (collection instanceof ByteArrayAsList) {
return ((ByteArrayAsList) collection).toByteArray();
}
@@ -238,7 +233,7 @@ public final class Bytes {
byte[] array = new byte[len];
for (int i = 0; i < len; i++) {
// checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).byteValue();
+ array[i] = (Byte) checkNotNull(boxedArray[i]);
}
return array;
}
@@ -325,8 +320,7 @@ public final class Bytes {
@Override public Byte set(int index, Byte element) {
checkElementIndex(index, size());
byte oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -377,7 +371,7 @@ public final class Bytes {
}
byte[] toByteArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
byte[] result = new byte[size];
System.arraycopy(array, start, result, 0, size);
diff --git a/guava/src/com/google/common/primitives/Chars.java b/guava/src/com/google/common/primitives/Chars.java
index 241814a..5ac57d1 100644
--- a/guava/src/com/google/common/primitives/Chars.java
+++ b/guava/src/com/google/common/primitives/Chars.java
@@ -40,10 +40,6 @@ import java.util.RandomAccess;
* <p>All the operations in this class treat {@code char} values strictly
* numerically; they are neither Unicode-aware nor locale-dependent.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
@@ -523,8 +519,7 @@ public final class Chars {
@Override public Character set(int index, Character element) {
checkElementIndex(index, size());
char oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -575,7 +570,7 @@ public final class Chars {
}
char[] toCharArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
char[] result = new char[size];
System.arraycopy(array, start, result, 0, size);
diff --git a/guava/src/com/google/common/primitives/Doubles.java b/guava/src/com/google/common/primitives/Doubles.java
index 068fc9d..dc3ea64 100644
--- a/guava/src/com/google/common/primitives/Doubles.java
+++ b/guava/src/com/google/common/primitives/Doubles.java
@@ -23,9 +23,7 @@ import static com.google.common.base.Preconditions.checkPositionIndexes;
import static java.lang.Double.NEGATIVE_INFINITY;
import static java.lang.Double.POSITIVE_INFINITY;
-import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import java.io.Serializable;
import java.util.AbstractList;
@@ -35,22 +33,15 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.RandomAccess;
-import java.util.regex.Pattern;
-
-import javax.annotation.Nullable;
/**
* Static utility methods pertaining to {@code double} primitives, that are not
* already found in either {@link Double} or {@link Arrays}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
-@GwtCompatible(emulated = true)
+@GwtCompatible
public final class Doubles {
private Doubles() {}
@@ -302,8 +293,8 @@ public final class Doubles {
* the string {@code "1.0-2.0-3.0"}.
*
* <p>Note that {@link Double#toString(double)} formats {@code double}
- * differently in GWT sometimes. In the previous example, it returns the
- * string {@code "1-2-3"}.
+ * differently in GWT sometimes. In the previous example, it returns the string
+ * {@code "1-2-3"}.
*
* @param separator the text that should appear between consecutive values in
* the resulting string (but not at the start or end)
@@ -361,21 +352,20 @@ public final class Doubles {
}
/**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code double} value in the manner of {@link Number#doubleValue}.
+ * Copies a collection of {@code Double} instances into a new array of
+ * primitive {@code double} values.
*
* <p>Elements are copied from the argument collection as if by {@code
* collection.toArray()}. Calling this method is as thread-safe as calling
* that method.
*
- * @param collection a collection of {@code Number} instances
+ * @param collection a collection of {@code Double} objects
* @return an array containing the same values as {@code collection}, in the
* same order, converted to primitives
* @throws NullPointerException if {@code collection} or any of its elements
* is null
- * @since 1.0 (parameter was {@code Collection<Double>} before 12.0)
*/
- public static double[] toArray(Collection<? extends Number> collection) {
+ public static double[] toArray(Collection<Double> collection) {
if (collection instanceof DoubleArrayAsList) {
return ((DoubleArrayAsList) collection).toDoubleArray();
}
@@ -385,7 +375,7 @@ public final class Doubles {
double[] array = new double[len];
for (int i = 0; i < len; i++) {
// checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).doubleValue();
+ array[i] = (Double) checkNotNull(boxedArray[i]);
}
return array;
}
@@ -475,8 +465,7 @@ public final class Doubles {
@Override public Double set(int index, Double element) {
checkElementIndex(index, size());
double oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -527,7 +516,7 @@ public final class Doubles {
}
double[] toDoubleArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
double[] result = new double[size];
System.arraycopy(array, start, result, 0, size);
@@ -536,59 +525,4 @@ public final class Doubles {
private static final long serialVersionUID = 0;
}
-
- /**
- * This is adapted from the regex suggested by {@link Double#valueOf(String)}
- * for prevalidating inputs. All valid inputs must pass this regex, but it's
- * semantically fine if not all inputs that pass this regex are valid --
- * only a performance hit is incurred, not a semantics bug.
- */
- @GwtIncompatible("regular expressions")
- static final Pattern FLOATING_POINT_PATTERN = fpPattern();
-
- @GwtIncompatible("regular expressions")
- private static Pattern fpPattern() {
- String decimal = "(?:\\d++(?:\\.\\d*+)?|\\.\\d++)";
- String completeDec = decimal + "(?:[eE][+-]?\\d++)?[fFdD]?";
- String hex = "(?:\\p{XDigit}++(?:\\.\\p{XDigit}*+)?|\\.\\p{XDigit}++)";
- String completeHex = "0[xX]" + hex + "[pP][+-]?\\d++[fFdD]?";
- String fpPattern = "[+-]?(?:NaN|Infinity|" + completeDec + "|" + completeHex + ")";
- return Pattern.compile(fpPattern);
- }
-
- /**
- * Parses the specified string as a double-precision floating point value.
- * The ASCII character {@code '-'} (<code>'&#92;u002D'</code>) is recognized
- * as the minus sign.
- *
- * <p>Unlike {@link Double#parseDouble(String)}, this method returns
- * {@code null} instead of throwing an exception if parsing fails.
- * Valid inputs are exactly those accepted by {@link Double#valueOf(String)},
- * except that leading and trailing whitespace is not permitted.
- *
- * <p>This implementation is likely to be faster than {@code
- * Double.parseDouble} if many failures are expected.
- *
- * @param string the string representation of a {@code double} value
- * @return the floating point value represented by {@code string}, or
- * {@code null} if {@code string} has a length of zero or cannot be
- * parsed as a {@code double} value
- * @since 14.0
- */
- @GwtIncompatible("regular expressions")
- @Nullable
- @Beta
- public static Double tryParse(String string) {
- if (FLOATING_POINT_PATTERN.matcher(string).matches()) {
- // TODO(user): could be potentially optimized, but only with
- // extensive testing
- try {
- return Double.parseDouble(string);
- } catch (NumberFormatException e) {
- // Double.parseDouble has changed specs several times, so fall through
- // gracefully
- }
- }
- return null;
- }
}
diff --git a/guava/src/com/google/common/primitives/Floats.java b/guava/src/com/google/common/primitives/Floats.java
index 03a1ed1..ffc932f 100644
--- a/guava/src/com/google/common/primitives/Floats.java
+++ b/guava/src/com/google/common/primitives/Floats.java
@@ -23,9 +23,7 @@ import static com.google.common.base.Preconditions.checkPositionIndexes;
import static java.lang.Float.NEGATIVE_INFINITY;
import static java.lang.Float.POSITIVE_INFINITY;
-import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
import java.io.Serializable;
import java.util.AbstractList;
@@ -36,20 +34,14 @@ import java.util.Comparator;
import java.util.List;
import java.util.RandomAccess;
-import javax.annotation.Nullable;
-
/**
* Static utility methods pertaining to {@code float} primitives, that are not
* already found in either {@link Float} or {@link Arrays}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
-@GwtCompatible(emulated = true)
+@GwtCompatible
public final class Floats {
private Floats() {}
@@ -357,21 +349,20 @@ public final class Floats {
}
/**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code float} value in the manner of {@link Number#floatValue}.
+ * Copies a collection of {@code Float} instances into a new array of
+ * primitive {@code float} values.
*
* <p>Elements are copied from the argument collection as if by {@code
* collection.toArray()}. Calling this method is as thread-safe as calling
* that method.
*
- * @param collection a collection of {@code Number} instances
+ * @param collection a collection of {@code Float} objects
* @return an array containing the same values as {@code collection}, in the
* same order, converted to primitives
* @throws NullPointerException if {@code collection} or any of its elements
* is null
- * @since 1.0 (parameter was {@code Collection<Float>} before 12.0)
*/
- public static float[] toArray(Collection<? extends Number> collection) {
+ public static float[] toArray(Collection<Float> collection) {
if (collection instanceof FloatArrayAsList) {
return ((FloatArrayAsList) collection).toFloatArray();
}
@@ -381,7 +372,7 @@ public final class Floats {
float[] array = new float[len];
for (int i = 0; i < len; i++) {
// checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).floatValue();
+ array[i] = (Float) checkNotNull(boxedArray[i]);
}
return array;
}
@@ -471,8 +462,7 @@ public final class Floats {
@Override public Float set(int index, Float element) {
checkElementIndex(index, size());
float oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -523,7 +513,7 @@ public final class Floats {
}
float[] toFloatArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
float[] result = new float[size];
System.arraycopy(array, start, result, 0, size);
@@ -532,40 +522,4 @@ public final class Floats {
private static final long serialVersionUID = 0;
}
-
- /**
- * Parses the specified string as a single-precision floating point value.
- * The ASCII character {@code '-'} (<code>'&#92;u002D'</code>) is recognized
- * as the minus sign.
- *
- * <p>Unlike {@link Float#parseFloat(String)}, this method returns
- * {@code null} instead of throwing an exception if parsing fails.
- * Valid inputs are exactly those accepted by {@link Float#valueOf(String)},
- * except that leading and trailing whitespace is not permitted.
- *
- * <p>This implementation is likely to be faster than {@code
- * Float.parseFloat} if many failures are expected.
- *
- * @param string the string representation of a {@code float} value
- * @return the floating point value represented by {@code string}, or
- * {@code null} if {@code string} has a length of zero or cannot be
- * parsed as a {@code float} value
- * @since 14.0
- */
- @GwtIncompatible("regular expressions")
- @Nullable
- @Beta
- public static Float tryParse(String string) {
- if (Doubles.FLOATING_POINT_PATTERN.matcher(string).matches()) {
- // TODO(user): could be potentially optimized, but only with
- // extensive testing
- try {
- return Float.parseFloat(string);
- } catch (NumberFormatException e) {
- // Float.parseFloat has changed specs several times, so fall through
- // gracefully
- }
- }
- return null;
- }
}
diff --git a/guava/src/com/google/common/primitives/Ints.java b/guava/src/com/google/common/primitives/Ints.java
index 966066d..bc7acb8 100644
--- a/guava/src/com/google/common/primitives/Ints.java
+++ b/guava/src/com/google/common/primitives/Ints.java
@@ -40,10 +40,6 @@ import javax.annotation.CheckForNull;
* Static utility methods pertaining to {@code int} primitives, that are not
* already found in either {@link Integer} or {@link Arrays}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
@@ -420,21 +416,20 @@ public final class Ints {
}
/**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code int} value in the manner of {@link Number#intValue}.
+ * Copies a collection of {@code Integer} instances into a new array of
+ * primitive {@code int} values.
*
* <p>Elements are copied from the argument collection as if by {@code
* collection.toArray()}. Calling this method is as thread-safe as calling
* that method.
*
- * @param collection a collection of {@code Number} instances
+ * @param collection a collection of {@code Integer} objects
* @return an array containing the same values as {@code collection}, in the
* same order, converted to primitives
* @throws NullPointerException if {@code collection} or any of its elements
* is null
- * @since 1.0 (parameter was {@code Collection<Integer>} before 12.0)
*/
- public static int[] toArray(Collection<? extends Number> collection) {
+ public static int[] toArray(Collection<Integer> collection) {
if (collection instanceof IntArrayAsList) {
return ((IntArrayAsList) collection).toIntArray();
}
@@ -444,7 +439,7 @@ public final class Ints {
int[] array = new int[len];
for (int i = 0; i < len; i++) {
// checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).intValue();
+ array[i] = (Integer) checkNotNull(boxedArray[i]);
}
return array;
}
@@ -531,8 +526,7 @@ public final class Ints {
@Override public Integer set(int index, Integer element) {
checkElementIndex(index, size());
int oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -583,7 +577,7 @@ public final class Ints {
}
int[] toIntArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
int[] result = new int[size];
System.arraycopy(array, start, result, 0, size);
diff --git a/guava/src/com/google/common/primitives/Longs.java b/guava/src/com/google/common/primitives/Longs.java
index 9460316..99c7033 100644
--- a/guava/src/com/google/common/primitives/Longs.java
+++ b/guava/src/com/google/common/primitives/Longs.java
@@ -21,8 +21,8 @@ import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkPositionIndexes;
-import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
import java.io.Serializable;
import java.util.AbstractList;
@@ -37,14 +37,10 @@ import java.util.RandomAccess;
* Static utility methods pertaining to {@code long} primitives, that are not
* already found in either {@link Long} or {@link Arrays}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
-@GwtCompatible
+@GwtCompatible(emulated = true)
public final class Longs {
private Longs() {}
@@ -258,15 +254,17 @@ public final class Longs {
* {@link com.google.common.io.ByteStreams#newDataOutput()} to get a growable
* buffer.
*/
+ @GwtIncompatible("doesn't work")
public static byte[] toByteArray(long value) {
- // Note that this code needs to stay compatible with GWT, which has known
- // bugs when narrowing byte casts of long values occur.
- byte[] result = new byte[8];
- for (int i = 7; i >= 0; i--) {
- result[i] = (byte) (value & 0xffL);
- value >>= 8;
- }
- return result;
+ return new byte[] {
+ (byte) (value >> 56),
+ (byte) (value >> 48),
+ (byte) (value >> 40),
+ (byte) (value >> 32),
+ (byte) (value >> 24),
+ (byte) (value >> 16),
+ (byte) (value >> 8),
+ (byte) value};
}
/**
@@ -282,6 +280,7 @@ public final class Longs {
* @throws IllegalArgumentException if {@code bytes} has fewer than 8
* elements
*/
+ @GwtIncompatible("doesn't work")
public static long fromByteArray(byte[] bytes) {
checkArgument(bytes.length >= BYTES,
"array too small: %s < %s", bytes.length, BYTES);
@@ -296,6 +295,7 @@ public final class Longs {
*
* @since 7.0
*/
+ @GwtIncompatible("doesn't work")
public static long fromBytes(byte b1, byte b2, byte b3, byte b4,
byte b5, byte b6, byte b7, byte b8) {
return (b1 & 0xFFL) << 56
@@ -309,60 +309,6 @@ public final class Longs {
}
/**
- * Parses the specified string as a signed decimal long value. The ASCII
- * character {@code '-'} (<code>'&#92;u002D'</code>) is recognized as the
- * minus sign.
- *
- * <p>Unlike {@link Long#parseLong(String)}, this method returns
- * {@code null} instead of throwing an exception if parsing fails.
- *
- * <p>Note that strings prefixed with ASCII {@code '+'} are rejected, even
- * under JDK 7, despite the change to {@link Long#parseLong(String)} for
- * that version.
- *
- * @param string the string representation of a long value
- * @return the long value represented by {@code string}, or {@code null} if
- * {@code string} has a length of zero or cannot be parsed as a long
- * value
- * @since 14.0
- */
- @Beta
- public static Long tryParse(String string) {
- if (checkNotNull(string).isEmpty()) {
- return null;
- }
- boolean negative = string.charAt(0) == '-';
- int index = negative ? 1 : 0;
- if (index == string.length()) {
- return null;
- }
- int digit = string.charAt(index++) - '0';
- if (digit < 0 || digit > 9) {
- return null;
- }
- long accum = -digit;
- while (index < string.length()) {
- digit = string.charAt(index++) - '0';
- if (digit < 0 || digit > 9 || accum < Long.MIN_VALUE / 10) {
- return null;
- }
- accum *= 10;
- if (accum < Long.MIN_VALUE + digit) {
- return null;
- }
- accum -= digit;
- }
-
- if (negative) {
- return accum;
- } else if (accum == Long.MIN_VALUE) {
- return null;
- } else {
- return -accum;
- }
- }
-
- /**
* Returns an array containing the same values as {@code array}, but
* guaranteed to be of a specified minimum length. If {@code array} already
* has a length of at least {@code minLength}, it is returned directly.
@@ -455,21 +401,20 @@ public final class Longs {
}
/**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code long} value in the manner of {@link Number#longValue}.
+ * Copies a collection of {@code Long} instances into a new array of
+ * primitive {@code long} values.
*
* <p>Elements are copied from the argument collection as if by {@code
* collection.toArray()}. Calling this method is as thread-safe as calling
* that method.
*
- * @param collection a collection of {@code Number} instances
+ * @param collection a collection of {@code Long} objects
* @return an array containing the same values as {@code collection}, in the
* same order, converted to primitives
* @throws NullPointerException if {@code collection} or any of its elements
* is null
- * @since 1.0 (parameter was {@code Collection<Long>} before 12.0)
*/
- public static long[] toArray(Collection<? extends Number> collection) {
+ public static long[] toArray(Collection<Long> collection) {
if (collection instanceof LongArrayAsList) {
return ((LongArrayAsList) collection).toLongArray();
}
@@ -479,7 +424,7 @@ public final class Longs {
long[] array = new long[len];
for (int i = 0; i < len; i++) {
// checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).longValue();
+ array[i] = (Long) checkNotNull(boxedArray[i]);
}
return array;
}
@@ -566,8 +511,7 @@ public final class Longs {
@Override public Long set(int index, Long element) {
checkElementIndex(index, size());
long oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -618,7 +562,7 @@ public final class Longs {
}
long[] toLongArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
long[] result = new long[size];
System.arraycopy(array, start, result, 0, size);
diff --git a/guava/src/com/google/common/primitives/ParseRequest.java b/guava/src/com/google/common/primitives/ParseRequest.java
deleted file mode 100644
index 98f29b4..0000000
--- a/guava/src/com/google/common/primitives/ParseRequest.java
+++ /dev/null
@@ -1,57 +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.primitives;
-
-import com.google.common.annotations.GwtCompatible;
-
-/**
- * A string to be parsed as a number and the radix to interpret it in.
- */
-@GwtCompatible
-final class ParseRequest {
- final String rawValue;
- final int radix;
-
- private ParseRequest(String rawValue, int radix) {
- this.rawValue = rawValue;
- this.radix = radix;
- }
-
- static ParseRequest fromString(String stringValue) {
- if (stringValue.length() == 0) {
- throw new NumberFormatException("empty string");
- }
-
- // Handle radix specifier if present
- String rawValue;
- int radix;
- char firstChar = stringValue.charAt(0);
- if (stringValue.startsWith("0x") || stringValue.startsWith("0X")) {
- rawValue = stringValue.substring(2);
- radix = 16;
- } else if (firstChar == '#') {
- rawValue = stringValue.substring(1);
- radix = 16;
- } else if (firstChar == '0' && stringValue.length() > 1) {
- rawValue = stringValue.substring(1);
- radix = 8;
- } else {
- rawValue = stringValue;
- radix = 10;
- }
-
- return new ParseRequest(rawValue, radix);
- }
-}
diff --git a/guava/src/com/google/common/primitives/Shorts.java b/guava/src/com/google/common/primitives/Shorts.java
index db3d206..d5859b3 100644
--- a/guava/src/com/google/common/primitives/Shorts.java
+++ b/guava/src/com/google/common/primitives/Shorts.java
@@ -37,10 +37,6 @@ import java.util.RandomAccess;
* Static utility methods pertaining to {@code short} primitives, that are not
* already found in either {@link Short} or {@link Arrays}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
@@ -418,21 +414,20 @@ public final class Shorts {
}
/**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code short} value in the manner of {@link Number#shortValue}.
+ * Copies a collection of {@code Short} instances into a new array of
+ * primitive {@code short} values.
*
* <p>Elements are copied from the argument collection as if by {@code
* collection.toArray()}. Calling this method is as thread-safe as calling
* that method.
*
- * @param collection a collection of {@code Number} instances
+ * @param collection a collection of {@code Short} objects
* @return an array containing the same values as {@code collection}, in the
* same order, converted to primitives
* @throws NullPointerException if {@code collection} or any of its elements
* is null
- * @since 1.0 (parameter was {@code Collection<Short>} before 12.0)
*/
- public static short[] toArray(Collection<? extends Number> collection) {
+ public static short[] toArray(Collection<Short> collection) {
if (collection instanceof ShortArrayAsList) {
return ((ShortArrayAsList) collection).toShortArray();
}
@@ -442,7 +437,7 @@ public final class Shorts {
short[] array = new short[len];
for (int i = 0; i < len; i++) {
// checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).shortValue();
+ array[i] = (Short) checkNotNull(boxedArray[i]);
}
return array;
}
@@ -529,8 +524,7 @@ public final class Shorts {
@Override public Short set(int index, Short element) {
checkElementIndex(index, size());
short oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -581,7 +575,7 @@ public final class Shorts {
}
short[] toShortArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
short[] result = new short[size];
System.arraycopy(array, start, result, 0, size);
diff --git a/guava/src/com/google/common/primitives/SignedBytes.java b/guava/src/com/google/common/primitives/SignedBytes.java
index 07e3bda..00a36d8 100644
--- a/guava/src/com/google/common/primitives/SignedBytes.java
+++ b/guava/src/com/google/common/primitives/SignedBytes.java
@@ -28,10 +28,6 @@ import java.util.Comparator;
* interpret values as signed. The corresponding methods that treat the values
* as unsigned are found in {@link UnsignedBytes}, and the methods for which
* signedness is not an issue are in {@link Bytes}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
*
* @author Kevin Bourrillion
* @since 1.0
diff --git a/guava/src/com/google/common/primitives/UnsignedBytes.java b/guava/src/com/google/common/primitives/UnsignedBytes.java
index c503f99..1651295 100644
--- a/guava/src/com/google/common/primitives/UnsignedBytes.java
+++ b/guava/src/com/google/common/primitives/UnsignedBytes.java
@@ -19,12 +19,16 @@ package com.google.common.primitives;
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.VisibleForTesting;
-import sun.misc.Unsafe;
+// BEGIN android-changed
+//import sun.misc.Unsafe;
+// END android-changed
+import java.lang.reflect.Field;
import java.nio.ByteOrder;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.Comparator;
/**
@@ -34,35 +38,20 @@ import java.util.Comparator;
* the values as signed are found in {@link SignedBytes}, and the methods for
* which signedness is not an issue are in {@link Bytes}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @author Martin Buchholz
* @author Hiroshi Yamauchi
- * @author Louis Wasserman
* @since 1.0
*/
public final class UnsignedBytes {
private UnsignedBytes() {}
/**
- * The largest power of two that can be represented as an unsigned {@code
- * byte}.
+ * The largest power of two that can be represented as an unsigned {@code byte}.
*
* @since 10.0
*/
- public static final byte MAX_POWER_OF_TWO = (byte) 0x80;
-
- /**
- * The largest value that fits into an unsigned byte.
- *
- * @since 13.0
- */
- public static final byte MAX_VALUE = (byte) 0xFF;
-
- private static final int UNSIGNED_MASK = 0xFF;
+ public static final byte MAX_POWER_OF_TWO = (byte) (1 << 7);
/**
* Returns the value of the given byte as an integer, when treated as
@@ -72,7 +61,7 @@ public final class UnsignedBytes {
* @since 6.0
*/
public static int toInt(byte value) {
- return value & UNSIGNED_MASK;
+ return value & 0xFF;
}
/**
@@ -86,7 +75,7 @@ public final class UnsignedBytes {
* than 255
*/
public static byte checkedCast(long value) {
- checkArgument(value >> Byte.SIZE == 0, "out of range: %s", value);
+ checkArgument(value >> 8 == 0, "out of range: %s", value);
return (byte) value;
}
@@ -99,8 +88,8 @@ public final class UnsignedBytes {
* {@code value <= 0}, and {@code value} cast to {@code byte} otherwise
*/
public static byte saturatedCast(long value) {
- if (value > toInt(MAX_VALUE)) {
- return MAX_VALUE; // -1
+ if (value > 255) {
+ return (byte) 255; // -1
}
if (value < 0) {
return (byte) 0;
@@ -164,71 +153,6 @@ public final class UnsignedBytes {
}
/**
- * Returns a string representation of x, where x is treated as unsigned.
- *
- * @since 13.0
- */
- @Beta
- public static String toString(byte x) {
- return toString(x, 10);
- }
-
- /**
- * Returns a string representation of {@code x} for the given radix, where {@code x} is treated
- * as unsigned.
- *
- * @param x the value to convert to a string.
- * @param radix the radix to use while working with {@code x}
- * @throws IllegalArgumentException if {@code radix} is not between {@link Character#MIN_RADIX}
- * and {@link Character#MAX_RADIX}.
- * @since 13.0
- */
- @Beta
- public static String toString(byte x, int radix) {
- checkArgument(radix >= Character.MIN_RADIX && radix <= Character.MAX_RADIX,
- "radix (%s) must be between Character.MIN_RADIX and Character.MAX_RADIX", radix);
- // Benchmarks indicate this is probably not worth optimizing.
- return Integer.toString(toInt(x), radix);
- }
-
- /**
- * Returns the unsigned {@code byte} value represented by the given decimal string.
- *
- * @throws NumberFormatException if the string does not contain a valid unsigned {@code byte}
- * value
- * @throws NullPointerException if {@code s} is null
- * (in contrast to {@link Byte#parseByte(String)})
- * @since 13.0
- */
- @Beta
- public static byte parseUnsignedByte(String string) {
- return parseUnsignedByte(string, 10);
- }
-
- /**
- * Returns the unsigned {@code byte} value represented by a string with the given radix.
- *
- * @param string the string containing the unsigned {@code byte} representation to be parsed.
- * @param radix the radix to use while parsing {@code string}
- * @throws NumberFormatException if the string does not contain a valid unsigned {@code byte}
- * with the given radix, or if {@code radix} is not between {@link Character#MIN_RADIX}
- * and {@link Character#MAX_RADIX}.
- * @throws NullPointerException if {@code s} is null
- * (in contrast to {@link Byte#parseByte(String)})
- * @since 13.0
- */
- @Beta
- public static byte parseUnsignedByte(String string, int radix) {
- int parse = Integer.parseInt(checkNotNull(string), radix);
- // We need to throw a NumberFormatException, so we have to duplicate checkedCast. =(
- if (parse >> Byte.SIZE == 0) {
- return (byte) parse;
- } else {
- throw new NumberFormatException("out of range: " + parse);
- }
- }
-
- /**
* Returns a string containing the supplied {@code byte} values separated by
* {@code separator}. For example, {@code join(":", (byte) 1, (byte) 2,
* (byte) 255)} returns the string {@code "1:2:255"}.
@@ -244,10 +168,10 @@ public final class UnsignedBytes {
}
// For pre-sizing a builder, just get the right order of magnitude
- StringBuilder builder = new StringBuilder(array.length * (3 + separator.length()));
+ StringBuilder builder = new StringBuilder(array.length * 5);
builder.append(toInt(array[0]));
for (int i = 1; i < array.length; i++) {
- builder.append(separator).append(toString(array[i]));
+ builder.append(separator).append(toInt(array[i]));
}
return builder.toString();
}
@@ -289,133 +213,123 @@ public final class UnsignedBytes {
static final String UNSAFE_COMPARATOR_NAME =
LexicographicalComparatorHolder.class.getName() + "$UnsafeComparator";
- static final Comparator<byte[]> BEST_COMPARATOR = getBestComparator();
-
- @VisibleForTesting
- enum UnsafeComparator implements Comparator<byte[]> {
- INSTANCE;
-
- static final boolean littleEndian =
- ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN);
-
- /*
- * The following static final fields exist for performance reasons.
- *
- * In UnsignedBytesBenchmark, accessing the following objects via static
- * final fields is the fastest (more than twice as fast as the Java
- * implementation, vs ~1.5x with non-final static fields, on x86_32)
- * under the Hotspot server compiler. The reason is obviously that the
- * non-final fields need to be reloaded inside the loop.
- *
- * And, no, defining (final or not) local variables out of the loop still
- * isn't as good because the null check on the theUnsafe object remains
- * inside the loop and BYTE_ARRAY_BASE_OFFSET doesn't get
- * constant-folded.
- *
- * The compiler can treat static final fields as compile-time constants
- * and can constant-fold them while (final or not) local variables are
- * run time values.
- */
-
- static final Unsafe theUnsafe;
-
- /** The offset to the first element in a byte array. */
- static final int BYTE_ARRAY_BASE_OFFSET;
-
- static {
- theUnsafe = getUnsafe();
-
- BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
-
- // sanity check - this should never fail
- if (theUnsafe.arrayIndexScale(byte[].class) != 1) {
- throw new AssertionError();
- }
- }
-
- /**
- * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
- * Replace with a simple call to Unsafe.getUnsafe when integrating
- * into a jdk.
- *
- * @return a sun.misc.Unsafe
- */
- private static sun.misc.Unsafe getUnsafe() {
- try {
- return sun.misc.Unsafe.getUnsafe();
- } catch (SecurityException tryReflectionInstead) {}
- try {
- return java.security.AccessController.doPrivileged
- (new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
- public sun.misc.Unsafe run() throws Exception {
- Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
- for (java.lang.reflect.Field f : k.getDeclaredFields()) {
- f.setAccessible(true);
- Object x = f.get(null);
- if (k.isInstance(x))
- return k.cast(x);
- }
- throw new NoSuchFieldError("the Unsafe");
- }});
- } catch (java.security.PrivilegedActionException e) {
- throw new RuntimeException("Could not initialize intrinsics",
- e.getCause());
- }
- }
-
- @Override public int compare(byte[] left, byte[] right) {
- int minLength = Math.min(left.length, right.length);
- int minWords = minLength / Longs.BYTES;
-
- /*
- * Compare 8 bytes at a time. Benchmarking shows comparing 8 bytes at a
- * time is no slower than comparing 4 bytes at a time even on 32-bit.
- * On the other hand, it is substantially faster on 64-bit.
- */
- for (int i = 0; i < minWords * Longs.BYTES; i += Longs.BYTES) {
- long lw = theUnsafe.getLong(left, BYTE_ARRAY_BASE_OFFSET + (long) i);
- long rw = theUnsafe.getLong(right, BYTE_ARRAY_BASE_OFFSET + (long) i);
- long diff = lw ^ rw;
-
- if (diff != 0) {
- if (!littleEndian) {
- return UnsignedLongs.compare(lw, rw);
- }
-
- // Use binary search
- int n = 0;
- int y;
- int x = (int) diff;
- if (x == 0) {
- x = (int) (diff >>> 32);
- n = 32;
- }
-
- y = x << 16;
- if (y == 0) {
- n += 16;
- } else {
- x = y;
- }
-
- y = x << 8;
- if (y == 0) {
- n += 8;
- }
- return (int) (((lw >>> n) & UNSIGNED_MASK) - ((rw >>> n) & UNSIGNED_MASK));
- }
- }
-
- // The epilogue to cover the last (minLength % 8) elements.
- for (int i = minWords * Longs.BYTES; i < minLength; i++) {
- int result = UnsignedBytes.compare(left[i], right[i]);
- if (result != 0) {
- return result;
- }
- }
- return left.length - right.length;
- }
- }
+ // BEGIN android-changed
+
+ static final Comparator<byte[]> BEST_COMPARATOR = lexicographicalComparatorJavaImpl();
+
+ // @VisibleForTesting
+ // enum UnsafeComparator implements Comparator<byte[]> {
+ // INSTANCE;
+
+ // static final boolean littleEndian =
+ // ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN);
+
+ // /*
+ // * The following static final fields exist for performance reasons.
+ // *
+ // * In UnsignedBytesBenchmark, accessing the following objects via static
+ // * final fields is the fastest (more than twice as fast as the Java
+ // * implementation, vs ~1.5x with non-final static fields, on x86_32)
+ // * under the Hotspot server compiler. The reason is obviously that the
+ // * non-final fields need to be reloaded inside the loop.
+ // *
+ // * And, no, defining (final or not) local variables out of the loop still
+ // * isn't as good because the null check on the theUnsafe object remains
+ // * inside the loop and BYTE_ARRAY_BASE_OFFSET doesn't get
+ // * constant-folded.
+ // *
+ // * The compiler can treat static final fields as compile-time constants
+ // * and can constant-fold them while (final or not) local variables are
+ // * run time values.
+ // */
+
+ // static final Unsafe theUnsafe;
+
+ // /** The offset to the first element in a byte array. */
+ // static final int BYTE_ARRAY_BASE_OFFSET;
+
+ // static {
+ // theUnsafe = (Unsafe) AccessController.doPrivileged(
+ // new PrivilegedAction<Object>() {
+ // @Override
+ // public Object run() {
+ // try {
+ // Field f = Unsafe.class.getDeclaredField("theUnsafe");
+ // f.setAccessible(true);
+ // return f.get(null);
+ // } catch (NoSuchFieldException e) {
+ // // It doesn't matter what we throw;
+ // // it's swallowed in getBestComparator().
+ // throw new Error();
+ // } catch (IllegalAccessException e) {
+ // throw new Error();
+ // }
+ // }
+ // });
+
+ // BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
+
+ // // sanity check - this should never fail
+ // if (theUnsafe.arrayIndexScale(byte[].class) != 1) {
+ // throw new AssertionError();
+ // }
+ // }
+
+ // @Override public int compare(byte[] left, byte[] right) {
+ // int minLength = Math.min(left.length, right.length);
+ // int minWords = minLength / Longs.BYTES;
+
+ // /*
+ // * Compare 8 bytes at a time. Benchmarking shows comparing 8 bytes at a
+ // * time is no slower than comparing 4 bytes at a time even on 32-bit.
+ // * On the other hand, it is substantially faster on 64-bit.
+ // */
+ // for (int i = 0; i < minWords * Longs.BYTES; i += Longs.BYTES) {
+ // long lw = theUnsafe.getLong(left, BYTE_ARRAY_BASE_OFFSET + (long) i);
+ // long rw = theUnsafe.getLong(right, BYTE_ARRAY_BASE_OFFSET + (long) i);
+ // long diff = lw ^ rw;
+
+ // if (diff != 0) {
+ // if (!littleEndian) {
+ // return UnsignedLongs.compare(lw, rw);
+ // }
+
+ // // Use binary search
+ // int n = 0;
+ // int y;
+ // int x = (int) diff;
+ // if (x == 0) {
+ // x = (int) (diff >>> 32);
+ // n = 32;
+ // }
+
+ // y = x << 16;
+ // if (y == 0) {
+ // n += 16;
+ // } else {
+ // x = y;
+ // }
+
+ // y = x << 8;
+ // if (y == 0) {
+ // n += 8;
+ // }
+ // return (int) (((lw >>> n) & 0xFFL) - ((rw >>> n) & 0xFFL));
+ // }
+ // }
+
+ // // The epilogue to cover the last (minLength % 8) elements.
+ // for (int i = minWords * Longs.BYTES; i < minLength; i++) {
+ // int result = UnsignedBytes.compare(left[i], right[i]);
+ // if (result != 0) {
+ // return result;
+ // }
+ // }
+ // return left.length - right.length;
+ // }
+ // }
+
+ // END android-changed
enum PureJavaComparator implements Comparator<byte[]> {
INSTANCE;
@@ -432,22 +346,28 @@ public final class UnsignedBytes {
}
}
- /**
- * Returns the Unsafe-using Comparator, or falls back to the pure-Java
- * implementation if unable to do so.
- */
- static Comparator<byte[]> getBestComparator() {
- try {
- Class<?> theClass = Class.forName(UNSAFE_COMPARATOR_NAME);
-
- // yes, UnsafeComparator does implement Comparator<byte[]>
- @SuppressWarnings("unchecked")
- Comparator<byte[]> comparator =
- (Comparator<byte[]>) theClass.getEnumConstants()[0];
- return comparator;
- } catch (Throwable t) { // ensure we really catch *everything*
- return lexicographicalComparatorJavaImpl();
- }
- }
+ // BEGIN android-changed
+
+ // /**
+ // * Returns the Unsafe-using Comparator, or falls back to the pure-Java
+ // * implementation if unable to do so.
+ // */
+ // static Comparator<byte[]> getBestComparator() {
+ // try {
+ // Class<?> theClass = Class.forName(UNSAFE_COMPARATOR_NAME);
+
+ // // yes, UnsafeComparator does implement Comparator<byte[]>
+ // @SuppressWarnings("unchecked")
+ // Comparator<byte[]> comparator =
+ // (Comparator<byte[]>) theClass.getEnumConstants()[0];
+ // return comparator;
+ // } catch (Throwable t) { // ensure we really catch *everything*
+ // return lexicographicalComparatorJavaImpl();
+ // }
+ // }
+
+ // END android-changed
+
}
}
+
diff --git a/guava/src/com/google/common/primitives/UnsignedInteger.java b/guava/src/com/google/common/primitives/UnsignedInteger.java
index 88d89b5..d64ff88 100644
--- a/guava/src/com/google/common/primitives/UnsignedInteger.java
+++ b/guava/src/com/google/common/primitives/UnsignedInteger.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
@@ -20,28 +20,24 @@ import static com.google.common.primitives.UnsignedInts.INT_MASK;
import static com.google.common.primitives.UnsignedInts.compare;
import static com.google.common.primitives.UnsignedInts.toLong;
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.GwtIncompatible;
-
import java.math.BigInteger;
-import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
/**
* A wrapper class for unsigned {@code int} values, supporting arithmetic operations.
- *
+ *
* <p>In some cases, when speed is more important than code readability, it may be faster simply to
* treat primitive {@code int} values as unsigned, using the methods from {@link UnsignedInts}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained#Unsigned_support">
- * unsigned primitive utilities</a>.
- *
+ *
* @author Louis Wasserman
* @since 11.0
*/
+@Beta
@GwtCompatible(emulated = true)
public final class UnsignedInteger extends Number implements Comparable<UnsignedInteger> {
public static final UnsignedInteger ZERO = asUnsigned(0);
@@ -51,37 +47,15 @@ public final class UnsignedInteger extends Number implements Comparable<Unsigned
private final int value;
private UnsignedInteger(int value) {
- // GWT doesn't consistently overflow values to make them 32-bit, so we need to force it.
this.value = value & 0xffffffff;
}
/**
* Returns an {@code UnsignedInteger} that, when treated as signed, is
* equal to {@code value}.
- *
- * @deprecated Use {@link #fromIntBits(int)}. This method is scheduled to be removed in Guava
- * release 15.0.
*/
- @Deprecated
- @Beta
public static UnsignedInteger asUnsigned(int value) {
- return fromIntBits(value);
- }
-
- /**
- * Returns an {@code UnsignedInteger} corresponding to a given bit representation.
- * The argument is interpreted as an unsigned 32-bit value. Specifically, the sign bit
- * of {@code bits} is interpreted as a normal bit, and all other bits are treated as usual.
- *
- * <p>If the argument is nonnegative, the returned result will be equal to {@code bits},
- * otherwise, the result will be equal to {@code 2^32 + bits}.
- *
- * <p>To represent unsigned decimal constants, consider {@link #valueOf(long)} instead.
- *
- * @since 14.0
- */
- public static UnsignedInteger fromIntBits(int bits) {
- return new UnsignedInteger(bits);
+ return new UnsignedInteger(value);
}
/**
@@ -91,26 +65,26 @@ public final class UnsignedInteger extends Number implements Comparable<Unsigned
public static UnsignedInteger valueOf(long value) {
checkArgument((value & INT_MASK) == value,
"value (%s) is outside the range for an unsigned integer value", value);
- return fromIntBits((int) value);
+ return asUnsigned((int) value);
}
/**
* Returns a {@code UnsignedInteger} representing the same value as the specified
* {@link BigInteger}. This is the inverse operation of {@link #bigIntegerValue()}.
- *
+ *
* @throws IllegalArgumentException if {@code value} is negative or {@code value >= 2^32}
*/
public static UnsignedInteger valueOf(BigInteger value) {
checkNotNull(value);
checkArgument(value.signum() >= 0 && value.bitLength() <= Integer.SIZE,
"value (%s) is outside the range for an unsigned integer value", value);
- return fromIntBits(value.intValue());
+ return asUnsigned(value.intValue());
}
/**
* Returns an {@code UnsignedInteger} holding the value of the specified {@code String}, parsed
* as an unsigned {@code int} value.
- *
+ *
* @throws NumberFormatException if the string does not contain a parsable unsigned {@code int}
* value
*/
@@ -121,139 +95,62 @@ public final class UnsignedInteger extends Number implements Comparable<Unsigned
/**
* Returns an {@code UnsignedInteger} holding the value of the specified {@code String}, parsed
* as an unsigned {@code int} value in the specified radix.
- *
+ *
* @throws NumberFormatException if the string does not contain a parsable unsigned {@code int}
* value
*/
public static UnsignedInteger valueOf(String string, int radix) {
- return fromIntBits(UnsignedInts.parseUnsignedInt(string, radix));
+ return asUnsigned(UnsignedInts.parseUnsignedInt(string, radix));
}
/**
* Returns the result of adding this and {@code val}. If the result would have more than 32 bits,
* returns the low 32 bits of the result.
- *
- * @deprecated Use {@link #plus(UnsignedInteger)}. This method is scheduled to be removed in Guava
- * release 15.0.
*/
- @Deprecated
- @Beta
public UnsignedInteger add(UnsignedInteger val) {
- return plus(val);
- }
-
- /**
- * Returns the result of adding this and {@code val}. If the result would have more than 32 bits,
- * returns the low 32 bits of the result.
- *
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedInteger plus(UnsignedInteger val) {
- return fromIntBits(this.value + checkNotNull(val).value);
+ checkNotNull(val);
+ return asUnsigned(this.value + val.value);
}
/**
* Returns the result of subtracting this and {@code val}. If the result would be negative,
* returns the low 32 bits of the result.
- *
- * @deprecated Use {@link #minus(UnsignedInteger)}. This method is scheduled to be removed in
- * Guava release 15.0.
*/
- @Deprecated
- @Beta
public UnsignedInteger subtract(UnsignedInteger val) {
- return minus(val);
- }
-
- /**
- * Returns the result of subtracting this and {@code val}. If the result would be negative,
- * returns the low 32 bits of the result.
- *
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedInteger minus(UnsignedInteger val) {
- return fromIntBits(value - checkNotNull(val).value);
+ checkNotNull(val);
+ return asUnsigned(this.value - val.value);
}
/**
* Returns the result of multiplying this and {@code val}. If the result would have more than 32
* bits, returns the low 32 bits of the result.
- *
- * @deprecated Use {@link #times(UnsignedInteger)}. This method is scheduled to be removed in
- * Guava release 15.0.
*/
- @Deprecated
- @Beta
@GwtIncompatible("Does not truncate correctly")
public UnsignedInteger multiply(UnsignedInteger val) {
- return times(val);
- }
-
- /**
- * Returns the result of multiplying this and {@code val}. If the result would have more than 32
- * bits, returns the low 32 bits of the result.
- *
- * @since 14.0
- */
- @CheckReturnValue
- @GwtIncompatible("Does not truncate correctly")
- public UnsignedInteger times(UnsignedInteger val) {
- // TODO(user): make this GWT-compatible
- return fromIntBits(value * checkNotNull(val).value);
+ checkNotNull(val);
+ return asUnsigned(value * val.value);
}
/**
* Returns the result of dividing this by {@code val}.
- *
- * @deprecated Use {@link #dividedBy(UnsignedInteger)}. This method is scheduled to be removed in
- * Guava release 15.0.
*/
- @Deprecated
- @Beta
public UnsignedInteger divide(UnsignedInteger val) {
- return dividedBy(val);
- }
-
- /**
- * Returns the result of dividing this by {@code val}.
- *
- * @throws ArithmeticException if {@code val} is zero
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedInteger dividedBy(UnsignedInteger val) {
- return fromIntBits(UnsignedInts.divide(value, checkNotNull(val).value));
+ checkNotNull(val);
+ return asUnsigned(UnsignedInts.divide(value, val.value));
}
/**
* Returns the remainder of dividing this by {@code val}.
- *
- * @deprecated Use {@link #mod(UnsignedInteger)}. This method is scheduled to be removed in Guava
- * release 15.0.
*/
- @Deprecated
- @Beta
public UnsignedInteger remainder(UnsignedInteger val) {
- return mod(val);
- }
-
- /**
- * Returns this mod {@code val}.
- *
- * @throws ArithmeticException if {@code val} is zero
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedInteger mod(UnsignedInteger val) {
- return fromIntBits(UnsignedInts.remainder(value, checkNotNull(val).value));
+ checkNotNull(val);
+ return asUnsigned(UnsignedInts.remainder(value, val.value));
}
/**
* Returns the value of this {@code UnsignedInteger} as an {@code int}. This is an inverse
- * operation to {@link #fromIntBits}.
- *
+ * operation to {@link #asUnsigned}.
+ *
* <p>Note that if this {@code UnsignedInteger} holds a value {@code >= 2^31}, the returned value
* will be equal to {@code this - 2^32}.
*/
diff --git a/guava/src/com/google/common/primitives/UnsignedInts.java b/guava/src/com/google/common/primitives/UnsignedInts.java
index 762b841..222d9f3 100644
--- a/guava/src/com/google/common/primitives/UnsignedInts.java
+++ b/guava/src/com/google/common/primitives/UnsignedInts.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
@@ -17,30 +17,26 @@ package com.google.common.primitives;
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 java.util.Arrays;
import java.util.Comparator;
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
/**
* Static utility methods pertaining to {@code int} primitives that interpret values as
* <i>unsigned</i> (that is, any negative value {@code x} is treated as the positive value
* {@code 2^32 + x}). The methods for which signedness is not an issue are in {@link Ints}, as well
* as signed versions of methods for which signedness is an issue.
- *
+ *
* <p>In addition, this class provides several static methods for converting an {@code int} to a
* {@code String} and a {@code String} to an {@code int} that treat the {@code int} as an unsigned
* number.
- *
+ *
* <p>Users of these utilities must be <i>extremely careful</i> not to mix up signed and unsigned
* {@code int} values. When possible, it is recommended that the {@link UnsignedInteger} wrapper
* class be used, at a small efficiency penalty, to enforce the distinction in the type system.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained#Unsigned_support">
- * unsigned primitive utilities</a>.
- *
+ *
* @author Louis Wasserman
* @since 11.0
*/
@@ -58,7 +54,7 @@ public final class UnsignedInts {
/**
* Compares the two specified {@code int} values, treating them as unsigned values between
* {@code 0} and {@code 2^32 - 1} inclusive.
- *
+ *
* @param a the first unsigned {@code int} to compare
* @param b the second unsigned {@code int} to compare
* @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
@@ -77,7 +73,7 @@ public final class UnsignedInts {
/**
* Returns the least value present in {@code array}, treating values as unsigned.
- *
+ *
* @param array a <i>nonempty</i> array of unsigned {@code int} values
* @return the value present in {@code array} that is less than or equal to every other value in
* the array according to {@link #compare}
@@ -97,7 +93,7 @@ public final class UnsignedInts {
/**
* Returns the greatest value present in {@code array}, treating values as unsigned.
- *
+ *
* @param array a <i>nonempty</i> array of unsigned {@code int} values
* @return the value present in {@code array} that is greater than or equal to every other value
* in the array according to {@link #compare}
@@ -118,7 +114,7 @@ public final class UnsignedInts {
/**
* Returns a string containing the supplied unsigned {@code int} values separated by
* {@code separator}. For example, {@code join("-", 1, 2, 3)} returns the string {@code "1-2-3"}.
- *
+ *
* @param separator the text that should appear between consecutive values in the resulting
* string (but not at the start or end)
* @param array an array of unsigned {@code int} values, possibly empty
@@ -131,7 +127,7 @@ public final class UnsignedInts {
// For pre-sizing a builder, just get the right order of magnitude
StringBuilder builder = new StringBuilder(array.length * 5);
- builder.append(toString(array[0]));
+ builder.append(array[0]);
for (int i = 1; i < array.length; i++) {
builder.append(separator).append(toString(array[i]));
}
@@ -143,10 +139,10 @@ public final class UnsignedInts {
* That is, it compares, using {@link #compare(int, int)}), the first pair of values that follow
* any common prefix, or when one array is a prefix of the other, treats the shorter array as the
* lesser. For example, {@code [] < [1] < [1, 2] < [2] < [1 << 31]}.
- *
+ *
* <p>The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays
* support only identity equality), but it is consistent with {@link Arrays#equals(int[], int[])}.
- *
+ *
* @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order"> Lexicographical order
* article at Wikipedia</a>
*/
@@ -172,7 +168,7 @@ public final class UnsignedInts {
/**
* Returns dividend / divisor, where the dividend and divisor are treated as unsigned 32-bit
* quantities.
- *
+ *
* @param dividend the dividend (numerator)
* @param divisor the divisor (denominator)
* @throws ArithmeticException if divisor is 0
@@ -184,7 +180,7 @@ public final class UnsignedInts {
/**
* Returns dividend % divisor, where the dividend and divisor are treated as unsigned 32-bit
* quantities.
- *
+ *
* @param dividend the dividend (numerator)
* @param divisor the divisor (denominator)
* @throws ArithmeticException if divisor is 0
@@ -194,39 +190,11 @@ public final class UnsignedInts {
}
/**
- * Returns the unsigned {@code int} value represented by the given string.
- *
- * Accepts a decimal, hexadecimal, or octal number given by specifying the following prefix:
- *
- * <ul>
- * <li>{@code 0x}<i>HexDigits</i>
- * <li>{@code 0X}<i>HexDigits</i>
- * <li>{@code #}<i>HexDigits</i>
- * <li>{@code 0}<i>OctalDigits</i>
- * </ul>
- *
- * @throws NumberFormatException if the string does not contain a valid unsigned {@code int} value
- * @since 13.0
- */
- public static int decode(String stringValue) {
- ParseRequest request = ParseRequest.fromString(stringValue);
-
- try {
- return parseUnsignedInt(request.rawValue, request.radix);
- } catch (NumberFormatException e) {
- NumberFormatException decodeException =
- new NumberFormatException("Error parsing value: " + stringValue);
- decodeException.initCause(e);
- throw decodeException;
- }
- }
-
- /**
* Returns the unsigned {@code int} value represented by the given decimal string.
- *
- * @throws NumberFormatException if the string does not contain a valid unsigned {@code int} value
- * @throws NullPointerException if {@code s} is null
- * (in contrast to {@link Integer#parseInt(String)})
+ *
+ * @throws NumberFormatException if the string does not contain a valid unsigned integer, or if
+ * the value represented is too large to fit in an unsigned {@code int}.
+ * @throws NullPointerException if {@code s} is null
*/
public static int parseUnsignedInt(String s) {
return parseUnsignedInt(s, 10);
@@ -234,14 +202,12 @@ public final class UnsignedInts {
/**
* Returns the unsigned {@code int} value represented by a string with the given radix.
- *
+ *
* @param string the string containing the unsigned integer representation to be parsed.
* @param radix the radix to use while parsing {@code s}; must be between
* {@link Character#MIN_RADIX} and {@link Character#MAX_RADIX}.
* @throws NumberFormatException if the string does not contain a valid unsigned {@code int}, or
* if supplied radix is invalid.
- * @throws NullPointerException if {@code s} is null
- * (in contrast to {@link Integer#parseInt(String)})
*/
public static int parseUnsignedInt(String string, int radix) {
checkNotNull(string);
@@ -263,7 +229,7 @@ public final class UnsignedInts {
/**
* Returns a string representation of {@code x} for the given radix, where {@code x} is treated
* as unsigned.
- *
+ *
* @param x the value to convert to a string.
* @param radix the radix to use while working with {@code x}
* @throws IllegalArgumentException if {@code radix} is not between {@link Character#MIN_RADIX}
diff --git a/guava/src/com/google/common/primitives/UnsignedLong.java b/guava/src/com/google/common/primitives/UnsignedLong.java
index a48de6b..62f7f81 100644
--- a/guava/src/com/google/common/primitives/UnsignedLong.java
+++ b/guava/src/com/google/common/primitives/UnsignedLong.java
@@ -17,31 +17,30 @@ package com.google.common.primitives;
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 java.io.Serializable;
import java.math.BigInteger;
-import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
/**
* A wrapper class for unsigned {@code long} values, supporting arithmetic operations.
*
* <p>In some cases, when speed is more important than code readability, it may be faster simply to
* treat primitive {@code long} values as unsigned, using the methods from {@link UnsignedLongs}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained#Unsigned_support">
- * unsigned primitive utilities</a>.
+ * <p><b>Please do not extend this class; it will be made final in the near future.</b>
*
* @author Louis Wasserman
* @author Colin Evans
* @since 11.0
*/
+@Beta
@GwtCompatible(serializable = true)
-public final class UnsignedLong extends Number implements Comparable<UnsignedLong>, Serializable {
+public class UnsignedLong extends Number implements Comparable<UnsignedLong>, Serializable {
+ // TODO(user): make final as soon as util.UnsignedLong is migrated over
private static final long UNSIGNED_MASK = 0x7fffffffffffffffL;
@@ -51,7 +50,7 @@ public final class UnsignedLong extends Number implements Comparable<UnsignedLon
private final long value;
- private UnsignedLong(long value) {
+ protected UnsignedLong(long value) {
this.value = value;
}
@@ -61,49 +60,14 @@ public final class UnsignedLong extends Number implements Comparable<UnsignedLon
*
* <p>Put another way, if {@code value} is negative, the returned result will be equal to
* {@code 2^64 + value}; otherwise, the returned result will be equal to {@code value}.
- *
- * @deprecated Use {@link #fromLongBits(long)}. This method is scheduled to be removed in Guava
- * release 15.0.
*/
- @Deprecated
- @Beta
public static UnsignedLong asUnsigned(long value) {
- return fromLongBits(value);
- }
-
- /**
- * Returns an {@code UnsignedLong} corresponding to a given bit representation.
- * The argument is interpreted as an unsigned 64-bit value. Specifically, the sign bit
- * of {@code bits} is interpreted as a normal bit, and all other bits are treated as usual.
- *
- * <p>If the argument is nonnegative, the returned result will be equal to {@code bits},
- * otherwise, the result will be equal to {@code 2^64 + bits}.
- *
- * <p>To represent decimal constants less than {@code 2^63}, consider {@link #valueOf(long)}
- * instead.
- *
- * @since 14.0
- */
- public static UnsignedLong fromLongBits(long bits) {
- // TODO(user): consider caching small values, like Long.valueOf
- return new UnsignedLong(bits);
+ return new UnsignedLong(value);
}
/**
- * Returns an {@code UnsignedLong} representing the same value as the specified {@code long}.
- *
- * @throws IllegalArgumentException if {@code value} is negative
- * @since 14.0
- */
- public static UnsignedLong valueOf(long value) {
- checkArgument(value >= 0,
- "value (%s) is outside the range for an unsigned long value", value);
- return fromLongBits(value);
- }
-
- /**
- * Returns a {@code UnsignedLong} representing the same value as the specified
- * {@code BigInteger}. This is the inverse operation of {@link #bigIntegerValue()}.
+ * Returns a {@code UnsignedLong} representing the same value as the specified {@code BigInteger}
+ * . This is the inverse operation of {@link #bigIntegerValue()}.
*
* @throws IllegalArgumentException if {@code value} is negative or {@code value >= 2^64}
*/
@@ -111,7 +75,7 @@ public final class UnsignedLong extends Number implements Comparable<UnsignedLon
checkNotNull(value);
checkArgument(value.signum() >= 0 && value.bitLength() <= Long.SIZE,
"value (%s) is outside the range for an unsigned long value", value);
- return fromLongBits(value.longValue());
+ return asUnsigned(value.longValue());
}
/**
@@ -134,121 +98,50 @@ public final class UnsignedLong extends Number implements Comparable<UnsignedLon
* {@link Character#MAX_RADIX}
*/
public static UnsignedLong valueOf(String string, int radix) {
- return fromLongBits(UnsignedLongs.parseUnsignedLong(string, radix));
+ return asUnsigned(UnsignedLongs.parseUnsignedLong(string, radix));
}
/**
* Returns the result of adding this and {@code val}. If the result would have more than 64 bits,
* returns the low 64 bits of the result.
- *
- * @deprecated Use {@link #plus(UnsignedLong)}. This method is scheduled to be removed in Guava
- * release 15.0.
*/
- @Deprecated
- @Beta
public UnsignedLong add(UnsignedLong val) {
- return plus(val);
- }
-
- /**
- * Returns the result of adding this and {@code val}. If the result would have more than 64 bits,
- * returns the low 64 bits of the result.
- *
- * @since 14.0
- */
- public UnsignedLong plus(UnsignedLong val) {
- return fromLongBits(this.value + checkNotNull(val).value);
+ checkNotNull(val);
+ return asUnsigned(this.value + val.value);
}
/**
* Returns the result of subtracting this and {@code val}. If the result would be negative,
* returns the low 64 bits of the result.
- *
- * @deprecated Use {@link #minus(UnsignedLong)}. This method is scheduled to be removed in Guava
- * release 15.0.
*/
- @Deprecated
- @Beta
public UnsignedLong subtract(UnsignedLong val) {
- return minus(val);
- }
-
- /**
- * Returns the result of subtracting this and {@code val}. If the result would have more than 64
- * bits, returns the low 64 bits of the result.
- *
- * @since 14.0
- */
- public UnsignedLong minus(UnsignedLong val) {
- return fromLongBits(this.value - checkNotNull(val).value);
+ checkNotNull(val);
+ return asUnsigned(this.value - val.value);
}
/**
* Returns the result of multiplying this and {@code val}. If the result would have more than 64
* bits, returns the low 64 bits of the result.
- *
- * @deprecated Use {@link #times(UnsignedLong)}. This method is scheduled to be removed in Guava
- * release 15.0.
*/
- @Deprecated
- @Beta
public UnsignedLong multiply(UnsignedLong val) {
- return times(val);
- }
-
- /**
- * Returns the result of multiplying this and {@code val}. If the result would have more than 64
- * bits, returns the low 64 bits of the result.
- *
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedLong times(UnsignedLong val) {
- return fromLongBits(value * checkNotNull(val).value);
+ checkNotNull(val);
+ return asUnsigned(value * val.value);
}
/**
* Returns the result of dividing this by {@code val}.
- *
- * @deprecated Use {@link #dividedBy(UnsignedLong)}. This method is scheduled to be removed in
- * Guava release 15.0.
*/
- @Deprecated
- @Beta
public UnsignedLong divide(UnsignedLong val) {
- return dividedBy(val);
- }
-
- /**
- * Returns the result of dividing this by {@code val}.
- *
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedLong dividedBy(UnsignedLong val) {
- return fromLongBits(UnsignedLongs.divide(value, checkNotNull(val).value));
+ checkNotNull(val);
+ return asUnsigned(UnsignedLongs.divide(value, val.value));
}
/**
* Returns the remainder of dividing this by {@code val}.
- *
- * @deprecated Use {@link #mod(UnsignedLong)}. This method is scheduled to be removed in Guava
- * release 15.0.
*/
- @Deprecated
- @Beta
public UnsignedLong remainder(UnsignedLong val) {
- return mod(val);
- }
-
- /**
- * Returns this modulo {@code val}.
- *
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedLong mod(UnsignedLong val) {
- return fromLongBits(UnsignedLongs.remainder(value, checkNotNull(val).value));
+ checkNotNull(val);
+ return asUnsigned(UnsignedLongs.remainder(value, val.value));
}
/**
diff --git a/guava/src/com/google/common/primitives/UnsignedLongs.java b/guava/src/com/google/common/primitives/UnsignedLongs.java
index cb9923f..b723a1b 100644
--- a/guava/src/com/google/common/primitives/UnsignedLongs.java
+++ b/guava/src/com/google/common/primitives/UnsignedLongs.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
@@ -17,31 +17,27 @@ package com.google.common.primitives;
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 java.math.BigInteger;
import java.util.Arrays;
import java.util.Comparator;
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
/**
* Static utility methods pertaining to {@code long} primitives that interpret values as
* <i>unsigned</i> (that is, any negative value {@code x} is treated as the positive value
* {@code 2^64 + x}). The methods for which signedness is not an issue are in {@link Longs}, as
* well as signed versions of methods for which signedness is an issue.
- *
+ *
* <p>In addition, this class provides several static methods for converting a {@code long} to a
* {@code String} and a {@code String} to a {@code long} that treat the {@code long} as an unsigned
* number.
- *
+ *
* <p>Users of these utilities must be <i>extremely careful</i> not to mix up signed and unsigned
- * {@code long} values. When possible, it is recommended that the {@link UnsignedLong} wrapper
+ * {@code long} values. When possible, it is recommended that the {@link UnsignedLong} wrapper
* class be used, at a small efficiency penalty, to enforce the distinction in the type system.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained#Unsigned_support">
- * unsigned primitive utilities</a>.
- *
+ *
* @author Louis Wasserman
* @author Brian Milch
* @author Colin Evans
@@ -56,7 +52,7 @@ public final class UnsignedLongs {
/**
* A (self-inverse) bijection which converts the ordering on unsigned longs to the ordering on
- * longs, that is, {@code a <= b} as unsigned longs if and only if {@code flip(a) <= flip(b)}
+ * longs, that is, {@code a <= b} as unsigned longs if and only if {@code rotate(a) <= rotate(b)}
* as signed longs.
*/
private static long flip(long a) {
@@ -66,7 +62,7 @@ public final class UnsignedLongs {
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
- *
+ *
* @param a the first unsigned {@code long} to compare
* @param b the second unsigned {@code long} to compare
* @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
@@ -78,7 +74,7 @@ public final class UnsignedLongs {
/**
* Returns the least value present in {@code array}, treating values as unsigned.
- *
+ *
* @param array a <i>nonempty</i> array of unsigned {@code long} values
* @return the value present in {@code array} that is less than or equal to every other value in
* the array according to {@link #compare}
@@ -98,7 +94,7 @@ public final class UnsignedLongs {
/**
* Returns the greatest value present in {@code array}, treating values as unsigned.
- *
+ *
* @param array a <i>nonempty</i> array of unsigned {@code long} values
* @return the value present in {@code array} that is greater than or equal to every other value
* in the array according to {@link #compare}
@@ -119,7 +115,7 @@ public final class UnsignedLongs {
/**
* Returns a string containing the supplied unsigned {@code long} values separated by
* {@code separator}. For example, {@code join("-", 1, 2, 3)} returns the string {@code "1-2-3"}.
- *
+ *
* @param separator the text that should appear between consecutive values in the resulting
* string (but not at the start or end)
* @param array an array of unsigned {@code long} values, possibly empty
@@ -132,7 +128,7 @@ public final class UnsignedLongs {
// For pre-sizing a builder, just get the right order of magnitude
StringBuilder builder = new StringBuilder(array.length * 5);
- builder.append(toString(array[0]));
+ builder.append(array[0]);
for (int i = 1; i < array.length; i++) {
builder.append(separator).append(toString(array[i]));
}
@@ -144,11 +140,11 @@ public final class UnsignedLongs {
* lexicographically. That is, it compares, using {@link #compare(long, long)}), the first pair of
* values that follow any common prefix, or when one array is a prefix of the other, treats the
* shorter array as the lesser. For example, {@code [] < [1L] < [1L, 2L] < [2L] < [1L << 63]}.
- *
+ *
* <p>The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays
* support only identity equality), but it is consistent with
* {@link Arrays#equals(long[], long[])}.
- *
+ *
* @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">Lexicographical order
* article at Wikipedia</a>
*/
@@ -174,7 +170,7 @@ public final class UnsignedLongs {
/**
* Returns dividend / divisor, where the dividend and divisor are treated as unsigned 64-bit
* quantities.
- *
+ *
* @param dividend the dividend (numerator)
* @param divisor the divisor (denominator)
* @throws ArithmeticException if divisor is 0
@@ -207,7 +203,7 @@ public final class UnsignedLongs {
/**
* Returns dividend % divisor, where the dividend and divisor are treated as unsigned 64-bit
* quantities.
- *
+ *
* @param dividend the dividend (numerator)
* @param divisor the divisor (denominator)
* @throws ArithmeticException if divisor is 0
@@ -240,55 +236,22 @@ public final class UnsignedLongs {
/**
* Returns the unsigned {@code long} value represented by the given decimal string.
- *
+ *
* @throws NumberFormatException if the string does not contain a valid unsigned {@code long}
* value
- * @throws NullPointerException if {@code s} is null
- * (in contrast to {@link Long#parseLong(String)})
*/
public static long parseUnsignedLong(String s) {
return parseUnsignedLong(s, 10);
}
/**
- * Returns the unsigned {@code long} value represented by the given string.
- *
- * Accepts a decimal, hexadecimal, or octal number given by specifying the following prefix:
- *
- * <ul>
- * <li>{@code 0x}<i>HexDigits</i>
- * <li>{@code 0X}<i>HexDigits</i>
- * <li>{@code #}<i>HexDigits</i>
- * <li>{@code 0}<i>OctalDigits</i>
- * </ul>
- *
- * @throws NumberFormatException if the string does not contain a valid unsigned {@code long}
- * value
- * @since 13.0
- */
- public static long decode(String stringValue) {
- ParseRequest request = ParseRequest.fromString(stringValue);
-
- try {
- return parseUnsignedLong(request.rawValue, request.radix);
- } catch (NumberFormatException e) {
- NumberFormatException decodeException =
- new NumberFormatException("Error parsing value: " + stringValue);
- decodeException.initCause(e);
- throw decodeException;
- }
- }
-
- /**
* Returns the unsigned {@code long} value represented by a string with the given radix.
- *
+ *
* @param s the string containing the unsigned {@code long} representation to be parsed.
* @param radix the radix to use while parsing {@code s}
* @throws NumberFormatException if the string does not contain a valid unsigned {@code long}
* with the given radix, or if {@code radix} is not between {@link Character#MIN_RADIX}
* and {@link Character#MAX_RADIX}.
- * @throws NullPointerException if {@code s} is null
- * (in contrast to {@link Long#parseLong(String)})
*/
public static long parseUnsignedLong(String s, int radix) {
checkNotNull(s);
@@ -296,7 +259,7 @@ public final class UnsignedLongs {
throw new NumberFormatException("empty string");
}
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
- throw new NumberFormatException("illegal radix: " + radix);
+ throw new NumberFormatException("illegal radix:" + radix);
}
int max_safe_pos = maxSafeDigits[radix] - 1;
@@ -347,7 +310,7 @@ public final class UnsignedLongs {
/**
* Returns a string representation of {@code x} for the given radix, where {@code x} is treated
* as unsigned.
- *
+ *
* @param x the value to convert to a string.
* @param radix the radix to use while working with {@code x}
* @throws IllegalArgumentException if {@code radix} is not between {@link Character#MIN_RADIX}
@@ -363,17 +326,23 @@ public final class UnsignedLongs {
char[] buf = new char[64];
int i = buf.length;
if (x < 0) {
- // Separate off the last digit using unsigned division. That will leave
- // a number that is nonnegative as a signed integer.
- long quotient = divide(x, radix);
- long rem = x - quotient * radix;
- buf[--i] = Character.forDigit((int) rem, radix);
- x = quotient;
- }
- // Simple modulo/division approach
- while (x > 0) {
- buf[--i] = Character.forDigit((int) (x % radix), radix);
- x /= radix;
+ // Split x into high-order and low-order halves.
+ // Individual digits are generated from the bottom half into which
+ // bits are moved continously from the top half.
+ long top = x >>> 32;
+ long bot = (x & 0xffffffffl) + ((top % radix) << 32);
+ top /= radix;
+ while ((bot > 0) || (top > 0)) {
+ buf[--i] = Character.forDigit((int) (bot % radix), radix);
+ bot = (bot / radix) + ((top % radix) << 32);
+ top /= radix;
+ }
+ } else {
+ // Simple modulo/division approach
+ while (x > 0) {
+ buf[--i] = Character.forDigit((int) (x % radix), radix);
+ x /= radix;
+ }
}
// Generate string
return new String(buf, i, buf.length - i);
diff --git a/guava/src/com/google/common/primitives/generate.sh b/guava/src/com/google/common/primitives/generate.sh
new file mode 100644
index 0000000..5d594a2
--- /dev/null
+++ b/guava/src/com/google/common/primitives/generate.sh
@@ -0,0 +1,604 @@
+#!/bin/sh
+#
+# Usage example: ./generate.sh int Int Integer"
+# Args are: primitive type, capitalized primitive type, wrapper type
+#
+# To make changes to the .java files in this package,
+# 1. run this script to generate the templates, move the .gen files
+# somewhere else
+# 2. modify the template with your intended changes, then rerun the
+# script
+# 3. use any three-way merge tool to edit the checked-in source files,
+# using the before-and-after generated files as the bases.
+#
+
+if [ "$#" -ne "3" ]
+then
+ echo "Usage example: ./generate.sh int Int Integer"
+ exit 1
+fi
+
+# Note: using the strange strings 'primtyp' and 'WrapperCl' so that they match
+# the maximum length of the real strings ('boolean' and 'Character').
+
+perl -pe "s/primtyp/$1/g; s/PrimTyp/$2/g; s/WrapperCl/$3/g" << "--EOF--" > $2s.java.gen
+/*
+ * 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.primitives;
+
+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.base.Preconditions.checkPositionIndexes;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.io.Serializable;
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.RandomAccess;
+
+/**
+ * Static utility methods pertaining to {@code primtyp} primitives, that are not
+ * already found in either {@link WrapperCl} or {@link Arrays}.
+ *
+ * @author Kevin Bourrillion
+ * @since 1.0
+ */
+@GwtCompatible
+public final class PrimTyps {
+ private PrimTyps() {}
+
+ /**
+ * The number of bytes required to represent a primitive {@code primtyp}
+ * value.
+ */
+ public static final int BYTES = WrapperCl.SIZE / Byte.SIZE;
+
+ /**
+ * Returns a hash code for {@code value}; equal to the result of invoking
+ * {@code ((WrapperCl) value).hashCode()}.
+ *
+ * @param value a primitive {@code primtyp} value
+ * @return a hash code for the value
+ */
+ public static int hashCode(primtyp value) {
+ return ??
+ }
+
+ /**
+ * Returns the {@code primtyp} value that is equal to {@code value}, if
+ * possible.
+ *
+ * @param value any value in the range of the {@code primtyp} type
+ * @return the {@code primtyp} value that equals {@code value}
+ * @throws IllegalArgumentException if {@code value} is greater than {@link
+ * WrapperCl#MAX_VALUE} or less than {@link WrapperCl#MIN_VALUE}
+ */
+ public static primtyp checkedCast(long value) {
+ primtyp result = (primtyp) value;
+ checkArgument(result == value, "Out of range: %s", value);
+ return result;
+ }
+
+ /**
+ * Returns the {@code primtyp} nearest in value to {@code value}.
+ *
+ * @param value any {@code long} value
+ * @return the same value cast to {@code primtyp} if it is in the range of the
+ * {@code primtyp} type, {@link WrapperCl#MAX_VALUE} if it is too large,
+ * or {@link WrapperCl#MIN_VALUE} if it is too small
+ */
+ public static primtyp saturatedCast(long value) {
+ if (value > WrapperCl.MAX_VALUE) {
+ return WrapperCl.MAX_VALUE;
+ }
+ if (value < WrapperCl.MIN_VALUE) {
+ return WrapperCl.MIN_VALUE;
+ }
+ return (primtyp) value;
+ }
+
+ /**
+ * Compares the two specified {@code primtyp} values. The sign of the value
+ * returned is the same as that of {@code ((WrapperCl) a).compareTo(b)}.
+ *
+ * @param a the first {@code primtyp} to compare
+ * @param b the second {@code primtyp} to compare
+ * @return a negative value if {@code a} is less than {@code b}; a positive
+ * value if {@code a} is greater than {@code b}; or zero if they are equal
+ */
+ public static int compare(primtyp a, primtyp b) {
+ return (a < b) ? -1 : ((a > b) ? 1 : 0);
+ }
+
+ /**
+ * Returns {@code true} if {@code target} is present as an element anywhere in
+ * {@code array}.
+ *
+ * @param array an array of {@code primtyp} values, possibly empty
+ * @param target a primitive {@code primtyp} value
+ * @return {@code true} if {@code array[i] == target} for some value of {@code
+ * i}
+ */
+ public static boolean contains(primtyp[] array, primtyp target) {
+ for (primtyp value : array) {
+ if (value == target) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the index of the first appearance of the value {@code target} in
+ * {@code array}.
+ *
+ * @param array an array of {@code primtyp} values, possibly empty
+ * @param target a primitive {@code primtyp} value
+ * @return the least index {@code i} for which {@code array[i] == target}, or
+ * {@code -1} if no such index exists.
+ */
+ public static int indexOf(primtyp[] array, primtyp target) {
+ return indexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int indexOf(
+ primtyp[] array, primtyp target, int start, int end) {
+ for (int i = start; i < end; i++) {
+ if (array[i] == target) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the start position of the first occurrence of the specified {@code
+ * target} within {@code array}, or {@code -1} if there is no such occurrence.
+ *
+ * <p>More formally, returns the lowest index {@code i} such that {@code
+ * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
+ * the same elements as {@code target}.
+ *
+ * @param array the array to search for the sequence {@code target}
+ * @param target the array to search for as a sub-sequence of {@code array}
+ */
+ public static int indexOf(primtyp[] array, primtyp[] target) {
+ checkNotNull(array, "array");
+ checkNotNull(target, "target");
+ if (target.length == 0) {
+ return 0;
+ }
+
+ outer:
+ for (int i = 0; i < array.length - target.length + 1; i++) {
+ for (int j = 0; j < target.length; j++) {
+ if (array[i + j] != target[j]) {
+ continue outer;
+ }
+ }
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the index of the last appearance of the value {@code target} in
+ * {@code array}.
+ *
+ * @param array an array of {@code primtyp} values, possibly empty
+ * @param target a primitive {@code primtyp} value
+ * @return the greatest index {@code i} for which {@code array[i] == target},
+ * or {@code -1} if no such index exists.
+ */
+ public static int lastIndexOf(primtyp[] array, primtyp target) {
+ return lastIndexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int lastIndexOf(
+ primtyp[] array, primtyp target, int start, int end) {
+ for (int i = end - 1; i >= start; i--) {
+ if (array[i] == target) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the least value present in {@code array}.
+ *
+ * @param array a <i>nonempty</i> array of {@code primtyp} values
+ * @return the value present in {@code array} that is less than or equal to
+ * every other value in the array
+ * @throws IllegalArgumentException if {@code array} is empty
+ */
+ public static primtyp min(primtyp... array) {
+ checkArgument(array.length > 0);
+ primtyp min = array[0];
+ for (int i = 1; i < array.length; i++) {
+ if (array[i] < min) {
+ min = array[i];
+ }
+ }
+ return min;
+ }
+
+ /**
+ * Returns the greatest value present in {@code array}.
+ *
+ * @param array a <i>nonempty</i> array of {@code primtyp} values
+ * @return the value present in {@code array} that is greater than or equal to
+ * every other value in the array
+ * @throws IllegalArgumentException if {@code array} is empty
+ */
+ public static primtyp max(primtyp... array) {
+ checkArgument(array.length > 0);
+ primtyp max = array[0];
+ for (int i = 1; i < array.length; i++) {
+ if (array[i] > max) {
+ max = array[i];
+ }
+ }
+ return max;
+ }
+
+ /**
+ * Returns the values from each provided array combined into a single array.
+ * For example, {@code concat(new primtyp[] {a, b}, new primtyp[] {}, new
+ * primtyp[] {c}} returns the array {@code {a, b, c}}.
+ *
+ * @param arrays zero or more {@code primtyp} arrays
+ * @return a single array containing all the values from the source arrays, in
+ * order
+ */
+ public static primtyp[] concat(primtyp[]... arrays) {
+ int length = 0;
+ for (primtyp[] array : arrays) {
+ length += array.length;
+ }
+ primtyp[] result = new primtyp[length];
+ int pos = 0;
+ for (primtyp[] array : arrays) {
+ System.arraycopy(array, 0, result, pos, array.length);
+ pos += array.length;
+ }
+ return result;
+ }
+
+ /**
+ * Returns a big-endian representation of {@code value} in a ?-element byte
+ * array; equivalent to {@code
+ * ByteBuffer.allocate(?).putPrimTyp(value).array()}. For example, the input
+ * value {@code ?} would yield the byte array {@code {?}}.
+ *
+ * <p>If you need to convert and concatenate several values (possibly even of
+ * different types), use a shared {@link java.nio.ByteBuffer} instance, or use
+ * {@link com.google.common.io.ByteStreams#newDataOutput()} to get a growable
+ * buffer.
+ */
+ @GwtIncompatible("doesn't work")
+ public static byte[] toByteArray(primtyp value) {
+ return new byte[] {
+ ?
+ };
+ }
+
+ /**
+ * Returns the {@code primtyp} value whose big-endian representation is
+ * stored in the first ? bytes of {@code bytes}; equivalent to {@code
+ * ByteBuffer.wrap(bytes).getPrimTyp()}. For example, the input byte array
+ * {@code {?}} would yield the {@code primtyp} value {@code ?}.
+ *
+ * <p>Arguably, it's preferable to use {@link java.nio.ByteBuffer}; that
+ * library exposes much more flexibility at little cost in readability.
+ *
+ * @throws IllegalArgumentException if {@code bytes} has fewer than ?
+ * elements
+ */
+ @GwtIncompatible("doesn't work")
+ public static primtyp fromByteArray(byte[] bytes) {
+ checkArgument(bytes.length >= BYTES,
+ "array too small: %s < %s", bytes.length, BYTES);
+ return fromBytes(bytes[0], bytes[1], bytes[2], bytes[3]);
+ }
+
+ /**
+ * Returns the {@code primtyp} value whose byte representation is the given ?
+ * bytes, in big-endian order; equivalent to {@code
+ * PrimTyps.fromByteArray(new byte[] { ? })}.
+ *
+ * @since 7.0
+ */
+ @GwtIncompatible("doesn't work")
+ public static primtyp fromBytes(byte b1, byte b2, byte b3, byte b4) {
+ return ?
+ }
+
+ /**
+ * Returns an array containing the same values as {@code array}, but
+ * guaranteed to be of a specified minimum length. If {@code array} already
+ * has a length of at least {@code minLength}, it is returned directly.
+ * Otherwise, a new array of size {@code minLength + padding} is returned,
+ * containing the values of {@code array}, and zeroes in the remaining places.
+ *
+ * @param array the source array
+ * @param minLength the minimum length the returned array must guarantee
+ * @param padding an extra amount to "grow" the array by if growth is
+ * necessary
+ * @throws IllegalArgumentException if {@code minLength} or {@code padding} is
+ * negative
+ * @return an array containing the values of {@code array}, with guaranteed
+ * minimum length {@code minLength}
+ */
+ public static primtyp[] ensureCapacity(
+ primtyp[] array, int minLength, int padding) {
+ checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
+ checkArgument(padding >= 0, "Invalid padding: %s", padding);
+ return (array.length < minLength)
+ ? copyOf(array, minLength + padding)
+ : array;
+ }
+
+ // Arrays.copyOf() requires Java 6
+ private static primtyp[] copyOf(primtyp[] original, int length) {
+ primtyp[] copy = new primtyp[length];
+ System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
+ return copy;
+ }
+
+ /**
+ * Returns a string containing the supplied {@code primtyp} values separated
+ * by {@code separator}. For example, {@code join("-", 1?, 2?, 3?)} returns
+ * the string {@code "1-2-3"}.
+ *
+ * @param separator the text that should appear between consecutive values in
+ * the resulting string (but not at the start or end)
+ * @param array an array of {@code primtyp} values, possibly empty
+ */
+ public static String join(String separator, primtyp... array) {
+ checkNotNull(separator);
+ if (array.length == 0) {
+ return "";
+ }
+
+ // For pre-sizing a builder, just get the right order of magnitude
+ StringBuilder builder = new StringBuilder(array.length * ??);
+ builder.append(array[0]);
+ for (int i = 1; i < array.length; i++) {
+ builder.append(separator).append(array[i]);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns a comparator that compares two {@code primtyp} arrays
+ * lexicographically. That is, it compares, using {@link
+ * #compare(primtyp, primtyp)}), the first pair of values that follow any
+ * common prefix, or when one array is a prefix of the other, treats the
+ * shorter array as the lesser. For example, {@code [] < [1] < [1, 2] < [2]}.
+ *
+ * <p>The returned comparator is inconsistent with {@link
+ * Object#equals(Object)} (since arrays support only identity equality), but
+ * it is consistent with {@link Arrays#equals(primtyp[], primtyp[])}.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
+ * Lexicographical order article at Wikipedia</a>
+ * @since 2.0
+ */
+ public static Comparator<primtyp[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ private enum LexicographicalComparator implements Comparator<primtyp[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(primtyp[] left, primtyp[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = PrimTyps.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * Copies a collection of {@code WrapperCl} instances into a new array of
+ * primitive {@code primtyp} values.
+ *
+ * <p>Elements are copied from the argument collection as if by {@code
+ * collection.toArray()}. Calling this method is as thread-safe as calling
+ * that method.
+ *
+ * @param collection a collection of {@code WrapperCl} objects
+ * @return an array containing the same values as {@code collection}, in the
+ * same order, converted to primitives
+ * @throws NullPointerException if {@code collection} or any of its elements
+ * is null
+ */
+ public static primtyp[] toArray(Collection<WrapperCl> collection) {
+ if (collection instanceof PrimTypArrayAsList) {
+ return ((PrimTypArrayAsList) collection).toPrimTypArray();
+ }
+
+ Object[] boxedArray = collection.toArray();
+ int len = boxedArray.length;
+ primtyp[] array = new primtyp[len];
+ for (int i = 0; i < len; i++) {
+ // checkNotNull for GWT (do not optimize)
+ array[i] = (WrapperCl) checkNotNull(boxedArray[i]);
+ }
+ return array;
+ }
+
+ /**
+ * Returns a fixed-size list backed by the specified array, similar to {@link
+ * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)},
+ * but any attempt to set a value to {@code null} will result in a {@link
+ * NullPointerException}.
+ *
+ * <p>The returned list maintains the values, but not the identities, of
+ * {@code WrapperCl} objects written to or read from it. For example, whether
+ * {@code list.get(0) == list.get(0)} is true for the returned list is
+ * unspecified.
+ *
+ * @param backingArray the array to back the list
+ * @return a list view of the array
+ */
+ public static List<WrapperCl> asList(primtyp... backingArray) {
+ if (backingArray.length == 0) {
+ return Collections.emptyList();
+ }
+ return new PrimTypArrayAsList(backingArray);
+ }
+
+ @GwtCompatible
+ private static class PrimTypArrayAsList extends AbstractList<WrapperCl>
+ implements RandomAccess, Serializable {
+ final primtyp[] array;
+ final int start;
+ final int end;
+
+ PrimTypArrayAsList(primtyp[] array) {
+ this(array, 0, array.length);
+ }
+
+ PrimTypArrayAsList(primtyp[] array, int start, int end) {
+ this.array = array;
+ this.start = start;
+ this.end = end;
+ }
+
+ @Override public int size() {
+ return end - start;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public WrapperCl get(int index) {
+ checkElementIndex(index, size());
+ return array[start + index];
+ }
+
+ @Override public boolean contains(Object target) {
+ // Overridden to prevent a ton of boxing
+ return (target instanceof WrapperCl)
+ && PrimTyps.indexOf(array, (WrapperCl) target, start, end) != -1;
+ }
+
+ @Override public int indexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof WrapperCl) {
+ int i = PrimTyps.indexOf(array, (WrapperCl) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @Override public int lastIndexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof WrapperCl) {
+ int i = PrimTyps.lastIndexOf(array, (WrapperCl) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @Override public WrapperCl set(int index, WrapperCl element) {
+ checkElementIndex(index, size());
+ primtyp oldValue = array[start + index];
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
+ return oldValue;
+ }
+
+ @Override public List<WrapperCl> subList(int fromIndex, int toIndex) {
+ int size = size();
+ checkPositionIndexes(fromIndex, toIndex, size);
+ if (fromIndex == toIndex) {
+ return Collections.emptyList();
+ }
+ return new PrimTypArrayAsList(array, start + fromIndex, start + toIndex);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof PrimTypArrayAsList) {
+ PrimTypArrayAsList that = (PrimTypArrayAsList) object;
+ int size = size();
+ if (that.size() != size) {
+ return false;
+ }
+ for (int i = 0; i < size; i++) {
+ if (array[start + i] != that.array[that.start + i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return super.equals(object);
+ }
+
+ @Override public int hashCode() {
+ int result = 1;
+ for (int i = start; i < end; i++) {
+ result = 31 * result + PrimTyps.hashCode(array[i]);
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder(size() * ??);
+ builder.append('[').append(array[start]);
+ for (int i = start + 1; i < end; i++) {
+ builder.append(", ").append(array[i]);
+ }
+ return builder.append(']').toString();
+ }
+
+ primtyp[] toPrimTypArray() {
+ // Arrays.copyOfRange() requires Java 6
+ int size = size();
+ primtyp[] result = new primtyp[size];
+ System.arraycopy(array, start, result, 0, size);
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
+--EOF--
+
diff --git a/guava/src/com/google/common/primitives/package-info.java b/guava/src/com/google/common/primitives/package-info.java
index 205183f..a3b3a01 100644
--- a/guava/src/com/google/common/primitives/package-info.java
+++ b/guava/src/com/google/common/primitives/package-info.java
@@ -15,15 +15,10 @@
*/
/**
- * Static utilities for working with the eight primitive types and {@code void},
- * and value types for treating them as unsigned.
+ * Static utilities for working with the eight primitive types and {@code void}.
*
* <p>This package is a part of the open-source
* <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
*
* <h2>Contents</h2>
*
@@ -66,4 +61,3 @@
package com.google.common.primitives;
import javax.annotation.ParametersAreNonnullByDefault;
-
diff --git a/guava/src/com/google/common/reflect/AbstractInvocationHandler.java b/guava/src/com/google/common/reflect/AbstractInvocationHandler.java
deleted file mode 100644
index 489dcff..0000000
--- a/guava/src/com/google/common/reflect/AbstractInvocationHandler.java
+++ /dev/null
@@ -1,112 +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.reflect;
-
-import com.google.common.annotations.Beta;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-import javax.annotation.Nullable;
-
-/**
- * Abstract implementation of {@link InvocationHandler} that handles {@link Object#equals},
- * {@link Object#hashCode} and {@link Object#toString}.
- *
- * @author Ben Yu
- * @since 12.0
- */
-@Beta
-public abstract class AbstractInvocationHandler implements InvocationHandler {
-
- private static final Object[] NO_ARGS = {};
-
- /**
- * {@inheritDoc}
- *
- * <p><ul>
- * <li>{@code proxy.hashCode()} delegates to {@link AbstractInvocationHandler#hashCode}
- * <li>{@code proxy.toString()} delegates to {@link AbstractInvocationHandler#toString}
- * <li>{@code proxy.equals(argument)} returns true if: <ul>
- * <li>{@code proxy} and {@code argument} are of the same type
- * <li>and {@link AbstractInvocationHandler#equals} returns true for the {@link
- * InvocationHandler} of {@code argument}
- * </ul>
- * <li>other method calls are dispatched to {@link #handleInvocation}.
- * </ul>
- */
- @Override public final Object invoke(Object proxy, Method method, @Nullable Object[] args)
- throws Throwable {
- if (args == null) {
- args = NO_ARGS;
- }
- if (args.length == 0 && method.getName().equals("hashCode")) {
- return hashCode();
- }
- if (args.length == 1
- && method.getName().equals("equals")
- && method.getParameterTypes()[0] == Object.class) {
- Object arg = args[0];
- return proxy.getClass().isInstance(arg) && equals(Proxy.getInvocationHandler(arg));
- }
- if (args.length == 0 && method.getName().equals("toString")) {
- return toString();
- }
- return handleInvocation(proxy, method, args);
- }
-
- /**
- * {@link #invoke} delegates to this method upon any method invocation on the proxy instance,
- * except {@link Object#equals}, {@link Object#hashCode} and {@link Object#toString}. The result
- * will be returned as the proxied method's return value.
- *
- * <p>Unlike {@link #invoke}, {@code args} will never be null. When the method has no parameter,
- * an empty array is passed in.
- */
- protected abstract Object handleInvocation(Object proxy, Method method, Object[] args)
- throws Throwable;
-
- /**
- * By default delegates to {@link Object#equals} so instances are only equal if they are
- * identical. {@code proxy.equals(argument)} returns true if: <ul>
- * <li>{@code proxy} and {@code argument} are of the same type
- * <li>and this method returns true for the {@link InvocationHandler} of {@code argument}
- * </ul>
- * Subclasses can override this method to provide custom equality.
- */
- @Override public boolean equals(Object obj) {
- return super.equals(obj);
- }
-
- /**
- * By default delegates to {@link Object#hashCode}. The dynamic proxies' {@code hashCode()} will
- * delegate to this method. Subclasses can override this method to provide custom equality.
- */
- @Override public int hashCode() {
- return super.hashCode();
- }
-
- /**
- * By default delegates to {@link Object#toString}. The dynamic proxies' {@code toString()} will
- * delegate to this method. Subclasses can override this method to provide custom string
- * representation for the proxies.
- */
- @Override public String toString() {
- return super.toString();
- }
-}
diff --git a/guava/src/com/google/common/reflect/ClassPath.java b/guava/src/com/google/common/reflect/ClassPath.java
deleted file mode 100644
index cfbc479..0000000
--- a/guava/src/com/google/common/reflect/ClassPath.java
+++ /dev/null
@@ -1,379 +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.reflect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Ordering;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.Enumeration;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import java.util.logging.Logger;
-
-import javax.annotation.Nullable;
-
-/**
- * Scans the source of a {@link ClassLoader} and finds all the classes loadable.
- *
- * @author Ben Yu
- * @since 14.0
- */
-@Beta
-public final class ClassPath {
-
- private static final Logger logger = Logger.getLogger(ClassPath.class.getName());
-
- /** Separator for the Class-Path manifest attribute value in jar files. */
- private static final Splitter CLASS_PATH_ATTRIBUTE_SEPARATOR =
- Splitter.on(" ").omitEmptyStrings();
-
- private static final String CLASS_FILE_NAME_EXTENSION = ".class";
-
- private final ImmutableSet<ResourceInfo> resources;
-
- private ClassPath(ImmutableSet<ResourceInfo> resources) {
- this.resources = resources;
- }
-
- /**
- * Returns a {@code ClassPath} representing all classes and resources loadable from {@code
- * classloader} and its parent class loaders.
- *
- * <p>Currently only {@link URLClassLoader} and only {@code file://} urls are supported.
- *
- * @throws IOException if the attempt to read class path resources (jar files or directories)
- * failed.
- */
- public static ClassPath from(ClassLoader classloader) throws IOException {
- ImmutableSortedSet.Builder<ResourceInfo> resources =
- new ImmutableSortedSet.Builder<ResourceInfo>(Ordering.usingToString());
- for (Map.Entry<URI, ClassLoader> entry : getClassPathEntries(classloader).entrySet()) {
- browse(entry.getKey(), entry.getValue(), resources);
- }
- return new ClassPath(resources.build());
- }
-
- /**
- * Returns all resources loadable from the current class path, including the class files of all
- * loadable classes.
- */
- public ImmutableSet<ResourceInfo> getResources() {
- return resources;
- }
-
- /** Returns all top level classes loadable from the current class path. */
- public ImmutableSet<ClassInfo> getTopLevelClasses() {
- ImmutableSet.Builder<ClassInfo> builder = ImmutableSet.builder();
- for (ResourceInfo resource : resources) {
- if (resource instanceof ClassInfo) {
- builder.add((ClassInfo) resource);
- }
- }
- return builder.build();
- }
-
- /** Returns all top level classes whose package name is {@code packageName}. */
- public ImmutableSet<ClassInfo> getTopLevelClasses(String packageName) {
- checkNotNull(packageName);
- ImmutableSet.Builder<ClassInfo> builder = ImmutableSet.builder();
- for (ClassInfo classInfo : getTopLevelClasses()) {
- if (classInfo.getPackageName().equals(packageName)) {
- builder.add(classInfo);
- }
- }
- return builder.build();
- }
-
- /**
- * Returns all top level classes whose package name is {@code packageName} or starts with
- * {@code packageName} followed by a '.'.
- */
- public ImmutableSet<ClassInfo> getTopLevelClassesRecursive(String packageName) {
- checkNotNull(packageName);
- String packagePrefix = packageName + '.';
- ImmutableSet.Builder<ClassInfo> builder = ImmutableSet.builder();
- for (ClassInfo classInfo : getTopLevelClasses()) {
- if (classInfo.getName().startsWith(packagePrefix)) {
- builder.add(classInfo);
- }
- }
- return builder.build();
- }
-
- /**
- * Represents a class path resource that can be either a class file or any other resource file
- * loadable from the class path.
- *
- * @since 14.0
- */
- @Beta
- public static class ResourceInfo {
- private final String resourceName;
- final ClassLoader loader;
-
- static ResourceInfo of(String resourceName, ClassLoader loader) {
- if (resourceName.endsWith(CLASS_FILE_NAME_EXTENSION) && !resourceName.contains("$")) {
- return new ClassInfo(resourceName, loader);
- } else {
- return new ResourceInfo(resourceName, loader);
- }
- }
-
- ResourceInfo(String resourceName, ClassLoader loader) {
- this.resourceName = checkNotNull(resourceName);
- this.loader = checkNotNull(loader);
- }
-
- /** Returns the url identifying the resource. */
- public final URL url() {
- return checkNotNull(loader.getResource(resourceName),
- "Failed to load resource: %s", resourceName);
- }
-
- /** Returns the fully qualified name of the resource. Such as "com/mycomp/foo/bar.txt". */
- public final String getResourceName() {
- return resourceName;
- }
-
- @Override public int hashCode() {
- return resourceName.hashCode();
- }
-
- @Override public boolean equals(Object obj) {
- if (obj instanceof ResourceInfo) {
- ResourceInfo that = (ResourceInfo) obj;
- return resourceName.equals(that.resourceName)
- && loader == that.loader;
- }
- return false;
- }
-
- @Override public String toString() {
- return resourceName;
- }
- }
-
- /**
- * Represents a class that can be loaded through {@link #load}.
- *
- * @since 14.0
- */
- @Beta
- public static final class ClassInfo extends ResourceInfo {
- private final String className;
-
- ClassInfo(String resourceName, ClassLoader loader) {
- super(resourceName, loader);
- this.className = getClassName(resourceName);
- }
-
- /** Returns the package name of the class, without attempting to load the class. */
- public String getPackageName() {
- return Reflection.getPackageName(className);
- }
-
- /** Returns the simple name of the underlying class as given in the source code. */
- public String getSimpleName() {
- String packageName = getPackageName();
- if (packageName.isEmpty()) {
- return className;
- }
- // Since this is a top level class, its simple name is always the part after package name.
- return className.substring(packageName.length() + 1);
- }
-
- /** Returns the fully qualified name of the class. */
- public String getName() {
- return className;
- }
-
- /** Loads (but doesn't link or initialize) the class. */
- public Class<?> load() {
- try {
- return loader.loadClass(className);
- } catch (ClassNotFoundException e) {
- // Shouldn't happen, since the class name is read from the class path.
- throw new IllegalStateException(e);
- }
- }
-
- @Override public String toString() {
- return className;
- }
- }
-
- @VisibleForTesting static ImmutableMap<URI, ClassLoader> getClassPathEntries(
- ClassLoader classloader) {
- LinkedHashMap<URI, ClassLoader> entries = Maps.newLinkedHashMap();
- // Search parent first, since it's the order ClassLoader#loadClass() uses.
- ClassLoader parent = classloader.getParent();
- if (parent != null) {
- entries.putAll(getClassPathEntries(parent));
- }
- if (classloader instanceof URLClassLoader) {
- URLClassLoader urlClassLoader = (URLClassLoader) classloader;
- for (URL entry : urlClassLoader.getURLs()) {
- URI uri;
- try {
- uri = entry.toURI();
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- if (!entries.containsKey(uri)) {
- entries.put(uri, classloader);
- }
- }
- }
- return ImmutableMap.copyOf(entries);
- }
-
- private static void browse(
- URI uri, ClassLoader classloader, ImmutableSet.Builder<ResourceInfo> resources)
- throws IOException {
- if (uri.getScheme().equals("file")) {
- browseFrom(new File(uri), classloader, resources);
- }
- }
-
- @VisibleForTesting static void browseFrom(
- File file, ClassLoader classloader, ImmutableSet.Builder<ResourceInfo> resources)
- throws IOException {
- if (!file.exists()) {
- return;
- }
- if (file.isDirectory()) {
- browseDirectory(file, classloader, resources);
- } else {
- browseJar(file, classloader, resources);
- }
- }
-
- private static void browseDirectory(
- File directory, ClassLoader classloader, ImmutableSet.Builder<ResourceInfo> resources) {
- browseDirectory(directory, classloader, "", resources);
- }
-
- private static void browseDirectory(
- File directory, ClassLoader classloader, String packagePrefix,
- ImmutableSet.Builder<ResourceInfo> resources) {
- for (File f : directory.listFiles()) {
- String name = f.getName();
- if (f.isDirectory()) {
- browseDirectory(f, classloader, packagePrefix + name + "/", resources);
- } else {
- String resourceName = packagePrefix + name;
- resources.add(ResourceInfo.of(resourceName, classloader));
- }
- }
- }
-
- private static void browseJar(
- File file, ClassLoader classloader, ImmutableSet.Builder<ResourceInfo> resources)
- throws IOException {
- JarFile jarFile;
- try {
- jarFile = new JarFile(file);
- } catch (IOException e) {
- // Not a jar file
- return;
- }
- try {
- for (URI uri : getClassPathFromManifest(file, jarFile.getManifest())) {
- browse(uri, classloader, resources);
- }
- Enumeration<JarEntry> entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- JarEntry entry = entries.nextElement();
- if (entry.isDirectory() || entry.getName().startsWith("META-INF/")) {
- continue;
- }
- resources.add(ResourceInfo.of(entry.getName(), classloader));
- }
- } finally {
- try {
- jarFile.close();
- } catch (IOException ignored) {}
- }
- }
-
- /**
- * Returns the class path URIs specified by the {@code Class-Path} manifest attribute, according
- * to <a href="http://docs.oracle.com/javase/1.4.2/docs/guide/jar/jar.html#Main%20Attributes">
- * JAR File Specification</a>. If {@code manifest} is null, it means the jar file has no manifest,
- * and an empty set will be returned.
- */
- @VisibleForTesting static ImmutableSet<URI> getClassPathFromManifest(
- File jarFile, @Nullable Manifest manifest) {
- if (manifest == null) {
- return ImmutableSet.of();
- }
- ImmutableSet.Builder<URI> builder = ImmutableSet.builder();
- String classpathAttribute = manifest.getMainAttributes().getValue("Class-Path");
- if (classpathAttribute != null) {
- for (String path : CLASS_PATH_ATTRIBUTE_SEPARATOR.split(classpathAttribute)) {
- URI uri;
- try {
- uri = getClassPathEntry(jarFile, path);
- } catch (URISyntaxException e) {
- // Ignore bad entry
- logger.warning("Invalid Class-Path entry: " + path);
- continue;
- }
- builder.add(uri);
- }
- }
- return builder.build();
- }
-
- /**
- * Returns the absolute uri of the Class-Path entry value as specified in
- * <a href="http://docs.oracle.com/javase/1.4.2/docs/guide/jar/jar.html#Main%20Attributes">
- * JAR File Specification</a>. Even though the specification only talks about relative urls,
- * absolute urls are actually supported too (for example, in Maven surefire plugin).
- */
- @VisibleForTesting static URI getClassPathEntry(File jarFile, String path)
- throws URISyntaxException {
- URI uri = new URI(path);
- if (uri.isAbsolute()) {
- return uri;
- } else {
- return new File(jarFile.getParentFile(), path.replace('/', File.separatorChar)).toURI();
- }
- }
-
- @VisibleForTesting static String getClassName(String filename) {
- int classNameEnd = filename.length() - CLASS_FILE_NAME_EXTENSION.length();
- return filename.substring(0, classNameEnd).replace('/', '.');
- }
-}
diff --git a/guava/src/com/google/common/reflect/Element.java b/guava/src/com/google/common/reflect/Element.java
deleted file mode 100644
index 14962b6..0000000
--- a/guava/src/com/google/common/reflect/Element.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.reflect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-
-import javax.annotation.Nullable;
-
-/**
- * Represents either a {@link Field}, a {@link Method} or a {@link Constructor}.
- * Provides convenience methods such as {@link #isPublic} and {@link #isPackagePrivate}.
- *
- * @author Ben Yu
- */
-class Element extends AccessibleObject implements Member {
-
- private final AccessibleObject accessibleObject;
- private final Member member;
-
- <M extends AccessibleObject & Member> Element(M member) {
- checkNotNull(member);
- this.accessibleObject = member;
- this.member = member;
- }
-
- @Override public final boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
- return accessibleObject.isAnnotationPresent(annotationClass);
- }
-
- @Override public final <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
- return accessibleObject.getAnnotation(annotationClass);
- }
-
- @Override public final Annotation[] getAnnotations() {
- return accessibleObject.getAnnotations();
- }
-
- @Override public final Annotation[] getDeclaredAnnotations() {
- return accessibleObject.getDeclaredAnnotations();
- }
-
- @Override public final void setAccessible(boolean flag) throws SecurityException {
- accessibleObject.setAccessible(flag);
- }
-
- @Override public final boolean isAccessible() {
- return accessibleObject.isAccessible();
- }
-
- @Override public Class<?> getDeclaringClass() {
- return member.getDeclaringClass();
- }
-
- @Override public final String getName() {
- return member.getName();
- }
-
- @Override public final int getModifiers() {
- return member.getModifiers();
- }
-
- @Override public final boolean isSynthetic() {
- return member.isSynthetic();
- }
-
- /** Returns true if the element is public. */
- public final boolean isPublic() {
- return Modifier.isPublic(getModifiers());
- }
-
- /** Returns true if the element is protected. */
- public final boolean isProtected() {
- return Modifier.isProtected(getModifiers());
- }
-
- /** Returns true if the element is package-private. */
- public final boolean isPackagePrivate() {
- return !isPrivate() && !isPublic() && !isProtected();
- }
-
- /** Returns true if the element is private. */
- public final boolean isPrivate() {
- return Modifier.isPrivate(getModifiers());
- }
-
- /** Returns true if the element is static. */
- public final boolean isStatic() {
- return Modifier.isStatic(getModifiers());
- }
-
- /**
- * Returns {@code true} if this method is final, per {@code Modifier.isFinal(getModifiers())}.
- *
- * <p>Note that a method may still be effectively "final", or non-overridable when it has no
- * {@code final} keyword. For example, it could be private, or it could be declared by a final
- * class. To tell whether a method is overridable, use {@link Invokable#isOverridable}.
- */
- public final boolean isFinal() {
- return Modifier.isFinal(getModifiers());
- }
-
- /** Returns true if the method is abstract. */
- public final boolean isAbstract() {
- return Modifier.isAbstract(getModifiers());
- }
-
- /** Returns true if the element is native. */
- public final boolean isNative() {
- return Modifier.isNative(getModifiers());
- }
-
- /** Returns true if the method is synchronized. */
- public final boolean isSynchronized() {
- return Modifier.isSynchronized(getModifiers());
- }
-
- /** Returns true if the field is volatile. */
- final boolean isVolatile() {
- return Modifier.isVolatile(getModifiers());
- }
-
- /** Returns true if the field is transient. */
- final boolean isTransient() {
- return Modifier.isTransient(getModifiers());
- }
-
- @Override public boolean equals(@Nullable Object obj) {
- if (obj instanceof Element) {
- Element that = (Element) obj;
- return member.equals(that.member);
- }
- return false;
- }
-
- @Override public int hashCode() {
- return member.hashCode();
- }
-
- @Override public String toString() {
- return member.toString();
- }
-}
diff --git a/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java b/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java
deleted file mode 100644
index 43e5e1e..0000000
--- a/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java
+++ /dev/null
@@ -1,138 +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.reflect;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ForwardingMap;
-import com.google.common.collect.ImmutableMap;
-
-import java.util.Map;
-
-/**
- * A type-to-instance map backed by an {@link ImmutableMap}. See also {@link
- * MutableTypeToInstanceMap}.
- *
- * @author Ben Yu
- * @since 13.0
- */
-@Beta
-public final class ImmutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<? extends B>, B>
- implements TypeToInstanceMap<B> {
-
- /** Returns an empty type to instance map. */
- public static <B> ImmutableTypeToInstanceMap<B> of() {
- return new ImmutableTypeToInstanceMap<B>(ImmutableMap.<TypeToken<? extends B>, B>of());
- }
-
- /** Returns a new builder. */
- public static <B> Builder<B> builder() {
- return new Builder<B>();
- }
-
- /**
- * A builder for creating immutable type-to-instance maps. Example:
- * <pre> {@code
- *
- * static final ImmutableTypeToInstanceMap<Handler<?>> HANDLERS =
- * ImmutableTypeToInstanceMap.<Handler<?>>builder()
- * .put(new TypeToken<Handler<Foo>>() {}, new FooHandler())
- * .put(new TypeToken<Handler<Bar>>() {}, new SubBarHandler())
- * .build();}</pre>
- *
- * After invoking {@link #build()} it is still possible to add more entries
- * and build again. Thus each map generated by this builder will be a superset
- * of any map generated before it.
- *
- * @since 13.0
- */
- @Beta
- public static final class Builder<B> {
- private final ImmutableMap.Builder<TypeToken<? extends B>, B> mapBuilder
- = ImmutableMap.builder();
-
- private Builder() {}
-
- /**
- * Associates {@code key} with {@code value} in the built map. Duplicate
- * keys are not allowed, and will cause {@link #build} to fail.
- */
- public <T extends B> Builder<B> put(Class<T> key, T value) {
- mapBuilder.put(TypeToken.of(key), value);
- return this;
- }
-
- /**
- * Associates {@code key} with {@code value} in the built map. Duplicate
- * keys are not allowed, and will cause {@link #build} to fail.
- */
- public <T extends B> Builder<B> put(TypeToken<T> key, T value) {
- mapBuilder.put(key.rejectTypeVariables(), value);
- return this;
- }
-
- /**
- * Returns a new immutable type-to-instance map containing the entries
- * provided to this builder.
- *
- * @throws IllegalArgumentException if duplicate keys were added
- */
- public ImmutableTypeToInstanceMap<B> build() {
- return new ImmutableTypeToInstanceMap<B>(mapBuilder.build());
- }
- }
-
- private final ImmutableMap<TypeToken<? extends B>, B> delegate;
-
- private ImmutableTypeToInstanceMap(ImmutableMap<TypeToken<? extends B>, B> delegate) {
- this.delegate = delegate;
- }
-
- @Override public <T extends B> T getInstance(TypeToken<T> type) {
- return trustedGet(type.rejectTypeVariables());
- }
-
- /**
- * Guaranteed to throw an exception and leave the map unmodified.
- *
- * @throws UnsupportedOperationException always
- */
- @Override public <T extends B> T putInstance(TypeToken<T> type, T value) {
- throw new UnsupportedOperationException();
- }
-
- @Override public <T extends B> T getInstance(Class<T> type) {
- return trustedGet(TypeToken.of(type));
- }
-
- /**
- * Guaranteed to throw an exception and leave the map unmodified.
- *
- * @throws UnsupportedOperationException always
- */
- @Override public <T extends B> T putInstance(Class<T> type, T value) {
- throw new UnsupportedOperationException();
- }
-
- @Override protected Map<TypeToken<? extends B>, B> delegate() {
- return delegate;
- }
-
- @SuppressWarnings("unchecked") // value could not get in if not a T
- private <T extends B> T trustedGet(TypeToken<T> type) {
- return (T) delegate.get(type);
- }
-}
diff --git a/guava/src/com/google/common/reflect/Invokable.java b/guava/src/com/google/common/reflect/Invokable.java
deleted file mode 100644
index a8f9b77..0000000
--- a/guava/src/com/google/common/reflect/Invokable.java
+++ /dev/null
@@ -1,286 +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.reflect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ImmutableList;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.GenericDeclaration;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.util.Arrays;
-
-import javax.annotation.Nullable;
-
-/**
- * Wrapper around either a {@link Method} or a {@link Constructor}.
- * Convenience API is provided to make common reflective operation easier to deal with,
- * such as {@link #isPublic}, {@link #getParameters} etc.
- *
- * <p>In addition to convenience methods, {@link TypeToken#method} and {@link
- * TypeToken#constructor} will resolve the type parameters of the method or constructor in the
- * context of the owner type, which may be a subtype of the declaring class. For example:
- * <pre> {@code
- *
- * Method getMethod = List.class.getMethod("get", int.class);
- * Invokable<List<String>, ?> invokable = new TypeToken<List<String>>() {}.method(getMethod);
- * assertEquals(TypeToken.of(String.class), invokable.getReturnType()); // Not Object.class!
- * assertEquals(new TypeToken<List<String>>() {}, invokable.getOwnerType());}</pre>
- *
- * @param <T> the type that owns this method or constructor.
- * @param <R> the return type of (or supertype thereof) the method or the declaring type of the
- * constructor.
- * @author Ben Yu
- * @since 14.0
- */
-@Beta
-public abstract class Invokable<T, R> extends Element implements GenericDeclaration {
-
- <M extends AccessibleObject & Member> Invokable(M member) {
- super(member);
- }
-
- /** Returns {@link Invokable} of {@code method}. */
- public static Invokable<?, Object> from(Method method) {
- return new MethodInvokable<Object>(method);
- }
-
- /** Returns {@link Invokable} of {@code constructor}. */
- public static <T> Invokable<T, T> from(Constructor<T> constructor) {
- return new ConstructorInvokable<T>(constructor);
- }
-
- /**
- * Returns {@code true} if this is an overridable method. Constructors, private, static or final
- * methods, or methods declared by final classes are not overridable.
- */
- public abstract boolean isOverridable();
-
- /** Returns {@code true} if this was declared to take a variable number of arguments. */
- public abstract boolean isVarArgs();
-
- /**
- * Invokes with {@code receiver} as 'this' and {@code args} passed to the underlying method
- * and returns the return value; or calls the underlying constructor with {@code args} and returns
- * the constructed instance.
- *
- * @throws IllegalAccessException if this {@code Constructor} object enforces Java language
- * access control and the underlying method or constructor is inaccessible.
- * @throws IllegalArgumentException if the number of actual and formal parameters differ;
- * if an unwrapping conversion for primitive arguments fails; or if, after possible
- * unwrapping, a parameter value cannot be converted to the corresponding formal
- * parameter type by a method invocation conversion.
- * @throws InvocationTargetException if the underlying method or constructor throws an exception.
- */
- // All subclasses are owned by us and we'll make sure to get the R type right.
- @SuppressWarnings("unchecked")
- public final R invoke(@Nullable T receiver, Object... args)
- throws InvocationTargetException, IllegalAccessException {
- return (R) invokeInternal(receiver, checkNotNull(args));
- }
-
- /** Returns the return type of this {@code Invokable}. */
- // All subclasses are owned by us and we'll make sure to get the R type right.
- @SuppressWarnings("unchecked")
- public final TypeToken<? extends R> getReturnType() {
- return (TypeToken<? extends R>) TypeToken.of(getGenericReturnType());
- }
-
- /**
- * Returns all declared parameters of this {@code Invokable}. Note that if this is a constructor
- * of a non-static inner class, unlike {@link Constructor#getParameterTypes}, the hidden
- * {@code this} parameter of the enclosing class is excluded from the returned parameters.
- */
- public final ImmutableList<Parameter> getParameters() {
- Type[] parameterTypes = getGenericParameterTypes();
- Annotation[][] annotations = getParameterAnnotations();
- ImmutableList.Builder<Parameter> builder = ImmutableList.builder();
- for (int i = 0; i < parameterTypes.length; i++) {
- builder.add(new Parameter(
- this, i, TypeToken.of(parameterTypes[i]), annotations[i]));
- }
- return builder.build();
- }
-
- /** Returns all declared exception types of this {@code Invokable}. */
- public final ImmutableList<TypeToken<? extends Throwable>> getExceptionTypes() {
- ImmutableList.Builder<TypeToken<? extends Throwable>> builder = ImmutableList.builder();
- for (Type type : getGenericExceptionTypes()) {
- // getGenericExceptionTypes() will never return a type that's not exception
- @SuppressWarnings("unchecked")
- TypeToken<? extends Throwable> exceptionType = (TypeToken<? extends Throwable>)
- TypeToken.of(type);
- builder.add(exceptionType);
- }
- return builder.build();
- }
-
- /**
- * Explicitly specifies the return type of this {@code Invokable}. For example:
- * <pre> {@code
- * Method factoryMethod = Person.class.getMethod("create");
- * Invokable<?, Person> factory = Invokable.of(getNameMethod).returning(Person.class);
- * }</pre>
- */
- public final <R1 extends R> Invokable<T, R1> returning(Class<R1> returnType) {
- return returning(TypeToken.of(returnType));
- }
-
- /** Explicitly specifies the return type of this {@code Invokable}. */
- public final <R1 extends R> Invokable<T, R1> returning(TypeToken<R1> returnType) {
- if (!returnType.isAssignableFrom(getReturnType())) {
- throw new IllegalArgumentException(
- "Invokable is known to return " + getReturnType() + ", not " + returnType);
- }
- @SuppressWarnings("unchecked") // guarded by previous check
- Invokable<T, R1> specialized = (Invokable<T, R1>) this;
- return specialized;
- }
-
- @SuppressWarnings("unchecked") // The declaring class is T's raw class, or one of its supertypes.
- @Override public final Class<? super T> getDeclaringClass() {
- return (Class<? super T>) super.getDeclaringClass();
- }
-
- /** Returns the type of {@code T}. */
- // Overridden in TypeToken#method() and TypeToken#constructor()
- @SuppressWarnings("unchecked") // The declaring class is T.
- public TypeToken<T> getOwnerType() {
- return (TypeToken<T>) TypeToken.of(getDeclaringClass());
- }
-
- abstract Object invokeInternal(@Nullable Object receiver, Object[] args)
- throws InvocationTargetException, IllegalAccessException;
-
- abstract Type[] getGenericParameterTypes();
-
- /** This should never return a type that's not a subtype of Throwable. */
- abstract Type[] getGenericExceptionTypes();
-
- abstract Annotation[][] getParameterAnnotations();
-
- abstract Type getGenericReturnType();
-
- static class MethodInvokable<T> extends Invokable<T, Object> {
-
- private final Method method;
-
- MethodInvokable(Method method) {
- super(method);
- this.method = method;
- }
-
- @Override final Object invokeInternal(@Nullable Object receiver, Object[] args)
- throws InvocationTargetException, IllegalAccessException {
- return method.invoke(receiver, args);
- }
-
- @Override Type getGenericReturnType() {
- return method.getGenericReturnType();
- }
-
- @Override Type[] getGenericParameterTypes() {
- return method.getGenericParameterTypes();
- }
-
- @Override Type[] getGenericExceptionTypes() {
- return method.getGenericExceptionTypes();
- }
-
- @Override final Annotation[][] getParameterAnnotations() {
- return method.getParameterAnnotations();
- }
-
- @Override public final TypeVariable<?>[] getTypeParameters() {
- return method.getTypeParameters();
- }
-
- @Override public final boolean isOverridable() {
- return !(isFinal() || isPrivate() || isStatic()
- || Modifier.isFinal(getDeclaringClass().getModifiers()));
- }
-
- @Override public final boolean isVarArgs() {
- return method.isVarArgs();
- }
- }
-
- static class ConstructorInvokable<T> extends Invokable<T, T> {
-
- private final Constructor<?> constructor;
-
- ConstructorInvokable(Constructor<?> constructor) {
- super(constructor);
- this.constructor = constructor;
- }
-
- @Override final Object invokeInternal(@Nullable Object receiver, Object[] args)
- throws InvocationTargetException, IllegalAccessException {
- try {
- return constructor.newInstance(args);
- } catch (InstantiationException e) {
- throw new RuntimeException(constructor + " failed.", e);
- }
- }
-
- @Override Type getGenericReturnType() {
- return constructor.getDeclaringClass();
- }
-
- @Override Type[] getGenericParameterTypes() {
- Type[] types = constructor.getGenericParameterTypes();
- Class<?> declaringClass = constructor.getDeclaringClass();
- if (!Modifier.isStatic(declaringClass.getModifiers())
- && declaringClass.getEnclosingClass() != null) {
- if (types.length == constructor.getParameterTypes().length) {
- // first parameter is the hidden 'this'
- return Arrays.copyOfRange(types, 1, types.length);
- }
- }
- return types;
- }
-
- @Override Type[] getGenericExceptionTypes() {
- return constructor.getGenericExceptionTypes();
- }
-
- @Override final Annotation[][] getParameterAnnotations() {
- return constructor.getParameterAnnotations();
- }
-
- @Override public final TypeVariable<?>[] getTypeParameters() {
- return constructor.getTypeParameters();
- }
-
- @Override public final boolean isOverridable() {
- return false;
- }
-
- @Override public final boolean isVarArgs() {
- return constructor.isVarArgs();
- }
- }
-}
diff --git a/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java b/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java
deleted file mode 100644
index 5f1249d..0000000
--- a/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java
+++ /dev/null
@@ -1,89 +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.reflect;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ForwardingMap;
-import com.google.common.collect.Maps;
-
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-/**
- * A mutable type-to-instance map.
- * See also {@link ImmutableTypeToInstanceMap}.
- *
- * @author Ben Yu
- * @since 13.0
- */
-@Beta
-public final class MutableTypeToInstanceMap<B> extends ForwardingMap<TypeToken<? extends B>, B>
- implements TypeToInstanceMap<B> {
-
- private final Map<TypeToken<? extends B>, B> backingMap = Maps.newHashMap();
-
- @Nullable
- @Override
- public <T extends B> T getInstance(Class<T> type) {
- return trustedGet(TypeToken.of(type));
- }
-
- @Nullable
- @Override
- public <T extends B> T putInstance(Class<T> type, @Nullable T value) {
- return trustedPut(TypeToken.of(type), value);
- }
-
- @Nullable
- @Override
- public <T extends B> T getInstance(TypeToken<T> type) {
- return trustedGet(type.rejectTypeVariables());
- }
-
- @Nullable
- @Override
- public <T extends B> T putInstance(TypeToken<T> type, @Nullable T value) {
- return trustedPut(type.rejectTypeVariables(), value);
- }
-
- /** Not supported. Use {@link #putInstance} instead. */
- @Override public B put(TypeToken<? extends B> key, B value) {
- throw new UnsupportedOperationException("Please use putInstance() instead.");
- }
-
- /** Not supported. Use {@link #putInstance} instead. */
- @Override public void putAll(Map<? extends TypeToken<? extends B>, ? extends B> map) {
- throw new UnsupportedOperationException("Please use putInstance() instead.");
- }
-
- @Override protected Map<TypeToken<? extends B>, B> delegate() {
- return backingMap;
- }
-
- @SuppressWarnings("unchecked") // value could not get in if not a T
- @Nullable
- private <T extends B> T trustedPut(TypeToken<T> type, @Nullable T value) {
- return (T) backingMap.put(type, value);
- }
-
- @SuppressWarnings("unchecked") // value could not get in if not a T
- @Nullable
- private <T extends B> T trustedGet(TypeToken<T> type) {
- return (T) backingMap.get(type);
- }
-}
diff --git a/guava/src/com/google/common/reflect/Parameter.java b/guava/src/com/google/common/reflect/Parameter.java
deleted file mode 100644
index 977bc8d..0000000
--- a/guava/src/com/google/common/reflect/Parameter.java
+++ /dev/null
@@ -1,103 +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.reflect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ImmutableList;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.AnnotatedElement;
-
-import javax.annotation.Nullable;
-
-/**
- * Represents a method or constructor parameter.
- *
- * @author Ben Yu
- * @since 14.0
- */
-@Beta
-public final class Parameter implements AnnotatedElement {
-
- private final Invokable<?, ?> declaration;
- private final int position;
- private final TypeToken<?> type;
- private final ImmutableList<Annotation> annotations;
-
- Parameter(
- Invokable<?, ?> declaration,
- int position,
- TypeToken<?> type,
- Annotation[] annotations) {
- this.declaration = declaration;
- this.position = position;
- this.type = type;
- this.annotations = ImmutableList.copyOf(annotations);
- }
-
- /** Returns the type of the parameter. */
- public TypeToken<?> getType() {
- return type;
- }
-
- /** Returns the {@link Invokable} that declares this parameter. */
- public Invokable<?, ?> getDeclaringInvokable() {
- return declaration;
- }
-
- @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
- return getAnnotation(annotationType) != null;
- }
-
- @Override
- @Nullable
- public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
- checkNotNull(annotationType);
- for (Annotation annotation : annotations) {
- if (annotationType.isInstance(annotation)) {
- return annotationType.cast(annotation);
- }
- }
- return null;
- }
-
- @Override public Annotation[] getAnnotations() {
- return getDeclaredAnnotations();
- }
-
- @Override public Annotation[] getDeclaredAnnotations() {
- return annotations.toArray(new Annotation[annotations.size()]);
- }
-
- @Override public boolean equals(@Nullable Object obj) {
- if (obj instanceof Parameter) {
- Parameter that = (Parameter) obj;
- return position == that.position && declaration.equals(that.declaration);
- }
- return false;
- }
-
- @Override public int hashCode() {
- return position;
- }
-
- @Override public String toString() {
- return type + " arg" + position;
- }
-}
diff --git a/guava/src/com/google/common/reflect/Reflection.java b/guava/src/com/google/common/reflect/Reflection.java
deleted file mode 100644
index 028c8a9..0000000
--- a/guava/src/com/google/common/reflect/Reflection.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2005 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.reflect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
-
-/**
- * Static utilities relating to Java reflection.
- *
- * @since 12.0
- */
-@Beta
-public final class Reflection {
-
- /**
- * Returns the package name of {@code clazz} according to the Java Language Specification (section
- * 6.7). Unlike {@link Class#getPackage}, this method only parses the class name, without
- * attempting to define the {@link Package} and hence load files.
- */
- public static String getPackageName(Class<?> clazz) {
- return getPackageName(clazz.getName());
- }
-
- /**
- * Returns the package name of {@code classFullName} according to the Java Language Specification
- * (section 6.7). Unlike {@link Class#getPackage}, this method only parses the class name, without
- * attempting to define the {@link Package} and hence load files.
- */
- public static String getPackageName(String classFullName) {
- int lastDot = classFullName.lastIndexOf('.');
- return (lastDot < 0) ? "" : classFullName.substring(0, lastDot);
- }
-
- /**
- * Ensures that the given classes are initialized, as described in
- * <a href="http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4.2">
- * JLS Section 12.4.2</a>.
- *
- * <p>WARNING: Normally it's a smell if a class needs to be explicitly initialized, because static
- * state hurts system maintainability and testability. In cases when you have no choice while
- * inter-operating with a legacy framework, this method helps to keep the code less ugly.
- *
- * @throws ExceptionInInitializerError if an exception is thrown during
- * initialization of a class
- */
- public static void initialize(Class<?>... classes) {
- for (Class<?> clazz : classes) {
- try {
- Class.forName(clazz.getName(), true, clazz.getClassLoader());
- } catch (ClassNotFoundException e) {
- throw new AssertionError(e);
- }
- }
- }
-
- /**
- * Returns a proxy instance that implements {@code interfaceType} by
- * dispatching method invocations to {@code handler}. The class loader of
- * {@code interfaceType} will be used to define the proxy class. To implement
- * multiple interfaces or specify a class loader, use
- * {@link Proxy#newProxyInstance}.
- *
- * @throws IllegalArgumentException if {@code interfaceType} does not specify
- * the type of a Java interface
- */
- public static <T> T newProxy(
- Class<T> interfaceType, InvocationHandler handler) {
- checkNotNull(handler);
- checkArgument(interfaceType.isInterface(), "%s is not an interface", interfaceType);
- Object object = Proxy.newProxyInstance(
- interfaceType.getClassLoader(),
- new Class<?>[] { interfaceType },
- handler);
- return interfaceType.cast(object);
- }
-
- private Reflection() {}
-}
diff --git a/guava/src/com/google/common/reflect/TypeCapture.java b/guava/src/com/google/common/reflect/TypeCapture.java
deleted file mode 100644
index c686661..0000000
--- a/guava/src/com/google/common/reflect/TypeCapture.java
+++ /dev/null
@@ -1,38 +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.reflect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-
-/**
- * Captures the actual type of {@code T}.
- *
- * @author Ben Yu
- */
-abstract class TypeCapture<T> {
-
- /** Returns the captured type. */
- final Type capture() {
- Type superclass = getClass().getGenericSuperclass();
- checkArgument(superclass instanceof ParameterizedType,
- "%s isn't parameterized", superclass);
- return ((ParameterizedType) superclass).getActualTypeArguments()[0];
- }
-}
diff --git a/guava/src/com/google/common/reflect/TypeParameter.java b/guava/src/com/google/common/reflect/TypeParameter.java
deleted file mode 100644
index 79bf076..0000000
--- a/guava/src/com/google/common/reflect/TypeParameter.java
+++ /dev/null
@@ -1,67 +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.reflect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import com.google.common.annotations.Beta;
-
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-
-import javax.annotation.Nullable;
-
-/**
- * Captures a free type variable that can be used in {@link TypeToken#where}.
- * For example: <pre> {@code
- *
- * static <T> TypeToken<List<T>> listOf(Class<T> elementType) {
- * return new TypeToken<List<T>>() {}
- * .where(new TypeParameter<T>() {}, elementType);
- * }
- * }</pre>
- *
- * @author Ben Yu
- * @since 12.0
- */
-@Beta
-public abstract class TypeParameter<T> extends TypeCapture<T> {
-
- final TypeVariable<?> typeVariable;
-
- protected TypeParameter() {
- Type type = capture();
- checkArgument(type instanceof TypeVariable, "%s should be a type variable.", type);
- this.typeVariable = (TypeVariable<?>) type;
- }
-
- @Override public final int hashCode() {
- return typeVariable.hashCode();
- }
-
- @Override public final boolean equals(@Nullable Object o) {
- if (o instanceof TypeParameter) {
- TypeParameter<?> that = (TypeParameter<?>) o;
- return typeVariable.equals(that.typeVariable);
- }
- return false;
- }
-
- @Override public String toString() {
- return typeVariable.toString();
- }
-}
diff --git a/guava/src/com/google/common/reflect/TypeResolver.java b/guava/src/com/google/common/reflect/TypeResolver.java
deleted file mode 100644
index 8c2d582..0000000
--- a/guava/src/com/google/common/reflect/TypeResolver.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * 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.reflect;
-
-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.base.Joiner;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.annotation.Nullable;
-
-/**
- * An object of this class encapsulates type mappings from type variables. Mappings are established
- * with {@link #where} and types are resolved using {@link #resolveType}.
- *
- * <p>Note that usually type mappings are already implied by the static type hierarchy (for example,
- * the {@code E} type variable declared by class {@code List} naturally maps to {@code String} in
- * the context of {@code class MyStringList implements List<String>}. In such case, prefer to use
- * {@link TypeToken#resolveType} since it's simpler and more type safe. This class should only be
- * used when the type mapping isn't implied by the static type hierarchy, but provided through other
- * means such as an annotation or external configuration file.
- *
- * @author Ben Yu
- */
-class TypeResolver {
-
- private final ImmutableMap<TypeVariable<?>, Type> typeTable;
-
- public TypeResolver() {
- this.typeTable = ImmutableMap.of();
- }
-
- private TypeResolver(ImmutableMap<TypeVariable<?>, Type> typeTable) {
- this.typeTable = typeTable;
- }
-
- static TypeResolver accordingTo(Type type) {
- return new TypeResolver().where(TypeMappingIntrospector.getTypeMappings(type));
- }
-
- /**
- * Returns a new {@code TypeResolver} with type variables in {@code formal} mapping to types in
- * {@code actual}.
- *
- * <p>For example, if {@code formal} is a {@code TypeVariable T}, and {@code actual} is {@code
- * String.class}, then {@code new TypeResolver().where(formal, actual)} will {@linkplain
- * #resolveType resolve} {@code ParameterizedType List<T>} to {@code List<String>}, and resolve
- * {@code Map<T, Something>} to {@code Map<String, Something>} etc. Similarly, {@code formal} and
- * {@code actual} can be {@code Map<K, V>} and {@code Map<String, Integer>} respectively, or they
- * can be {@code E[]} and {@code String[]} respectively, or even any arbitrary combination
- * thereof.
- *
- * @param formal The type whose type variables or itself is mapped to other type(s). It's almost
- * always a bug if {@code formal} isn't a type variable and contains no type variable. Make
- * sure you are passing the two parameters in the right order.
- * @param actual The type that the formal type variable(s) are mapped to. It can be or contain yet
- * other type variables, in which case these type variables will be further resolved if
- * corresponding mappings exist in the current {@code TypeResolver} instance.
- */
- public final TypeResolver where(Type formal, Type actual) {
- Map<TypeVariable<?>, Type> mappings = Maps.newHashMap();
- populateTypeMappings(mappings, checkNotNull(formal), checkNotNull(actual));
- return where(mappings);
- }
-
- /** Returns a new {@code TypeResolver} with {@code variable} mapping to {@code type}. */
- final TypeResolver where(Map<? extends TypeVariable<?>, ? extends Type> mappings) {
- ImmutableMap.Builder<TypeVariable<?>, Type> builder = ImmutableMap.builder();
- builder.putAll(typeTable);
- for (Map.Entry<? extends TypeVariable<?>, ? extends Type> mapping : mappings.entrySet()) {
- TypeVariable<?> variable = mapping.getKey();
- Type type = mapping.getValue();
- checkArgument(!variable.equals(type), "Type variable %s bound to itself", variable);
- builder.put(variable, type);
- }
- return new TypeResolver(builder.build());
- }
-
- private static void populateTypeMappings(
- Map<TypeVariable<?>, Type> mappings, Type from, Type to) {
- if (from.equals(to)) {
- return;
- }
- if (from instanceof TypeVariable) {
- mappings.put((TypeVariable<?>) from, to);
- } else if (from instanceof GenericArrayType) {
- populateTypeMappings(mappings,
- ((GenericArrayType) from).getGenericComponentType(),
- checkNonNullArgument(Types.getComponentType(to), "%s is not an array type.", to));
- } else if (from instanceof ParameterizedType) {
- ParameterizedType fromParameterizedType = (ParameterizedType) from;
- ParameterizedType toParameterizedType = expectArgument(ParameterizedType.class, to);
- checkArgument(fromParameterizedType.getRawType().equals(toParameterizedType.getRawType()),
- "Inconsistent raw type: %s vs. %s", from, to);
- Type[] fromArgs = fromParameterizedType.getActualTypeArguments();
- Type[] toArgs = toParameterizedType.getActualTypeArguments();
- checkArgument(fromArgs.length == toArgs.length);
- for (int i = 0; i < fromArgs.length; i++) {
- populateTypeMappings(mappings, fromArgs[i], toArgs[i]);
- }
- } else if (from instanceof WildcardType) {
- WildcardType fromWildcardType = (WildcardType) from;
- WildcardType toWildcardType = expectArgument(WildcardType.class, to);
- Type[] fromUpperBounds = fromWildcardType.getUpperBounds();
- Type[] toUpperBounds = toWildcardType.getUpperBounds();
- Type[] fromLowerBounds = fromWildcardType.getLowerBounds();
- Type[] toLowerBounds = toWildcardType.getLowerBounds();
- checkArgument(
- fromUpperBounds.length == toUpperBounds.length
- && fromLowerBounds.length == toLowerBounds.length,
- "Incompatible type: %s vs. %s", from, to);
- for (int i = 0; i < fromUpperBounds.length; i++) {
- populateTypeMappings(mappings, fromUpperBounds[i], toUpperBounds[i]);
- }
- for (int i = 0; i < fromLowerBounds.length; i++) {
- populateTypeMappings(mappings, fromLowerBounds[i], toLowerBounds[i]);
- }
- } else {
- throw new IllegalArgumentException("No type mapping from " + from);
- }
- }
-
- /**
- * Resolves all type variables in {@code type} and all downstream types and
- * returns a corresponding type with type variables resolved.
- */
- public final Type resolveType(Type type) {
- checkNotNull(type);
- if (type instanceof TypeVariable) {
- return resolveTypeVariable((TypeVariable<?>) type);
- } else if (type instanceof ParameterizedType) {
- return resolveParameterizedType((ParameterizedType) type);
- } else if (type instanceof GenericArrayType) {
- return resolveGenericArrayType((GenericArrayType) type);
- } else if (type instanceof WildcardType) {
- WildcardType wildcardType = (WildcardType) type;
- return new Types.WildcardTypeImpl(
- resolveTypes(wildcardType.getLowerBounds()),
- resolveTypes(wildcardType.getUpperBounds()));
- } else {
- // if Class<?>, no resolution needed, we are done.
- return type;
- }
- }
-
- private Type[] resolveTypes(Type[] types) {
- Type[] result = new Type[types.length];
- for (int i = 0; i < types.length; i++) {
- result[i] = resolveType(types[i]);
- }
- return result;
- }
-
- private Type resolveGenericArrayType(GenericArrayType type) {
- Type componentType = resolveType(type.getGenericComponentType());
- return Types.newArrayType(componentType);
- }
-
- private Type resolveTypeVariable(final TypeVariable<?> var) {
- final TypeResolver unguarded = this;
- TypeResolver guarded = new TypeResolver(typeTable) {
- @Override Type resolveTypeVariable(
- TypeVariable<?> intermediateVar, TypeResolver guardedResolver) {
- if (intermediateVar.getGenericDeclaration().equals(var.getGenericDeclaration())) {
- return intermediateVar;
- }
- return unguarded.resolveTypeVariable(intermediateVar, guardedResolver);
- }
- };
- return resolveTypeVariable(var, guarded);
- }
-
- /**
- * Resolves {@code var} using the encapsulated type mapping. If it maps to yet another
- * non-reified type, {@code guardedResolver} is used to do further resolution, which doesn't try
- * to resolve any type variable on generic declarations that are already being resolved.
- */
- Type resolveTypeVariable(TypeVariable<?> var, TypeResolver guardedResolver) {
- checkNotNull(guardedResolver);
- Type type = typeTable.get(var);
- if (type == null) {
- Type[] bounds = var.getBounds();
- if (bounds.length == 0) {
- return var;
- }
- return Types.newTypeVariable(
- var.getGenericDeclaration(),
- var.getName(),
- guardedResolver.resolveTypes(bounds));
- }
- return guardedResolver.resolveType(type); // in case the type is yet another type variable.
- }
-
- private ParameterizedType resolveParameterizedType(ParameterizedType type) {
- Type owner = type.getOwnerType();
- Type resolvedOwner = (owner == null) ? null : resolveType(owner);
- Type resolvedRawType = resolveType(type.getRawType());
-
- Type[] vars = type.getActualTypeArguments();
- Type[] resolvedArgs = new Type[vars.length];
- for (int i = 0; i < vars.length; i++) {
- resolvedArgs[i] = resolveType(vars[i]);
- }
- return Types.newParameterizedTypeWithOwner(
- resolvedOwner, (Class<?>) resolvedRawType, resolvedArgs);
- }
-
- private static <T> T checkNonNullArgument(T arg, String format, Object... messageParams) {
- checkArgument(arg != null, format, messageParams);
- return arg;
- }
-
- private static <T> T expectArgument(Class<T> type, Object arg) {
- try {
- return type.cast(arg);
- } catch (ClassCastException e) {
- throw new IllegalArgumentException(arg + " is not a " + type.getSimpleName());
- }
- }
-
- private static final class TypeMappingIntrospector {
-
- private static final WildcardCapturer wildcardCapturer = new WildcardCapturer();
-
- private final Map<TypeVariable<?>, Type> mappings = Maps.newHashMap();
- private final Set<Type> introspectedTypes = Sets.newHashSet();
-
- /**
- * Returns type mappings using type parameters and type arguments found in
- * the generic superclass and the super interfaces of {@code contextClass}.
- */
- static ImmutableMap<TypeVariable<?>, Type> getTypeMappings(
- Type contextType) {
- TypeMappingIntrospector introspector = new TypeMappingIntrospector();
- introspector.introspect(wildcardCapturer.capture(contextType));
- return ImmutableMap.copyOf(introspector.mappings);
- }
-
- private void introspect(Type type) {
- if (!introspectedTypes.add(type)) {
- return;
- }
- if (type instanceof ParameterizedType) {
- introspectParameterizedType((ParameterizedType) type);
- } else if (type instanceof Class) {
- introspectClass((Class<?>) type);
- } else if (type instanceof TypeVariable) {
- for (Type bound : ((TypeVariable<?>) type).getBounds()) {
- introspect(bound);
- }
- } else if (type instanceof WildcardType) {
- for (Type bound : ((WildcardType) type).getUpperBounds()) {
- introspect(bound);
- }
- }
- }
-
- private void introspectClass(Class<?> clazz) {
- introspect(clazz.getGenericSuperclass());
- for (Type interfaceType : clazz.getGenericInterfaces()) {
- introspect(interfaceType);
- }
- }
-
- private void introspectParameterizedType(
- ParameterizedType parameterizedType) {
- Class<?> rawClass = (Class<?>) parameterizedType.getRawType();
- TypeVariable<?>[] vars = rawClass.getTypeParameters();
- Type[] typeArgs = parameterizedType.getActualTypeArguments();
- checkState(vars.length == typeArgs.length);
- for (int i = 0; i < vars.length; i++) {
- map(vars[i], typeArgs[i]);
- }
- introspectClass(rawClass);
- introspect(parameterizedType.getOwnerType());
- }
-
- private void map(final TypeVariable<?> var, final Type arg) {
- if (mappings.containsKey(var)) {
- // Mapping already established
- // This is possible when following both superClass -> enclosingClass
- // and enclosingclass -> superClass paths.
- // Since we follow the path of superclass first, enclosing second,
- // superclass mapping should take precedence.
- return;
- }
- // First, check whether var -> arg forms a cycle
- for (Type t = arg; t != null; t = mappings.get(t)) {
- if (var.equals(t)) {
- // cycle detected, remove the entire cycle from the mapping so that
- // each type variable resolves deterministically to itself.
- // Otherwise, a F -> T cycle will end up resolving both F and T
- // nondeterministically to either F or T.
- for (Type x = arg; x != null; x = mappings.remove(x)) {}
- return;
- }
- }
- mappings.put(var, arg);
- }
- }
-
- // This is needed when resolving types against a context with wildcards
- // For example:
- // class Holder<T> {
- // void set(T data) {...}
- // }
- // Holder<List<?>> should *not* resolve the set() method to set(List<?> data).
- // Instead, it should create a capture of the wildcard so that set() rejects any List<T>.
- private static final class WildcardCapturer {
-
- private final AtomicInteger id = new AtomicInteger();
-
- Type capture(Type type) {
- checkNotNull(type);
- if (type instanceof Class) {
- return type;
- }
- if (type instanceof TypeVariable) {
- return type;
- }
- if (type instanceof GenericArrayType) {
- GenericArrayType arrayType = (GenericArrayType) type;
- return Types.newArrayType(capture(arrayType.getGenericComponentType()));
- }
- if (type instanceof ParameterizedType) {
- ParameterizedType parameterizedType = (ParameterizedType) type;
- return Types.newParameterizedTypeWithOwner(
- captureNullable(parameterizedType.getOwnerType()),
- (Class<?>) parameterizedType.getRawType(),
- capture(parameterizedType.getActualTypeArguments()));
- }
- if (type instanceof WildcardType) {
- WildcardType wildcardType = (WildcardType) type;
- Type[] lowerBounds = wildcardType.getLowerBounds();
- if (lowerBounds.length == 0) { // ? extends something changes to capture-of
- Type[] upperBounds = wildcardType.getUpperBounds();
- String name = "capture#" + id.incrementAndGet() + "-of ? extends "
- + Joiner.on('&').join(upperBounds);
- return Types.newTypeVariable(
- WildcardCapturer.class, name, wildcardType.getUpperBounds());
- } else {
- // TODO(benyu): handle ? super T somehow.
- return type;
- }
- }
- throw new AssertionError("must have been one of the known types");
- }
-
- private Type captureNullable(@Nullable Type type) {
- if (type == null) {
- return null;
- }
- return capture(type);
- }
-
- private Type[] capture(Type[] types) {
- Type[] result = new Type[types.length];
- for (int i = 0; i < types.length; i++) {
- result[i] = capture(types[i]);
- }
- return result;
- }
- }
-}
diff --git a/guava/src/com/google/common/reflect/TypeToInstanceMap.java b/guava/src/com/google/common/reflect/TypeToInstanceMap.java
deleted file mode 100644
index 3b00820..0000000
--- a/guava/src/com/google/common/reflect/TypeToInstanceMap.java
+++ /dev/null
@@ -1,92 +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.reflect;
-
-import com.google.common.annotations.Beta;
-
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-/**
- * A map, each entry of which maps a {@link TypeToken} to an instance of that type.
- * In addition to implementing {@code Map}, the additional type-safe operations
- * {@link #putInstance} and {@link #getInstance} are available.
- *
- * <p>Generally, implementations don't support {@link #put} and {@link #putAll}
- * because there is no way to check an object at runtime to be an instance of a
- * {@link TypeToken}. Instead, caller should use the type safe {@link #putInstance}.
- *
- * <p>Also, if caller suppresses unchecked warnings and passes in an {@code Iterable<String>}
- * for type {@code Iterable<Integer>}, the map won't be able to detect and throw type error.
- *
- * <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.
- *
- * @param <B> the common supertype that all entries must share; often this is
- * simply {@link Object}
- *
- * @author Ben Yu
- * @since 13.0
- */
-@Beta
-public interface TypeToInstanceMap<B> extends Map<TypeToken<? extends B>, B> {
-
- /**
- * Returns the value the specified class is mapped to, or {@code null} if no
- * entry for this class is present. This will only return a value that was
- * bound to this specific class, not a value that may have been bound to a
- * subtype.
- *
- * <p>{@code getInstance(Foo.class)} is equivalent to
- * {@code getInstance(TypeToken.of(Foo.class))}.
- */
- @Nullable
- <T extends B> T getInstance(Class<T> type);
-
- /**
- * Maps the specified class to the specified value. Does <i>not</i> associate
- * this value with any of the class's supertypes.
- *
- * <p>{@code putInstance(Foo.class, foo)} is equivalent to
- * {@code putInstance(TypeToken.of(Foo.class), foo)}.
- *
- * @return the value previously associated with this class (possibly {@code null}),
- * or {@code null} if there was no previous entry.
- */
- @Nullable
- <T extends B> T putInstance(Class<T> type, @Nullable T value);
-
- /**
- * Returns the value the specified type is mapped to, or {@code null} if no
- * entry for this type is present. This will only return a value that was
- * bound to this specific type, not a value that may have been bound to a subtype.
- */
- @Nullable
- <T extends B> T getInstance(TypeToken<T> type);
-
- /**
- * Maps the specified type to the specified value. Does <i>not</i> associate
- * this value with any of the type's supertypes.
- *
- * @return the value previously associated with this type (possibly {@code null}),
- * or {@code null} if there was no previous entry.
- */
- @Nullable
- <T extends B> T putInstance(TypeToken<T> type, @Nullable T value);
-}
diff --git a/guava/src/com/google/common/reflect/TypeToken.java b/guava/src/com/google/common/reflect/TypeToken.java
deleted file mode 100644
index 61469b5..0000000
--- a/guava/src/com/google/common/reflect/TypeToken.java
+++ /dev/null
@@ -1,1146 +0,0 @@
-/*
- * Copyright (C) 2006 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.reflect;
-
-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.VisibleForTesting;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ForwardingSet;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Ordering;
-
-import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * A {@link Type} with generics.
- *
- * <p>Operations that are otherwise only available in {@link Class} are implemented to support
- * {@code Type}, for example {@link #isAssignableFrom}, {@link #isArray} and {@link
- * #getComponentType}. It also provides additional utilities such as {@link #getTypes} and {@link
- * #resolveType} etc.
- *
- * <p>There are three ways to get a {@code TypeToken} instance: <ul>
- * <li>Wrap a {@code Type} obtained via reflection. For example: {@code
- * TypeToken.of(method.getGenericReturnType())}.
- * <li>Capture a generic type with a (usually anonymous) subclass. For example: <pre> {@code
- *
- * new TypeToken<List<String>>() {}
- * }</pre>
- * Note that it's critical that the actual type argument is carried by a subclass.
- * The following code is wrong because it only captures the {@code <T>} type variable
- * of the {@code listType()} method signature; while {@code <String>} is lost in erasure:
- * <pre> {@code
- *
- * class Util {
- * static <T> TypeToken<List<T>> listType() {
- * return new TypeToken<List<T>>() {};
- * }
- * }
- *
- * TypeToken<List<String>> stringListType = Util.<String>listType();
- * }</pre>
- * <li>Capture a generic type with a (usually anonymous) subclass and resolve it against
- * a context class that knows what the type parameters are. For example: <pre> {@code
- * abstract class IKnowMyType<T> {
- * TypeToken<T> type = new TypeToken<T>(getClass()) {};
- * }
- * new IKnowMyType<String>() {}.type => String
- * }</pre>
- * </ul>
- *
- * <p>{@code TypeToken} is serializable when no type variable is contained in the type.
- *
- * <p>Note to Guice users: {@code} TypeToken is similar to Guice's {@code TypeLiteral} class,
- * but with one important difference: it supports non-reified types such as {@code T},
- * {@code List<T>} or even {@code List<? extends Number>}; while TypeLiteral does not.
- * TypeToken is also serializable and offers numerous additional utility methods.
- *
- * @author Bob Lee
- * @author Sven Mawson
- * @author Ben Yu
- * @since 12.0
- */
-@Beta
-@SuppressWarnings("serial") // SimpleTypeToken is the serialized form.
-public abstract class TypeToken<T> extends TypeCapture<T> implements Serializable {
-
- private final Type runtimeType;
-
- /** Resolver for resolving types with {@link #runtimeType} as context. */
- private transient TypeResolver typeResolver;
-
- /**
- * Constructs a new type token of {@code T}.
- *
- * <p>Clients create an empty anonymous subclass. Doing so embeds the type
- * parameter in the anonymous class's type hierarchy so we can reconstitute
- * it at runtime despite erasure.
- *
- * <p>For example: <pre> {@code
- *
- * TypeToken<List<String>> t = new TypeToken<List<String>>() {};
- * }</pre>
- */
- protected TypeToken() {
- this.runtimeType = capture();
- checkState(!(runtimeType instanceof TypeVariable),
- "Cannot construct a TypeToken for a type variable.\n" +
- "You probably meant to call new TypeToken<%s>(getClass()) " +
- "that can resolve the type variable for you.\n" +
- "If you do need to create a TypeToken of a type variable, " +
- "please use TypeToken.of() instead.", runtimeType);
- }
-
- /**
- * Constructs a new type token of {@code T} while resolving free type variables in the context of
- * {@code declaringClass}.
- *
- * <p>Clients create an empty anonymous subclass. Doing so embeds the type
- * parameter in the anonymous class's type hierarchy so we can reconstitute
- * it at runtime despite erasure.
- *
- * <p>For example: <pre> {@code
- *
- * abstract class IKnowMyType<T> {
- * TypeToken<T> getMyType() {
- * return new TypeToken<T>(getClass()) {};
- * }
- * }
- *
- * new IKnowMyType<String>() {}.getMyType() => String
- * }</pre>
- */
- protected TypeToken(Class<?> declaringClass) {
- Type captured = super.capture();
- if (captured instanceof Class) {
- this.runtimeType = captured;
- } else {
- this.runtimeType = of(declaringClass).resolveType(captured).runtimeType;
- }
- }
-
- private TypeToken(Type type) {
- this.runtimeType = checkNotNull(type);
- }
-
- /** Returns an instance of type token that wraps {@code type}. */
- public static <T> TypeToken<T> of(Class<T> type) {
- return new SimpleTypeToken<T>(type);
- }
-
- /** Returns an instance of type token that wraps {@code type}. */
- public static TypeToken<?> of(Type type) {
- return new SimpleTypeToken<Object>(type);
- }
-
- /**
- * Returns the raw type of {@code T}. Formally speaking, if {@code T} is returned by
- * {@link java.lang.reflect.Method#getGenericReturnType}, the raw type is what's returned by
- * {@link java.lang.reflect.Method#getReturnType} of the same method object. Specifically:
- * <ul>
- * <li>If {@code T} is a {@code Class} itself, {@code T} itself is returned.
- * <li>If {@code T} is a {@link ParameterizedType}, the raw type of the parameterized type is
- * returned.
- * <li>If {@code T} is a {@link GenericArrayType}, the returned type is the corresponding array
- * class. For example: {@code List<Integer>[] => List[]}.
- * <li>If {@code T} is a type variable or a wildcard type, the raw type of the first upper bound
- * is returned. For example: {@code <X extends Foo> => Foo}.
- * </ul>
- */
- public final Class<? super T> getRawType() {
- Class<?> rawType = getRawType(runtimeType);
- @SuppressWarnings("unchecked") // raw type is |T|
- Class<? super T> result = (Class<? super T>) rawType;
- return result;
- }
-
- /**
- * Returns the raw type of the class or parameterized type; if {@code T} is type variable or
- * wildcard type, the raw types of all its upper bounds are returned.
- */
- private ImmutableSet<Class<? super T>> getImmediateRawTypes() {
- // Cast from ImmutableSet<Class<?>> to ImmutableSet<Class<? super T>>
- @SuppressWarnings({"unchecked", "rawtypes"})
- ImmutableSet<Class<? super T>> result = (ImmutableSet) getRawTypes(runtimeType);
- return result;
- }
-
- /** Returns the represented type. */
- public final Type getType() {
- return runtimeType;
- }
-
- /**
- * Returns a new {@code TypeToken} where type variables represented by {@code typeParam}
- * are substituted by {@code typeArg}. For example, it can be used to construct
- * {@code Map<K, V>} for any {@code K} and {@code V} type: <pre> {@code
- *
- * static <K, V> TypeToken<Map<K, V>> mapOf(
- * TypeToken<K> keyType, TypeToken<V> valueType) {
- * return new TypeToken<Map<K, V>>() {}
- * .where(new TypeParameter<K>() {}, keyType)
- * .where(new TypeParameter<V>() {}, valueType);
- * }
- * }</pre>
- *
- * @param <X> The parameter type
- * @param typeParam the parameter type variable
- * @param typeArg the actual type to substitute
- */
- public final <X> TypeToken<T> where(TypeParameter<X> typeParam, TypeToken<X> typeArg) {
- TypeResolver resolver = new TypeResolver()
- .where(ImmutableMap.of(typeParam.typeVariable, typeArg.runtimeType));
- // If there's any type error, we'd report now rather than later.
- return new SimpleTypeToken<T>(resolver.resolveType(runtimeType));
- }
-
- /**
- * Returns a new {@code TypeToken} where type variables represented by {@code typeParam}
- * are substituted by {@code typeArg}. For example, it can be used to construct
- * {@code Map<K, V>} for any {@code K} and {@code V} type: <pre> {@code
- *
- * static <K, V> TypeToken<Map<K, V>> mapOf(
- * Class<K> keyType, Class<V> valueType) {
- * return new TypeToken<Map<K, V>>() {}
- * .where(new TypeParameter<K>() {}, keyType)
- * .where(new TypeParameter<V>() {}, valueType);
- * }
- * }</pre>
- *
- * @param <X> The parameter type
- * @param typeParam the parameter type variable
- * @param typeArg the actual type to substitute
- */
- public final <X> TypeToken<T> where(TypeParameter<X> typeParam, Class<X> typeArg) {
- return where(typeParam, of(typeArg));
- }
-
- /**
- * Resolves the given {@code type} against the type context represented by this type.
- * For example: <pre> {@code
- *
- * new TypeToken<List<String>>() {}.resolveType(
- * List.class.getMethod("get", int.class).getGenericReturnType())
- * => String.class
- * }</pre>
- */
- public final TypeToken<?> resolveType(Type type) {
- checkNotNull(type);
- TypeResolver resolver = typeResolver;
- if (resolver == null) {
- resolver = (typeResolver = TypeResolver.accordingTo(runtimeType));
- }
- return of(resolver.resolveType(type));
- }
-
- private Type[] resolveInPlace(Type[] types) {
- for (int i = 0; i < types.length; i++) {
- types[i] = resolveType(types[i]).getType();
- }
- return types;
- }
-
- private TypeToken<?> resolveSupertype(Type type) {
- TypeToken<?> supertype = resolveType(type);
- // super types' type mapping is a subset of type mapping of this type.
- supertype.typeResolver = typeResolver;
- return supertype;
- }
-
- /**
- * Returns the generic superclass of this type or {@code null} if the type represents
- * {@link Object} or an interface. This method is similar but different from {@link
- * Class#getGenericSuperclass}. For example, {@code
- * new TypeToken<StringArrayList>() {}.getGenericSuperclass()} will return {@code
- * new TypeToken<ArrayList<String>>() {}}; while {@code
- * StringArrayList.class.getGenericSuperclass()} will return {@code ArrayList<E>}, where {@code E}
- * is the type variable declared by class {@code ArrayList}.
- *
- * <p>If this type is a type variable or wildcard, its first upper bound is examined and returned
- * if the bound is a class or extends from a class. This means that the returned type could be a
- * type variable too.
- */
- @Nullable
- final TypeToken<? super T> getGenericSuperclass() {
- if (runtimeType instanceof TypeVariable) {
- // First bound is always the super class, if one exists.
- return boundAsSuperclass(((TypeVariable<?>) runtimeType).getBounds()[0]);
- }
- if (runtimeType instanceof WildcardType) {
- // wildcard has one and only one upper bound.
- return boundAsSuperclass(((WildcardType) runtimeType).getUpperBounds()[0]);
- }
- Type superclass = getRawType().getGenericSuperclass();
- if (superclass == null) {
- return null;
- }
- @SuppressWarnings("unchecked") // super class of T
- TypeToken<? super T> superToken = (TypeToken<? super T>) resolveSupertype(superclass);
- return superToken;
- }
-
- @Nullable private TypeToken<? super T> boundAsSuperclass(Type bound) {
- TypeToken<?> token = of(bound);
- if (token.getRawType().isInterface()) {
- return null;
- }
- @SuppressWarnings("unchecked") // only upper bound of T is passed in.
- TypeToken<? super T> superclass = (TypeToken<? super T>) token;
- return superclass;
- }
-
- /**
- * Returns the generic interfaces that this type directly {@code implements}. This method is
- * similar but different from {@link Class#getGenericInterfaces()}. For example, {@code
- * new TypeToken<List<String>>() {}.getGenericInterfaces()} will return a list that contains
- * {@code new TypeToken<Iterable<String>>() {}}; while {@code List.class.getGenericInterfaces()}
- * will return an array that contains {@code Iterable<T>}, where the {@code T} is the type
- * variable declared by interface {@code Iterable}.
- *
- * <p>If this type is a type variable or wildcard, its upper bounds are examined and those that
- * are either an interface or upper-bounded only by interfaces are returned. This means that the
- * returned types could include type variables too.
- */
- final ImmutableList<TypeToken<? super T>> getGenericInterfaces() {
- if (runtimeType instanceof TypeVariable) {
- return boundsAsInterfaces(((TypeVariable<?>) runtimeType).getBounds());
- }
- if (runtimeType instanceof WildcardType) {
- return boundsAsInterfaces(((WildcardType) runtimeType).getUpperBounds());
- }
- ImmutableList.Builder<TypeToken<? super T>> builder = ImmutableList.builder();
- for (Type interfaceType : getRawType().getGenericInterfaces()) {
- @SuppressWarnings("unchecked") // interface of T
- TypeToken<? super T> resolvedInterface = (TypeToken<? super T>)
- resolveSupertype(interfaceType);
- builder.add(resolvedInterface);
- }
- return builder.build();
- }
-
- private ImmutableList<TypeToken<? super T>> boundsAsInterfaces(Type[] bounds) {
- ImmutableList.Builder<TypeToken<? super T>> builder = ImmutableList.builder();
- for (Type bound : bounds) {
- @SuppressWarnings("unchecked") // upper bound of T
- TypeToken<? super T> boundType = (TypeToken<? super T>) of(bound);
- if (boundType.getRawType().isInterface()) {
- builder.add(boundType);
- }
- }
- return builder.build();
- }
-
- /**
- * Returns the set of interfaces and classes that this type is or is a subtype of. The returned
- * types are parameterized with proper type arguments.
- *
- * <p>Subtypes are always listed before supertypes. But the reverse is not true. A type isn't
- * necessarily a subtype of all the types following. Order between types without subtype
- * relationship is arbitrary and not guaranteed.
- *
- * <p>If this type is a type variable or wildcard, upper bounds that are themselves type variables
- * aren't included (their super interfaces and superclasses are).
- */
- public final TypeSet getTypes() {
- return new TypeSet();
- }
-
- /**
- * Returns the generic form of {@code superclass}. For example, if this is
- * {@code ArrayList<String>}, {@code Iterable<String>} is returned given the
- * input {@code Iterable.class}.
- */
- public final TypeToken<? super T> getSupertype(Class<? super T> superclass) {
- checkArgument(superclass.isAssignableFrom(getRawType()),
- "%s is not a super class of %s", superclass, this);
- if (runtimeType instanceof TypeVariable) {
- return getSupertypeFromUpperBounds(superclass, ((TypeVariable<?>) runtimeType).getBounds());
- }
- if (runtimeType instanceof WildcardType) {
- return getSupertypeFromUpperBounds(superclass, ((WildcardType) runtimeType).getUpperBounds());
- }
- if (superclass.isArray()) {
- return getArraySupertype(superclass);
- }
- @SuppressWarnings("unchecked") // resolved supertype
- TypeToken<? super T> supertype = (TypeToken<? super T>)
- resolveSupertype(toGenericType(superclass).runtimeType);
- return supertype;
- }
-
- /**
- * Returns subtype of {@code this} with {@code subclass} as the raw class.
- * For example, if this is {@code Iterable<String>} and {@code subclass} is {@code List},
- * {@code List<String>} is returned.
- */
- public final TypeToken<? extends T> getSubtype(Class<?> subclass) {
- checkArgument(!(runtimeType instanceof TypeVariable),
- "Cannot get subtype of type variable <%s>", this);
- if (runtimeType instanceof WildcardType) {
- return getSubtypeFromLowerBounds(subclass, ((WildcardType) runtimeType).getLowerBounds());
- }
- checkArgument(getRawType().isAssignableFrom(subclass),
- "%s isn't a subclass of %s", subclass, this);
- // unwrap array type if necessary
- if (isArray()) {
- return getArraySubtype(subclass);
- }
- @SuppressWarnings("unchecked") // guarded by the isAssignableFrom() statement above
- TypeToken<? extends T> subtype = (TypeToken<? extends T>)
- of(resolveTypeArgsForSubclass(subclass));
- return subtype;
- }
-
- /** Returns true if this type is assignable from the given {@code type}. */
- public final boolean isAssignableFrom(TypeToken<?> type) {
- return isAssignableFrom(type.runtimeType);
- }
-
- /** Check if this type is assignable from the given {@code type}. */
- public final boolean isAssignableFrom(Type type) {
- return isAssignable(checkNotNull(type), runtimeType);
- }
-
- /**
- * Returns true if this type is known to be an array type, such as {@code int[]}, {@code T[]},
- * {@code <? extends Map<String, Integer>[]>} etc.
- */
- public final boolean isArray() {
- return getComponentType() != null;
- }
-
- /**
- * Returns the array component type if this type represents an array ({@code int[]}, {@code T[]},
- * {@code <? extends Map<String, Integer>[]>} etc.), or else {@code null} is returned.
- */
- @Nullable public final TypeToken<?> getComponentType() {
- Type componentType = Types.getComponentType(runtimeType);
- if (componentType == null) {
- return null;
- }
- return of(componentType);
- }
-
- /**
- * Returns the {@link Invokable} for {@code method}, which must be a member of {@code T}.
- *
- * @since 14.0
- */
- public final Invokable<T, Object> method(Method method) {
- checkArgument(of(method.getDeclaringClass()).isAssignableFrom(this),
- "%s not declared by %s", method, this);
- return new Invokable.MethodInvokable<T>(method) {
- @Override Type getGenericReturnType() {
- return resolveType(super.getGenericReturnType()).getType();
- }
- @Override Type[] getGenericParameterTypes() {
- return resolveInPlace(super.getGenericParameterTypes());
- }
- @Override Type[] getGenericExceptionTypes() {
- return resolveInPlace(super.getGenericExceptionTypes());
- }
- @Override public TypeToken<T> getOwnerType() {
- return TypeToken.this;
- }
- };
- }
-
- /**
- * Returns the {@link Invokable} for {@code constructor}, which must be a member of {@code T}.
- *
- * @since 14.0
- */
- public final Invokable<T, T> constructor(Constructor<?> constructor) {
- checkArgument(constructor.getDeclaringClass() == getRawType(),
- "%s not declared by %s", constructor, getRawType());
- return new Invokable.ConstructorInvokable<T>(constructor) {
- @Override Type getGenericReturnType() {
- return resolveType(super.getGenericReturnType()).getType();
- }
- @Override Type[] getGenericParameterTypes() {
- return resolveInPlace(super.getGenericParameterTypes());
- }
- @Override Type[] getGenericExceptionTypes() {
- return resolveInPlace(super.getGenericExceptionTypes());
- }
- @Override public TypeToken<T> getOwnerType() {
- return TypeToken.this;
- }
- };
- }
-
- /**
- * The set of interfaces and classes that {@code T} is or is a subtype of. {@link Object} is not
- * included in the set if this type is an interface.
- */
- public class TypeSet extends ForwardingSet<TypeToken<? super T>> implements Serializable {
-
- private transient ImmutableSet<TypeToken<? super T>> types;
-
- TypeSet() {}
-
- /** Returns the types that are interfaces implemented by this type. */
- public TypeSet interfaces() {
- return new InterfaceSet(this);
- }
-
- /** Returns the types that are classes. */
- public TypeSet classes() {
- return new ClassSet();
- }
-
- @Override protected Set<TypeToken<? super T>> delegate() {
- ImmutableSet<TypeToken<? super T>> filteredTypes = types;
- if (filteredTypes == null) {
- // Java has no way to express ? super T when we parameterize TypeToken vs. Class.
- @SuppressWarnings({"unchecked", "rawtypes"})
- ImmutableList<TypeToken<? super T>> collectedTypes = (ImmutableList)
- TypeCollector.FOR_GENERIC_TYPE.collectTypes(TypeToken.this);
- return (types = FluentIterable.from(collectedTypes)
- .filter(TypeFilter.IGNORE_TYPE_VARIABLE_OR_WILDCARD)
- .toSet());
- } else {
- return filteredTypes;
- }
- }
-
- /** Returns the raw types of the types in this set, in the same order. */
- public Set<Class<? super T>> rawTypes() {
- // Java has no way to express ? super T when we parameterize TypeToken vs. Class.
- @SuppressWarnings({"unchecked", "rawtypes"})
- ImmutableList<Class<? super T>> collectedTypes = (ImmutableList)
- TypeCollector.FOR_RAW_TYPE.collectTypes(getImmediateRawTypes());
- return ImmutableSet.copyOf(collectedTypes);
- }
-
- private static final long serialVersionUID = 0;
- }
-
- private final class InterfaceSet extends TypeSet {
-
- private transient final TypeSet allTypes;
- private transient ImmutableSet<TypeToken<? super T>> interfaces;
-
- InterfaceSet(TypeSet allTypes) {
- this.allTypes = allTypes;
- }
-
- @Override protected Set<TypeToken<? super T>> delegate() {
- ImmutableSet<TypeToken<? super T>> result = interfaces;
- if (result == null) {
- return (interfaces = FluentIterable.from(allTypes)
- .filter(TypeFilter.INTERFACE_ONLY)
- .toSet());
- } else {
- return result;
- }
- }
-
- @Override public TypeSet interfaces() {
- return this;
- }
-
- @Override public Set<Class<? super T>> rawTypes() {
- // Java has no way to express ? super T when we parameterize TypeToken vs. Class.
- @SuppressWarnings({"unchecked", "rawtypes"})
- ImmutableList<Class<? super T>> collectedTypes = (ImmutableList)
- TypeCollector.FOR_RAW_TYPE.collectTypes(getImmediateRawTypes());
- return FluentIterable.from(collectedTypes)
- .filter(new Predicate<Class<?>>() {
- @Override public boolean apply(Class<?> type) {
- return type.isInterface();
- }
- })
- .toSet();
- }
-
- @Override public TypeSet classes() {
- throw new UnsupportedOperationException("interfaces().classes() not supported.");
- }
-
- private Object readResolve() {
- return getTypes().interfaces();
- }
-
- private static final long serialVersionUID = 0;
- }
-
- private final class ClassSet extends TypeSet {
-
- private transient ImmutableSet<TypeToken<? super T>> classes;
-
- @Override protected Set<TypeToken<? super T>> delegate() {
- ImmutableSet<TypeToken<? super T>> result = classes;
- if (result == null) {
- @SuppressWarnings({"unchecked", "rawtypes"})
- ImmutableList<TypeToken<? super T>> collectedTypes = (ImmutableList)
- TypeCollector.FOR_GENERIC_TYPE.classesOnly().collectTypes(TypeToken.this);
- return (classes = FluentIterable.from(collectedTypes)
- .filter(TypeFilter.IGNORE_TYPE_VARIABLE_OR_WILDCARD)
- .toSet());
- } else {
- return result;
- }
- }
-
- @Override public TypeSet classes() {
- return this;
- }
-
- @Override public Set<Class<? super T>> rawTypes() {
- // Java has no way to express ? super T when we parameterize TypeToken vs. Class.
- @SuppressWarnings({"unchecked", "rawtypes"})
- ImmutableList<Class<? super T>> collectedTypes = (ImmutableList)
- TypeCollector.FOR_RAW_TYPE.classesOnly().collectTypes(getImmediateRawTypes());
- return ImmutableSet.copyOf(collectedTypes);
- }
-
- @Override public TypeSet interfaces() {
- throw new UnsupportedOperationException("classes().interfaces() not supported.");
- }
-
- private Object readResolve() {
- return getTypes().classes();
- }
-
- private static final long serialVersionUID = 0;
- }
-
- private enum TypeFilter implements Predicate<TypeToken<?>> {
-
- IGNORE_TYPE_VARIABLE_OR_WILDCARD {
- @Override public boolean apply(TypeToken<?> type) {
- return !(type.runtimeType instanceof TypeVariable
- || type.runtimeType instanceof WildcardType);
- }
- },
- INTERFACE_ONLY {
- @Override public boolean apply(TypeToken<?> type) {
- return type.getRawType().isInterface();
- }
- }
- }
-
- /**
- * Returns true if {@code o} is another {@code TypeToken} that represents the same {@link Type}.
- */
- @Override public boolean equals(@Nullable Object o) {
- if (o instanceof TypeToken) {
- TypeToken<?> that = (TypeToken<?>) o;
- return runtimeType.equals(that.runtimeType);
- }
- return false;
- }
-
- @Override public int hashCode() {
- return runtimeType.hashCode();
- }
-
- @Override public String toString() {
- return Types.toString(runtimeType);
- }
-
- /** Implemented to support serialization of subclasses. */
- protected Object writeReplace() {
- // TypeResolver just transforms the type to our own impls that are Serializable
- // except TypeVariable.
- return of(new TypeResolver().resolveType(runtimeType));
- }
-
- /**
- * Ensures that this type token doesn't contain type variables, which can cause unchecked type
- * errors for callers like {@link TypeToInstanceMap}.
- */
- final TypeToken<T> rejectTypeVariables() {
- checkArgument(!Types.containsTypeVariable(runtimeType),
- "%s contains a type variable and is not safe for the operation");
- return this;
- }
-
- private static boolean isAssignable(Type from, Type to) {
- if (to.equals(from)) {
- return true;
- }
- if (to instanceof WildcardType) {
- return isAssignableToWildcardType(from, (WildcardType) to);
- }
- // if "from" is type variable, it's assignable if any of its "extends"
- // bounds is assignable to "to".
- if (from instanceof TypeVariable) {
- return isAssignableFromAny(((TypeVariable<?>) from).getBounds(), to);
- }
- // if "from" is wildcard, it'a assignable to "to" if any of its "extends"
- // bounds is assignable to "to".
- if (from instanceof WildcardType) {
- return isAssignableFromAny(((WildcardType) from).getUpperBounds(), to);
- }
- if (from instanceof GenericArrayType) {
- return isAssignableFromGenericArrayType((GenericArrayType) from, to);
- }
- // Proceed to regular Type assignability check
- if (to instanceof Class) {
- return isAssignableToClass(from, (Class<?>) to);
- } else if (to instanceof ParameterizedType) {
- return isAssignableToParameterizedType(from, (ParameterizedType) to);
- } else if (to instanceof GenericArrayType) {
- return isAssignableToGenericArrayType(from, (GenericArrayType) to);
- } else { // to instanceof TypeVariable
- return false;
- }
- }
-
- private static boolean isAssignableFromAny(Type[] fromTypes, Type to) {
- for (Type from : fromTypes) {
- if (isAssignable(from, to)) {
- return true;
- }
- }
- return false;
- }
-
- private static boolean isAssignableToClass(Type from, Class<?> to) {
- return to.isAssignableFrom(getRawType(from));
- }
-
- private static boolean isAssignableToWildcardType(
- Type from, WildcardType to) {
- // if "to" is <? extends Foo>, "from" can be:
- // Foo, SubFoo, <? extends Foo>, <? extends SubFoo>, <T extends Foo> or
- // <T extends SubFoo>.
- // if "to" is <? super Foo>, "from" can be:
- // Foo, SuperFoo, <? super Foo> or <? super SuperFoo>.
- return isAssignable(from, supertypeBound(to)) && isAssignableBySubtypeBound(from, to);
- }
-
- private static boolean isAssignableBySubtypeBound(Type from, WildcardType to) {
- Type toSubtypeBound = subtypeBound(to);
- if (toSubtypeBound == null) {
- return true;
- }
- Type fromSubtypeBound = subtypeBound(from);
- if (fromSubtypeBound == null) {
- return false;
- }
- return isAssignable(toSubtypeBound, fromSubtypeBound);
- }
-
- private static boolean isAssignableToParameterizedType(Type from, ParameterizedType to) {
- Class<?> matchedClass = getRawType(to);
- if (!matchedClass.isAssignableFrom(getRawType(from))) {
- return false;
- }
- Type[] typeParams = matchedClass.getTypeParameters();
- Type[] toTypeArgs = to.getActualTypeArguments();
- TypeToken<?> fromTypeToken = of(from);
- for (int i = 0; i < typeParams.length; i++) {
- // If "to" is "List<? extends CharSequence>"
- // and "from" is StringArrayList,
- // First step is to figure out StringArrayList "is-a" List<E> and <E> is
- // String.
- // typeParams[0] is E and fromTypeToken.get(typeParams[0]) will resolve to
- // String.
- // String is then matched against <? extends CharSequence>.
- Type fromTypeArg = fromTypeToken.resolveType(typeParams[i]).runtimeType;
- if (!matchTypeArgument(fromTypeArg, toTypeArgs[i])) {
- return false;
- }
- }
- return true;
- }
-
- private static boolean isAssignableToGenericArrayType(Type from, GenericArrayType to) {
- if (from instanceof Class) {
- Class<?> fromClass = (Class<?>) from;
- if (!fromClass.isArray()) {
- return false;
- }
- return isAssignable(fromClass.getComponentType(), to.getGenericComponentType());
- } else if (from instanceof GenericArrayType) {
- GenericArrayType fromArrayType = (GenericArrayType) from;
- return isAssignable(fromArrayType.getGenericComponentType(), to.getGenericComponentType());
- } else {
- return false;
- }
- }
-
- private static boolean isAssignableFromGenericArrayType(GenericArrayType from, Type to) {
- if (to instanceof Class) {
- Class<?> toClass = (Class<?>) to;
- if (!toClass.isArray()) {
- return toClass == Object.class; // any T[] is assignable to Object
- }
- return isAssignable(from.getGenericComponentType(), toClass.getComponentType());
- } else if (to instanceof GenericArrayType) {
- GenericArrayType toArrayType = (GenericArrayType) to;
- return isAssignable(from.getGenericComponentType(), toArrayType.getGenericComponentType());
- } else {
- return false;
- }
- }
-
- private static boolean matchTypeArgument(Type from, Type to) {
- if (from.equals(to)) {
- return true;
- }
- if (to instanceof WildcardType) {
- return isAssignableToWildcardType(from, (WildcardType) to);
- }
- return false;
- }
-
- private static Type supertypeBound(Type type) {
- if (type instanceof WildcardType) {
- return supertypeBound((WildcardType) type);
- }
- return type;
- }
-
- private static Type supertypeBound(WildcardType type) {
- Type[] upperBounds = type.getUpperBounds();
- if (upperBounds.length == 1) {
- return supertypeBound(upperBounds[0]);
- } else if (upperBounds.length == 0) {
- return Object.class;
- } else {
- throw new AssertionError(
- "There should be at most one upper bound for wildcard type: " + type);
- }
- }
-
- @Nullable private static Type subtypeBound(Type type) {
- if (type instanceof WildcardType) {
- return subtypeBound((WildcardType) type);
- } else {
- return type;
- }
- }
-
- @Nullable private static Type subtypeBound(WildcardType type) {
- Type[] lowerBounds = type.getLowerBounds();
- if (lowerBounds.length == 1) {
- return subtypeBound(lowerBounds[0]);
- } else if (lowerBounds.length == 0) {
- return null;
- } else {
- throw new AssertionError(
- "Wildcard should have at most one lower bound: " + type);
- }
- }
-
- @VisibleForTesting static Class<?> getRawType(Type type) {
- // For wildcard or type variable, the first bound determines the runtime type.
- return getRawTypes(type).iterator().next();
- }
-
- @VisibleForTesting static ImmutableSet<Class<?>> getRawTypes(Type type) {
- if (type instanceof Class) {
- return ImmutableSet.<Class<?>>of((Class<?>) type);
- } else if (type instanceof ParameterizedType) {
- ParameterizedType parameterizedType = (ParameterizedType) type;
- // JDK implementation declares getRawType() to return Class<?>: http://goo.gl/YzaEd
- return ImmutableSet.<Class<?>>of((Class<?>) parameterizedType.getRawType());
- } else if (type instanceof GenericArrayType) {
- GenericArrayType genericArrayType = (GenericArrayType) type;
- return ImmutableSet.<Class<?>>of(Types.getArrayClass(
- getRawType(genericArrayType.getGenericComponentType())));
- } else if (type instanceof TypeVariable) {
- return getRawTypes(((TypeVariable<?>) type).getBounds());
- } else if (type instanceof WildcardType) {
- return getRawTypes(((WildcardType) type).getUpperBounds());
- } else {
- throw new AssertionError(type + " unsupported");
- }
- }
-
- private static ImmutableSet<Class<?>> getRawTypes(Type[] types) {
- ImmutableSet.Builder<Class<?>> builder = ImmutableSet.builder();
- for (Type type : types) {
- builder.addAll(getRawTypes(type));
- }
- return builder.build();
- }
-
- /**
- * Returns the type token representing the generic type declaration of {@code cls}. For example:
- * {@code TypeToken.getGenericType(Iterable.class)} returns {@code Iterable<T>}.
- *
- * <p>If {@code cls} isn't parameterized and isn't a generic array, the type token of the class is
- * returned.
- */
- @VisibleForTesting static <T> TypeToken<? extends T> toGenericType(Class<T> cls) {
- if (cls.isArray()) {
- Type arrayOfGenericType = Types.newArrayType(
- // If we are passed with int[].class, don't turn it to GenericArrayType
- toGenericType(cls.getComponentType()).runtimeType);
- @SuppressWarnings("unchecked") // array is covariant
- TypeToken<? extends T> result = (TypeToken<? extends T>) of(arrayOfGenericType);
- return result;
- }
- TypeVariable<Class<T>>[] typeParams = cls.getTypeParameters();
- if (typeParams.length > 0) {
- @SuppressWarnings("unchecked") // Like, it's Iterable<T> for Iterable.class
- TypeToken<? extends T> type = (TypeToken<? extends T>)
- of(Types.newParameterizedType(cls, typeParams));
- return type;
- } else {
- return of(cls);
- }
- }
-
- private TypeToken<? super T> getSupertypeFromUpperBounds(
- Class<? super T> supertype, Type[] upperBounds) {
- for (Type upperBound : upperBounds) {
- @SuppressWarnings("unchecked") // T's upperbound is <? super T>.
- TypeToken<? super T> bound = (TypeToken<? super T>) of(upperBound);
- if (of(supertype).isAssignableFrom(bound)) {
- @SuppressWarnings({"rawtypes", "unchecked"}) // guarded by the isAssignableFrom check.
- TypeToken<? super T> result = bound.getSupertype((Class) supertype);
- return result;
- }
- }
- throw new IllegalArgumentException(supertype + " isn't a super type of " + this);
- }
-
- private TypeToken<? extends T> getSubtypeFromLowerBounds(Class<?> subclass, Type[] lowerBounds) {
- for (Type lowerBound : lowerBounds) {
- @SuppressWarnings("unchecked") // T's lower bound is <? extends T>
- TypeToken<? extends T> bound = (TypeToken<? extends T>) of(lowerBound);
- // Java supports only one lowerbound anyway.
- return bound.getSubtype(subclass);
- }
- throw new IllegalArgumentException(subclass + " isn't a subclass of " + this);
- }
-
- private TypeToken<? super T> getArraySupertype(Class<? super T> supertype) {
- // with component type, we have lost generic type information
- // Use raw type so that compiler allows us to call getSupertype()
- @SuppressWarnings("rawtypes")
- TypeToken componentType = checkNotNull(getComponentType(),
- "%s isn't a super type of %s", supertype, this);
- // array is covariant. component type is super type, so is the array type.
- @SuppressWarnings("unchecked") // going from raw type back to generics
- TypeToken<?> componentSupertype = componentType.getSupertype(supertype.getComponentType());
- @SuppressWarnings("unchecked") // component type is super type, so is array type.
- TypeToken<? super T> result = (TypeToken<? super T>)
- // If we are passed with int[].class, don't turn it to GenericArrayType
- of(newArrayClassOrGenericArrayType(componentSupertype.runtimeType));
- return result;
- }
-
- private TypeToken<? extends T> getArraySubtype(Class<?> subclass) {
- // array is covariant. component type is subtype, so is the array type.
- TypeToken<?> componentSubtype = getComponentType()
- .getSubtype(subclass.getComponentType());
- @SuppressWarnings("unchecked") // component type is subtype, so is array type.
- TypeToken<? extends T> result = (TypeToken<? extends T>)
- // If we are passed with int[].class, don't turn it to GenericArrayType
- of(newArrayClassOrGenericArrayType(componentSubtype.runtimeType));
- return result;
- }
-
- private Type resolveTypeArgsForSubclass(Class<?> subclass) {
- if (runtimeType instanceof Class) {
- // no resolution needed
- return subclass;
- }
- // class Base<A, B> {}
- // class Sub<X, Y> extends Base<X, Y> {}
- // Base<String, Integer>.subtype(Sub.class):
-
- // Sub<X, Y>.getSupertype(Base.class) => Base<X, Y>
- // => X=String, Y=Integer
- // => Sub<X, Y>=Sub<String, Integer>
- TypeToken<?> genericSubtype = toGenericType(subclass);
- @SuppressWarnings({"rawtypes", "unchecked"}) // subclass isn't <? extends T>
- Type supertypeWithArgsFromSubtype = genericSubtype
- .getSupertype((Class) getRawType())
- .runtimeType;
- return new TypeResolver().where(supertypeWithArgsFromSubtype, runtimeType)
- .resolveType(genericSubtype.runtimeType);
- }
-
- /**
- * Creates an array class if {@code componentType} is a class, or else, a
- * {@link GenericArrayType}. This is what Java7 does for generic array type
- * parameters.
- */
- private static Type newArrayClassOrGenericArrayType(Type componentType) {
- return Types.JavaVersion.JAVA7.newArrayType(componentType);
- }
-
- private static final class SimpleTypeToken<T> extends TypeToken<T> {
-
- SimpleTypeToken(Type type) {
- super(type);
- }
-
- private static final long serialVersionUID = 0;
- }
-
- /**
- * Collects parent types from a sub type.
- *
- * @param <K> The type "kind". Either a TypeToken, or Class.
- */
- private abstract static class TypeCollector<K> {
-
- static final TypeCollector<TypeToken<?>> FOR_GENERIC_TYPE =
- new TypeCollector<TypeToken<?>>() {
- @Override Class<?> getRawType(TypeToken<?> type) {
- return type.getRawType();
- }
-
- @Override Iterable<? extends TypeToken<?>> getInterfaces(TypeToken<?> type) {
- return type.getGenericInterfaces();
- }
-
- @Nullable
- @Override TypeToken<?> getSuperclass(TypeToken<?> type) {
- return type.getGenericSuperclass();
- }
- };
-
- static final TypeCollector<Class<?>> FOR_RAW_TYPE =
- new TypeCollector<Class<?>>() {
- @Override Class<?> getRawType(Class<?> type) {
- return type;
- }
-
- @Override Iterable<? extends Class<?>> getInterfaces(Class<?> type) {
- return Arrays.asList(type.getInterfaces());
- }
-
- @Nullable
- @Override Class<?> getSuperclass(Class<?> type) {
- return type.getSuperclass();
- }
- };
-
- /** For just classes, we don't have to traverse interfaces. */
- final TypeCollector<K> classesOnly() {
- return new ForwardingTypeCollector<K>(this) {
- @Override Iterable<? extends K> getInterfaces(K type) {
- return ImmutableSet.of();
- }
- @Override ImmutableList<K> collectTypes(Iterable<? extends K> types) {
- ImmutableList.Builder<K> builder = ImmutableList.builder();
- for (K type : types) {
- if (!getRawType(type).isInterface()) {
- builder.add(type);
- }
- }
- return super.collectTypes(builder.build());
- }
- };
- }
-
- final ImmutableList<K> collectTypes(K type) {
- return collectTypes(ImmutableList.of(type));
- }
-
- ImmutableList<K> collectTypes(Iterable<? extends K> types) {
- // type -> order number. 1 for Object, 2 for anything directly below, so on so forth.
- Map<K, Integer> map = Maps.newHashMap();
- for (K type : types) {
- collectTypes(type, map);
- }
- return sortKeysByValue(map, Ordering.natural().reverse());
- }
-
- /** Collects all types to map, and returns the total depth from T up to Object. */
- private int collectTypes(K type, Map<? super K, Integer> map) {
- Integer existing = map.get(this);
- if (existing != null) {
- // short circuit: if set contains type it already contains its supertypes
- return existing;
- }
- int aboveMe = getRawType(type).isInterface()
- ? 1 // interfaces should be listed before Object
- : 0;
- for (K interfaceType : getInterfaces(type)) {
- aboveMe = Math.max(aboveMe, collectTypes(interfaceType, map));
- }
- K superclass = getSuperclass(type);
- if (superclass != null) {
- aboveMe = Math.max(aboveMe, collectTypes(superclass, map));
- }
- /*
- * TODO(benyu): should we include Object for interface?
- * Also, CharSequence[] and Object[] for String[]?
- *
- */
- map.put(type, aboveMe + 1);
- return aboveMe + 1;
- }
-
- private static <K, V> ImmutableList<K> sortKeysByValue(
- final Map<K, V> map, final Comparator<? super V> valueComparator) {
- Ordering<K> keyOrdering = new Ordering<K>() {
- @Override public int compare(K left, K right) {
- return valueComparator.compare(map.get(left), map.get(right));
- }
- };
- return keyOrdering.immutableSortedCopy(map.keySet());
- }
-
- abstract Class<?> getRawType(K type);
- abstract Iterable<? extends K> getInterfaces(K type);
- @Nullable abstract K getSuperclass(K type);
-
- private static class ForwardingTypeCollector<K> extends TypeCollector<K> {
-
- private final TypeCollector<K> delegate;
-
- ForwardingTypeCollector(TypeCollector<K> delegate) {
- this.delegate = delegate;
- }
-
- @Override Class<?> getRawType(K type) {
- return delegate.getRawType(type);
- }
-
- @Override Iterable<? extends K> getInterfaces(K type) {
- return delegate.getInterfaces(type);
- }
-
- @Override K getSuperclass(K type) {
- return delegate.getSuperclass(type);
- }
- }
- }
-}
diff --git a/guava/src/com/google/common/reflect/Types.java b/guava/src/com/google/common/reflect/Types.java
deleted file mode 100644
index c19f38e..0000000
--- a/guava/src/com/google/common/reflect/Types.java
+++ /dev/null
@@ -1,504 +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.reflect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Iterables.transform;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-import java.io.Serializable;
-import java.lang.reflect.Array;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.GenericDeclaration;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.util.Arrays;
-import java.util.Collection;
-
-import javax.annotation.Nullable;
-
-/**
- * Utilities for working with {@link Type}.
- *
- * @author Ben Yu
- */
-final class Types {
-
- /** Class#toString without the "class " and "interface " prefixes */
- private static final Function<Type, String> TYPE_TO_STRING =
- new Function<Type, String>() {
- @Override public String apply(Type from) {
- return Types.toString(from);
- }
- };
-
- private static final Joiner COMMA_JOINER = Joiner.on(", ").useForNull("null");
-
- /** Returns the array type of {@code componentType}. */
- static Type newArrayType(Type componentType) {
- if (componentType instanceof WildcardType) {
- WildcardType wildcard = (WildcardType) componentType;
- Type[] lowerBounds = wildcard.getLowerBounds();
- checkArgument(lowerBounds.length <= 1, "Wildcard cannot have more than one lower bounds.");
- if (lowerBounds.length == 1) {
- return supertypeOf(newArrayType(lowerBounds[0]));
- } else {
- Type[] upperBounds = wildcard.getUpperBounds();
- checkArgument(upperBounds.length == 1, "Wildcard should have only one upper bound.");
- return subtypeOf(newArrayType(upperBounds[0]));
- }
- }
- return JavaVersion.CURRENT.newArrayType(componentType);
- }
-
- /**
- * Returns a type where {@code rawType} is parameterized by
- * {@code arguments} and is owned by {@code ownerType}.
- */
- static ParameterizedType newParameterizedTypeWithOwner(
- @Nullable Type ownerType, Class<?> rawType, Type... arguments) {
- if (ownerType == null) {
- return newParameterizedType(rawType, arguments);
- }
- // ParameterizedTypeImpl constructor already checks, but we want to throw NPE before IAE
- checkNotNull(arguments);
- checkArgument(rawType.getEnclosingClass() != null, "Owner type for unenclosed %s", rawType);
- return new ParameterizedTypeImpl(ownerType, rawType, arguments);
- }
-
- /**
- * Returns a type where {@code rawType} is parameterized by
- * {@code arguments}.
- */
- static ParameterizedType newParameterizedType(Class<?> rawType, Type... arguments) {
- return new ParameterizedTypeImpl(
- ClassOwnership.JVM_BEHAVIOR.getOwnerType(rawType), rawType, arguments);
- }
-
- /** Decides what owner type to use for constructing {@link ParameterizedType} from a raw class. */
- private enum ClassOwnership {
-
- OWNED_BY_ENCLOSING_CLASS {
- @Nullable
- @Override
- Class<?> getOwnerType(Class<?> rawType) {
- return rawType.getEnclosingClass();
- }
- },
- LOCAL_CLASS_HAS_NO_OWNER {
- @Nullable
- @Override
- Class<?> getOwnerType(Class<?> rawType) {
- if (rawType.isLocalClass()) {
- return null;
- } else {
- return rawType.getEnclosingClass();
- }
- }
- };
-
- @Nullable abstract Class<?> getOwnerType(Class<?> rawType);
-
- static final ClassOwnership JVM_BEHAVIOR = detectJvmBehavior();
-
- private static ClassOwnership detectJvmBehavior() {
- class LocalClass<T> {}
- Class<?> subclass = new LocalClass<String>() {}.getClass();
- ParameterizedType parameterizedType = (ParameterizedType)
- subclass.getGenericSuperclass();
- for (ClassOwnership behavior : ClassOwnership.values()) {
- if (behavior.getOwnerType(LocalClass.class) == parameterizedType.getOwnerType()) {
- return behavior;
- }
- }
- throw new AssertionError();
- }
- }
-
- /**
- * Returns a new {@link TypeVariable} that belongs to {@code declaration} with
- * {@code name} and {@code bounds}.
- */
- static <D extends GenericDeclaration> TypeVariable<D> newTypeVariable(
- D declaration, String name, Type... bounds) {
- return new TypeVariableImpl<D>(
- declaration,
- name,
- (bounds.length == 0)
- ? new Type[] { Object.class }
- : bounds);
- }
-
- /** Returns a new {@link WildcardType} with {@code upperBound}. */
- @VisibleForTesting static WildcardType subtypeOf(Type upperBound) {
- return new WildcardTypeImpl(new Type[0], new Type[] { upperBound });
- }
-
- /** Returns a new {@link WildcardType} with {@code lowerBound}. */
- @VisibleForTesting static WildcardType supertypeOf(Type lowerBound) {
- return new WildcardTypeImpl(new Type[] { lowerBound }, new Type[] { Object.class });
- }
-
- /**
- * Returns human readable string representation of {@code type}.
- * <ul>
- * <li> For array type {@code Foo[]}, {@code "com.mypackage.Foo[]"} are
- * returned.
- * <li> For any class, {@code theClass.getName()} are returned.
- * <li> For all other types, {@code type.toString()} are returned.
- * </ul>
- */
- static String toString(Type type) {
- return (type instanceof Class)
- ? ((Class<?>) type).getName()
- : type.toString();
- }
-
- @Nullable static Type getComponentType(Type type) {
- checkNotNull(type);
- if (type instanceof Class) {
- return ((Class<?>) type).getComponentType();
- } else if (type instanceof GenericArrayType) {
- return ((GenericArrayType) type).getGenericComponentType();
- } else if (type instanceof WildcardType) {
- return subtypeOfComponentType(((WildcardType) type).getUpperBounds());
- } else if (type instanceof TypeVariable) {
- return subtypeOfComponentType(((TypeVariable<?>) type).getBounds());
- } else {
- return null;
- }
- }
-
- /**
- * Returns {@code ? extends X} if any of {@code bounds} is a subtype of {@code X[]}; or null
- * otherwise.
- */
- @Nullable private static Type subtypeOfComponentType(Type[] bounds) {
- for (Type bound : bounds) {
- Type componentType = getComponentType(bound);
- if (componentType != null) {
- // Only the first bound can be a class or array.
- // Bounds after the first can only be interfaces.
- if (componentType instanceof Class) {
- Class<?> componentClass = (Class<?>) componentType;
- if (componentClass.isPrimitive()) {
- return componentClass;
- }
- }
- return subtypeOf(componentType);
- }
- }
- return null;
- }
-
- static boolean containsTypeVariable(@Nullable Type type) {
- if (type instanceof TypeVariable) {
- return true;
- }
- if (type instanceof GenericArrayType) {
- return containsTypeVariable(((GenericArrayType) type).getGenericComponentType());
- }
- if (type instanceof ParameterizedType) {
- return containsTypeVariable(((ParameterizedType) type).getActualTypeArguments());
- }
- if (type instanceof WildcardType) {
- WildcardType wildcard = (WildcardType) type;
- return containsTypeVariable(wildcard.getUpperBounds())
- || containsTypeVariable(wildcard.getLowerBounds());
- }
- return false;
- }
-
- private static boolean containsTypeVariable(Type[] types) {
- for (Type paramType : types) {
- if (containsTypeVariable(paramType)) {
- return true;
- }
- }
- return false;
- }
-
- private static final class GenericArrayTypeImpl
- implements GenericArrayType, Serializable {
-
- private final Type componentType;
-
- GenericArrayTypeImpl(Type componentType) {
- this.componentType = JavaVersion.CURRENT.usedInGenericType(componentType);
- }
-
- @Override public Type getGenericComponentType() {
- return componentType;
- }
-
- @Override public String toString() {
- return Types.toString(componentType) + "[]";
- }
-
- @Override public int hashCode() {
- return componentType.hashCode();
- }
-
- @Override public boolean equals(Object obj) {
- if (obj instanceof GenericArrayType) {
- GenericArrayType that = (GenericArrayType) obj;
- return Objects.equal(
- getGenericComponentType(), that.getGenericComponentType());
- }
- return false;
- }
-
- private static final long serialVersionUID = 0;
- }
-
- private static final class ParameterizedTypeImpl
- implements ParameterizedType, Serializable {
-
- private final Type ownerType;
- private final ImmutableList<Type> argumentsList;
- private final Class<?> rawType;
-
- ParameterizedTypeImpl(
- @Nullable Type ownerType, Class<?> rawType, Type[] typeArguments) {
- checkNotNull(rawType);
- checkArgument(typeArguments.length == rawType.getTypeParameters().length);
- disallowPrimitiveType(typeArguments, "type parameter");
- this.ownerType = ownerType;
- this.rawType = rawType;
- this.argumentsList = JavaVersion.CURRENT.usedInGenericType(typeArguments);
- }
-
- @Override public Type[] getActualTypeArguments() {
- return toArray(argumentsList);
- }
-
- @Override public Type getRawType() {
- return rawType;
- }
-
- @Override public Type getOwnerType() {
- return ownerType;
- }
-
- @Override public String toString() {
- StringBuilder builder = new StringBuilder();
- if (ownerType != null) {
- builder.append(Types.toString(ownerType)).append('.');
- }
- builder.append(rawType.getName())
- .append('<')
- .append(COMMA_JOINER.join(transform(argumentsList, TYPE_TO_STRING)))
- .append('>');
- return builder.toString();
- }
-
- @Override public int hashCode() {
- return (ownerType == null ? 0 : ownerType.hashCode())
- ^ argumentsList.hashCode() ^ rawType.hashCode();
- }
-
- @Override public boolean equals(Object other) {
- if (!(other instanceof ParameterizedType)) {
- return false;
- }
- ParameterizedType that = (ParameterizedType) other;
- return getRawType().equals(that.getRawType())
- && Objects.equal(getOwnerType(), that.getOwnerType())
- && Arrays.equals(
- getActualTypeArguments(), that.getActualTypeArguments());
- }
-
- private static final long serialVersionUID = 0;
- }
-
- private static final class TypeVariableImpl<D extends GenericDeclaration>
- implements TypeVariable<D> {
-
- private final D genericDeclaration;
- private final String name;
- private final ImmutableList<Type> bounds;
-
- TypeVariableImpl(D genericDeclaration, String name, Type[] bounds) {
- disallowPrimitiveType(bounds, "bound for type variable");
- this.genericDeclaration = checkNotNull(genericDeclaration);
- this.name = checkNotNull(name);
- this.bounds = ImmutableList.copyOf(bounds);
- }
-
- @Override public Type[] getBounds() {
- return toArray(bounds);
- }
-
- @Override public D getGenericDeclaration() {
- return genericDeclaration;
- }
-
- @Override public String getName() {
- return name;
- }
-
- @Override public String toString() {
- return name;
- }
-
- @Override public int hashCode() {
- return genericDeclaration.hashCode() ^ name.hashCode();
- }
-
- @Override public boolean equals(Object obj) {
- if (obj instanceof TypeVariable) {
- TypeVariable<?> that = (TypeVariable<?>) obj;
- return name.equals(that.getName())
- && genericDeclaration.equals(that.getGenericDeclaration());
- }
- return false;
- }
- }
-
- static final class WildcardTypeImpl implements WildcardType, Serializable {
-
- private final ImmutableList<Type> lowerBounds;
- private final ImmutableList<Type> upperBounds;
-
- WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
- disallowPrimitiveType(lowerBounds, "lower bound for wildcard");
- disallowPrimitiveType(upperBounds, "upper bound for wildcard");
- this.lowerBounds = JavaVersion.CURRENT.usedInGenericType(lowerBounds);
- this.upperBounds = JavaVersion.CURRENT.usedInGenericType(upperBounds);
- }
-
- @Override public Type[] getLowerBounds() {
- return toArray(lowerBounds);
- }
-
- @Override public Type[] getUpperBounds() {
- return toArray(upperBounds);
- }
-
- @Override public boolean equals(Object obj) {
- if (obj instanceof WildcardType) {
- WildcardType that = (WildcardType) obj;
- return lowerBounds.equals(Arrays.asList(that.getLowerBounds()))
- && upperBounds.equals(Arrays.asList(that.getUpperBounds()));
- }
- return false;
- }
-
- @Override public int hashCode() {
- return lowerBounds.hashCode() ^ upperBounds.hashCode();
- }
-
- @Override public String toString() {
- StringBuilder builder = new StringBuilder("?");
- for (Type lowerBound : lowerBounds) {
- builder.append(" super ").append(Types.toString(lowerBound));
- }
- for (Type upperBound : filterUpperBounds(upperBounds)) {
- builder.append(" extends ").append(Types.toString(upperBound));
- }
- return builder.toString();
- }
-
- private static final long serialVersionUID = 0;
- }
-
- private static Type[] toArray(Collection<Type> types) {
- return types.toArray(new Type[types.size()]);
- }
-
- private static Iterable<Type> filterUpperBounds(Iterable<Type> bounds) {
- return Iterables.filter(
- bounds, Predicates.not(Predicates.<Type>equalTo(Object.class)));
- }
-
- private static void disallowPrimitiveType(Type[] types, String usedAs) {
- for (Type type : types) {
- if (type instanceof Class) {
- Class<?> cls = (Class<?>) type;
- checkArgument(!cls.isPrimitive(),
- "Primitive type '%s' used as %s", cls, usedAs);
- }
- }
- }
-
- /** Returns the {@code Class} object of arrays with {@code componentType}. */
- static Class<?> getArrayClass(Class<?> componentType) {
- // TODO(user): This is not the most efficient way to handle generic
- // arrays, but is there another way to extract the array class in a
- // non-hacky way (i.e. using String value class names- "[L...")?
- return Array.newInstance(componentType, 0).getClass();
- }
-
- // TODO(benyu): Once we are on Java 7, delete this abstraction
- enum JavaVersion {
-
- JAVA6 {
- @Override GenericArrayType newArrayType(Type componentType) {
- return new GenericArrayTypeImpl(componentType);
- }
- @Override Type usedInGenericType(Type type) {
- checkNotNull(type);
- if (type instanceof Class) {
- Class<?> cls = (Class<?>) type;
- if (cls.isArray()) {
- return new GenericArrayTypeImpl(cls.getComponentType());
- }
- }
- return type;
- }
- },
- JAVA7 {
- @Override Type newArrayType(Type componentType) {
- if (componentType instanceof Class) {
- return getArrayClass((Class<?>) componentType);
- } else {
- return new GenericArrayTypeImpl(componentType);
- }
- }
- @Override Type usedInGenericType(Type type) {
- return checkNotNull(type);
- }
- }
- ;
-
- static final JavaVersion CURRENT =
- (new TypeCapture<int[]>() {}.capture() instanceof Class)
- ? JAVA7 : JAVA6;
- abstract Type newArrayType(Type componentType);
- abstract Type usedInGenericType(Type type);
-
- final ImmutableList<Type> usedInGenericType(Type[] types) {
- ImmutableList.Builder<Type> builder = ImmutableList.builder();
- for (Type type : types) {
- builder.add(usedInGenericType(type));
- }
- return builder.build();
- }
- }
-
- private Types() {}
-}
diff --git a/guava/src/com/google/common/reflect/package-info.java b/guava/src/com/google/common/reflect/package-info.java
deleted file mode 100644
index e8ac02a..0000000
--- a/guava/src/com/google/common/reflect/package-info.java
+++ /dev/null
@@ -1,23 +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.
- */
-
-/**
- * This package contains utilities to work with Java reflection.
- * It is a part of the open-source
- * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
- */
-@javax.annotation.ParametersAreNonnullByDefault
-package com.google.common.reflect;
diff --git a/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java b/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
index a1cb641..8136d23 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
@@ -55,8 +55,7 @@ public abstract class AbstractExecutionThreadService implements Service {
shutDown();
} catch (Exception ignored) {
logger.log(Level.WARNING,
- "Error while attempting to shut down the service"
- + " after failure.", ignored);
+ "Error while attempting to shut down the service after failure.", ignored);
}
throw t;
}
@@ -78,14 +77,7 @@ public abstract class AbstractExecutionThreadService implements Service {
};
/**
- * Constructor for use by subclasses.
- */
- protected AbstractExecutionThreadService() {}
-
- /**
* Start the service. This method is invoked on the execution thread.
- *
- * <p>By default this method does nothing.
*/
protected void startUp() throws Exception {}
@@ -107,16 +99,12 @@ public abstract class AbstractExecutionThreadService implements Service {
/**
* Stop the service. This method is invoked on the execution thread.
- *
- * <p>By default this method does nothing.
*/
// TODO: consider supporting a TearDownTestCase-like API
protected void shutDown() throws Exception {}
/**
* Invoked to request the service to stop.
- *
- * <p>By default this method does nothing.
*/
protected void triggerShutdown() {}
@@ -129,19 +117,19 @@ public abstract class AbstractExecutionThreadService implements Service {
* promptly.
*
* <p>The default implementation returns a new {@link Executor} that sets the
- * name of its threads to the string returned by {@link #serviceName}
+ * name of its threads to the string returned by {@link #getServiceName}
*/
protected Executor executor() {
return new Executor() {
@Override
public void execute(Runnable command) {
- MoreExecutors.newThread(serviceName(), command).start();
+ new Thread(command, getServiceName()).start();
}
};
}
@Override public String toString() {
- return serviceName() + " [" + state() + "]";
+ return getServiceName() + " [" + state() + "]";
}
// We override instead of using ForwardingService so that these can be final.
@@ -171,28 +159,14 @@ public abstract class AbstractExecutionThreadService implements Service {
}
/**
- * @since 13.0
- */
- @Override public final void addListener(Listener listener, Executor executor) {
- delegate.addListener(listener, executor);
- }
-
- /**
- * @since 14.0
- */
- @Override public final Throwable failureCause() {
- return delegate.failureCause();
- }
-
- /**
- * Returns the name of this service. {@link AbstractExecutionThreadService}
- * may include the name in debugging output.
+ * Returns the name of this service. {@link AbstractExecutionThreadService} may include the name
+ * in debugging output.
*
* <p>Subclasses may override this method.
*
- * @since 14.0 (present in 10.0 as getServiceName)
+ * @since 10.0
*/
- protected String serviceName() {
+ protected String getServiceName() {
return getClass().getSimpleName();
}
}
diff --git a/guava/src/com/google/common/util/concurrent/AbstractFuture.java b/guava/src/com/google/common/util/concurrent/AbstractFuture.java
index e14a111..bef3d3d 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractFuture.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractFuture.java
@@ -70,11 +70,6 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
// The execution list to hold our executors.
private final ExecutionList executionList = new ExecutionList();
- /**
- * Constructor for use by subclasses.
- */
- protected AbstractFuture() {}
-
/*
* Improve the documentation of when InterruptedException is thrown. Our
* behavior matches the JDK's, but the JDK's documentation is misleading.
@@ -128,7 +123,7 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
- if (!sync.cancel(mayInterruptIfRunning)) {
+ if (!sync.cancel()) {
return false;
}
executionList.execute();
@@ -151,16 +146,6 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
}
/**
- * Returns true if this future was cancelled with {@code
- * mayInterruptIfRunning} set to {@code true}.
- *
- * @since 14.0
- */
- protected final boolean wasInterrupted() {
- return sync.wasInterrupted();
- }
-
- /**
* {@inheritDoc}
*
* @since 10.0
@@ -216,14 +201,13 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
* private subclass to hold the synchronizer. This synchronizer is used to
* implement the blocking and waiting calls as well as to handle state changes
* in a thread-safe manner. The current state of the future is held in the
- * Sync state, and the lock is released whenever the state changes to
- * {@link #COMPLETED}, {@link #CANCELLED}, or {@link #INTERRUPTED}
+ * Sync state, and the lock is released whenever the state changes to either
+ * {@link #COMPLETED} or {@link #CANCELLED}.
*
* <p>To avoid races between threads doing release and acquire, we transition
* to the final state in two steps. One thread will successfully CAS from
* RUNNING to COMPLETING, that thread will then set the result of the
- * computation, and only then transition to COMPLETED, CANCELLED, or
- * INTERRUPTED.
+ * computation, and only then transition to COMPLETED or CANCELLED.
*
* <p>We don't use the integer argument passed between acquire methods so we
* pass around a -1 everywhere.
@@ -237,7 +221,6 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
static final int COMPLETING = 1;
static final int COMPLETED = 2;
static final int CANCELLED = 4;
- static final int INTERRUPTED = 8;
private V value;
private Throwable exception;
@@ -309,9 +292,7 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
}
case CANCELLED:
- case INTERRUPTED:
- throw cancellationExceptionWithCause(
- "Task was cancelled.", exception);
+ throw new CancellationException("Task was cancelled.");
default:
throw new IllegalStateException(
@@ -320,25 +301,17 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
}
/**
- * Checks if the state is {@link #COMPLETED}, {@link #CANCELLED}, or {@link
- * INTERRUPTED}.
+ * Checks if the state is {@link #COMPLETED} or {@link #CANCELLED}.
*/
boolean isDone() {
- return (getState() & (COMPLETED | CANCELLED | INTERRUPTED)) != 0;
+ return (getState() & (COMPLETED | CANCELLED)) != 0;
}
/**
- * Checks if the state is {@link #CANCELLED} or {@link #INTERRUPTED}.
+ * Checks if the state is {@link #CANCELLED}.
*/
boolean isCancelled() {
- return (getState() & (CANCELLED | INTERRUPTED)) != 0;
- }
-
- /**
- * Checks if the state is {@link #INTERRUPTED}.
- */
- boolean wasInterrupted() {
- return getState() == INTERRUPTED;
+ return getState() == CANCELLED;
}
/**
@@ -356,10 +329,10 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
}
/**
- * Transition to the CANCELLED or INTERRUPTED state.
+ * Transition to the CANCELLED state.
*/
- boolean cancel(boolean interrupt) {
- return complete(null, null, interrupt ? INTERRUPTED : CANCELLED);
+ boolean cancel() {
+ return complete(null, null, CANCELLED);
}
/**
@@ -367,8 +340,7 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
* be set but not both. The {@code finalState} is the state to change to
* from {@link #RUNNING}. If the state is not in the RUNNING state we
* return {@code false} after waiting for the state to be set to a valid
- * final state ({@link #COMPLETED}, {@link #CANCELLED}, or {@link
- * #INTERRUPTED}).
+ * final state ({@link #COMPLETED} or {@link #CANCELLED}).
*
* @param v the value to set as the result of the computation.
* @param t the exception to set as the result of the computation.
@@ -381,9 +353,7 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
// If this thread successfully transitioned to COMPLETING, set the value
// and exception and then release to the final state.
this.value = v;
- // Don't actually construct a CancellationException until necessary.
- this.exception = ((finalState & (CANCELLED | INTERRUPTED)) != 0)
- ? new CancellationException("Future.cancel() was called.") : t;
+ this.exception = t;
releaseShared(finalState);
} else if (getState() == COMPLETING) {
// If some other thread is currently completing the future, block until
@@ -393,11 +363,4 @@ public abstract class AbstractFuture<V> implements ListenableFuture<V> {
return doCompletion;
}
}
-
- static final CancellationException cancellationExceptionWithCause(
- @Nullable String message, @Nullable Throwable cause) {
- CancellationException exception = new CancellationException(message);
- exception.initCause(cause);
- return exception;
- }
}
diff --git a/guava/src/com/google/common/util/concurrent/AbstractIdleService.java b/guava/src/com/google/common/util/concurrent/AbstractIdleService.java
index 96a6ff3..504a6bc 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractIdleService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractIdleService.java
@@ -37,7 +37,7 @@ public abstract class AbstractIdleService implements Service {
/* use AbstractService for state management */
private final Service delegate = new AbstractService() {
@Override protected final void doStart() {
- executor().execute(new Runnable() {
+ executor(State.STARTING).execute(new Runnable() {
@Override public void run() {
try {
startUp();
@@ -51,7 +51,7 @@ public abstract class AbstractIdleService implements Service {
}
@Override protected final void doStop() {
- executor().execute(new Runnable() {
+ executor(State.STOPPING).execute(new Runnable() {
@Override public void run() {
try {
shutDown();
@@ -65,9 +65,6 @@ public abstract class AbstractIdleService implements Service {
}
};
- /** Constructor for use by subclasses. */
- protected AbstractIdleService() {}
-
/** Start the service. */
protected abstract void startUp() throws Exception;
@@ -81,19 +78,22 @@ public abstract class AbstractIdleService implements Service {
* priority. The returned executor's {@link Executor#execute(Runnable)
* execute()} method is called when this service is started and stopped,
* and should return promptly.
+ *
+ * @param state {@link Service.State#STARTING} or
+ * {@link Service.State#STOPPING}, used by the default implementation for
+ * naming the thread
*/
- protected Executor executor() {
- final State state = state();
+ protected Executor executor(final State state) {
return new Executor() {
@Override
public void execute(Runnable command) {
- MoreExecutors.newThread(serviceName() + " " + state, command).start();
+ new Thread(command, getServiceName() + " " + state).start();
}
};
}
@Override public String toString() {
- return serviceName() + " [" + state() + "]";
+ return getServiceName() + " [" + state() + "]";
}
// We override instead of using ForwardingService so that these can be final.
@@ -122,27 +122,7 @@ public abstract class AbstractIdleService implements Service {
return delegate.stopAndWait();
}
- /**
- * @since 13.0
- */
- @Override public final void addListener(Listener listener, Executor executor) {
- delegate.addListener(listener, executor);
- }
-
- /**
- * @since 14.0
- */
- @Override public final Throwable failureCause() {
- return delegate.failureCause();
- }
-
- /**
- * Returns the name of this service. {@link AbstractIdleService} may include the name in debugging
- * output.
- *
- * @since 14.0
- */
- protected String serviceName() {
+ private String getServiceName() {
return getClass().getSimpleName();
}
}
diff --git a/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java b/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java
index c3e33a5..24f596f 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java
@@ -14,9 +14,7 @@
package com.google.common.util.concurrent;
-import static com.google.common.util.concurrent.MoreExecutors.invokeAnyImpl;
-
-import com.google.common.annotations.Beta;
+import static com.google.common.base.Preconditions.checkArgument;
import java.util.ArrayList;
import java.util.Collection;
@@ -25,12 +23,11 @@ import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import javax.annotation.Nullable;
-
/**
* Implements {@link ListeningExecutorService} execution methods atop the abstract {@link #execute}
* method. More concretely, the {@code submit}, {@code invokeAny} and {@code invokeAll} methods
@@ -40,17 +37,15 @@ import javax.annotation.Nullable;
* termination.
*
* @author Doug Lea
- * @since 14.0
*/
-@Beta
-public abstract class AbstractListeningExecutorService implements ListeningExecutorService {
+abstract class AbstractListeningExecutorService implements ListeningExecutorService {
@Override public ListenableFuture<?> submit(Runnable task) {
ListenableFutureTask<Void> ftask = ListenableFutureTask.create(task, null);
execute(ftask);
return ftask;
}
- @Override public <T> ListenableFuture<T> submit(Runnable task, @Nullable T result) {
+ @Override public <T> ListenableFuture<T> submit(Runnable task, T result) {
ListenableFutureTask<T> ftask = ListenableFutureTask.create(task, result);
execute(ftask);
return ftask;
@@ -62,10 +57,82 @@ public abstract class AbstractListeningExecutorService implements ListeningExecu
return ftask;
}
+ /**
+ * the main mechanics of invokeAny.
+ */
+ private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ int ntasks = tasks.size();
+ checkArgument(ntasks > 0);
+ List<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
+ ExecutorCompletionService<T> ecs = new ExecutorCompletionService<T>(this);
+
+ // For efficiency, especially in executors with limited
+ // parallelism, check to see if previously submitted tasks are
+ // done before submitting more of them. This interleaving
+ // plus the exception mechanics account for messiness of main
+ // loop.
+
+ try {
+ // Record exceptions so that if we fail to obtain any
+ // result, we can throw the last exception we got.
+ ExecutionException ee = null;
+ long lastTime = timed ? System.nanoTime() : 0;
+ Iterator<? extends Callable<T>> it = tasks.iterator();
+
+ // Start one task for sure; the rest incrementally
+ futures.add(ecs.submit(it.next()));
+ --ntasks;
+ int active = 1;
+
+ for (;;) {
+ Future<T> f = ecs.poll();
+ if (f == null) {
+ if (ntasks > 0) {
+ --ntasks;
+ futures.add(ecs.submit(it.next()));
+ ++active;
+ } else if (active == 0) {
+ break;
+ } else if (timed) {
+ f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
+ if (f == null) {
+ throw new TimeoutException();
+ }
+ long now = System.nanoTime();
+ nanos -= now - lastTime;
+ lastTime = now;
+ } else {
+ f = ecs.take();
+ }
+ }
+ if (f != null) {
+ --active;
+ try {
+ return f.get();
+ } catch (ExecutionException eex) {
+ ee = eex;
+ } catch (RuntimeException rex) {
+ ee = new ExecutionException(rex);
+ }
+ }
+ }
+
+ if (ee == null) {
+ ee = new ExecutionException(null);
+ }
+ throw ee;
+ } finally {
+ for (Future<T> f : futures) {
+ f.cancel(true);
+ }
+ }
+ }
+
@Override public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
- return invokeAnyImpl(this, tasks, false, 0);
+ return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) {
throw new AssertionError();
}
@@ -74,7 +141,7 @@ public abstract class AbstractListeningExecutorService implements ListeningExecu
@Override public <T> T invokeAny(
Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
- return invokeAnyImpl(this, tasks, true, unit.toNanos(timeout));
+ return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
@Override public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
diff --git a/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
index 949f76a..f847205 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
@@ -21,11 +21,9 @@ import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import java.util.concurrent.Callable;
-import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
@@ -98,8 +96,9 @@ public abstract class AbstractScheduledService implements Service {
*
* <p>Consider using the {@link #newFixedDelaySchedule} and {@link #newFixedRateSchedule} factory
* methods, these provide {@link Scheduler} instances for the common use case of running the
- * service with a fixed schedule. If more flexibility is needed then consider subclassing
- * {@link CustomScheduler}.
+ * service with a fixed schedule. If more flexibility is needed then consider subclassing the
+ * {@link CustomScheduler} abstract class in preference to creating your own {@link Scheduler}
+ * implementation.
*
* @author Luke Sandberg
* @since 11.0
@@ -230,9 +229,6 @@ public abstract class AbstractScheduledService implements Service {
}
};
- /** Constructor for use by subclasses. */
- protected AbstractScheduledService() {}
-
/**
* Run one iteration of the scheduled task. If any invocation of this method throws an exception,
* the service will transition to the {@link Service.State#FAILED} state and this method will no
@@ -240,19 +236,11 @@ public abstract class AbstractScheduledService implements Service {
*/
protected abstract void runOneIteration() throws Exception;
- /**
- * Start the service.
- *
- * <p>By default this method does nothing.
- */
- protected void startUp() throws Exception {}
+ /** Start the service. */
+ protected abstract void startUp() throws Exception;
- /**
- * Stop the service. This is guaranteed not to run concurrently with {@link #runOneIteration}.
- *
- * <p>By default this method does nothing.
- */
- protected void shutDown() throws Exception {}
+ /** Stop the service. This is guaranteed not to run concurrently with {@link #runOneIteration}. */
+ protected abstract void shutDown() throws Exception;
/**
* Returns the {@link Scheduler} object used to configure this service. This method will only be
@@ -262,56 +250,19 @@ public abstract class AbstractScheduledService implements Service {
/**
* Returns the {@link ScheduledExecutorService} that will be used to execute the {@link #startUp},
- * {@link #runOneIteration} and {@link #shutDown} methods. If this method is overridden the
- * executor will not be {@linkplain ScheduledExecutorService#shutdown shutdown} when this
- * service {@linkplain Service.State#TERMINATED terminates} or
- * {@linkplain Service.State#TERMINATED fails}. Subclasses may override this method to supply a
- * custom {@link ScheduledExecutorService} instance. This method is guaranteed to only be called
- * once.
+ * {@link #runOneIteration} and {@link #shutDown} methods. The executor will not be
+ * {@link ScheduledExecutorService#shutdown} when this service stops. Subclasses may override this
+ * method to use a custom {@link ScheduledExecutorService} instance.
*
* <p>By default this returns a new {@link ScheduledExecutorService} with a single thread thread
- * pool that sets the name of the thread to the {@linkplain #serviceName() service name}.
- * Also, the pool will be {@linkplain ScheduledExecutorService#shutdown() shut down} when the
- * service {@linkplain Service.State#TERMINATED terminates} or
- * {@linkplain Service.State#TERMINATED fails}.
+ * pool. This method will only be called once.
*/
protected ScheduledExecutorService executor() {
- final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(
- new ThreadFactory() {
- @Override public Thread newThread(Runnable runnable) {
- return MoreExecutors.newThread(serviceName(), runnable);
- }
- });
- // Add a listener to shutdown the executor after the service is stopped. This ensures that the
- // JVM shutdown will not be prevented from exiting after this service has stopped or failed.
- // Technically this listener is added after start() was called so it is a little gross, but it
- // is called within doStart() so we know that the service cannot terminate or fail concurrently
- // with adding this listener so it is impossible to miss an event that we are interested in.
- addListener(new Listener() {
- @Override public void starting() {}
- @Override public void running() {}
- @Override public void stopping(State from) {}
- @Override public void terminated(State from) {
- executor.shutdown();
- }
- @Override public void failed(State from, Throwable failure) {
- executor.shutdown();
- }}, MoreExecutors.sameThreadExecutor());
- return executor;
+ return Executors.newSingleThreadScheduledExecutor();
}
- /**
- * Returns the name of this service. {@link AbstractScheduledService} may include the name in
- * debugging output.
- *
- * @since 14.0
- */
- protected String serviceName() {
- return getClass().getSimpleName();
- }
-
@Override public String toString() {
- return serviceName() + " [" + state() + "]";
+ return getClass().getSimpleName() + " [" + state() + "]";
}
// We override instead of using ForwardingService so that these can be final.
@@ -341,20 +292,6 @@ public abstract class AbstractScheduledService implements Service {
}
/**
- * @since 13.0
- */
- @Override public final void addListener(Listener listener, Executor executor) {
- delegate.addListener(listener, executor);
- }
-
- /**
- * @since 14.0
- */
- @Override public final Throwable failureCause() {
- return delegate.failureCause();
- }
-
- /**
* A {@link Scheduler} that provides a convenient way for the {@link AbstractScheduledService} to
* use a dynamically changing schedule. After every execution of the task, assuming it hasn't
* been cancelled, the {@link #getNextSchedule} method will be called.
diff --git a/guava/src/com/google/common/util/concurrent/AbstractService.java b/guava/src/com/google/common/util/concurrent/AbstractService.java
index f028a59..f84b374 100644
--- a/guava/src/com/google/common/util/concurrent/AbstractService.java
+++ b/guava/src/com/google/common/util/concurrent/AbstractService.java
@@ -16,148 +16,68 @@
package com.google.common.util.concurrent;
-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.collect.Lists;
-import com.google.common.collect.Queues;
import com.google.common.util.concurrent.Service.State; // javadoc needs this
-import java.util.List;
-import java.util.Queue;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.GuardedBy;
-import javax.annotation.concurrent.Immutable;
/**
- * Base class for implementing services that can handle {@link #doStart} and {@link #doStop}
- * requests, responding to them with {@link #notifyStarted()} and {@link #notifyStopped()}
- * callbacks. Its subclasses must manage threads manually; consider
- * {@link AbstractExecutionThreadService} if you need only a single execution thread.
+ * Base class for implementing services that can handle {@link #doStart} and
+ * {@link #doStop} requests, responding to them with {@link #notifyStarted()}
+ * and {@link #notifyStopped()} callbacks. Its subclasses must manage threads
+ * manually; consider {@link AbstractExecutionThreadService} if you need only a
+ * single execution thread.
*
* @author Jesse Wilson
- * @author Luke Sandberg
* @since 1.0
*/
@Beta
public abstract class AbstractService implements Service {
- private static final Logger logger = Logger.getLogger(AbstractService.class.getName());
+
private final ReentrantLock lock = new ReentrantLock();
private final Transition startup = new Transition();
private final Transition shutdown = new Transition();
/**
- * The listeners to notify during a state transition.
- */
- @GuardedBy("lock")
- private final List<ListenerExecutorPair> listeners = Lists.newArrayList();
-
- /**
- * The queue of listeners that are waiting to be executed.
- *
- * <p>Enqueue operations should be protected by {@link #lock} while dequeue operations should be
- * protected by the implicit lock on this object. Dequeue operations should be executed atomically
- * with the execution of the {@link Runnable} and additionally the {@link #lock} should not be
- * held when the listeners are being executed. Use {@link #executeListeners} for this operation.
- * This is necessary to ensure that elements on the queue are executed in the correct order.
- * Enqueue operations should be protected so that listeners are added in the correct order. We use
- * a concurrent queue implementation so that enqueues can be executed concurrently with dequeues.
+ * The internal state, which equals external state unless
+ * shutdownWhenStartupFinishes is true. Guarded by {@code lock}.
*/
- @GuardedBy("queuedListeners")
- private final Queue<Runnable> queuedListeners = Queues.newConcurrentLinkedQueue();
-
+ private State state = State.NEW;
+
/**
- * The current state of the service. This should be written with the lock held but can be read
- * without it because it is an immutable object in a volatile field. This is desirable so that
- * methods like {@link #state}, {@link #failureCause} and notably {@link #toString} can be run
- * without grabbing the lock.
- *
- * <p>To update this field correctly the lock must be held to guarantee that the state is
- * consistent.
+ * If true, the user requested a shutdown while the service was still starting
+ * up. Guarded by {@code lock}.
*/
- @GuardedBy("lock")
- private volatile StateSnapshot snapshot = new StateSnapshot(State.NEW);
+ private boolean shutdownWhenStartupFinishes = false;
- /** Constructor for use by subclasses. */
- protected AbstractService() {
- // Add a listener to update the futures. This needs to be added first so that it is executed
- // before the other listeners. This way the other listeners can access the completed futures.
- addListener(
- new Listener() {
- @Override public void starting() {}
-
- @Override public void running() {
- startup.set(State.RUNNING);
- }
-
- @Override public void stopping(State from) {
- if (from == State.STARTING) {
- startup.set(State.STOPPING);
- }
- }
-
- @Override public void terminated(State from) {
- if (from == State.NEW) {
- startup.set(State.TERMINATED);
- }
- shutdown.set(State.TERMINATED);
- }
-
- @Override public void failed(State from, Throwable failure) {
- switch (from) {
- case STARTING:
- startup.setException(failure);
- shutdown.setException(new Exception("Service failed to start.", failure));
- break;
- case RUNNING:
- shutdown.setException(new Exception("Service failed while running", failure));
- break;
- case STOPPING:
- shutdown.setException(failure);
- break;
- case TERMINATED: /* fall-through */
- case FAILED: /* fall-through */
- case NEW: /* fall-through */
- default:
- throw new AssertionError("Unexpected from state: " + from);
- }
- }
- },
- MoreExecutors.sameThreadExecutor());
- }
-
/**
- * This method is called by {@link #start} to initiate service startup. The invocation of this
- * method should cause a call to {@link #notifyStarted()}, either during this method's run, or
- * after it has returned. If startup fails, the invocation should cause a call to
- * {@link #notifyFailed(Throwable)} instead.
+ * This method is called by {@link #start} to initiate service startup. The
+ * invocation of this method should cause a call to {@link #notifyStarted()},
+ * either during this method's run, or after it has returned. If startup
+ * fails, the invocation should cause a call to {@link
+ * #notifyFailed(Throwable)} instead.
*
- * <p>This method should return promptly; prefer to do work on a different thread where it is
- * convenient. It is invoked exactly once on service startup, even when {@link #start} is called
- * multiple times.
+ * <p>This method should return promptly; prefer to do work on a different
+ * thread where it is convenient. It is invoked exactly once on service
+ * startup, even when {@link #start} is called multiple times.
*/
protected abstract void doStart();
/**
- * This method should be used to initiate service shutdown. The invocation of this method should
- * cause a call to {@link #notifyStopped()}, either during this method's run, or after it has
- * returned. If shutdown fails, the invocation should cause a call to
- * {@link #notifyFailed(Throwable)} instead.
+ * This method should be used to initiate service shutdown. The invocation
+ * of this method should cause a call to {@link #notifyStopped()}, either
+ * during this method's run, or after it has returned. If shutdown fails, the
+ * invocation should cause a call to {@link #notifyFailed(Throwable)} instead.
*
- * <p> This method should return promptly; prefer to do work on a different thread where it is
- * convenient. It is invoked exactly once on service shutdown, even when {@link #stop} is called
- * multiple times.
+ * <p>This method should return promptly; prefer to do work on a different
+ * thread where it is convenient. It is invoked exactly once on service
+ * shutdown, even when {@link #stop} is called multiple times.
*/
protected abstract void doStop();
@@ -165,16 +85,15 @@ public abstract class AbstractService implements Service {
public final ListenableFuture<State> start() {
lock.lock();
try {
- if (snapshot.state == State.NEW) {
- snapshot = new StateSnapshot(State.STARTING);
- starting();
+ if (state == State.NEW) {
+ state = State.STARTING;
doStart();
}
} catch (Throwable startupFailure) {
+ // put the exception in the future, the user can get it via Future.get()
notifyFailed(startupFailure);
} finally {
lock.unlock();
- executeListeners();
}
return startup;
@@ -184,33 +103,22 @@ public abstract class AbstractService implements Service {
public final ListenableFuture<State> stop() {
lock.lock();
try {
- switch (snapshot.state) {
- case NEW:
- snapshot = new StateSnapshot(State.TERMINATED);
- terminated(State.NEW);
- break;
- case STARTING:
- snapshot = new StateSnapshot(State.STARTING, true, null);
- stopping(State.STARTING);
- break;
- case RUNNING:
- snapshot = new StateSnapshot(State.STOPPING);
- stopping(State.RUNNING);
- doStop();
- break;
- case STOPPING:
- case TERMINATED:
- case FAILED:
- // do nothing
- break;
- default:
- throw new AssertionError("Unexpected state: " + snapshot.state);
+ if (state == State.NEW) {
+ state = State.TERMINATED;
+ startup.set(State.TERMINATED);
+ shutdown.set(State.TERMINATED);
+ } else if (state == State.STARTING) {
+ shutdownWhenStartupFinishes = true;
+ startup.set(State.STOPPING);
+ } else if (state == State.RUNNING) {
+ state = State.STOPPING;
+ doStop();
}
} catch (Throwable shutdownFailure) {
+ // put the exception in the future, the user can get it via Future.get()
notifyFailed(shutdownFailure);
} finally {
lock.unlock();
- executeListeners();
}
return shutdown;
@@ -227,91 +135,84 @@ public abstract class AbstractService implements Service {
}
/**
- * Implementing classes should invoke this method once their service has started. It will cause
- * the service to transition from {@link State#STARTING} to {@link State#RUNNING}.
+ * Implementing classes should invoke this method once their service has
+ * started. It will cause the service to transition from {@link
+ * State#STARTING} to {@link State#RUNNING}.
*
- * @throws IllegalStateException if the service is not {@link State#STARTING}.
+ * @throws IllegalStateException if the service is not
+ * {@link State#STARTING}.
*/
protected final void notifyStarted() {
lock.lock();
try {
- if (snapshot.state != State.STARTING) {
+ if (state != State.STARTING) {
IllegalStateException failure = new IllegalStateException(
- "Cannot notifyStarted() when the service is " + snapshot.state);
+ "Cannot notifyStarted() when the service is " + state);
notifyFailed(failure);
throw failure;
}
- if (snapshot.shutdownWhenStartupFinishes) {
- snapshot = new StateSnapshot(State.STOPPING);
- // We don't call listeners here because we already did that when we set the
- // shutdownWhenStartupFinishes flag.
- doStop();
+ state = State.RUNNING;
+ if (shutdownWhenStartupFinishes) {
+ stop();
} else {
- snapshot = new StateSnapshot(State.RUNNING);
- running();
+ startup.set(State.RUNNING);
}
} finally {
lock.unlock();
- executeListeners();
}
}
/**
- * Implementing classes should invoke this method once their service has stopped. It will cause
- * the service to transition from {@link State#STOPPING} to {@link State#TERMINATED}.
+ * Implementing classes should invoke this method once their service has
+ * stopped. It will cause the service to transition from {@link
+ * State#STOPPING} to {@link State#TERMINATED}.
*
- * @throws IllegalStateException if the service is neither {@link State#STOPPING} nor
- * {@link State#RUNNING}.
+ * @throws IllegalStateException if the service is neither {@link
+ * State#STOPPING} nor {@link State#RUNNING}.
*/
protected final void notifyStopped() {
lock.lock();
try {
- if (snapshot.state != State.STOPPING && snapshot.state != State.RUNNING) {
+ if (state != State.STOPPING && state != State.RUNNING) {
IllegalStateException failure = new IllegalStateException(
- "Cannot notifyStopped() when the service is " + snapshot.state);
+ "Cannot notifyStopped() when the service is " + state);
notifyFailed(failure);
throw failure;
}
- State previous = snapshot.state;
- snapshot = new StateSnapshot(State.TERMINATED);
- terminated(previous);
+
+ state = State.TERMINATED;
+ shutdown.set(State.TERMINATED);
} finally {
lock.unlock();
- executeListeners();
}
}
/**
- * Invoke this method to transition the service to the {@link State#FAILED}. The service will
- * <b>not be stopped</b> if it is running. Invoke this method when a service has failed critically
- * or otherwise cannot be started nor stopped.
+ * Invoke this method to transition the service to the
+ * {@link State#FAILED}. The service will <b>not be stopped</b> if it
+ * is running. Invoke this method when a service has failed critically or
+ * otherwise cannot be started nor stopped.
*/
protected final void notifyFailed(Throwable cause) {
checkNotNull(cause);
lock.lock();
try {
- switch (snapshot.state) {
- case NEW:
- case TERMINATED:
- throw new IllegalStateException("Failed while in state:" + snapshot.state, cause);
- case RUNNING:
- case STARTING:
- case STOPPING:
- State previous = snapshot.state;
- snapshot = new StateSnapshot(State.FAILED, false, cause);
- failed(previous, cause);
- break;
- case FAILED:
- // Do nothing
- break;
- default:
- throw new AssertionError("Unexpected state: " + snapshot.state);
+ if (state == State.STARTING) {
+ startup.setException(cause);
+ shutdown.setException(new Exception(
+ "Service failed to start.", cause));
+ } else if (state == State.STOPPING) {
+ shutdown.setException(cause);
+ } else if (state == State.RUNNING) {
+ shutdown.setException(new Exception("Service failed while running", cause));
+ } else if (state == State.NEW || state == State.TERMINATED) {
+ throw new IllegalStateException("Failed while in state:" + state, cause);
}
+ state = State.FAILED;
} finally {
lock.unlock();
- executeListeners();
}
}
@@ -322,28 +223,12 @@ public abstract class AbstractService implements Service {
@Override
public final State state() {
- return snapshot.externalState();
- }
-
- /**
- * @since 14.0
- */
- @Override
- public final Throwable failureCause() {
- return snapshot.failureCause();
- }
-
- /**
- * @since 13.0
- */
- @Override
- public final void addListener(Listener listener, Executor executor) {
- checkNotNull(listener, "listener");
- checkNotNull(executor, "executor");
lock.lock();
try {
- if (snapshot.state != State.TERMINATED && snapshot.state != State.FAILED) {
- listeners.add(new ListenerExecutorPair(listener, executor));
+ if (shutdownWhenStartupFinishes && state == State.STARTING) {
+ return State.STOPPING;
+ } else {
+ return state;
}
} finally {
lock.unlock();
@@ -368,182 +253,4 @@ public abstract class AbstractService implements Service {
}
}
}
-
- /**
- * Attempts to execute all the listeners in {@link #queuedListeners} while not holding the
- * {@link #lock}.
- */
- private void executeListeners() {
- if (!lock.isHeldByCurrentThread()) {
- synchronized (queuedListeners) {
- Runnable listener;
- while ((listener = queuedListeners.poll()) != null) {
- listener.run();
- }
- }
- }
- }
-
- @GuardedBy("lock")
- private void starting() {
- for (final ListenerExecutorPair pair : listeners) {
- queuedListeners.add(new Runnable() {
- @Override public void run() {
- pair.execute(new Runnable() {
- @Override public void run() {
- pair.listener.starting();
- }
- });
- }
- });
- }
- }
-
- @GuardedBy("lock")
- private void running() {
- for (final ListenerExecutorPair pair : listeners) {
- queuedListeners.add(new Runnable() {
- @Override public void run() {
- pair.execute(new Runnable() {
- @Override public void run() {
- pair.listener.running();
- }
- });
- }
- });
- }
- }
-
- @GuardedBy("lock")
- private void stopping(final State from) {
- for (final ListenerExecutorPair pair : listeners) {
- queuedListeners.add(new Runnable() {
- @Override public void run() {
- pair.execute(new Runnable() {
- @Override public void run() {
- pair.listener.stopping(from);
- }
- });
- }
- });
- }
- }
-
- @GuardedBy("lock")
- private void terminated(final State from) {
- for (final ListenerExecutorPair pair : listeners) {
- queuedListeners.add(new Runnable() {
- @Override public void run() {
- pair.execute(new Runnable() {
- @Override public void run() {
- pair.listener.terminated(from);
- }
- });
- }
- });
- }
- // There are no more state transitions so we can clear this out.
- listeners.clear();
- }
-
- @GuardedBy("lock")
- private void failed(final State from, final Throwable cause) {
- for (final ListenerExecutorPair pair : listeners) {
- queuedListeners.add(new Runnable() {
- @Override public void run() {
- pair.execute(new Runnable() {
- @Override public void run() {
- pair.listener.failed(from, cause);
- }
- });
- }
- });
- }
- // There are no more state transitions so we can clear this out.
- listeners.clear();
- }
-
- /** A simple holder for a listener and its executor. */
- private static class ListenerExecutorPair {
- final Listener listener;
- final Executor executor;
-
- ListenerExecutorPair(Listener listener, Executor executor) {
- this.listener = listener;
- this.executor = executor;
- }
-
- /**
- * Executes the given {@link Runnable} on {@link #executor} logging and swallowing all
- * exceptions
- */
- void execute(Runnable runnable) {
- try {
- executor.execute(runnable);
- } catch (Exception e) {
- logger.log(Level.SEVERE, "Exception while executing listener " + listener
- + " with executor " + executor, e);
- }
- }
- }
-
- /**
- * An immutable snapshot of the current state of the service. This class represents a consistent
- * snapshot of the state and therefore it can be used to answer simple queries without needing to
- * grab a lock.
- */
- @Immutable
- private static final class StateSnapshot {
- /**
- * The internal state, which equals external state unless
- * shutdownWhenStartupFinishes is true.
- */
- final State state;
-
- /**
- * If true, the user requested a shutdown while the service was still starting
- * up.
- */
- final boolean shutdownWhenStartupFinishes;
-
- /**
- * The exception that caused this service to fail. This will be {@code null}
- * unless the service has failed.
- */
- @Nullable
- final Throwable failure;
-
- StateSnapshot(State internalState) {
- this(internalState, false, null);
- }
-
- StateSnapshot(
- State internalState, boolean shutdownWhenStartupFinishes, @Nullable Throwable failure) {
- checkArgument(!shutdownWhenStartupFinishes || internalState == State.STARTING,
- "shudownWhenStartupFinishes can only be set if state is STARTING. Got %s instead.",
- internalState);
- checkArgument(!(failure != null ^ internalState == State.FAILED),
- "A failure cause should be set if and only if the state is failed. Got %s and %s "
- + "instead.", internalState, failure);
- this.state = internalState;
- this.shutdownWhenStartupFinishes = shutdownWhenStartupFinishes;
- this.failure = failure;
- }
-
- /** @see Service#state() */
- State externalState() {
- if (shutdownWhenStartupFinishes && state == State.STARTING) {
- return State.STOPPING;
- } else {
- return state;
- }
- }
-
- /** @see Service#failureCause() */
- Throwable failureCause() {
- checkState(state == State.FAILED,
- "failureCause() is only valid if the service has failed, service is %s", state);
- return failure;
- }
- }
}
diff --git a/guava/src/com/google/common/util/concurrent/AsyncFunction.java b/guava/src/com/google/common/util/concurrent/AsyncFunction.java
index cdb1228..441c029 100644
--- a/guava/src/com/google/common/util/concurrent/AsyncFunction.java
+++ b/guava/src/com/google/common/util/concurrent/AsyncFunction.java
@@ -16,6 +16,8 @@
package com.google.common.util.concurrent;
+import com.google.common.annotations.Beta;
+
import java.util.concurrent.Future;
/**
@@ -25,6 +27,7 @@ import java.util.concurrent.Future;
* @author Chris Povirk
* @since 11.0
*/
+@Beta
public interface AsyncFunction<I, O> {
/**
* Returns an output {@code Future} to use in place of the given {@code
diff --git a/guava/src/com/google/common/util/concurrent/AtomicDouble.java b/guava/src/com/google/common/util/concurrent/AtomicDouble.java
index d007f45..0f38fb9 100644
--- a/guava/src/com/google/common/util/concurrent/AtomicDouble.java
+++ b/guava/src/com/google/common/util/concurrent/AtomicDouble.java
@@ -14,9 +14,10 @@
package com.google.common.util.concurrent;
+import com.google.common.annotations.Beta;
+
import static java.lang.Double.doubleToRawLongBits;
import static java.lang.Double.longBitsToDouble;
-
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
/**
@@ -42,16 +43,17 @@ import java.util.concurrent.atomic.AtomicLongFieldUpdater;
*
* <p>It is possible to write a more scalable updater, at the cost of
* giving up strict atomicity. See for example
- * <a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166edocs/jsr166e/DoubleAdder.html">
- * DoubleAdder</a>
+ * <a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166edocs/jsr166e/DoubleAdder.html"
+ * DoubleAdder>
* and
- * <a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166edocs/jsr166e/DoubleMaxUpdater.html">
- * DoubleMaxUpdater</a>.
+ * <a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166edocs/jsr166e/DoubleMaxUpdater.html"
+ * DoubleMaxUpdater>.
*
* @author Doug Lea
* @author Martin Buchholz
* @since 11.0
*/
+@Beta
public class AtomicDouble extends Number implements java.io.Serializable {
private static final long serialVersionUID = 0L;
diff --git a/guava/src/com/google/common/util/concurrent/AtomicDoubleArray.java b/guava/src/com/google/common/util/concurrent/AtomicDoubleArray.java
index 407cd7c..37f4c5c 100644
--- a/guava/src/com/google/common/util/concurrent/AtomicDoubleArray.java
+++ b/guava/src/com/google/common/util/concurrent/AtomicDoubleArray.java
@@ -13,9 +13,10 @@
package com.google.common.util.concurrent;
+import com.google.common.annotations.Beta;
+
import static java.lang.Double.doubleToRawLongBits;
import static java.lang.Double.longBitsToDouble;
-
import java.util.concurrent.atomic.AtomicLongArray;
/**
@@ -39,6 +40,7 @@ import java.util.concurrent.atomic.AtomicLongArray;
* @author Martin Buchholz
* @since 11.0
*/
+@Beta
public class AtomicDoubleArray implements java.io.Serializable {
private static final long serialVersionUID = 0L;
diff --git a/guava/src/com/google/common/util/concurrent/AtomicLongMap.java b/guava/src/com/google/common/util/concurrent/AtomicLongMap.java
index d0af965..c49f84c 100644
--- a/guava/src/com/google/common/util/concurrent/AtomicLongMap.java
+++ b/guava/src/com/google/common/util/concurrent/AtomicLongMap.java
@@ -1,24 +1,10 @@
-/*
- * 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.
- */
+// Copyright 2011 Google Inc. All Rights Reserved.
package com.google.common.util.concurrent;
import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
@@ -50,7 +36,7 @@ import java.util.concurrent.atomic.AtomicLong;
* @author Charles Fry
* @since 11.0
*/
-@GwtCompatible
+@Beta
public final class AtomicLongMap<K> {
private final ConcurrentHashMap<K, AtomicLong> map;
diff --git a/guava/src/com/google/common/util/concurrent/Atomics.java b/guava/src/com/google/common/util/concurrent/Atomics.java
index efb7946..fece83d 100644
--- a/guava/src/com/google/common/util/concurrent/Atomics.java
+++ b/guava/src/com/google/common/util/concurrent/Atomics.java
@@ -16,6 +16,8 @@
package com.google.common.util.concurrent;
+import com.google.common.annotations.Beta;
+
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;
@@ -28,6 +30,7 @@ import javax.annotation.Nullable;
* @author Kurt Alfred Kluever
* @since 10.0
*/
+@Beta
public final class Atomics {
private Atomics() {}
diff --git a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java
deleted file mode 100644
index 528fc8e..0000000
--- a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java
+++ /dev/null
@@ -1,1038 +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.util.concurrent;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.collect.MapMaker;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.ThreadSafe;
-
-/**
- * The {@code CycleDetectingLockFactory} creates {@link ReentrantLock} instances and
- * {@link ReentrantReadWriteLock} instances that detect potential deadlock by checking
- * for cycles in lock acquisition order.
- * <p>
- * Potential deadlocks detected when calling the {@code lock()},
- * {@code lockInterruptibly()}, or {@code tryLock()} methods will result in the
- * execution of the {@link Policy} specified when creating the factory. The
- * currently available policies are:
- * <ul>
- * <li>DISABLED
- * <li>WARN
- * <li>THROW
- * </ul>
- * The locks created by a factory instance will detect lock acquisition cycles
- * with locks created by other {@code CycleDetectingLockFactory} instances
- * (except those with {@code Policy.DISABLED}). A lock's behavior when a cycle
- * is detected, however, is defined by the {@code Policy} of the factory that
- * created it. This allows detection of cycles across components while
- * delegating control over lock behavior to individual components.
- * <p>
- * Applications are encouraged to use a {@code CycleDetectingLockFactory} to
- * create any locks for which external/unmanaged code is executed while the lock
- * is held. (See caveats under <strong>Performance</strong>).
- * <p>
- * <strong>Cycle Detection</strong>
- * <p>
- * Deadlocks can arise when locks are acquired in an order that forms a cycle.
- * In a simple example involving two locks and two threads, deadlock occurs
- * when one thread acquires Lock A, and then Lock B, while another thread
- * acquires Lock B, and then Lock A:
- * <pre>
- * Thread1: acquire(LockA) --X acquire(LockB)
- * Thread2: acquire(LockB) --X acquire(LockA)
- * </pre>
- * Neither thread will progress because each is waiting for the other. In more
- * complex applications, cycles can arise from interactions among more than 2
- * locks:
- * <pre>
- * Thread1: acquire(LockA) --X acquire(LockB)
- * Thread2: acquire(LockB) --X acquire(LockC)
- * ...
- * ThreadN: acquire(LockN) --X acquire(LockA)
- * </pre>
- * The implementation detects cycles by constructing a directed graph in which
- * each lock represents a node and each edge represents an acquisition ordering
- * between two locks.
- * <ul>
- * <li>Each lock adds (and removes) itself to/from a ThreadLocal Set of acquired
- * locks when the Thread acquires its first hold (and releases its last
- * remaining hold).
- * <li>Before the lock is acquired, the lock is checked against the current set
- * of acquired locks---to each of the acquired locks, an edge from the
- * soon-to-be-acquired lock is either verified or created.
- * <li>If a new edge needs to be created, the outgoing edges of the acquired
- * locks are traversed to check for a cycle that reaches the lock to be
- * acquired. If no cycle is detected, a new "safe" edge is created.
- * <li>If a cycle is detected, an "unsafe" (cyclic) edge is created to represent
- * a potential deadlock situation, and the appropriate Policy is executed.
- * </ul>
- * Note that detection of potential deadlock does not necessarily indicate that
- * deadlock will happen, as it is possible that higher level application logic
- * prevents the cyclic lock acquisition from occurring. One example of a false
- * positive is:
- * <pre>
- * LockA -&gt; LockB -&gt; LockC
- * LockA -&gt; LockC -&gt; LockB
- * </pre>
- *
- * <strong>ReadWriteLocks</strong>
- * <p>
- * While {@code ReadWriteLock} instances have different properties and can form cycles
- * without potential deadlock, this class treats {@code ReadWriteLock} instances as
- * equivalent to traditional exclusive locks. Although this increases the false
- * positives that the locks detect (i.e. cycles that will not actually result in
- * deadlock), it simplifies the algorithm and implementation considerably. The
- * assumption is that a user of this factory wishes to eliminate any cyclic
- * acquisition ordering.
- * <p>
- * <strong>Explicit Lock Acquisition Ordering</strong>
- * <p>
- * The {@link CycleDetectingLockFactory.WithExplicitOrdering} class can be used
- * to enforce an application-specific ordering in addition to performing general
- * cycle detection.
- * <p>
- * <strong>Garbage Collection</strong>
- * <p>
- * In order to allow proper garbage collection of unused locks, the edges of
- * the lock graph are weak references.
- * <p>
- * <strong>Performance</strong>
- * <p>
- * The extra bookkeeping done by cycle detecting locks comes at some cost to
- * performance. Benchmarks (as of December 2011) show that:
- *
- * <ul>
- * <li>for an unnested {@code lock()} and {@code unlock()}, a cycle detecting
- * lock takes 38ns as opposed to the 24ns taken by a plain lock.
- * <li>for nested locking, the cost increases with the depth of the nesting:
- * <ul>
- * <li> 2 levels: average of 64ns per lock()/unlock()
- * <li> 3 levels: average of 77ns per lock()/unlock()
- * <li> 4 levels: average of 99ns per lock()/unlock()
- * <li> 5 levels: average of 103ns per lock()/unlock()
- * <li>10 levels: average of 184ns per lock()/unlock()
- * <li>20 levels: average of 393ns per lock()/unlock()
- * </ul>
- * </ul>
- *
- * As such, the CycleDetectingLockFactory may not be suitable for
- * performance-critical applications which involve tightly-looped or
- * deeply-nested locking algorithms.
- *
- * @author Darick Tong
- * @since 13.0
- */
-@Beta
-@ThreadSafe
-public class CycleDetectingLockFactory {
-
- /**
- * Encapsulates the action to be taken when a potential deadlock is
- * encountered. Clients can use one of the predefined {@link Policies} or
- * specify a custom implementation. Implementations must be thread-safe.
- *
- * @since 13.0
- */
- @Beta
- @ThreadSafe
- public interface Policy {
-
- /**
- * Called when a potential deadlock is encountered. Implementations can
- * throw the given {@code exception} and/or execute other desired logic.
- * <p>
- * Note that the method will be called even upon an invocation of
- * {@code tryLock()}. Although {@code tryLock()} technically recovers from
- * deadlock by eventually timing out, this behavior is chosen based on the
- * assumption that it is the application's wish to prohibit any cyclical
- * lock acquisitions.
- */
- void handlePotentialDeadlock(PotentialDeadlockException exception);
- }
-
- /**
- * Pre-defined {@link Policy} implementations.
- *
- * @since 13.0
- */
- @Beta
- public enum Policies implements Policy {
- /**
- * When potential deadlock is detected, this policy results in the throwing
- * of the {@code PotentialDeadlockException} indicating the potential
- * deadlock, which includes stack traces illustrating the cycle in lock
- * acquisition order.
- */
- THROW {
- @Override
- public void handlePotentialDeadlock(PotentialDeadlockException e) {
- throw e;
- }
- },
-
- /**
- * When potential deadlock is detected, this policy results in the logging
- * of a {@link Level#SEVERE} message indicating the potential deadlock,
- * which includes stack traces illustrating the cycle in lock acquisition
- * order.
- */
- WARN {
- @Override
- public void handlePotentialDeadlock(PotentialDeadlockException e) {
- logger.log(Level.SEVERE, "Detected potential deadlock", e);
- }
- },
-
- /**
- * Disables cycle detection. This option causes the factory to return
- * unmodified lock implementations provided by the JDK, and is provided to
- * allow applications to easily parameterize when cycle detection is
- * enabled.
- * <p>
- * Note that locks created by a factory with this policy will <em>not</em>
- * participate the cycle detection performed by locks created by other
- * factories.
- */
- DISABLED {
- @Override
- public void handlePotentialDeadlock(PotentialDeadlockException e) {
- }
- };
- }
-
- /**
- * Creates a new factory with the specified policy.
- */
- public static CycleDetectingLockFactory newInstance(Policy policy) {
- return new CycleDetectingLockFactory(policy);
- }
-
- /**
- * Equivalent to {@code newReentrantLock(lockName, false)}.
- */
- public ReentrantLock newReentrantLock(String lockName) {
- return newReentrantLock(lockName, false);
- }
-
- /**
- * Creates a {@link ReentrantLock} with the given fairness policy. The
- * {@code lockName} is used in the warning or exception output to help
- * identify the locks involved in the detected deadlock.
- */
- public ReentrantLock newReentrantLock(String lockName, boolean fair) {
- return policy == Policies.DISABLED ? new ReentrantLock(fair)
- : new CycleDetectingReentrantLock(
- new LockGraphNode(lockName), fair);
- }
-
- /**
- * Equivalent to {@code newReentrantReadWriteLock(lockName, false)}.
- */
- public ReentrantReadWriteLock newReentrantReadWriteLock(String lockName) {
- return newReentrantReadWriteLock(lockName, false);
- }
-
- /**
- * Creates a {@link ReentrantReadWriteLock} with the given fairness policy.
- * The {@code lockName} is used in the warning or exception output to help
- * identify the locks involved in the detected deadlock.
- */
- public ReentrantReadWriteLock newReentrantReadWriteLock(
- String lockName, boolean fair) {
- return policy == Policies.DISABLED ? new ReentrantReadWriteLock(fair)
- : new CycleDetectingReentrantReadWriteLock(
- new LockGraphNode(lockName), fair);
- }
-
- // A static mapping from an Enum type to its set of LockGraphNodes.
- private static final Map<Class<? extends Enum>,
- Map<? extends Enum, LockGraphNode>> lockGraphNodesPerType =
- new MapMaker().weakKeys().makeComputingMap(
- new OrderedLockGraphNodesCreator());
-
- /**
- * Creates a {@code CycleDetectingLockFactory.WithExplicitOrdering<E>}.
- */
- public static <E extends Enum<E>> WithExplicitOrdering<E>
- newInstanceWithExplicitOrdering(Class<E> enumClass, Policy policy) {
- // OrderedLockGraphNodesCreator maps each enumClass to a Map with the
- // corresponding enum key type.
- checkNotNull(enumClass);
- checkNotNull(policy);
- @SuppressWarnings("unchecked")
- Map<E, LockGraphNode> lockGraphNodes =
- (Map<E, LockGraphNode>) lockGraphNodesPerType.get(enumClass);
- return new WithExplicitOrdering<E>(policy, lockGraphNodes);
- }
-
- /**
- * A {@code CycleDetectingLockFactory.WithExplicitOrdering} provides the
- * additional enforcement of an application-specified ordering of lock
- * acquisitions. The application defines the allowed ordering with an
- * {@code Enum} whose values each correspond to a lock type. The order in
- * which the values are declared dictates the allowed order of lock
- * acquisition. In other words, locks corresponding to smaller values of
- * {@link Enum#ordinal()} should only be acquired before locks with larger
- * ordinals. Example:
- *
- * <pre> {@code
- * enum MyLockOrder {
- * FIRST, SECOND, THIRD;
- * }
- *
- * CycleDetectingLockFactory.WithExplicitOrdering<MyLockOrder> factory =
- * CycleDetectingLockFactory.newInstanceWithExplicitOrdering(Policies.THROW);
- *
- * Lock lock1 = factory.newReentrantLock(MyLockOrder.FIRST);
- * Lock lock2 = factory.newReentrantLock(MyLockOrder.SECOND);
- * Lock lock3 = factory.newReentrantLock(MyLockOrder.THIRD);
- *
- * lock1.lock();
- * lock3.lock();
- * lock2.lock(); // will throw an IllegalStateException
- * }</pre>
- *
- * As with all locks created by instances of {@code CycleDetectingLockFactory}
- * explicitly ordered locks participate in general cycle detection with all
- * other cycle detecting locks, and a lock's behavior when detecting a cyclic
- * lock acquisition is defined by the {@code Policy} of the factory that
- * created it.
- * <p>
- * Note, however, that although multiple locks can be created for a given Enum
- * value, whether it be through separate factory instances or through multiple
- * calls to the same factory, attempting to acquire multiple locks with the
- * same Enum value (within the same thread) will result in an
- * IllegalStateException regardless of the factory's policy. For example:
- *
- * <pre> {@code
- * CycleDetectingLockFactory.WithExplicitOrdering<MyLockOrder> factory1 =
- * CycleDetectingLockFactory.newInstanceWithExplicitOrdering(...);
- * CycleDetectingLockFactory.WithExplicitOrdering<MyLockOrder> factory2 =
- * CycleDetectingLockFactory.newInstanceWithExplicitOrdering(...);
- *
- * Lock lockA = factory1.newReentrantLock(MyLockOrder.FIRST);
- * Lock lockB = factory1.newReentrantLock(MyLockOrder.FIRST);
- * Lock lockC = factory2.newReentrantLock(MyLockOrder.FIRST);
- *
- * lockA.lock();
- *
- * lockB.lock(); // will throw an IllegalStateException
- * lockC.lock(); // will throw an IllegalStateException
- *
- * lockA.lock(); // reentrant acquisition is okay
- * }</pre>
- *
- * It is the responsibility of the application to ensure that multiple lock
- * instances with the same rank are never acquired in the same thread.
- *
- * @param <E> The Enum type representing the explicit lock ordering.
- * @since 13.0
- */
- @Beta
- public static final class WithExplicitOrdering<E extends Enum<E>>
- extends CycleDetectingLockFactory {
-
- private final Map<E, LockGraphNode> lockGraphNodes;
-
- @VisibleForTesting
- WithExplicitOrdering(
- Policy policy, Map<E, LockGraphNode> lockGraphNodes) {
- super(policy);
- this.lockGraphNodes = lockGraphNodes;
- }
-
- /**
- * Equivalent to {@code newReentrantLock(rank, false)}.
- */
- public ReentrantLock newReentrantLock(E rank) {
- return newReentrantLock(rank, false);
- }
-
- /**
- * Creates a {@link ReentrantLock} with the given fairness policy and rank.
- * The values returned by {@link Enum#getDeclaringClass()} and
- * {@link Enum#name()} are used to describe the lock in warning or
- * exception output.
- *
- * @throws IllegalStateException If the factory has already created a
- * {@code Lock} with the specified rank.
- */
- public ReentrantLock newReentrantLock(E rank, boolean fair) {
- return policy == Policies.DISABLED ? new ReentrantLock(fair)
- : new CycleDetectingReentrantLock(lockGraphNodes.get(rank), fair);
- }
-
- /**
- * Equivalent to {@code newReentrantReadWriteLock(rank, false)}.
- */
- public ReentrantReadWriteLock newReentrantReadWriteLock(E rank) {
- return newReentrantReadWriteLock(rank, false);
- }
-
- /**
- * Creates a {@link ReentrantReadWriteLock} with the given fairness policy
- * and rank. The values returned by {@link Enum#getDeclaringClass()} and
- * {@link Enum#name()} are used to describe the lock in warning or exception
- * output.
- *
- * @throws IllegalStateException If the factory has already created a
- * {@code Lock} with the specified rank.
- */
- public ReentrantReadWriteLock newReentrantReadWriteLock(
- E rank, boolean fair) {
- return policy == Policies.DISABLED ? new ReentrantReadWriteLock(fair)
- : new CycleDetectingReentrantReadWriteLock(
- lockGraphNodes.get(rank), fair);
- }
- }
-
- /**
- * For a given Enum type, creates an immutable map from each of the Enum's
- * values to a corresponding LockGraphNode, with the
- * {@code allowedPriorLocks} and {@code disallowedPriorLocks} prepopulated
- * with nodes according to the natural ordering of the associated Enum values.
- */
- @VisibleForTesting
- static class OrderedLockGraphNodesCreator
- implements Function<Class<? extends Enum>,
- Map<? extends Enum, LockGraphNode>> {
-
- @Override
- @SuppressWarnings("unchecked") // There's no way to properly express with
- // wildcards the recursive Enum type required by createNodesFor(), and the
- // Map/Function types must use wildcards since they accept any Enum class.
- public Map<? extends Enum, LockGraphNode> apply(
- Class<? extends Enum> clazz) {
- return createNodesFor(clazz);
- }
-
- <E extends Enum<E>> Map<E, LockGraphNode> createNodesFor(Class<E> clazz) {
- EnumMap<E, LockGraphNode> map = Maps.newEnumMap(clazz);
- E[] keys = clazz.getEnumConstants();
- final int numKeys = keys.length;
- ArrayList<LockGraphNode> nodes =
- Lists.newArrayListWithCapacity(numKeys);
- // Create a LockGraphNode for each enum value.
- for (E key : keys) {
- LockGraphNode node = new LockGraphNode(getLockName(key));
- nodes.add(node);
- map.put(key, node);
- }
- // Pre-populate all allowedPriorLocks with nodes of smaller ordinal.
- for (int i = 1; i < numKeys; i++) {
- nodes.get(i).checkAcquiredLocks(Policies.THROW, nodes.subList(0, i));
- }
- // Pre-populate all disallowedPriorLocks with nodes of larger ordinal.
- for (int i = 0; i < numKeys - 1; i++) {
- nodes.get(i).checkAcquiredLocks(
- Policies.DISABLED, nodes.subList(i + 1, numKeys));
- }
- return Collections.unmodifiableMap(map);
- }
-
- /**
- * For the given Enum value {@code rank}, returns the value's
- * {@code "EnumClass.name"}, which is used in exception and warning
- * output.
- */
- private String getLockName(Enum<?> rank) {
- return rank.getDeclaringClass().getSimpleName() + "." + rank.name();
- }
- }
-
- //////// Implementation /////////
-
- private static final Logger logger = Logger.getLogger(
- CycleDetectingLockFactory.class.getName());
-
- final Policy policy;
-
- private CycleDetectingLockFactory(Policy policy) {
- this.policy = checkNotNull(policy);
- }
-
- /**
- * Tracks the currently acquired locks for each Thread, kept up to date by
- * calls to {@link #aboutToAcquire(CycleDetectingLock)} and
- * {@link #lockStateChanged(CycleDetectingLock)}.
- */
- // This is logically a Set, but an ArrayList is used to minimize the amount
- // of allocation done on lock()/unlock().
- private static final ThreadLocal<ArrayList<LockGraphNode>>
- acquiredLocks = new ThreadLocal<ArrayList<LockGraphNode>>() {
- @Override
- protected ArrayList<LockGraphNode> initialValue() {
- return Lists.<LockGraphNode>newArrayListWithCapacity(3);
- }
- };
-
- /**
- * A Throwable used to record a stack trace that illustrates an example of
- * a specific lock acquisition ordering. The top of the stack trace is
- * truncated such that it starts with the acquisition of the lock in
- * question, e.g.
- *
- * <pre>
- * com...ExampleStackTrace: LockB -&gt; LockC
- * at com...CycleDetectingReentrantLock.lock(CycleDetectingLockFactory.java:443)
- * at ...
- * at ...
- * at com...MyClass.someMethodThatAcquiresLockB(MyClass.java:123)
- * </pre>
- */
- private static class ExampleStackTrace extends IllegalStateException {
-
- static final StackTraceElement[] EMPTY_STACK_TRACE =
- new StackTraceElement[0];
-
- static Set<String> EXCLUDED_CLASS_NAMES = ImmutableSet.of(
- CycleDetectingLockFactory.class.getName(),
- ExampleStackTrace.class.getName(),
- LockGraphNode.class.getName());
-
- ExampleStackTrace(LockGraphNode node1, LockGraphNode node2) {
- super(node1.getLockName() + " -> " + node2.getLockName());
- StackTraceElement[] origStackTrace = getStackTrace();
- for (int i = 0, n = origStackTrace.length; i < n; i++) {
- if (WithExplicitOrdering.class.getName().equals(
- origStackTrace[i].getClassName())) {
- // For pre-populated disallowedPriorLocks edges, omit the stack trace.
- setStackTrace(EMPTY_STACK_TRACE);
- break;
- }
- if (!EXCLUDED_CLASS_NAMES.contains(origStackTrace[i].getClassName())) {
- setStackTrace(Arrays.copyOfRange(origStackTrace, i, n));
- break;
- }
- }
- }
- }
-
- /**
- * Represents a detected cycle in lock acquisition ordering. The exception
- * includes a causal chain of {@code ExampleStackTrace} instances to illustrate the
- * cycle, e.g.
- *
- * <pre>
- * com....PotentialDeadlockException: Potential Deadlock from LockC -&gt; ReadWriteA
- * at ...
- * at ...
- * Caused by: com...ExampleStackTrace: LockB -&gt; LockC
- * at ...
- * at ...
- * Caused by: com...ExampleStackTrace: ReadWriteA -&gt; LockB
- * at ...
- * at ...
- * </pre>
- *
- * Instances are logged for the {@code Policies.WARN}, and thrown for
- * {@code Policies.THROW}.
- *
- * @since 13.0
- */
- @Beta
- public static final class PotentialDeadlockException
- extends ExampleStackTrace {
-
- private final ExampleStackTrace conflictingStackTrace;
-
- private PotentialDeadlockException(
- LockGraphNode node1,
- LockGraphNode node2,
- ExampleStackTrace conflictingStackTrace) {
- super(node1, node2);
- this.conflictingStackTrace = conflictingStackTrace;
- initCause(conflictingStackTrace);
- }
-
- public ExampleStackTrace getConflictingStackTrace() {
- return conflictingStackTrace;
- }
-
- /**
- * Appends the chain of messages from the {@code conflictingStackTrace} to
- * the original {@code message}.
- */
- @Override
- public String getMessage() {
- StringBuilder message = new StringBuilder(super.getMessage());
- for (Throwable t = conflictingStackTrace; t != null; t = t.getCause()) {
- message.append(", ").append(t.getMessage());
- }
- return message.toString();
- }
- }
-
- /**
- * Internal Lock implementations implement the {@code CycleDetectingLock}
- * interface, allowing the detection logic to treat all locks in the same
- * manner.
- */
- private interface CycleDetectingLock {
-
- /** @return the {@link LockGraphNode} associated with this lock. */
- LockGraphNode getLockGraphNode();
-
- /** @return {@code true} if the current thread has acquired this lock. */
- boolean isAcquiredByCurrentThread();
- }
-
- /**
- * A {@code LockGraphNode} associated with each lock instance keeps track of
- * the directed edges in the lock acquisition graph.
- */
- private static class LockGraphNode {
-
- /**
- * The map tracking the locks that are known to be acquired before this
- * lock, each associated with an example stack trace. Locks are weakly keyed
- * to allow proper garbage collection when they are no longer referenced.
- */
- final Map<LockGraphNode, ExampleStackTrace> allowedPriorLocks =
- new MapMaker().weakKeys().makeMap();
-
- /**
- * The map tracking lock nodes that can cause a lock acquisition cycle if
- * acquired before this node.
- */
- final Map<LockGraphNode, PotentialDeadlockException>
- disallowedPriorLocks = new MapMaker().weakKeys().makeMap();
-
- final String lockName;
-
- LockGraphNode(String lockName) {
- this.lockName = Preconditions.checkNotNull(lockName);
- }
-
- String getLockName() {
- return lockName;
- }
-
- void checkAcquiredLocks(
- Policy policy, List<LockGraphNode> acquiredLocks) {
- for (int i = 0, size = acquiredLocks.size(); i < size; i++) {
- checkAcquiredLock(policy, acquiredLocks.get(i));
- }
- }
-
- /**
- * Checks the acquisition-ordering between {@code this}, which is about to
- * be acquired, and the specified {@code acquiredLock}.
- * <p>
- * When this method returns, the {@code acquiredLock} should be in either
- * the {@code preAcquireLocks} map, for the case in which it is safe to
- * acquire {@code this} after the {@code acquiredLock}, or in the
- * {@code disallowedPriorLocks} map, in which case it is not safe.
- */
- void checkAcquiredLock(Policy policy, LockGraphNode acquiredLock) {
- // checkAcquiredLock() should never be invoked by a lock that has already
- // been acquired. For unordered locks, aboutToAcquire() ensures this by
- // checking isAcquiredByCurrentThread(). For ordered locks, however, this
- // can happen because multiple locks may share the same LockGraphNode. In
- // this situation, throw an IllegalStateException as defined by contract
- // described in the documentation of WithExplicitOrdering.
- Preconditions.checkState(
- this != acquiredLock,
- "Attempted to acquire multiple locks with the same rank " +
- acquiredLock.getLockName());
-
- if (allowedPriorLocks.containsKey(acquiredLock)) {
- // The acquisition ordering from "acquiredLock" to "this" has already
- // been verified as safe. In a properly written application, this is
- // the common case.
- return;
- }
- PotentialDeadlockException previousDeadlockException =
- disallowedPriorLocks.get(acquiredLock);
- if (previousDeadlockException != null) {
- // Previously determined to be an unsafe lock acquisition.
- // Create a new PotentialDeadlockException with the same causal chain
- // (the example cycle) as that of the cached exception.
- PotentialDeadlockException exception = new PotentialDeadlockException(
- acquiredLock, this,
- previousDeadlockException.getConflictingStackTrace());
- policy.handlePotentialDeadlock(exception);
- return;
- }
- // Otherwise, it's the first time seeing this lock relationship. Look for
- // a path from the acquiredLock to this.
- Set<LockGraphNode> seen = Sets.newIdentityHashSet();
- ExampleStackTrace path = acquiredLock.findPathTo(this, seen);
-
- if (path == null) {
- // this can be safely acquired after the acquiredLock.
- //
- // Note that there is a race condition here which can result in missing
- // a cyclic edge: it's possible for two threads to simultaneous find
- // "safe" edges which together form a cycle. Preventing this race
- // condition efficiently without _introducing_ deadlock is probably
- // tricky. For now, just accept the race condition---missing a warning
- // now and then is still better than having no deadlock detection.
- allowedPriorLocks.put(
- acquiredLock, new ExampleStackTrace(acquiredLock, this));
- } else {
- // Unsafe acquisition order detected. Create and cache a
- // PotentialDeadlockException.
- PotentialDeadlockException exception =
- new PotentialDeadlockException(acquiredLock, this, path);
- disallowedPriorLocks.put(acquiredLock, exception);
- policy.handlePotentialDeadlock(exception);
- }
- }
-
- /**
- * Performs a depth-first traversal of the graph edges defined by each
- * node's {@code allowedPriorLocks} to find a path between {@code this} and
- * the specified {@code lock}.
- *
- * @return If a path was found, a chained {@link ExampleStackTrace}
- * illustrating the path to the {@code lock}, or {@code null} if no path
- * was found.
- */
- @Nullable
- private ExampleStackTrace findPathTo(
- LockGraphNode node, Set<LockGraphNode> seen) {
- if (!seen.add(this)) {
- return null; // Already traversed this node.
- }
- ExampleStackTrace found = allowedPriorLocks.get(node);
- if (found != null) {
- return found; // Found a path ending at the node!
- }
- // Recurse the edges.
- for (Map.Entry<LockGraphNode, ExampleStackTrace> entry :
- allowedPriorLocks.entrySet()) {
- LockGraphNode preAcquiredLock = entry.getKey();
- found = preAcquiredLock.findPathTo(node, seen);
- if (found != null) {
- // One of this node's allowedPriorLocks found a path. Prepend an
- // ExampleStackTrace(preAcquiredLock, this) to the returned chain of
- // ExampleStackTraces.
- ExampleStackTrace path =
- new ExampleStackTrace(preAcquiredLock, this);
- path.setStackTrace(entry.getValue().getStackTrace());
- path.initCause(found);
- return path;
- }
- }
- return null;
- }
- }
-
- /**
- * CycleDetectingLock implementations must call this method before attempting
- * to acquire the lock.
- */
- private void aboutToAcquire(CycleDetectingLock lock) {
- if (!lock.isAcquiredByCurrentThread()) {
- ArrayList<LockGraphNode> acquiredLockList = acquiredLocks.get();
- LockGraphNode node = lock.getLockGraphNode();
- node.checkAcquiredLocks(policy, acquiredLockList);
- acquiredLockList.add(node);
- }
- }
-
- /**
- * CycleDetectingLock implementations must call this method in a
- * {@code finally} clause after any attempt to change the lock state,
- * including both lock and unlock attempts. Failure to do so can result in
- * corrupting the acquireLocks set.
- */
- private void lockStateChanged(CycleDetectingLock lock) {
- if (!lock.isAcquiredByCurrentThread()) {
- ArrayList<LockGraphNode> acquiredLockList = acquiredLocks.get();
- LockGraphNode node = lock.getLockGraphNode();
- // Iterate in reverse because locks are usually locked/unlocked in a
- // LIFO order.
- for (int i = acquiredLockList.size() - 1; i >=0; i--) {
- if (acquiredLockList.get(i) == node) {
- acquiredLockList.remove(i);
- break;
- }
- }
- }
- }
-
- final class CycleDetectingReentrantLock
- extends ReentrantLock implements CycleDetectingLock {
-
- private final LockGraphNode lockGraphNode;
-
- private CycleDetectingReentrantLock(
- LockGraphNode lockGraphNode, boolean fair) {
- super(fair);
- this.lockGraphNode = Preconditions.checkNotNull(lockGraphNode);
- }
-
- ///// CycleDetectingLock methods. /////
-
- @Override
- public LockGraphNode getLockGraphNode() {
- return lockGraphNode;
- }
-
- @Override
- public boolean isAcquiredByCurrentThread() {
- return isHeldByCurrentThread();
- }
-
- ///// Overridden ReentrantLock methods. /////
-
- @Override
- public void lock() {
- aboutToAcquire(this);
- try {
- super.lock();
- } finally {
- lockStateChanged(this);
- }
- }
-
- @Override
- public void lockInterruptibly() throws InterruptedException {
- aboutToAcquire(this);
- try {
- super.lockInterruptibly();
- } finally {
- lockStateChanged(this);
- }
- }
-
- @Override
- public boolean tryLock() {
- aboutToAcquire(this);
- try {
- return super.tryLock();
- } finally {
- lockStateChanged(this);
- }
- }
-
- @Override
- public boolean tryLock(long timeout, TimeUnit unit)
- throws InterruptedException {
- aboutToAcquire(this);
- try {
- return super.tryLock(timeout, unit);
- } finally {
- lockStateChanged(this);
- }
- }
-
- @Override
- public void unlock() {
- try {
- super.unlock();
- } finally {
- lockStateChanged(this);
- }
- }
- }
-
- final class CycleDetectingReentrantReadWriteLock
- extends ReentrantReadWriteLock implements CycleDetectingLock {
-
- // These ReadLock/WriteLock implementations shadow those in the
- // ReentrantReadWriteLock superclass. They are simply wrappers around the
- // internal Sync object, so this is safe since the shadowed locks are never
- // exposed or used.
- private final CycleDetectingReentrantReadLock readLock;
- private final CycleDetectingReentrantWriteLock writeLock;
-
- private final LockGraphNode lockGraphNode;
-
- private CycleDetectingReentrantReadWriteLock(
- LockGraphNode lockGraphNode, boolean fair) {
- super(fair);
- this.readLock = new CycleDetectingReentrantReadLock(this);
- this.writeLock = new CycleDetectingReentrantWriteLock(this);
- this.lockGraphNode = Preconditions.checkNotNull(lockGraphNode);
- }
-
- ///// Overridden ReentrantReadWriteLock methods. /////
-
- @Override
- public ReadLock readLock() {
- return readLock;
- }
-
- @Override
- public WriteLock writeLock() {
- return writeLock;
- }
-
- ///// CycleDetectingLock methods. /////
-
- @Override
- public LockGraphNode getLockGraphNode() {
- return lockGraphNode;
- }
-
- @Override
- public boolean isAcquiredByCurrentThread() {
- return isWriteLockedByCurrentThread() || getReadHoldCount() > 0;
- }
- }
-
- private class CycleDetectingReentrantReadLock
- extends ReentrantReadWriteLock.ReadLock {
-
- final CycleDetectingReentrantReadWriteLock readWriteLock;
-
- CycleDetectingReentrantReadLock(
- CycleDetectingReentrantReadWriteLock readWriteLock) {
- super(readWriteLock);
- this.readWriteLock = readWriteLock;
- }
-
- @Override
- public void lock() {
- aboutToAcquire(readWriteLock);
- try {
- super.lock();
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
-
- @Override
- public void lockInterruptibly() throws InterruptedException {
- aboutToAcquire(readWriteLock);
- try {
- super.lockInterruptibly();
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
-
- @Override
- public boolean tryLock() {
- aboutToAcquire(readWriteLock);
- try {
- return super.tryLock();
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
-
- @Override
- public boolean tryLock(long timeout, TimeUnit unit)
- throws InterruptedException {
- aboutToAcquire(readWriteLock);
- try {
- return super.tryLock(timeout, unit);
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
-
- @Override
- public void unlock() {
- try {
- super.unlock();
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
- }
-
- private class CycleDetectingReentrantWriteLock
- extends ReentrantReadWriteLock.WriteLock {
-
- final CycleDetectingReentrantReadWriteLock readWriteLock;
-
- CycleDetectingReentrantWriteLock(
- CycleDetectingReentrantReadWriteLock readWriteLock) {
- super(readWriteLock);
- this.readWriteLock = readWriteLock;
- }
-
- @Override
- public void lock() {
- aboutToAcquire(readWriteLock);
- try {
- super.lock();
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
-
- @Override
- public void lockInterruptibly() throws InterruptedException {
- aboutToAcquire(readWriteLock);
- try {
- super.lockInterruptibly();
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
-
- @Override
- public boolean tryLock() {
- aboutToAcquire(readWriteLock);
- try {
- return super.tryLock();
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
-
- @Override
- public boolean tryLock(long timeout, TimeUnit unit)
- throws InterruptedException {
- aboutToAcquire(readWriteLock);
- try {
- return super.tryLock(timeout, unit);
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
-
- @Override
- public void unlock() {
- try {
- super.unlock();
- } finally {
- lockStateChanged(readWriteLock);
- }
- }
- }
-}
diff --git a/guava/src/com/google/common/util/concurrent/ExecutionError.java b/guava/src/com/google/common/util/concurrent/ExecutionError.java
index e462969..ce588eb 100644
--- a/guava/src/com/google/common/util/concurrent/ExecutionError.java
+++ b/guava/src/com/google/common/util/concurrent/ExecutionError.java
@@ -17,8 +17,7 @@
package com.google.common.util.concurrent;
import com.google.common.annotations.GwtCompatible;
-
-import javax.annotation.Nullable;
+import com.google.common.annotations.Beta;
/**
* {@link Error} variant of {@link java.util.concurrent.ExecutionException}. As
@@ -32,6 +31,7 @@ import javax.annotation.Nullable;
* @author Chris Povirk
* @since 10.0
*/
+@Beta
@GwtCompatible
public class ExecutionError extends Error {
/**
@@ -42,21 +42,21 @@ public class ExecutionError extends Error {
/**
* Creates a new instance with the given detail message.
*/
- protected ExecutionError(@Nullable String message) {
+ protected ExecutionError(String message) {
super(message);
}
/**
* Creates a new instance with the given detail message and cause.
*/
- public ExecutionError(@Nullable String message, @Nullable Error cause) {
+ public ExecutionError(String message, Error cause) {
super(message, cause);
}
/**
* Creates a new instance with the given cause.
*/
- public ExecutionError(@Nullable Error cause) {
+ public ExecutionError(Error cause) {
super(cause);
}
diff --git a/guava/src/com/google/common/util/concurrent/ExecutionList.java b/guava/src/com/google/common/util/concurrent/ExecutionList.java
index e1a40d0..d1b78f5 100644
--- a/guava/src/com/google/common/util/concurrent/ExecutionList.java
+++ b/guava/src/com/google/common/util/concurrent/ExecutionList.java
@@ -16,7 +16,6 @@
package com.google.common.util.concurrent;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
@@ -46,7 +45,7 @@ import java.util.logging.Logger;
public final class ExecutionList {
// Logger to log exceptions caught when running runnables.
- @VisibleForTesting static final Logger log =
+ private static final Logger log =
Logger.getLogger(ExecutionList.class.getName());
// The runnable,executor pairs to execute.
diff --git a/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java b/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java
index 75a1e94..890479d 100644
--- a/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java
+++ b/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java
@@ -16,8 +16,6 @@
package com.google.common.util.concurrent;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.Beta;
import java.util.concurrent.Callable;
@@ -38,16 +36,12 @@ public final class FakeTimeLimiter implements TimeLimiter {
@Override
public <T> T newProxy(T target, Class<T> interfaceType, long timeoutDuration,
TimeUnit timeoutUnit) {
- checkNotNull(target);
- checkNotNull(interfaceType);
- checkNotNull(timeoutUnit);
return target; // ha ha
}
@Override
public <T> T callWithTimeout(Callable<T> callable, long timeoutDuration,
TimeUnit timeoutUnit, boolean amInterruptible) throws Exception {
- checkNotNull(timeoutUnit);
return callable.call(); // fooled you
}
}
diff --git a/guava/src/com/google/common/util/concurrent/ForwardingService.java b/guava/src/com/google/common/util/concurrent/ForwardingService.java
index 8774232..e39e4db 100644
--- a/guava/src/com/google/common/util/concurrent/ForwardingService.java
+++ b/guava/src/com/google/common/util/concurrent/ForwardingService.java
@@ -19,22 +19,13 @@ package com.google.common.util.concurrent;
import com.google.common.annotations.Beta;
import com.google.common.collect.ForwardingObject;
-import java.util.concurrent.Executor;
-
/**
* A {@link Service} that forwards all method calls to another service.
*
- * @deprecated Instead of using a {@link ForwardingService}, consider using the
- * {@link Service.Listener} functionality to hook into the {@link Service}
- * lifecycle, or if you really do need to provide access to some Service
- * methods, consider just providing the few that you actually need (e.g. just
- * {@link #startAndWait()}) and not implementing Service.
- *
* @author Chris Nokleberg
* @since 1.0
*/
@Beta
-@Deprecated
public abstract class ForwardingService extends ForwardingObject
implements Service {
@@ -66,20 +57,6 @@ public abstract class ForwardingService extends ForwardingObject
@Override public boolean isRunning() {
return delegate().isRunning();
}
-
- /**
- * @since 13.0
- */
- @Override public void addListener(Listener listener, Executor executor) {
- delegate().addListener(listener, executor);
- }
-
- /**
- * @since 14.0
- */
- @Override public Throwable failureCause() {
- return delegate().failureCause();
- }
/**
* A sensible default implementation of {@link #startAndWait()}, in terms of
diff --git a/guava/src/com/google/common/util/concurrent/FutureCallback.java b/guava/src/com/google/common/util/concurrent/FutureCallback.java
index 735d6ab..7b39d4a 100644
--- a/guava/src/com/google/common/util/concurrent/FutureCallback.java
+++ b/guava/src/com/google/common/util/concurrent/FutureCallback.java
@@ -16,6 +16,8 @@
package com.google.common.util.concurrent;
+import com.google.common.annotations.Beta;
+
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@@ -28,6 +30,7 @@ import java.util.concurrent.Future;
* @author Anthony Zana
* @since 10.0
*/
+@Beta
public interface FutureCallback<V> {
/**
* Invoked with the result of the {@code Future} computation when it is
diff --git a/guava/src/com/google/common/util/concurrent/FutureFallback.java b/guava/src/com/google/common/util/concurrent/FutureFallback.java
deleted file mode 100644
index 7d03c67..0000000
--- a/guava/src/com/google/common/util/concurrent/FutureFallback.java
+++ /dev/null
@@ -1,48 +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.util.concurrent;
-
-import com.google.common.annotations.Beta;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
-/**
- * Provides a backup {@code Future} to replace an earlier failed {@code Future}.
- * An implementation of this interface can be applied to an input {@code Future}
- * with {@link Futures#withFallback}.
- *
- * @param <V> the result type of the provided backup {@code Future}
- *
- * @author Bruno Diniz
- * @since 14.0
- */
-@Beta
-public interface FutureFallback<V> {
- /**
- * Returns a {@code Future} to be used in place of the {@code Future} that
- * failed with the given exception. The exception is provided so that the
- * {@code Fallback} implementation can conditionally determine whether to
- * propagate the exception or to attempt to recover.
- *
- * @param t the exception that made the future fail. If the future's {@link
- * Future#get() get} method throws an {@link ExecutionException}, then the
- * cause is passed to this method. Any other thrown object is passed
- * unaltered.
- */
- ListenableFuture<V> create(Throwable t) throws Exception;
-}
diff --git a/guava/src/com/google/common/util/concurrent/Futures.java b/guava/src/com/google/common/util/concurrent/Futures.java
index aad6b43..dc703c5 100644
--- a/guava/src/com/google/common/util/concurrent/Futures.java
+++ b/guava/src/com/google/common/util/concurrent/Futures.java
@@ -21,14 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
+import static com.google.common.util.concurrent.Uninterruptibles.putUninterruptibly;
+import static com.google.common.util.concurrent.Uninterruptibles.takeUninterruptibly;
import static java.lang.Thread.currentThread;
import static java.util.Arrays.asList;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
-import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
@@ -38,27 +39,22 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import javax.annotation.Nullable;
/**
* Static utility methods pertaining to the {@link Future} interface.
*
- * <p>Many of these methods use the {@link ListenableFuture} API; consult the
- * Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained">
- * {@code ListenableFuture}</a>.
- *
* @author Kevin Bourrillion
* @author Nishant Thakkar
* @author Sven Mawson
@@ -75,7 +71,7 @@ public final class Futures {
*
* <p>The given mapping function will be applied to an
* {@link InterruptedException}, a {@link CancellationException}, or an
- * {@link ExecutionException}.
+ * {@link ExecutionException} with the actual cause of the exception.
* See {@link Future#get()} for details on the exceptions thrown.
*
* @since 9.0 (source-compatible since 1.0)
@@ -85,151 +81,6 @@ public final class Futures {
return new MappingCheckedFuture<V, X>(checkNotNull(future), mapper);
}
- private abstract static class ImmediateFuture<V>
- implements ListenableFuture<V> {
-
- private static final Logger log =
- Logger.getLogger(ImmediateFuture.class.getName());
-
- @Override
- public void addListener(Runnable listener, Executor executor) {
- checkNotNull(listener, "Runnable was null.");
- checkNotNull(executor, "Executor was null.");
- try {
- executor.execute(listener);
- } catch (RuntimeException e) {
- // ListenableFuture's contract is that it will not throw unchecked
- // exceptions, so log the bad runnable and/or executor and swallow it.
- log.log(Level.SEVERE, "RuntimeException while executing runnable "
- + listener + " with executor " + executor, e);
- }
- }
-
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- return false;
- }
-
- @Override
- public abstract V get() throws ExecutionException;
-
- @Override
- public V get(long timeout, TimeUnit unit) throws ExecutionException {
- checkNotNull(unit);
- return get();
- }
-
- @Override
- public boolean isCancelled() {
- return false;
- }
-
- @Override
- public boolean isDone() {
- return true;
- }
- }
-
- private static class ImmediateSuccessfulFuture<V> extends ImmediateFuture<V> {
-
- @Nullable private final V value;
-
- ImmediateSuccessfulFuture(@Nullable V value) {
- this.value = value;
- }
-
- @Override
- public V get() {
- return value;
- }
- }
-
- private static class ImmediateSuccessfulCheckedFuture<V, X extends Exception>
- extends ImmediateFuture<V> implements CheckedFuture<V, X> {
-
- @Nullable private final V value;
-
- ImmediateSuccessfulCheckedFuture(@Nullable V value) {
- this.value = value;
- }
-
- @Override
- public V get() {
- return value;
- }
-
- @Override
- public V checkedGet() {
- return value;
- }
-
- @Override
- public V checkedGet(long timeout, TimeUnit unit) {
- checkNotNull(unit);
- return value;
- }
- }
-
- private static class ImmediateFailedFuture<V> extends ImmediateFuture<V> {
-
- private final Throwable thrown;
-
- ImmediateFailedFuture(Throwable thrown) {
- this.thrown = thrown;
- }
-
- @Override
- public V get() throws ExecutionException {
- throw new ExecutionException(thrown);
- }
- }
-
- private static class ImmediateCancelledFuture<V> extends ImmediateFuture<V> {
-
- private final CancellationException thrown;
-
- ImmediateCancelledFuture() {
- this.thrown = new CancellationException("Immediate cancelled future.");
- }
-
- @Override
- public boolean isCancelled() {
- return true;
- }
-
- @Override
- public V get() {
- throw AbstractFuture.cancellationExceptionWithCause(
- "Task was cancelled.", thrown);
- }
- }
-
- private static class ImmediateFailedCheckedFuture<V, X extends Exception>
- extends ImmediateFuture<V> implements CheckedFuture<V, X> {
-
- private final X thrown;
-
- ImmediateFailedCheckedFuture(X thrown) {
- this.thrown = thrown;
- }
-
- @Override
- public V get() throws ExecutionException {
- throw new ExecutionException(thrown);
- }
-
- @Override
- public V checkedGet() throws X {
- throw thrown;
- }
-
- @Override
- public V checkedGet(long timeout, TimeUnit unit) throws X {
- checkNotNull(unit);
- throw thrown;
- }
- }
-
/**
* Creates a {@code ListenableFuture} which has its value set immediately upon
* construction. The getters just return the value. This {@code Future} can't
@@ -237,7 +88,9 @@ public final class Futures {
* {@code true}.
*/
public static <V> ListenableFuture<V> immediateFuture(@Nullable V value) {
- return new ImmediateSuccessfulFuture<V>(value);
+ SettableFuture<V> future = SettableFuture.create();
+ future.set(value);
+ return future;
}
/**
@@ -250,7 +103,14 @@ public final class Futures {
*/
public static <V, X extends Exception> CheckedFuture<V, X>
immediateCheckedFuture(@Nullable V value) {
- return new ImmediateSuccessfulCheckedFuture<V, X>(value);
+ SettableFuture<V> future = SettableFuture.create();
+ future.set(value);
+ return Futures.makeChecked(future, new Function<Exception, X>() {
+ @Override
+ public X apply(Exception e) {
+ throw new AssertionError("impossible");
+ }
+ });
}
/**
@@ -261,21 +121,15 @@ public final class Futures {
* method always returns {@code true}. Calling {@code get()} will immediately
* throw the provided {@code Throwable} wrapped in an {@code
* ExecutionException}.
+ *
+ * @throws Error if the throwable is an {@link Error}.
*/
public static <V> ListenableFuture<V> immediateFailedFuture(
Throwable throwable) {
checkNotNull(throwable);
- return new ImmediateFailedFuture<V>(throwable);
- }
-
- /**
- * Creates a {@code ListenableFuture} which is cancelled immediately upon
- * construction, so that {@code isCancelled()} always returns {@code true}.
- *
- * @since 14.0
- */
- public static <V> ListenableFuture<V> immediateCancelledFuture() {
- return new ImmediateCancelledFuture<V>();
+ SettableFuture<V> future = SettableFuture.create();
+ future.setException(throwable);
+ return future;
}
/**
@@ -284,224 +138,149 @@ public final class Futures {
*
* <p>The returned {@code Future} can't be cancelled, and its {@code isDone()}
* method always returns {@code true}. Calling {@code get()} will immediately
- * throw the provided {@code Exception} wrapped in an {@code
+ * throw the provided {@code Throwable} wrapped in an {@code
* ExecutionException}, and calling {@code checkedGet()} will throw the
* provided exception itself.
+ *
+ * @throws Error if the throwable is an {@link Error}.
*/
public static <V, X extends Exception> CheckedFuture<V, X>
- immediateFailedCheckedFuture(X exception) {
+ immediateFailedCheckedFuture(final X exception) {
checkNotNull(exception);
- return new ImmediateFailedCheckedFuture<V, X>(exception);
+ return makeChecked(Futures.<V>immediateFailedFuture(exception),
+ new Function<Exception, X>() {
+ @Override
+ public X apply(Exception e) {
+ return exception;
+ }
+ });
}
/**
- * Returns a {@code Future} whose result is taken from the given primary
- * {@code input} or, if the primary input fails, from the {@code Future}
- * provided by the {@code fallback}. {@link FutureFallback#create} is not
- * invoked until the primary input has failed, so if the primary input
- * succeeds, it is never invoked. If, during the invocation of {@code
- * fallback}, an exception is thrown, this exception is used as the result of
- * the output {@code Future}.
- *
- * <p>Below is an example of a fallback that returns a default value if an
- * exception occurs:
- *
- * <pre> {@code
- * ListenableFuture<Integer> fetchCounterFuture = ...;
- *
- * // Falling back to a zero counter in case an exception happens when
- * // processing the RPC to fetch counters.
- * ListenableFuture<Integer> faultTolerantFuture = Futures.withFallback(
- * fetchCounterFuture, new FutureFallback<Integer>() {
- * public ListenableFuture<Integer> create(Throwable t) {
- * // Returning "0" as the default for the counter when the
- * // exception happens.
- * return immediateFuture(0);
- * }
- * });
- * }</pre>
- *
- * The fallback can also choose to propagate the original exception when
- * desired:
+ * <p>Returns a new {@code ListenableFuture} whose result is asynchronously
+ * derived from the result of the given {@code Future}. More precisely, the
+ * returned {@code Future} takes its result from a {@code Future} produced by
+ * applying the given {@code Function} to the result of the original {@code
+ * Future}. Example:
*
* <pre> {@code
- * ListenableFuture<Integer> fetchCounterFuture = ...;
- *
- * // Falling back to a zero counter only in case the exception was a
- * // TimeoutException.
- * ListenableFuture<Integer> faultTolerantFuture = Futures.withFallback(
- * fetchCounterFuture, new FutureFallback<Integer>() {
- * public ListenableFuture<Integer> create(Throwable t) {
- * if (t instanceof TimeoutException) {
- * return immediateFuture(0);
- * }
- * return immediateFailedFuture(t);
+ * ListenableFuture<RowKey> rowKeyFuture = indexService.lookUp(query);
+ * Function<RowKey, ListenableFuture<QueryResult>> queryFunction =
+ * new Function<RowKey, ListenableFuture<QueryResult>>() {
+ * public ListenableFuture<QueryResult> apply(RowKey rowKey) {
+ * return dataService.read(rowKey);
* }
- * });
+ * };
+ * ListenableFuture<QueryResult> queryFuture =
+ * chain(rowKeyFuture, queryFunction);
* }</pre>
*
- * Note: If the derived {@code Future} is slow or heavyweight to create
- * (whether the {@code Future} itself is slow or heavyweight to complete is
- * irrelevant), consider {@linkplain #withFallback(ListenableFuture,
- * FutureFallback, Executor) supplying an executor}. If you do not supply an
- * executor, {@code withFallback} will use {@link
- * MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some
- * caveats for heavier operations. For example, the call to {@code
- * fallback.create} may run on an unpredictable or undesirable thread:
- *
- * <ul>
- * <li>If the input {@code Future} is done at the time {@code withFallback}
- * is called, {@code withFallback} will call {@code fallback.create} inline.
- * <li>If the input {@code Future} is not yet done, {@code withFallback} will
- * schedule {@code fallback.create} to be run by the thread that completes
- * the input {@code Future}, which may be an internal system thread such as
- * an RPC network thread.
- * </ul>
+ * <p>Note: This overload of {@code chain} is designed for cases in which the
+ * work of creating the derived future is fast and lightweight, as the method
+ * does not accept an {@code Executor} in which to perform the the work. For
+ * heavier derivations, this overload carries some caveats: First, the thread
+ * that the derivation runs in depends on whether the input {@code Future} is
+ * done at the time {@code chain} is called. In particular, if called late,
+ * {@code chain} will run the derivation in the thread that called {@code
+ * chain}. Second, derivations may run in an internal thread of the system
+ * responsible for the input {@code Future}, such as an RPC network thread.
+ * Finally, during the execution of a {@code sameThreadExecutor} {@code
+ * chain} function, all other registered but unexecuted listeners are
+ * prevented from running, even if those listeners are to run in other
+ * executors.
*
- * Also note that, regardless of which thread executes {@code
- * fallback.create}, all other registered but unexecuted listeners are
- * prevented from running during its execution, even if those listeners are
- * to run in other executors.
+ * <p>The returned {@code Future} attempts to keep its cancellation state in
+ * sync with that of the input future and that of the future returned by the
+ * chain function. That is, if the returned {@code Future} is cancelled, it
+ * will attempt to cancel the other two, and if either of the other two is
+ * cancelled, the returned {@code Future} will receive a callback in which it
+ * will attempt to cancel itself.
*
- * @param input the primary input {@code Future}
- * @param fallback the {@link FutureFallback} implementation to be called if
- * {@code input} fails
- * @since 14.0
+ * @param input The future to chain
+ * @param function A function to chain the results of the provided future
+ * to the results of the returned future. This will be run in the thread
+ * that notifies input it is complete.
+ * @return A future that holds result of the chain.
+ * @deprecated Convert your {@code Function} to a {@code AsyncFunction}, and
+ * use {@link #transform(ListenableFuture, AsyncFunction)}. This method is
+ * scheduled to be removed from Guava in Guava release 12.0.
*/
- public static <V> ListenableFuture<V> withFallback(
- ListenableFuture<? extends V> input,
- FutureFallback<? extends V> fallback) {
- return withFallback(input, fallback, sameThreadExecutor());
+ @Deprecated
+ public static <I, O> ListenableFuture<O> chain(
+ ListenableFuture<I> input,
+ Function<? super I, ? extends ListenableFuture<? extends O>> function) {
+ return chain(input, function, MoreExecutors.sameThreadExecutor());
}
/**
- * Returns a {@code Future} whose result is taken from the given primary
- * {@code input} or, if the primary input fails, from the {@code Future}
- * provided by the {@code fallback}. {@link FutureFallback#create} is not
- * invoked until the primary input has failed, so if the primary input
- * succeeds, it is never invoked. If, during the invocation of {@code
- * fallback}, an exception is thrown, this exception is used as the result of
- * the output {@code Future}.
- *
- * <p>Below is an example of a fallback that returns a default value if an
- * exception occurs:
+ * <p>Returns a new {@code ListenableFuture} whose result is asynchronously
+ * derived from the result of the given {@code Future}. More precisely, the
+ * returned {@code Future} takes its result from a {@code Future} produced by
+ * applying the given {@code Function} to the result of the original {@code
+ * Future}. Example:
*
* <pre> {@code
- * ListenableFuture<Integer> fetchCounterFuture = ...;
- *
- * // Falling back to a zero counter in case an exception happens when
- * // processing the RPC to fetch counters.
- * ListenableFuture<Integer> faultTolerantFuture = Futures.withFallback(
- * fetchCounterFuture, new FutureFallback<Integer>() {
- * public ListenableFuture<Integer> create(Throwable t) {
- * // Returning "0" as the default for the counter when the
- * // exception happens.
- * return immediateFuture(0);
+ * ListenableFuture<RowKey> rowKeyFuture = indexService.lookUp(query);
+ * Function<RowKey, ListenableFuture<QueryResult>> queryFunction =
+ * new Function<RowKey, ListenableFuture<QueryResult>>() {
+ * public ListenableFuture<QueryResult> apply(RowKey rowKey) {
+ * return dataService.read(rowKey);
* }
- * }, sameThreadExecutor());
+ * };
+ * ListenableFuture<QueryResult> queryFuture =
+ * chain(rowKeyFuture, queryFunction, executor);
* }</pre>
*
- * The fallback can also choose to propagate the original exception when
- * desired:
- *
- * <pre> {@code
- * ListenableFuture<Integer> fetchCounterFuture = ...;
- *
- * // Falling back to a zero counter only in case the exception was a
- * // TimeoutException.
- * ListenableFuture<Integer> faultTolerantFuture = Futures.withFallback(
- * fetchCounterFuture, new FutureFallback<Integer>() {
- * public ListenableFuture<Integer> create(Throwable t) {
- * if (t instanceof TimeoutException) {
- * return immediateFuture(0);
- * }
- * return immediateFailedFuture(t);
- * }
- * }, sameThreadExecutor());
- * }</pre>
+ * <p>The returned {@code Future} attempts to keep its cancellation state in
+ * sync with that of the input future and that of the future returned by the
+ * chain function. That is, if the returned {@code Future} is cancelled, it
+ * will attempt to cancel the other two, and if either of the other two is
+ * cancelled, the returned {@code Future} will receive a callback in which it
+ * will attempt to cancel itself.
*
- * When the execution of {@code fallback.create} is fast and lightweight
- * (though the {@code Future} it returns need not meet these criteria),
- * consider {@linkplain #withFallback(ListenableFuture, FutureFallback)
- * omitting the executor} or explicitly specifying {@code
- * sameThreadExecutor}. However, be aware of the caveats documented in the
- * link above.
- *
- * @param input the primary input {@code Future}
- * @param fallback the {@link FutureFallback} implementation to be called if
- * {@code input} fails
- * @param executor the executor that runs {@code fallback} if {@code input}
- * fails
- * @since 14.0
- */
- public static <V> ListenableFuture<V> withFallback(
- ListenableFuture<? extends V> input,
- FutureFallback<? extends V> fallback, Executor executor) {
- checkNotNull(fallback);
- return new FallbackFuture<V>(input, fallback, executor);
- }
-
- /**
- * A future that falls back on a second, generated future, in case its
- * original future fails.
+ * <p>Note: For cases in which the work of creating the derived future is
+ * fast and lightweight, consider {@linkplain Futures#chain(ListenableFuture,
+ * Function) the other overload} or explicit use of {@code
+ * sameThreadExecutor}. For heavier derivations, this choice carries some
+ * caveats: First, the thread that the derivation runs in depends on whether
+ * the input {@code Future} is done at the time {@code chain} is called. In
+ * particular, if called late, {@code chain} will run the derivation in the
+ * thread that called {@code chain}. Second, derivations may run in an
+ * internal thread of the system responsible for the input {@code Future},
+ * such as an RPC network thread. Finally, during the execution of a {@code
+ * sameThreadExecutor} {@code chain} function, all other registered but
+ * unexecuted listeners are prevented from running, even if those listeners
+ * are to run in other executors.
+ *
+ * @param input The future to chain
+ * @param function A function to chain the results of the provided future
+ * to the results of the returned future.
+ * @param executor Executor to run the function in.
+ * @return A future that holds result of the chain.
+ * @deprecated Convert your {@code Function} to a {@code AsyncFunction}, and
+ * use {@link #transform(ListenableFuture, AsyncFunction, Executor)}. This
+ * method is scheduled to be removed from Guava in Guava release 12.0.
*/
- private static class FallbackFuture<V> extends AbstractFuture<V> {
-
- private volatile ListenableFuture<? extends V> running;
-
- FallbackFuture(ListenableFuture<? extends V> input,
- final FutureFallback<? extends V> fallback,
- final Executor executor) {
- running = input;
- addCallback(running, new FutureCallback<V>() {
- @Override
- public void onSuccess(V value) {
- set(value);
- }
-
- @Override
- public void onFailure(Throwable t) {
- if (isCancelled()) {
- return;
- }
- try {
- running = fallback.create(t);
- if (isCancelled()) { // in case cancel called in the meantime
- running.cancel(wasInterrupted());
- return;
- }
- addCallback(running, new FutureCallback<V>() {
- @Override
- public void onSuccess(V value) {
- set(value);
- }
-
- @Override
- public void onFailure(Throwable t) {
- if (running.isCancelled()) {
- cancel(false);
- } else {
- setException(t);
- }
- }
- }, sameThreadExecutor());
- } catch (Exception e) {
- setException(e);
- } catch (Error e) {
- setException(e); // note: rethrows
+ @Deprecated
+ public static <I, O> ListenableFuture<O> chain(ListenableFuture<I> input,
+ final Function<? super I, ? extends ListenableFuture<? extends O>>
+ function,
+ Executor executor) {
+ checkNotNull(function);
+ ChainingListenableFuture<I, O> chain =
+ new ChainingListenableFuture<I, O>(new AsyncFunction<I, O>() {
+ @Override
+ /*
+ * All methods of ListenableFuture are covariant, and we don't expose
+ * the object anywhere that would allow it to be downcast.
+ */
+ @SuppressWarnings("unchecked")
+ public ListenableFuture<O> apply(I input) {
+ return (ListenableFuture) function.apply(input);
}
- }
- }, executor);
- }
-
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- if (super.cancel(mayInterruptIfRunning)) {
- running.cancel(mayInterruptIfRunning);
- return true;
- }
- return false;
- }
+ }, input);
+ input.addListener(chain, executor);
+ return chain;
}
/**
@@ -523,28 +302,20 @@ public final class Futures {
* transform(rowKeyFuture, queryFunction);
* }</pre>
*
- * Note: If the derived {@code Future} is slow or heavyweight to create
- * (whether the {@code Future} itself is slow or heavyweight to complete is
- * irrelevant), consider {@linkplain #transform(ListenableFuture,
- * AsyncFunction, Executor) supplying an executor}. If you do not supply an
- * executor, {@code transform} will use {@link
- * MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some
- * caveats for heavier operations. For example, the call to {@code
- * function.apply} may run on an unpredictable or undesirable thread:
- *
- * <ul>
- * <li>If the input {@code Future} is done at the time {@code transform} is
- * called, {@code transform} will call {@code function.apply} inline.
- * <li>If the input {@code Future} is not yet done, {@code transform} will
- * schedule {@code function.apply} to be run by the thread that completes the
- * input {@code Future}, which may be an internal system thread such as an
- * RPC network thread.
- * </ul>
- *
- * Also note that, regardless of which thread executes {@code
- * function.apply}, all other registered but unexecuted listeners are
- * prevented from running during its execution, even if those listeners are
- * to run in other executors.
+ * <p>Note: This overload of {@code transform} is designed for cases in which
+ * the work of creating the derived {@code Future} is fast and lightweight,
+ * as the method does not accept an {@code Executor} in which to perform the
+ * the work. (The created {@code Future} itself need not complete quickly.)
+ * For heavier operations, this overload carries some caveats: First, the
+ * thread that {@code function.apply} runs in depends on whether the input
+ * {@code Future} is done at the time {@code transform} is called. In
+ * particular, if called late, {@code transform} will run the operation in
+ * the thread that called {@code transform}. Second, {@code function.apply}
+ * may run in an internal thread of the system responsible for the input
+ * {@code Future}, such as an RPC network thread. Finally, during the
+ * execution of a {@code sameThreadExecutor} {@code function.apply}, all
+ * other registered but unexecuted listeners are prevented from running, even
+ * if those listeners are to run in other executors.
*
* <p>The returned {@code Future} attempts to keep its cancellation state in
* sync with that of the input future and that of the future returned by the
@@ -591,11 +362,20 @@ public final class Futures {
* cancelled, the returned {@code Future} will receive a callback in which it
* will attempt to cancel itself.
*
- * <p>When the execution of {@code function.apply} is fast and lightweight
- * (though the {@code Future} it returns need not meet these criteria),
- * consider {@linkplain #transform(ListenableFuture, AsyncFunction) omitting
- * the executor} or explicitly specifying {@code sameThreadExecutor}.
- * However, be aware of the caveats documented in the link above.
+ * <p>Note: For cases in which the work of creating the derived future is
+ * fast and lightweight, consider {@linkplain
+ * Futures#transform(ListenableFuture, Function) the other overload} or
+ * explicit use of {@code sameThreadExecutor}. For heavier derivations, this
+ * choice carries some caveats: First, the thread that {@code function.apply}
+ * runs in depends on whether the input {@code Future} is done at the time
+ * {@code transform} is called. In particular, if called late, {@code
+ * transform} will run the operation in the thread that called {@code
+ * transform}. Second, {@code function.apply} may run in an internal thread
+ * of the system responsible for the input {@code Future}, such as an RPC
+ * network thread. Finally, during the execution of a {@code
+ * sameThreadExecutor} {@code function.apply}, all other registered but
+ * unexecuted listeners are prevented from running, even if those listeners
+ * are to run in other executors.
*
* @param input The future to transform
* @param function A function to transform the result of the input future
@@ -631,26 +411,19 @@ public final class Futures {
* transform(queryFuture, rowsFunction);
* }</pre>
*
- * Note: If the transformation is slow or heavyweight, consider {@linkplain
- * #transform(ListenableFuture, Function, Executor) supplying an executor}.
- * If you do not supply an executor, {@code transform} will use {@link
- * MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some
- * caveats for heavier operations. For example, the call to {@code
- * function.apply} may run on an unpredictable or undesirable thread:
- *
- * <ul>
- * <li>If the input {@code Future} is done at the time {@code transform} is
- * called, {@code transform} will call {@code function.apply} inline.
- * <li>If the input {@code Future} is not yet done, {@code transform} will
- * schedule {@code function.apply} to be run by the thread that completes the
- * input {@code Future}, which may be an internal system thread such as an
- * RPC network thread.
- * </ul>
- *
- * Also note that, regardless of which thread executes {@code
- * function.apply}, all other registered but unexecuted listeners are
- * prevented from running during its execution, even if those listeners are
- * to run in other executors.
+ * <p>Note: This overload of {@code transform} is designed for cases in which
+ * the transformation is fast and lightweight, as the method does not accept
+ * an {@code Executor} in which to perform the the work. For heavier
+ * transformations, this overload carries some caveats: First, the thread
+ * that the transformation runs in depends on whether the input {@code
+ * Future} is done at the time {@code transform} is called. In particular, if
+ * called late, {@code transform} will perform the transformation in the
+ * thread that called {@code transform}. Second, transformations may run in
+ * an internal thread of the system responsible for the input {@code Future},
+ * such as an RPC network thread. Finally, during the execution of a {@code
+ * sameThreadExecutor} transformation, all other registered but unexecuted
+ * listeners are prevented from running, even if those listeners are to run
+ * in other executors.
*
* <p>The returned {@code Future} attempts to keep its cancellation state in
* sync with that of the input future. That is, if the returned {@code Future}
@@ -661,16 +434,16 @@ public final class Futures {
* <p>An example use of this method is to convert a serializable object
* returned from an RPC into a POJO.
*
- * @param input The future to transform
+ * @param future The future to transform
* @param function A Function to transform the results of the provided future
* to the results of the returned future. This will be run in the thread
* that notifies input it is complete.
* @return A future that holds result of the transformation.
* @since 9.0 (in 1.0 as {@code compose})
*/
- public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> input,
+ public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> future,
final Function<? super I, ? extends O> function) {
- return transform(input, function, MoreExecutors.sameThreadExecutor());
+ return transform(future, function, MoreExecutors.sameThreadExecutor());
}
/**
@@ -699,29 +472,39 @@ public final class Futures {
* <p>An example use of this method is to convert a serializable object
* returned from an RPC into a POJO.
*
- * <p>When the transformation is fast and lightweight, consider {@linkplain
- * #transform(ListenableFuture, Function) omitting the executor} or
- * explicitly specifying {@code sameThreadExecutor}. However, be aware of the
- * caveats documented in the link above.
- *
- * @param input The future to transform
+ * <p>Note: For cases in which the transformation is fast and lightweight,
+ * consider {@linkplain Futures#transform(ListenableFuture, Function) the
+ * other overload} or explicit use of {@link
+ * MoreExecutors#sameThreadExecutor}. For heavier transformations, this
+ * choice carries some caveats: First, the thread that the transformation
+ * runs in depends on whether the input {@code Future} is done at the time
+ * {@code transform} is called. In particular, if called late, {@code
+ * transform} will perform the transformation in the thread that called
+ * {@code transform}. Second, transformations may run in an internal thread
+ * of the system responsible for the input {@code Future}, such as an RPC
+ * network thread. Finally, during the execution of a {@code
+ * sameThreadExecutor} transformation, all other registered but unexecuted
+ * listeners are prevented from running, even if those listeners are to run
+ * in other executors.
+ *
+ * @param future The future to transform
* @param function A Function to transform the results of the provided future
* to the results of the returned future.
* @param executor Executor to run the function in.
* @return A future that holds result of the transformation.
* @since 9.0 (in 2.0 as {@code compose})
*/
- public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> input,
+ public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> future,
final Function<? super I, ? extends O> function, Executor executor) {
checkNotNull(function);
- AsyncFunction<I, O> wrapperFunction
- = new AsyncFunction<I, O>() {
+ Function<I, ListenableFuture<O>> wrapperFunction
+ = new Function<I, ListenableFuture<O>>() {
@Override public ListenableFuture<O> apply(I input) {
O output = function.apply(input);
return immediateFuture(output);
}
};
- return transform(input, wrapperFunction, executor);
+ return chain(future, wrapperFunction, executor);
}
/**
@@ -741,43 +524,43 @@ public final class Futures {
* who don't have a {@code ListenableFuture} available and
* do not mind repeated, lazy function evaluation.
*
- * @param input The future to transform
+ * @param future The future to transform
* @param function A Function to transform the results of the provided future
* to the results of the returned future.
* @return A future that returns the result of the transformation.
* @since 10.0
*/
@Beta
- public static <I, O> Future<O> lazyTransform(final Future<I> input,
+ public static <I, O> Future<O> lazyTransform(final Future<I> future,
final Function<? super I, ? extends O> function) {
- checkNotNull(input);
+ checkNotNull(future);
checkNotNull(function);
return new Future<O>() {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
- return input.cancel(mayInterruptIfRunning);
+ return future.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled() {
- return input.isCancelled();
+ return future.isCancelled();
}
@Override
public boolean isDone() {
- return input.isDone();
+ return future.isDone();
}
@Override
public O get() throws InterruptedException, ExecutionException {
- return applyTransformation(input.get());
+ return applyTransformation(future.get());
}
@Override
public O get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
- return applyTransformation(input.get(timeout, unit));
+ return applyTransformation(future.get(timeout, unit));
}
private O applyTransformation(I input) throws ExecutionException {
@@ -806,6 +589,8 @@ public final class Futures {
private AsyncFunction<? super I, ? extends O> function;
private ListenableFuture<? extends I> inputFuture;
private volatile ListenableFuture<? extends O> outputFuture;
+ private final BlockingQueue<Boolean> mayInterruptIfRunningChannel =
+ new LinkedBlockingQueue<Boolean>(1);
private final CountDownLatch outputCreated = new CountDownLatch(1);
private ChainingListenableFuture(
@@ -815,6 +600,90 @@ public final class Futures {
this.inputFuture = checkNotNull(inputFuture);
}
+ /**
+ * Delegate the get() to the input and output futures, in case
+ * their implementations defer starting computation until their
+ * own get() is invoked.
+ */
+ @Override
+ public O get() throws InterruptedException, ExecutionException {
+ if (!isDone()) {
+ // Invoking get on the inputFuture will ensure our own run()
+ // method below is invoked as a listener when inputFuture sets
+ // its value. Therefore when get() returns we should then see
+ // the outputFuture be created.
+ ListenableFuture<? extends I> inputFuture = this.inputFuture;
+ if (inputFuture != null) {
+ inputFuture.get();
+ }
+
+ // If our listener was scheduled to run on an executor we may
+ // need to wait for our listener to finish running before the
+ // outputFuture has been constructed by the function.
+ outputCreated.await();
+
+ // Like above with the inputFuture, we have a listener on
+ // the outputFuture that will set our own value when its
+ // value is set. Invoking get will ensure the output can
+ // complete and invoke our listener, so that we can later
+ // get the result.
+ ListenableFuture<? extends O> outputFuture = this.outputFuture;
+ if (outputFuture != null) {
+ outputFuture.get();
+ }
+ }
+ return super.get();
+ }
+
+ /**
+ * Delegate the get() to the input and output futures, in case
+ * their implementations defer starting computation until their
+ * own get() is invoked.
+ */
+ @Override
+ public O get(long timeout, TimeUnit unit) throws TimeoutException,
+ ExecutionException, InterruptedException {
+ if (!isDone()) {
+ // Use a single time unit so we can decrease remaining timeout
+ // as we wait for various phases to complete.
+ if (unit != NANOSECONDS) {
+ timeout = NANOSECONDS.convert(timeout, unit);
+ unit = NANOSECONDS;
+ }
+
+ // Invoking get on the inputFuture will ensure our own run()
+ // method below is invoked as a listener when inputFuture sets
+ // its value. Therefore when get() returns we should then see
+ // the outputFuture be created.
+ ListenableFuture<? extends I> inputFuture = this.inputFuture;
+ if (inputFuture != null) {
+ long start = System.nanoTime();
+ inputFuture.get(timeout, unit);
+ timeout -= Math.max(0, System.nanoTime() - start);
+ }
+
+ // If our listener was scheduled to run on an executor we may
+ // need to wait for our listener to finish running before the
+ // outputFuture has been constructed by the function.
+ long start = System.nanoTime();
+ if (!outputCreated.await(timeout, unit)) {
+ throw new TimeoutException();
+ }
+ timeout -= Math.max(0, System.nanoTime() - start);
+
+ // Like above with the inputFuture, we have a listener on
+ // the outputFuture that will set our own value when its
+ // value is set. Invoking get will ensure the output can
+ // complete and invoke our listener, so that we can later
+ // get the result.
+ ListenableFuture<? extends O> outputFuture = this.outputFuture;
+ if (outputFuture != null) {
+ outputFuture.get(timeout, unit);
+ }
+ }
+ return super.get(timeout, unit);
+ }
+
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
/*
@@ -824,6 +693,7 @@ public final class Futures {
if (super.cancel(mayInterruptIfRunning)) {
// This should never block since only one thread is allowed to cancel
// this Future.
+ putUninterruptibly(mayInterruptIfRunningChannel, mayInterruptIfRunning);
cancel(inputFuture, mayInterruptIfRunning);
cancel(outputFuture, mayInterruptIfRunning);
return true;
@@ -859,7 +729,13 @@ public final class Futures {
final ListenableFuture<? extends O> outputFuture = this.outputFuture =
function.apply(sourceResult);
if (isCancelled()) {
- outputFuture.cancel(wasInterrupted());
+ // Handles the case where cancel was called while the function was
+ // being applied.
+ // There is a gap in cancel(boolean) between calling sync.cancel()
+ // and storing the value of mayInterruptIfRunning, so this thread
+ // needs to block, waiting for that value.
+ outputFuture.cancel(
+ takeUninterruptibly(mayInterruptIfRunningChannel));
this.outputFuture = null;
return;
}
@@ -907,52 +783,14 @@ public final class Futures {
}
/**
- * Returns a new {@code ListenableFuture} whose result is the product of
- * calling {@code get()} on the {@code Future} nested within the given {@code
- * Future}, effectively chaining the futures one after the other. Example:
- *
- * <pre> {@code
- * SettableFuture<ListenableFuture<String>> nested = SettableFuture.create();
- * ListenableFuture<String> dereferenced = dereference(nested);
- * }</pre>
- *
- * <p>This call has the same cancellation and execution semantics as {@link
- * #transform(ListenableFuture, AsyncFunction)}, in that the returned {@code
- * Future} attempts to keep its cancellation state in sync with both the
- * input {@code Future} and the nested {@code Future}. The transformation
- * is very lightweight and therefore takes place in the thread that called
- * {@code dereference}.
- *
- * @param nested The nested future to transform.
- * @return A future that holds result of the inner future.
- * @since 13.0
- */
- @Beta
- @SuppressWarnings({"rawtypes", "unchecked"})
- public static <V> ListenableFuture<V> dereference(
- ListenableFuture<? extends ListenableFuture<? extends V>> nested) {
- return Futures.transform((ListenableFuture) nested, (AsyncFunction) DEREFERENCER);
- }
-
- /**
- * Helper {@code Function} for {@link #dereference}.
- */
- private static final AsyncFunction<ListenableFuture<Object>, Object> DEREFERENCER =
- new AsyncFunction<ListenableFuture<Object>, Object>() {
- @Override public ListenableFuture<Object> apply(ListenableFuture<Object> input) {
- return input;
- }
- };
-
- /**
* Creates a new {@code ListenableFuture} whose value is a list containing the
* values of all its input futures, if all succeed. If any input fails, the
* returned future fails.
*
* <p>The list of results is in the same order as the input list.
*
- * <p>Canceling this future will attempt to cancel all the component futures,
- * and if any of the provided futures fails or is canceled, this one is,
+ * <p>Canceling this future does not cancel any of the component futures;
+ * however, if any of the provided futures fails or is canceled, this one is,
* too.
*
* @param futures futures to combine
@@ -963,7 +801,7 @@ public final class Futures {
@Beta
public static <V> ListenableFuture<List<V>> allAsList(
ListenableFuture<? extends V>... futures) {
- return listFuture(ImmutableList.copyOf(futures), true,
+ return new ListFuture<V>(ImmutableList.copyOf(futures), true,
MoreExecutors.sameThreadExecutor());
}
@@ -974,8 +812,8 @@ public final class Futures {
*
* <p>The list of results is in the same order as the input list.
*
- * <p>Canceling this future will attempt to cancel all the component futures,
- * and if any of the provided futures fails or is canceled, this one is,
+ * <p>Canceling this future does not cancel any of the component futures;
+ * however, if any of the provided futures fails or is canceled, this one is,
* too.
*
* @param futures futures to combine
@@ -986,7 +824,7 @@ public final class Futures {
@Beta
public static <V> ListenableFuture<List<V>> allAsList(
Iterable<? extends ListenableFuture<? extends V>> futures) {
- return listFuture(ImmutableList.copyOf(futures), true,
+ return new ListFuture<V>(ImmutableList.copyOf(futures), true,
MoreExecutors.sameThreadExecutor());
}
@@ -998,8 +836,6 @@ public final class Futures {
* indistinguishable from the future having a successful value of
* {@code null}).
*
- * <p>Canceling this future will attempt to cancel all the component futures.
- *
* @param futures futures to combine
* @return a future that provides a list of the results of the component
* futures
@@ -1008,7 +844,7 @@ public final class Futures {
@Beta
public static <V> ListenableFuture<List<V>> successfulAsList(
ListenableFuture<? extends V>... futures) {
- return listFuture(ImmutableList.copyOf(futures), false,
+ return new ListFuture<V>(ImmutableList.copyOf(futures), false,
MoreExecutors.sameThreadExecutor());
}
@@ -1020,8 +856,6 @@ public final class Futures {
* indistinguishable from the future having a successful value of
* {@code null}).
*
- * <p>Canceling this future will attempt to cancel all the component futures.
- *
* @param futures futures to combine
* @return a future that provides a list of the results of the component
* futures
@@ -1030,7 +864,7 @@ public final class Futures {
@Beta
public static <V> ListenableFuture<List<V>> successfulAsList(
Iterable<? extends ListenableFuture<? extends V>> futures) {
- return listFuture(ImmutableList.copyOf(futures), false,
+ return new ListFuture<V>(ImmutableList.copyOf(futures), false,
MoreExecutors.sameThreadExecutor());
}
@@ -1055,26 +889,19 @@ public final class Futures {
* }
* });}</pre>
*
- * Note: If the callback is slow or heavyweight, consider {@linkplain
- * #addCallback(ListenableFuture, FutureCallback, Executor) supplying an
- * executor}. If you do not supply an executor, {@code addCallback} will use
- * {@link MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries
- * some caveats for heavier operations. For example, the callback may run on
- * an unpredictable or undesirable thread:
- *
- * <ul>
- * <li>If the input {@code Future} is done at the time {@code addCallback} is
- * called, {@code addCallback} will execute the callback inline.
- * <li>If the input {@code Future} is not yet done, {@code addCallback} will
- * schedule the callback to be run by the thread that completes the input
- * {@code Future}, which may be an internal system thread such as an RPC
- * network thread.
- * </ul>
- *
- * Also note that, regardless of which thread executes the callback, all
- * other registered but unexecuted listeners are prevented from running
- * during its execution, even if those listeners are to run in other
- * executors.
+ * <p>Note: This overload of {@code addCallback} is designed for cases in
+ * which the callack is fast and lightweight, as the method does not accept
+ * an {@code Executor} in which to perform the the work. For heavier
+ * callbacks, this overload carries some caveats: First, the thread that the
+ * callback runs in depends on whether the input {@code Future} is done at the
+ * time {@code addCallback} is called and on whether the input {@code Future}
+ * is ever cancelled. In particular, {@code addCallback} may execute the
+ * callback in the thread that calls {@code addCallback} or {@code
+ * Future.cancel}. Second, callbacks may run in an internal thread of the
+ * system responsible for the input {@code Future}, such as an RPC network
+ * thread. Finally, during the execution of a {@code sameThreadExecutor}
+ * callback, all other registered but unexecuted listeners are prevented from
+ * running, even if those listeners are to run in other executors.
*
* <p>For a more general interface to attach a completion listener to a
* {@code Future}, see {@link ListenableFuture#addListener addListener}.
@@ -1111,10 +938,20 @@ public final class Futures {
* }
* });}</pre>
*
- * When the callback is fast and lightweight, consider {@linkplain
- * #addCallback(ListenableFuture, FutureCallback) omitting the executor} or
- * explicitly specifying {@code sameThreadExecutor}. However, be aware of the
- * caveats documented in the link above.
+ * When the callback is fast and lightweight consider {@linkplain
+ * Futures#addCallback(ListenableFuture, FutureCallback) the other overload}
+ * or explicit use of {@link MoreExecutors#sameThreadExecutor
+ * sameThreadExecutor}. For heavier callbacks, this choice carries some
+ * caveats: First, the thread that the callback runs in depends on whether
+ * the input {@code Future} is done at the time {@code addCallback} is called
+ * and on whether the input {@code Future} is ever cancelled. In particular,
+ * {@code addCallback} may execute the callback in the thread that calls
+ * {@code addCallback} or {@code Future.cancel}. Second, callbacks may run in
+ * an internal thread of the system responsible for the input {@code Future},
+ * such as an RPC network thread. Finally, during the execution of a {@code
+ * sameThreadExecutor} callback, all other registered but unexecuted
+ * listeners are prevented from running, even if those listeners are to run
+ * in other executors.
*
* <p>For a more general interface to attach a completion listener to a
* {@code Future}, see {@link ListenableFuture#addListener addListener}.
@@ -1131,22 +968,18 @@ public final class Futures {
Runnable callbackListener = new Runnable() {
@Override
public void run() {
- final V value;
try {
// TODO(user): (Before Guava release), validate that this
// is the thing for IE.
- value = getUninterruptibly(future);
+ V value = getUninterruptibly(future);
+ callback.onSuccess(value);
} catch (ExecutionException e) {
callback.onFailure(e.getCause());
- return;
} catch (RuntimeException e) {
callback.onFailure(e);
- return;
} catch (Error e) {
callback.onFailure(e);
- return;
}
- callback.onSuccess(value);
}
};
future.addListener(callbackListener, executor);
@@ -1434,53 +1267,49 @@ public final class Futures {
}
}
- private interface FutureCombiner<V, C> {
- C combine(List<Optional<V>> values);
- }
-
- private static class CombinedFuture<V, C> extends AbstractFuture<C> {
- ImmutableCollection<? extends ListenableFuture<? extends V>> futures;
+ /**
+ * Class that implements {@link #allAsList} and {@link #successfulAsList}.
+ * The idea is to create a (null-filled) List and register a listener with
+ * each component future to fill out the value in the List when that future
+ * completes.
+ */
+ private static class ListFuture<V> extends AbstractFuture<List<V>> {
+ ImmutableList<? extends ListenableFuture<? extends V>> futures;
final boolean allMustSucceed;
final AtomicInteger remaining;
- FutureCombiner<V, C> combiner;
- List<Optional<V>> values;
+ List<V> values;
- CombinedFuture(
- ImmutableCollection<? extends ListenableFuture<? extends V>> futures,
- boolean allMustSucceed, Executor listenerExecutor,
- FutureCombiner<V, C> combiner) {
+ /**
+ * Constructor.
+ *
+ * @param futures all the futures to build the list from
+ * @param allMustSucceed whether a single failure or cancellation should
+ * propagate to this future
+ * @param listenerExecutor used to run listeners on all the passed in
+ * futures.
+ */
+ ListFuture(
+ final ImmutableList<? extends ListenableFuture<? extends V>> futures,
+ final boolean allMustSucceed, final Executor listenerExecutor) {
this.futures = futures;
+ this.values = Lists.newArrayListWithCapacity(futures.size());
this.allMustSucceed = allMustSucceed;
this.remaining = new AtomicInteger(futures.size());
- this.combiner = combiner;
- this.values = Lists.newArrayListWithCapacity(futures.size());
+
init(listenerExecutor);
}
- /**
- * Must be called at the end of the constructor.
- */
- protected void init(final Executor listenerExecutor) {
+ private void init(final Executor listenerExecutor) {
// First, schedule cleanup to execute when the Future is done.
addListener(new Runnable() {
@Override
public void run() {
- // Cancel all the component futures.
- if (CombinedFuture.this.isCancelled()) {
- for (ListenableFuture<?> future : CombinedFuture.this.futures) {
- future.cancel(CombinedFuture.this.wasInterrupted());
- }
- }
-
// By now the values array has either been set as the Future's value,
// or (in case of failure) is no longer useful.
- CombinedFuture.this.futures = null;
+ ListFuture.this.values = null;
// Let go of the memory held by other futures
- CombinedFuture.this.values = null;
-
- // The combiner may also hold state, so free that as well
- CombinedFuture.this.combiner = null;
+ ListFuture.this.futures = null;
}
}, MoreExecutors.sameThreadExecutor());
@@ -1488,7 +1317,7 @@ public final class Futures {
// Corner case: List is empty.
if (futures.isEmpty()) {
- set(combiner.combine(ImmutableList.<Optional<V>>of()));
+ set(Lists.newArrayList(values));
return;
}
@@ -1503,11 +1332,11 @@ public final class Futures {
// this loop, the last call to addListener() will callback to
// setOneValue(), transitively call our cleanup listener, and set
// this.futures to null.
- // This is not actually a problem, since the foreach only needs
- // this.futures to be non-null at the beginning of the loop.
- int i = 0;
- for (final ListenableFuture<? extends V> listenable : futures) {
- final int index = i++;
+ // We store a reference to futures to avoid the NPE.
+ ImmutableList<? extends ListenableFuture<? extends V>> localFutures = futures;
+ for (int i = 0; i < localFutures.size(); i++) {
+ final ListenableFuture<? extends V> listenable = localFutures.get(i);
+ final int index = i;
listenable.addListener(new Runnable() {
@Override
public void run() {
@@ -1521,12 +1350,12 @@ public final class Futures {
* Sets the value at the given index to that of the given future.
*/
private void setOneValue(int index, Future<? extends V> future) {
- List<Optional<V>> localValues = values;
+ List<V> localValues = values;
if (isDone() || localValues == null) {
// Some other future failed or has been cancelled, causing this one to
// also be cancelled or have an exception set. This should only happen
- // if allMustSucceed is true or if the output itself has been cancelled.
- checkState(allMustSucceed || isCancelled(),
+ // if allMustSucceed is true.
+ checkState(allMustSucceed,
"Future was done before all dependencies completed");
return;
}
@@ -1534,8 +1363,7 @@ public final class Futures {
try {
checkState(future.isDone(),
"Tried to set value from future which is not done");
- V returnValue = getUninterruptibly(future);
- localValues.set(index, Optional.fromNullable(returnValue));
+ localValues.set(index, getUninterruptibly(future));
} catch (CancellationException e) {
if (allMustSucceed) {
// Set ourselves as cancelled. Let the input futures keep running
@@ -1561,9 +1389,9 @@ public final class Futures {
int newRemaining = remaining.decrementAndGet();
checkState(newRemaining >= 0, "Less than 0 remaining futures");
if (newRemaining == 0) {
- FutureCombiner<V, C> localCombiner = combiner;
- if (localCombiner != null) {
- set(localCombiner.combine(localValues));
+ localValues = values;
+ if (localValues != null) {
+ set(Lists.newArrayList(localValues));
} else {
checkState(isDone());
}
@@ -1571,25 +1399,46 @@ public final class Futures {
}
}
- }
+ @Override
+ public List<V> get() throws InterruptedException, ExecutionException {
+ callAllGets();
- /** Used for {@link #allAsList} and {@link #successfulAsList}. */
- private static <V> ListenableFuture<List<V>> listFuture(
- ImmutableList<ListenableFuture<? extends V>> futures,
- boolean allMustSucceed, Executor listenerExecutor) {
- return new CombinedFuture<V, List<V>>(
- futures, allMustSucceed, listenerExecutor,
- new FutureCombiner<V, List<V>>() {
- @Override
- public List<V> combine(List<Optional<V>> values) {
- List<V> result = Lists.newArrayList();
- for (Optional<V> element : values) {
- result.add(element != null ? element.orNull() : null);
+ // This may still block in spite of the calls above, as the listeners may
+ // be scheduled for execution in other threads.
+ return super.get();
+ }
+
+ /**
+ * Calls the get method of all dependency futures to work around a bug in
+ * some ListenableFutures where the listeners aren't called until get() is
+ * called.
+ */
+ private void callAllGets() throws InterruptedException {
+ List<? extends ListenableFuture<? extends V>> oldFutures = futures;
+ if (oldFutures != null && !isDone()) {
+ for (ListenableFuture<? extends V> future : oldFutures) {
+ // We wait for a little while for the future, but if it's not done,
+ // we check that no other futures caused a cancellation or failure.
+ // This can introduce a delay of up to 10ms in reporting an exception.
+ while (!future.isDone()) {
+ try {
+ future.get();
+ } catch (Error e) {
+ throw e;
+ } catch (InterruptedException e) {
+ throw e;
+ } catch (Throwable e) {
+ // ExecutionException / CancellationException / RuntimeException
+ if (allMustSucceed) {
+ return;
+ } else {
+ continue;
+ }
}
- // TODO(user): This should ultimately return an unmodifiableList
- return result;
}
- });
+ }
+ }
+ }
}
/**
diff --git a/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java b/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java
index 645a648..6d74bda 100644
--- a/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java
+++ b/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java
@@ -19,6 +19,7 @@ package com.google.common.util.concurrent;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -41,7 +42,7 @@ public final class JdkFutureAdapters {
* Assigns a thread to the given {@link Future} to provide {@link
* ListenableFuture} functionality.
*
- * <p><b>Warning:</b> If the input future does not already implement {@code
+ * <p><b>Warning:</b> If the input future does not already implement {@link
* ListenableFuture}, the returned future will emulate {@link
* ListenableFuture#addListener} by taking a thread from an internal,
* unbounded pool at the first call to {@code addListener} and holding it
@@ -56,40 +57,17 @@ public final class JdkFutureAdapters {
*/
public static <V> ListenableFuture<V> listenInPoolThread(
Future<V> future) {
- if (future instanceof ListenableFuture) {
+ if (future instanceof ListenableFuture<?>) {
return (ListenableFuture<V>) future;
}
return new ListenableFutureAdapter<V>(future);
}
- /**
- * Submits a blocking task for the given {@link Future} to provide {@link
- * ListenableFuture} functionality.
- *
- * <p><b>Warning:</b> If the input future does not already implement {@code
- * ListenableFuture}, the returned future will emulate {@link
- * ListenableFuture#addListener} by submitting a task to the given executor at
- * at the first call to {@code addListener}. The task must be started by the
- * executor promptly, or else the returned {@code ListenableFuture} may fail
- * to work. The task's execution consists of blocking until the input future
- * is {@linkplain Future#isDone() done}, so each call to this method may
- * claim and hold a thread for an arbitrary length of time. Use of bounded
- * executors or other executors that may fail to execute a task promptly may
- * result in deadlocks.
- *
- * <p>Prefer to create {@code ListenableFuture} instances with {@link
- * SettableFuture}, {@link MoreExecutors#listeningDecorator(
- * java.util.concurrent.ExecutorService)}, {@link ListenableFutureTask},
- * {@link AbstractFuture}, and other utilities over creating plain {@code
- * Future} instances to be upgraded to {@code ListenableFuture} after the
- * fact.
- *
- * @since 12.0
- */
- public static <V> ListenableFuture<V> listenInPoolThread(
+ @VisibleForTesting
+ static <V> ListenableFuture<V> listenInPoolThread(
Future<V> future, Executor executor) {
checkNotNull(executor);
- if (future instanceof ListenableFuture) {
+ if (future instanceof ListenableFuture<?>) {
return (ListenableFuture<V>) future;
}
return new ListenableFutureAdapter<V>(future, executor);
diff --git a/guava/src/com/google/common/util/concurrent/ListenableFuture.java b/guava/src/com/google/common/util/concurrent/ListenableFuture.java
index eb05354..a0ab2db 100644
--- a/guava/src/com/google/common/util/concurrent/ListenableFuture.java
+++ b/guava/src/com/google/common/util/concurrent/ListenableFuture.java
@@ -28,10 +28,6 @@ import java.util.concurrent.RejectedExecutionException;
* computation is {@linkplain Future#isDone() complete}. If the computation has
* already completed when the listener is added, the listener will execute
* immediately.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained">
- * {@code ListenableFuture}</a>.
*
* <h3>Purpose</h3>
*
@@ -102,28 +98,20 @@ public interface ListenableFuture<V> extends Future<V> {
*
* <p>Note: For fast, lightweight listeners that would be safe to execute in
* any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier
- * listeners, {@code sameThreadExecutor()} carries some caveats. For
- * example, the listener may run on an unpredictable or undesirable thread:
+ * listeners, {@code sameThreadExecutor()} carries some caveats: First, the
+ * thread that the listener runs in depends on whether the {@code Future} is
+ * done at the time it is added and on whether it is ever canclled. In
+ * particular, listeners may run in the thread that calls {@code addListener}
+ * or the thread that calls {@code cancel}. Second, listeners may run in an
+ * internal thread of the system responsible for the input {@code Future},
+ * such as an RPC network thread. Finally, during the execution of a {@code
+ * sameThreadExecutor()} listener, all other registered but unexecuted
+ * listeners are prevented from running, even if those listeners are to run
+ * in other executors.
*
- * <ul>
- * <li>If the input {@code Future} is done at the time {@code addListener} is
- * called, {@code addListener} will execute the listener inline.
- * <li>If the input {@code Future} is not yet done, {@code addListener} will
- * schedule the listener to be run by the thread that completes the input
- * {@code Future}, which may be an internal system thread such as an RPC
- * network thread.
- * </ul>
- *
- * Also note that, regardless of which thread executes the listener, all
- * other registered but unexecuted listeners are prevented from running
- * during its execution, even if those listeners are to run in other
- * executors.
- *
- * <p>This is the most general listener interface. For common operations
- * performed using listeners, see {@link
- * com.google.common.util.concurrent.Futures}. For a simplified but general
- * listener interface, see {@link
- * com.google.common.util.concurrent.Futures#addCallback addCallback()}.
+ * <p>This is the most general listener interface.
+ * For common operations performed using listeners,
+ * see {@link com.google.common.util.concurrent.Futures}
*
* @param listener the listener to run when the computation is complete
* @param executor the executor to run the listener in
diff --git a/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java b/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java
index 35d6f13..474635c 100644
--- a/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java
+++ b/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java
@@ -27,17 +27,12 @@ import javax.annotation.Nullable;
* interface. Unlike {@code FutureTask}, {@code ListenableFutureTask} does not
* provide an overrideable {@link FutureTask#done() done()} method. For similar
* functionality, call {@link #addListener}.
- *
- * <p>
*
* @author Sven Mawson
* @since 1.0
*/
-public class ListenableFutureTask<V> extends FutureTask<V>
+public final class ListenableFutureTask<V> extends FutureTask<V>
implements ListenableFuture<V> {
- // TODO(cpovirk): explore ways of making ListenableFutureTask final. There are
- // some valid reasons such as BoundedQueueExecutorService to allow extends but it
- // would be nice to make it final to avoid unintended usage.
// The execution list to hold our listeners.
private final ExecutionList executionList = new ExecutionList();
@@ -70,11 +65,11 @@ public class ListenableFutureTask<V> extends FutureTask<V>
return new ListenableFutureTask<V>(runnable, result);
}
- ListenableFutureTask(Callable<V> callable) {
+ private ListenableFutureTask(Callable<V> callable) {
super(callable);
}
- ListenableFutureTask(Runnable runnable, @Nullable V result) {
+ private ListenableFutureTask(Runnable runnable, @Nullable V result) {
super(runnable, result);
}
diff --git a/guava/src/com/google/common/util/concurrent/MoreExecutors.java b/guava/src/com/google/common/util/concurrent/MoreExecutors.java
index bd94db7..915b96d 100644
--- a/guava/src/com/google/common/util/concurrent/MoreExecutors.java
+++ b/guava/src/com/google/common/util/concurrent/MoreExecutors.java
@@ -16,26 +16,15 @@
package com.google.common.util.concurrent;
-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.VisibleForTesting;
-import com.google.common.base.Throwables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Queues;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Collection;
import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
-import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -44,7 +33,6 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -79,8 +67,16 @@ public final class MoreExecutors {
@Beta
public static ExecutorService getExitingExecutorService(
ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
- return new Application()
- .getExitingExecutorService(executor, terminationTimeout, timeUnit);
+ executor.setThreadFactory(new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setThreadFactory(executor.getThreadFactory())
+ .build());
+
+ ExecutorService service = Executors.unconfigurableExecutorService(executor);
+
+ addDelayedShutdownHook(service, terminationTimeout, timeUnit);
+
+ return service;
}
/**
@@ -101,9 +97,19 @@ public final class MoreExecutors {
*/
@Beta
public static ScheduledExecutorService getExitingScheduledExecutorService(
- ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
- return new Application()
- .getExitingScheduledExecutorService(executor, terminationTimeout, timeUnit);
+ ScheduledThreadPoolExecutor executor, long terminationTimeout,
+ TimeUnit timeUnit) {
+ executor.setThreadFactory(new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setThreadFactory(executor.getThreadFactory())
+ .build());
+
+ ScheduledExecutorService service =
+ Executors.unconfigurableScheduledExecutorService(executor);
+
+ addDelayedShutdownHook(service, terminationTimeout, timeUnit);
+
+ return service;
}
/**
@@ -119,9 +125,24 @@ public final class MoreExecutors {
*/
@Beta
public static void addDelayedShutdownHook(
- ExecutorService service, long terminationTimeout, TimeUnit timeUnit) {
- new Application()
- .addDelayedShutdownHook(service, terminationTimeout, timeUnit);
+ final ExecutorService service, final long terminationTimeout,
+ final TimeUnit timeUnit) {
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // We'd like to log progress and failures that may arise in the
+ // following code, but unfortunately the behavior of logging
+ // is undefined in shutdown hooks.
+ // This is because the logging code installs a shutdown hook of its
+ // own. See Cleaner class inside {@link LogManager}.
+ service.shutdown();
+ service.awaitTermination(terminationTimeout, timeUnit);
+ } catch (InterruptedException ignored) {
+ // We're shutting down anyway, so just ignore.
+ }
+ }
+ }));
}
/**
@@ -140,8 +161,9 @@ public final class MoreExecutors {
* @return an unmodifiable version of the input which will not hang the JVM
*/
@Beta
- public static ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) {
- return new Application().getExitingExecutorService(executor);
+ public static ExecutorService getExitingExecutorService(
+ ThreadPoolExecutor executor) {
+ return getExitingExecutorService(executor, 120, TimeUnit.SECONDS);
}
/**
@@ -162,69 +184,7 @@ public final class MoreExecutors {
@Beta
public static ScheduledExecutorService getExitingScheduledExecutorService(
ScheduledThreadPoolExecutor executor) {
- return new Application().getExitingScheduledExecutorService(executor);
- }
-
- /** Represents the current application to register shutdown hooks. */
- @VisibleForTesting static class Application {
-
- final ExecutorService getExitingExecutorService(
- ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
- useDaemonThreadFactory(executor);
- ExecutorService service = Executors.unconfigurableExecutorService(executor);
- addDelayedShutdownHook(service, terminationTimeout, timeUnit);
- return service;
- }
-
- final ScheduledExecutorService getExitingScheduledExecutorService(
- ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
- useDaemonThreadFactory(executor);
- ScheduledExecutorService service = Executors.unconfigurableScheduledExecutorService(executor);
- addDelayedShutdownHook(service, terminationTimeout, timeUnit);
- return service;
- }
-
- final void addDelayedShutdownHook(
- final ExecutorService service, final long terminationTimeout, final TimeUnit timeUnit) {
- checkNotNull(service);
- checkNotNull(timeUnit);
- addShutdownHook(MoreExecutors.newThread("DelayedShutdownHook-for-" + service, new Runnable() {
- @Override
- public void run() {
- try {
- // We'd like to log progress and failures that may arise in the
- // following code, but unfortunately the behavior of logging
- // is undefined in shutdown hooks.
- // This is because the logging code installs a shutdown hook of its
- // own. See Cleaner class inside {@link LogManager}.
- service.shutdown();
- service.awaitTermination(terminationTimeout, timeUnit);
- } catch (InterruptedException ignored) {
- // We're shutting down anyway, so just ignore.
- }
- }
- }));
- }
-
- final ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) {
- return getExitingExecutorService(executor, 120, TimeUnit.SECONDS);
- }
-
- final ScheduledExecutorService getExitingScheduledExecutorService(
- ScheduledThreadPoolExecutor executor) {
- return getExitingScheduledExecutorService(executor, 120, TimeUnit.SECONDS);
- }
-
- @VisibleForTesting void addShutdownHook(Thread hook) {
- Runtime.getRuntime().addShutdownHook(hook);
- }
- }
-
- private static void useDaemonThreadFactory(ThreadPoolExecutor executor) {
- executor.setThreadFactory(new ThreadFactoryBuilder()
- .setDaemon(true)
- .setThreadFactory(executor.getThreadFactory())
- .build());
+ return getExitingScheduledExecutorService(executor, 120, TimeUnit.SECONDS);
}
/**
@@ -483,7 +443,6 @@ public final class MoreExecutors {
private static class ScheduledListeningDecorator
extends ListeningDecorator implements ListeningScheduledExecutorService {
- @SuppressWarnings("hiding")
final ScheduledExecutorService delegate;
ScheduledListeningDecorator(ScheduledExecutorService delegate) {
@@ -516,172 +475,4 @@ public final class MoreExecutors {
command, initialDelay, delay, unit);
}
}
-
- /*
- * This following method is a modified version of one found in
- * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck/AbstractExecutorServiceTest.java?revision=1.30
- * which contained the following notice:
- *
- * 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/publicdomain/zero/1.0/
- * Other contributors include Andrew Wright, Jeffrey Hayes,
- * Pat Fisher, Mike Judd.
- */
-
- /**
- * An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService}
- * implementations.
- */ static <T> T invokeAnyImpl(ListeningExecutorService executorService,
- Collection<? extends Callable<T>> tasks, boolean timed, long nanos)
- throws InterruptedException, ExecutionException, TimeoutException {
- checkNotNull(executorService);
- int ntasks = tasks.size();
- checkArgument(ntasks > 0);
- List<Future<T>> futures = Lists.newArrayListWithCapacity(ntasks);
- BlockingQueue<Future<T>> futureQueue = Queues.newLinkedBlockingQueue();
-
- // For efficiency, especially in executors with limited
- // parallelism, check to see if previously submitted tasks are
- // done before submitting more of them. This interleaving
- // plus the exception mechanics account for messiness of main
- // loop.
-
- try {
- // Record exceptions so that if we fail to obtain any
- // result, we can throw the last exception we got.
- ExecutionException ee = null;
- long lastTime = timed ? System.nanoTime() : 0;
- Iterator<? extends Callable<T>> it = tasks.iterator();
-
- futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue));
- --ntasks;
- int active = 1;
-
- for (;;) {
- Future<T> f = futureQueue.poll();
- if (f == null) {
- if (ntasks > 0) {
- --ntasks;
- futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue));
- ++active;
- } else if (active == 0) {
- break;
- } else if (timed) {
- f = futureQueue.poll(nanos, TimeUnit.NANOSECONDS);
- if (f == null) {
- throw new TimeoutException();
- }
- long now = System.nanoTime();
- nanos -= now - lastTime;
- lastTime = now;
- } else {
- f = futureQueue.take();
- }
- }
- if (f != null) {
- --active;
- try {
- return f.get();
- } catch (ExecutionException eex) {
- ee = eex;
- } catch (RuntimeException rex) {
- ee = new ExecutionException(rex);
- }
- }
- }
-
- if (ee == null) {
- ee = new ExecutionException(null);
- }
- throw ee;
- } finally {
- for (Future<T> f : futures) {
- f.cancel(true);
- }
- }
- }
-
- /**
- * Submits the task and adds a listener that adds the future to {@code queue} when it completes.
- */
- private static <T> ListenableFuture<T> submitAndAddQueueListener(
- ListeningExecutorService executorService, Callable<T> task,
- final BlockingQueue<Future<T>> queue) {
- final ListenableFuture<T> future = executorService.submit(task);
- future.addListener(new Runnable() {
- @Override public void run() {
- queue.add(future);
- }
- }, MoreExecutors.sameThreadExecutor());
- return future;
- }
-
- /**
- * Returns a default thread factory used to create new threads.
- *
- * <p>On AppEngine, returns {@code ThreadManager.currentRequestThreadFactory()}.
- * Otherwise, returns {@link Executors#defaultThreadFactory()}.
- *
- * @since 14.0
- */
- @Beta
- public static ThreadFactory platformThreadFactory() {
- if (!isAppEngine()) {
- return Executors.defaultThreadFactory();
- }
- try {
- return (ThreadFactory) Class.forName("com.google.appengine.api.ThreadManager")
- .getMethod("currentRequestThreadFactory")
- .invoke(null);
- } catch (IllegalAccessException e) {
- throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e);
- } catch (InvocationTargetException e) {
- throw Throwables.propagate(e.getCause());
- }
- }
-
- private static boolean isAppEngine() {
- if (System.getProperty("com.google.appengine.runtime.environment") == null) {
- return false;
- }
- try {
- // If the current environment is null, we're not inside AppEngine.
- return Class.forName("com.google.apphosting.api.ApiProxy")
- .getMethod("getCurrentEnvironment")
- .invoke(null) != null;
- } catch (ClassNotFoundException e) {
- // If ApiProxy doesn't exist, we're not on AppEngine at all.
- return false;
- } catch (InvocationTargetException e) {
- // If ApiProxy throws an exception, we're not in a proper AppEngine environment.
- return false;
- } catch (IllegalAccessException e) {
- // If the method isn't accessible, we're not on a supported version of AppEngine;
- return false;
- } catch (NoSuchMethodException e) {
- // If the method doesn't exist, we're not on a supported version of AppEngine;
- return false;
- }
- }
-
- /**
- * Creates a thread using {@link #platformThreadFactory}, and sets its name to {@code name}
- * unless changing the name is forbidden by the security manager.
- */
- static Thread newThread(String name, Runnable runnable) {
- checkNotNull(name);
- checkNotNull(runnable);
- Thread result = platformThreadFactory().newThread(runnable);
- try {
- result.setName(name);
- } catch (SecurityException e) {
- // OK if we can't set the name in this environment.
- }
- return result;
- }
}
diff --git a/guava/src/com/google/common/util/concurrent/RateLimiter.java b/guava/src/com/google/common/util/concurrent/RateLimiter.java
deleted file mode 100644
index 4085654..0000000
--- a/guava/src/com/google/common/util/concurrent/RateLimiter.java
+++ /dev/null
@@ -1,690 +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.util.concurrent;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Ticker;
-
-import java.util.concurrent.TimeUnit;
-
-import javax.annotation.concurrent.ThreadSafe;
-
-/**
- * A rate limiter. Conceptually, a rate limiter distributes permits at a
- * configurable rate. Each {@link #acquire()} blocks if necessary until a permit is
- * available, and then takes it. Once acquired, permits need not be released.
- *
- * <p>Rate limiters are often used to restrict the rate at which some
- * physical or logical resource is accessed. This is in contrast to {@link
- * java.util.concurrent.Semaphore} which restricts the number of concurrent
- * accesses instead of the rate (note though that concurrency and rate are closely related,
- * e.g. see <a href="http://en.wikipedia.org/wiki/Little's_law">Little's Law</a>).
- *
- * <p>A {@code RateLimiter} is defined primarily by the rate at which permits
- * are issued. Absent additional configuration, permits will be distributed at a
- * fixed rate, defined in terms of permits per second. Permits will be distributed
- * smoothly, with the delay between individual permits being adjusted to ensure
- * that the configured rate is maintained.
- *
- * <p>It is possible to configure a {@code RateLimiter} to have a warmup
- * period during which time the permits issued each second steadily increases until
- * it hits the stable rate.
- *
- * <p>As an example, imagine that we have a list of tasks to execute, but we don't want to
- * submit more than 2 per second:
- *<pre> {@code
- * final RateLimiter rateLimiter = RateLimiter.create(2.0); // rate is "2 permits per second"
- * void submitTasks(List<Runnable> tasks, Executor executor) {
- * for (Runnable task : tasks) {
- * rateLimiter.acquire(); // may wait
- * executor.execute(task);
- * }
- * }
- *}</pre>
- *
- * <p>As another example, imagine that we produce a stream of data, and we want to cap it
- * at 5kb per second. This could be accomplished by requiring a permit per byte, and specifying
- * a rate of 5000 permits per second:
- *<pre> {@code
- * final RateLimiter rateLimiter = RateLimiter.create(5000.0); // rate = 5000 permits per second
- * void submitPacket(byte[] packet) {
- * rateLimiter.acquire(packet.length);
- * networkService.send(packet);
- * }
- *}</pre>
- *
- * <p>It is important to note that the number of permits requested <i>never</i>
- * affect the throttling of the request itself (an invocation to {@code acquire(1)}
- * and an invocation to {@code acquire(1000)} will result in exactly the same throttling, if any),
- * but it affects the throttling of the <i>next</i> request. I.e., if an expensive task
- * arrives at an idle RateLimiter, it will be granted immediately, but it is the <i>next</i>
- * request that will experience extra throttling, thus paying for the cost of the expensive
- * task.
- *
- * <p>Note: {@code RateLimiter} does not provide fairness guarantees.
- *
- * @author Dimitris Andreou
- * @since 13.0
- */
-// TODO(user): switch to nano precision. A natural unit of cost is "bytes", and a micro precision
-// would mean a maximum rate of "1MB/s", which might be small in some cases.
-@ThreadSafe
-@Beta
-public abstract class RateLimiter {
- /*
- * How is the RateLimiter designed, and why?
- *
- * The primary feature of a RateLimiter is its "stable rate", the maximum rate that
- * is should allow at normal conditions. This is enforced by "throttling" incoming
- * requests as needed, i.e. compute, for an incoming request, the appropriate throttle time,
- * and make the calling thread wait as much.
- *
- * The simplest way to maintain a rate of QPS is to keep the timestamp of the last
- * granted request, and ensure that (1/QPS) seconds have elapsed since then. For example,
- * for a rate of QPS=5 (5 tokens per second), if we ensure that a request isn't granted
- * earlier than 200ms after the the last one, then we achieve the intended rate.
- * If a request comes and the last request was granted only 100ms ago, then we wait for
- * another 100ms. At this rate, serving 15 fresh permits (i.e. for an acquire(15) request)
- * naturally takes 3 seconds.
- *
- * It is important to realize that such a RateLimiter has a very superficial memory
- * of the past: it only remembers the last request. What if the RateLimiter was unused for
- * a long period of time, then a request arrived and was immediately granted?
- * This RateLimiter would immediately forget about that past underutilization. This may
- * result in either underutilization or overflow, depending on the real world consequences
- * of not using the expected rate.
- *
- * Past underutilization could mean that excess resources are available. Then, the RateLimiter
- * should speed up for a while, to take advantage of these resources. This is important
- * when the rate is applied to networking (limiting bandwidth), where past underutilization
- * typically translates to "almost empty buffers", which can be filled immediately.
- *
- * On the other hand, past underutilization could mean that "the server responsible for
- * handling the request has become less ready for future requests", i.e. its caches become
- * stale, and requests become more likely to trigger expensive operations (a more extreme
- * case of this example is when a server has just booted, and it is mostly busy with getting
- * itself up to speed).
- *
- * To deal with such scenarios, we add an extra dimension, that of "past underutilization",
- * modeled by "storedPermits" variable. This variable is zero when there is no
- * underutilization, and it can grow up to maxStoredPermits, for sufficiently large
- * underutilization. So, the requested permits, by an invocation acquire(permits),
- * are served from:
- * - stored permits (if available)
- * - fresh permits (for any remaining permits)
- *
- * How this works is best explained with an example:
- *
- * For a RateLimiter that produces 1 token per second, every second
- * that goes by with the RateLimiter being unused, we increase storedPermits by 1.
- * Say we leave the RateLimiter unused for 10 seconds (i.e., we expected a request at time
- * X, but we are at time X + 10 seconds before a request actually arrives; this is
- * also related to the point made in the last paragraph), thus storedPermits
- * becomes 10.0 (assuming maxStoredPermits >= 10.0). At that point, a request of acquire(3)
- * arrives. We serve this request out of storedPermits, and reduce that to 7.0 (how this is
- * translated to throttling time is discussed later). Immediately after, assume that an
- * acquire(10) request arriving. We serve the request partly from storedPermits,
- * using all the remaining 7.0 permits, and the remaining 3.0, we serve them by fresh permits
- * produced by the rate limiter.
- *
- * We already know how much time it takes to serve 3 fresh permits: if the rate is
- * "1 token per second", then this will take 3 seconds. But what does it mean to serve 7
- * stored permits? As explained above, there is no unique answer. If we are primarily
- * interested to deal with underutilization, then we want stored permits to be given out
- * /faster/ than fresh ones, because underutilization = free resources for the taking.
- * If we are primarily interested to deal with overflow, then stored permits could
- * be given out /slower/ than fresh ones. Thus, we require a (different in each case)
- * function that translates storedPermits to throtting time.
- *
- * This role is played by storedPermitsToWaitTime(double storedPermits, double permitsToTake).
- * The underlying model is a continuous function mapping storedPermits
- * (from 0.0 to maxStoredPermits) onto the 1/rate (i.e. intervals) that is effective at the given
- * storedPermits. "storedPermits" essentially measure unused time; we spend unused time
- * buying/storing permits. Rate is "permits / time", thus "1 / rate = time / permits".
- * Thus, "1/rate" (time / permits) times "permits" gives time, i.e., integrals on this
- * function (which is what storedPermitsToWaitTime() computes) correspond to minimum intervals
- * between subsequent requests, for the specified number of requested permits.
- *
- * Here is an example of storedPermitsToWaitTime:
- * If storedPermits == 10.0, and we want 3 permits, we take them from storedPermits,
- * reducing them to 7.0, and compute the throttling for these as a call to
- * storedPermitsToWaitTime(storedPermits = 10.0, permitsToTake = 3.0), which will
- * evaluate the integral of the function from 7.0 to 10.0.
- *
- * Using integrals guarantees that the effect of a single acquire(3) is equivalent
- * to { acquire(1); acquire(1); acquire(1); }, or { acquire(2); acquire(1); }, etc,
- * since the integral of the function in [7.0, 10.0] is equivalent to the sum of the
- * integrals of [7.0, 8.0], [8.0, 9.0], [9.0, 10.0] (and so on), no matter
- * what the function is. This guarantees that we handle correctly requests of varying weight
- * (permits), /no matter/ what the actual function is - so we can tweak the latter freely.
- * (The only requirement, obviously, is that we can compute its integrals).
- *
- * Note well that if, for this function, we chose a horizontal line, at height of exactly
- * (1/QPS), then the effect of the function is non-existent: we serve storedPermits at
- * exactly the same cost as fresh ones (1/QPS is the cost for each). We use this trick later.
- *
- * If we pick a function that goes /below/ that horizontal line, it means that we reduce
- * the area of the function, thus time. Thus, the RateLimiter becomes /faster/ after a
- * period of underutilization. If, on the other hand, we pick a function that
- * goes /above/ that horizontal line, then it means that the area (time) is increased,
- * thus storedPermits are more costly than fresh permits, thus the RateLimiter becomes
- * /slower/ after a period of underutilization.
- *
- * Last, but not least: consider a RateLimiter with rate of 1 permit per second, currently
- * completely unused, and an expensive acquire(100) request comes. It would be nonsensical
- * to just wait for 100 seconds, and /then/ start the actual task. Why wait without doing
- * anything? A much better approach is to /allow/ the request right away (as if it was an
- * acquire(1) request instead), and postpone /subsequent/ requests as needed. In this version,
- * we allow starting the task immediately, and postpone by 100 seconds future requests,
- * thus we allow for work to get done in the meantime instead of waiting idly.
- *
- * This has important consequences: it means that the RateLimiter doesn't remember the time
- * of the _last_ request, but it remembers the (expected) time of the _next_ request. This
- * also enables us to tell immediately (see tryAcquire(timeout)) whether a particular
- * timeout is enough to get us to the point of the next scheduling time, since we always
- * maintain that. And what we mean by "an unused RateLimiter" is also defined by that
- * notion: when we observe that the "expected arrival time of the next request" is actually
- * in the past, then the difference (now - past) is the amount of time that the RateLimiter
- * was formally unused, and it is that amount of time which we translate to storedPermits.
- * (We increase storedPermits with the amount of permits that would have been produced
- * in that idle time). So, if rate == 1 permit per second, and arrivals come exactly
- * one second after the previous, then storedPermits is _never_ increased -- we would only
- * increase it for arrivals _later_ than the expected one second.
- */
-
- /**
- * Creates a {@code RateLimiter} with the specified stable throughput, given as
- * "permits per second" (commonly referred to as <i>QPS</i>, queries per second).
- *
- * <p>The returned {@code RateLimiter} ensures that on average no more than {@code
- * permitsPerSecond} are issued during any given second, with sustained requests
- * being smoothly spread over each second. When the incoming request rate exceeds
- * {@code permitsPerSecond} the rate limiter will release one permit every {@code
- * (1.0 / permitsPerSecond)} seconds. When the rate limiter is unused,
- * bursts of up to {@code permitsPerSecond} permits will be allowed, with subsequent
- * requests being smoothly limited at the stable rate of {@code permitsPerSecond}.
- *
- * @param permitsPerSecond the rate of the returned {@code RateLimiter}, measured in
- * how many permits become available per second.
- */
- public static RateLimiter create(double permitsPerSecond) {
- return create(SleepingTicker.SYSTEM_TICKER, permitsPerSecond);
- }
-
- @VisibleForTesting
- static RateLimiter create(SleepingTicker ticker, double permitsPerSecond) {
- RateLimiter rateLimiter = new Bursty(ticker);
- rateLimiter.setRate(permitsPerSecond);
- return rateLimiter;
- }
-
- /**
- * Creates a {@code RateLimiter} with the specified stable throughput, given as
- * "permits per second" (commonly referred to as <i>QPS</i>, queries per second), and a
- * <i>warmup period</i>, during which the {@code RateLimiter} smoothly ramps up its rate,
- * until it reaches its maximum rate at the end of the period (as long as there are enough
- * requests to saturate it). Similarly, if the {@code RateLimiter} is left <i>unused</i> for
- * a duration of {@code warmupPeriod}, it will gradually return to its "cold" state,
- * i.e. it will go through the same warming up process as when it was first created.
- *
- * <p>The returned {@code RateLimiter} is intended for cases where the resource that actually
- * fulfils the requests (e.g., a remote server) needs "warmup" time, rather than
- * being immediately accessed at the stable (maximum) rate.
- *
- * <p>The returned {@code RateLimiter} starts in a "cold" state (i.e. the warmup period
- * will follow), and if it is left unused for long enough, it will return to that state.
- *
- * @param permitsPerSecond the rate of the returned {@code RateLimiter}, measured in
- * how many permits become available per second
- * @param warmupPeriod the duration of the period where the {@code RateLimiter} ramps up its
- * rate, before reaching its stable (maximum) rate
- * @param unit the time unit of the warmupPeriod argument
- */
- // TODO(user): add a burst size of 1-second-worth of permits, as in the metronome?
- public static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit) {
- return create(SleepingTicker.SYSTEM_TICKER, permitsPerSecond, warmupPeriod, unit);
- }
-
- @VisibleForTesting
- static RateLimiter create(
- SleepingTicker ticker, double permitsPerSecond, long warmupPeriod, TimeUnit timeUnit) {
- RateLimiter rateLimiter = new WarmingUp(ticker, warmupPeriod, timeUnit);
- rateLimiter.setRate(permitsPerSecond);
- return rateLimiter;
- }
-
- @VisibleForTesting
- static RateLimiter createBursty(
- SleepingTicker ticker, double permitsPerSecond, int maxBurstSize) {
- Bursty rateLimiter = new Bursty(ticker);
- rateLimiter.setRate(permitsPerSecond);
- rateLimiter.maxPermits = maxBurstSize;
- return rateLimiter;
- }
-
- /**
- * The underlying timer; used both to measure elapsed time and sleep as necessary. A separate
- * object to facilitate testing.
- */
- private final SleepingTicker ticker;
-
- /**
- * The timestamp when the RateLimiter was created; used to avoid possible overflow/time-wrapping
- * errors.
- */
- private final long offsetNanos;
-
- /**
- * The currently stored permits.
- */
- double storedPermits;
-
- /**
- * The maximum number of stored permits.
- */
- double maxPermits;
-
- /**
- * The interval between two unit requests, at our stable rate. E.g., a stable rate of 5 permits
- * per second has a stable interval of 200ms.
- */
- volatile double stableIntervalMicros;
-
- private final Object mutex = new Object();
-
- /**
- * The time when the next request (no matter its size) will be granted. After granting a request,
- * this is pushed further in the future. Large requests push this further than small requests.
- */
- private long nextFreeTicketMicros = 0L; // could be either in the past or future
-
- private RateLimiter(SleepingTicker ticker) {
- this.ticker = ticker;
- this.offsetNanos = ticker.read();
- }
-
- /**
- * Updates the stable rate of this {@code RateLimiter}, that is, the
- * {@code permitsPerSecond} argument provided in the factory method that
- * constructed the {@code RateLimiter}. Currently throttled threads will <b>not</b>
- * be awakened as a result of this invocation, thus they do not observe the new rate;
- * only subsequent requests will.
- *
- * <p>Note though that, since each request repays (by waiting, if necessary) the cost
- * of the <i>previous</i> request, this means that the very next request
- * after an invocation to {@code setRate} will not be affected by the new rate;
- * it will pay the cost of the previous request, which is in terms of the previous rate.
- *
- * <p>The behavior of the {@code RateLimiter} is not modified in any other way,
- * e.g. if the {@code RateLimiter} was configured with a warmup period of 20 seconds,
- * it still has a warmup period of 20 seconds after this method invocation.
- *
- * @param permitsPerSecond the new stable rate of this {@code RateLimiter}.
- */
- public final void setRate(double permitsPerSecond) {
- Preconditions.checkArgument(permitsPerSecond > 0.0
- && !Double.isNaN(permitsPerSecond), "rate must be positive");
- synchronized (mutex) {
- resync(readSafeMicros());
- double stableIntervalMicros = TimeUnit.SECONDS.toMicros(1L) / permitsPerSecond;
- this.stableIntervalMicros = stableIntervalMicros;
- doSetRate(permitsPerSecond, stableIntervalMicros);
- }
- }
-
- abstract void doSetRate(double permitsPerSecond, double stableIntervalMicros);
-
- /**
- * Returns the stable rate (as {@code permits per seconds}) with which this
- * {@code RateLimiter} is configured with. The initial value of this is the same as
- * the {@code permitsPerSecond} argument passed in the factory method that produced
- * this {@code RateLimiter}, and it is only updated after invocations
- * to {@linkplain #setRate}.
- */
- public final double getRate() {
- return TimeUnit.SECONDS.toMicros(1L) / stableIntervalMicros;
- }
-
- /**
- * Acquires a permit from this {@code RateLimiter}, blocking until the request can be granted.
- *
- * <p>This method is equivalent to {@code acquire(1)}.
- */
- public void acquire() {
- acquire(1);
- }
-
- /**
- * Acquires the given number of permits from this {@code RateLimiter}, blocking until the
- * request be granted.
- *
- * @param permits the number of permits to acquire
- */
- public void acquire(int permits) {
- checkPermits(permits);
- long microsToWait;
- synchronized (mutex) {
- microsToWait = reserveNextTicket(permits, readSafeMicros());
- }
- ticker.sleepMicrosUninterruptibly(microsToWait);
- }
-
- /**
- * Acquires a permit from this {@code RateLimiter} if it can be obtained
- * without exceeding the specified {@code timeout}, or returns {@code false}
- * immediately (without waiting) if the permit would not have been granted
- * before the timeout expired.
- *
- * <p>This method is equivalent to {@code tryAcquire(1, timeout, unit)}.
- *
- * @param timeout the maximum time to wait for the permit
- * @param unit the time unit of the timeout argument
- * @return {@code true} if the permit was acquired, {@code false} otherwise
- */
- public boolean tryAcquire(long timeout, TimeUnit unit) {
- return tryAcquire(1, timeout, unit);
- }
-
- /**
- * Acquires permits from this {@link RateLimiter} if it can be acquired immediately without delay.
- *
- * <p>
- * This method is equivalent to {@code tryAcquire(permits, 0, anyUnit)}.
- *
- * @param permits the number of permits to acquire
- * @return {@code true} if the permits were acquired, {@code false} otherwise
- * @since 14.0
- */
- public boolean tryAcquire(int permits) {
- return tryAcquire(permits, 0, TimeUnit.MICROSECONDS);
- }
-
- /**
- * Acquires a permit from this {@link RateLimiter} if it can be acquired immediately without
- * delay.
- *
- * <p>
- * This method is equivalent to {@code tryAcquire(1)}.
- *
- * @return {@code true} if the permit was acquired, {@code false} otherwise
- * @since 14.0
- */
- public boolean tryAcquire() {
- return tryAcquire(1, 0, TimeUnit.MICROSECONDS);
- }
-
- /**
- * Acquires the given number of permits from this {@code RateLimiter} if it can be obtained
- * without exceeding the specified {@code timeout}, or returns {@code false}
- * immediately (without waiting) if the permits would not have been granted
- * before the timeout expired.
- *
- * @param permits the number of permits to acquire
- * @param timeout the maximum time to wait for the permits
- * @param unit the time unit of the timeout argument
- * @return {@code true} if the permits were acquired, {@code false} otherwise
- */
- public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
- long timeoutMicros = unit.toMicros(timeout);
- checkPermits(permits);
- long microsToWait;
- synchronized (mutex) {
- long nowMicros = readSafeMicros();
- if (nextFreeTicketMicros > nowMicros + timeoutMicros) {
- return false;
- } else {
- microsToWait = reserveNextTicket(permits, nowMicros);
- }
- }
- ticker.sleepMicrosUninterruptibly(microsToWait);
- return true;
- }
-
- private static void checkPermits(int permits) {
- Preconditions.checkArgument(permits > 0, "Requested permits must be positive");
- }
-
- /**
- * Reserves next ticket and returns the wait time that the caller must wait for.
- */
- private long reserveNextTicket(double requiredPermits, long nowMicros) {
- resync(nowMicros);
- long microsToNextFreeTicket = nextFreeTicketMicros - nowMicros;
- double storedPermitsToSpend = Math.min(requiredPermits, this.storedPermits);
- double freshPermits = requiredPermits - storedPermitsToSpend;
-
- long waitMicros = storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
- + (long) (freshPermits * stableIntervalMicros);
-
- this.nextFreeTicketMicros = nextFreeTicketMicros + waitMicros;
- this.storedPermits -= storedPermitsToSpend;
- return microsToNextFreeTicket;
- }
-
- /**
- * Translates a specified portion of our currently stored permits which we want to
- * spend/acquire, into a throttling time. Conceptually, this evaluates the integral
- * of the underlying function we use, for the range of
- * [(storedPermits - permitsToTake), storedPermits].
- *
- * This always holds: {@code 0 <= permitsToTake <= storedPermits}
- */
- abstract long storedPermitsToWaitTime(double storedPermits, double permitsToTake);
-
- private void resync(long nowMicros) {
- // if nextFreeTicket is in the past, resync to now
- if (nowMicros > nextFreeTicketMicros) {
- storedPermits = Math.min(maxPermits,
- storedPermits + (nowMicros - nextFreeTicketMicros) / stableIntervalMicros);
- nextFreeTicketMicros = nowMicros;
- }
- }
-
- private long readSafeMicros() {
- return TimeUnit.NANOSECONDS.toMicros(ticker.read() - offsetNanos);
- }
-
- @Override
- public String toString() {
- return String.format("RateLimiter[stableRate=%3.1fqps]", 1000000.0 / stableIntervalMicros);
- }
-
- /**
- * This implements the following function:
- *
- * ^ throttling
- * |
- * 3*stable + /
- * interval | /.
- * (cold) | / .
- * | / . <-- "warmup period" is the area of the trapezoid between
- * 2*stable + / . halfPermits and maxPermits
- * interval | / .
- * | / .
- * | / .
- * stable +----------/ WARM . }
- * interval | . UP . } <-- this rectangle (from 0 to maxPermits, and
- * | . PERIOD. } height == stableInterval) defines the cooldown period,
- * | . . } and we want cooldownPeriod == warmupPeriod
- * |---------------------------------> storedPermits
- * (halfPermits) (maxPermits)
- *
- * Before going into the details of this particular function, let's keep in mind the basics:
- * 1) The state of the RateLimiter (storedPermits) is a vertical line in this figure.
- * 2) When the RateLimiter is not used, this goes right (up to maxPermits)
- * 3) When the RateLimiter is used, this goes left (down to zero), since if we have storedPermits,
- * we serve from those first
- * 4) When _unused_, we go right at the same speed (rate)! I.e., if our rate is
- * 2 permits per second, and 3 unused seconds pass, we will always save 6 permits
- * (no matter what our initial position was), up to maxPermits.
- * If we invert the rate, we get the "stableInterval" (interval between two requests
- * in a perfectly spaced out sequence of requests of the given rate). Thus, if you
- * want to see "how much time it will take to go from X storedPermits to X+K storedPermits?",
- * the answer is always stableInterval * K. In the same example, for 2 permits per second,
- * stableInterval is 500ms. Thus to go from X storedPermits to X+6 storedPermits, we
- * require 6 * 500ms = 3 seconds.
- *
- * In short, the time it takes to move to the right (save K permits) is equal to the
- * rectangle of width == K and height == stableInterval.
- * 4) When _used_, the time it takes, as explained in the introductory class note, is
- * equal to the integral of our function, between X permits and X-K permits, assuming
- * we want to spend K saved permits.
- *
- * In summary, the time it takes to move to the left (spend K permits), is equal to the
- * area of the function of width == K.
- *
- * Let's dive into this function now:
- *
- * When we have storedPermits <= halfPermits (the left portion of the function), then
- * we spend them at the exact same rate that
- * fresh permits would be generated anyway (that rate is 1/stableInterval). We size
- * this area to be equal to _half_ the specified warmup period. Why we need this?
- * And why half? We'll explain shortly below (after explaining the second part).
- *
- * Stored permits that are beyond halfPermits, are mapped to an ascending line, that goes
- * from stableInterval to 3 * stableInterval. The average height for that part is
- * 2 * stableInterval, and is sized appropriately to have an area _equal_ to the
- * specified warmup period. Thus, by point (4) above, it takes "warmupPeriod" amount of time
- * to go from maxPermits to halfPermits.
- *
- * BUT, by point (3) above, it only takes "warmupPeriod / 2" amount of time to return back
- * to maxPermits, from halfPermits! (Because the trapezoid has double the area of the rectangle
- * of height stableInterval and equivalent width). We decided that the "cooldown period"
- * time should be equivalent to "warmup period", thus a fully saturated RateLimiter
- * (with zero stored permits, serving only fresh ones) can go to a fully unsaturated
- * (with storedPermits == maxPermits) in the same amount of time it takes for a fully
- * unsaturated RateLimiter to return to the stableInterval -- which happens in halfPermits,
- * since beyond that point, we use a horizontal line of "stableInterval" height, simulating
- * the regular rate.
- *
- * Thus, we have figured all dimensions of this shape, to give all the desired
- * properties:
- * - the width is warmupPeriod / stableInterval, to make cooldownPeriod == warmupPeriod
- * - the slope starts at the middle, and goes from stableInterval to 3*stableInterval so
- * to have halfPermits being spend in double the usual time (half the rate), while their
- * respective rate is steadily ramping up
- */
- private static class WarmingUp extends RateLimiter {
-
- final long warmupPeriodMicros;
- /**
- * The slope of the line from the stable interval (when permits == 0), to the cold interval
- * (when permits == maxPermits)
- */
- private double slope;
- private double halfPermits;
-
- WarmingUp(SleepingTicker ticker, long warmupPeriod, TimeUnit timeUnit) {
- super(ticker);
- this.warmupPeriodMicros = timeUnit.toMicros(warmupPeriod);
- }
-
- @Override
- void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
- double oldMaxPermits = maxPermits;
- maxPermits = warmupPeriodMicros / stableIntervalMicros;
- halfPermits = maxPermits / 2.0;
- // Stable interval is x, cold is 3x, so on average it's 2x. Double the time -> halve the rate
- double coldIntervalMicros = stableIntervalMicros * 3.0;
- slope = (coldIntervalMicros - stableIntervalMicros) / halfPermits;
- if (oldMaxPermits == Double.POSITIVE_INFINITY) {
- // if we don't special-case this, we would get storedPermits == NaN, below
- storedPermits = 0.0;
- } else {
- storedPermits = (oldMaxPermits == 0.0)
- ? maxPermits // initial state is cold
- : storedPermits * maxPermits / oldMaxPermits;
- }
- }
-
- @Override
- long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
- double availablePermitsAboveHalf = storedPermits - halfPermits;
- long micros = 0;
- // measuring the integral on the right part of the function (the climbing line)
- if (availablePermitsAboveHalf > 0.0) {
- double permitsAboveHalfToTake = Math.min(availablePermitsAboveHalf, permitsToTake);
- micros = (long) (permitsAboveHalfToTake * (permitsToTime(availablePermitsAboveHalf)
- + permitsToTime(availablePermitsAboveHalf - permitsAboveHalfToTake)) / 2.0);
- permitsToTake -= permitsAboveHalfToTake;
- }
- // measuring the integral on the left part of the function (the horizontal line)
- micros += (stableIntervalMicros * permitsToTake);
- return micros;
- }
-
- private double permitsToTime(double permits) {
- return stableIntervalMicros + permits * slope;
- }
- }
-
- /**
- * This implements a trivial function, where storedPermits are translated to
- * zero throttling - thus, a client gets an infinite speedup for permits acquired out
- * of the storedPermits pool. This is also used for the special case of the "metronome",
- * where the width of the function is also zero; maxStoredPermits is zero, thus
- * storedPermits and permitsToTake are always zero as well. Such a RateLimiter can
- * not save permits when unused, thus all permits it serves are fresh, using the
- * designated rate.
- */
- private static class Bursty extends RateLimiter {
- Bursty(SleepingTicker ticker) {
- super(ticker);
- }
-
- @Override
- void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
- double oldMaxPermits = this.maxPermits;
- /*
- * We allow the equivalent work of up to one second to be granted with zero waiting, if the
- * rate limiter has been unused for as much. This is to avoid potentially producing tiny
- * wait interval between subsequent requests for sufficiently large rates, which would
- * unnecessarily overconstrain the thread scheduler.
- */
- maxPermits = permitsPerSecond; // one second worth of permits
- storedPermits = (oldMaxPermits == 0.0)
- ? 0.0 // initial state
- : storedPermits * maxPermits / oldMaxPermits;
- }
-
- @Override
- long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
- return 0L;
- }
- }
-
- @VisibleForTesting
- static abstract class SleepingTicker extends Ticker {
- abstract void sleepMicrosUninterruptibly(long micros);
-
- static final SleepingTicker SYSTEM_TICKER = new SleepingTicker() {
- @Override
- public long read() {
- return systemTicker().read();
- }
-
- @Override
- public void sleepMicrosUninterruptibly(long micros) {
- if (micros > 0) {
- Uninterruptibles.sleepUninterruptibly(micros, TimeUnit.MICROSECONDS);
- }
- }
- };
- }
-}
diff --git a/guava/src/com/google/common/util/concurrent/Service.java b/guava/src/com/google/common/util/concurrent/Service.java
index 861164e..9ad1f3d 100644
--- a/guava/src/com/google/common/util/concurrent/Service.java
+++ b/guava/src/com/google/common/util/concurrent/Service.java
@@ -19,58 +19,57 @@ package com.google.common.util.concurrent;
import com.google.common.annotations.Beta;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
/**
- * An object with an operational state, plus asynchronous {@link #start()} and {@link #stop()}
- * lifecycle methods to transition between states. Example services include webservers, RPC servers
- * and timers.
- *
- * <p>The normal lifecycle of a service is:
+ * An object with an operational state, plus asynchronous {@link #start()} and
+ * {@link #stop()} lifecycle methods to transfer into and out of this state.
+ * Example services include webservers, RPC servers and timers. The normal
+ * lifecycle of a service is:
* <ul>
- * <li>{@linkplain State#NEW NEW} -&gt;
- * <li>{@linkplain State#STARTING STARTING} -&gt;
- * <li>{@linkplain State#RUNNING RUNNING} -&gt;
- * <li>{@linkplain State#STOPPING STOPPING} -&gt;
- * <li>{@linkplain State#TERMINATED TERMINATED}
+ * <li>{@link State#NEW} -&gt;</li>
+ * <li>{@link State#STARTING} -&gt;</li>
+ * <li>{@link State#RUNNING} -&gt;</li>
+ * <li>{@link State#STOPPING} -&gt;</li>
+ * <li>{@link State#TERMINATED}</li>
* </ul>
*
- * <p>There are deviations from this if there are failures or if {@link Service#stop} is called
- * before the {@link Service} reaches the {@linkplain State#RUNNING RUNNING} state. The set of legal
- * transitions form a <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph">DAG</a>,
- * therefore every method of the listener will be called at most once. N.B. The {@link State#FAILED}
- * and {@link State#TERMINATED} states are terminal states, once a service enters either of these
- * states it cannot ever leave them.
+ * If the service fails while starting, running or stopping, its state will be
+ * {@link State#FAILED}, and its behavior is undefined. Such a service cannot be
+ * started nor stopped.
*
- * <p>Implementors of this interface are strongly encouraged to extend one of the abstract classes
- * in this package which implement this interface and make the threading and state management
- * easier.
+ * <p>Implementors of this interface are strongly encouraged to extend one of
+ * the abstract classes in this package which implement this interface and
+ * make the threading and state management easier.
*
* @author Jesse Wilson
- * @author Luke Sandberg
- * @since 9.0 (in 1.0 as {@code com.google.common.base.Service})
+ * @since 9.0 (in 1.0 as
+ * {@code com.google.common.base.Service})
*/
-@Beta
+@Beta // TODO(kevinb): make abstract class?
public interface Service {
/**
- * If the service state is {@link State#NEW}, this initiates service startup and returns
- * immediately. If the service has already been started, this method returns immediately without
- * taking action. A stopped service may not be restarted.
+ * If the service state is {@link State#NEW}, this initiates service startup
+ * and returns immediately. If the service has already been started, this
+ * method returns immediately without taking action. A stopped service may not
+ * be restarted.
*
- * @return a future for the startup result, regardless of whether this call initiated startup.
- * Calling {@link ListenableFuture#get} will block until the service has finished
- * starting, and returns one of {@link State#RUNNING}, {@link State#STOPPING} or
- * {@link State#TERMINATED}. If the service fails to start, {@link ListenableFuture#get}
- * will throw an {@link ExecutionException}, and the service's state will be
- * {@link State#FAILED}. If it has already finished starting, {@link ListenableFuture#get}
- * returns immediately. Cancelling this future has no effect on the service.
+ * @return a future for the startup result, regardless of whether this call
+ * initiated startup. Calling {@link ListenableFuture#get} will block
+ * until the service has finished starting, and returns one of {@link
+ * State#RUNNING}, {@link State#STOPPING} or {@link State#TERMINATED}. If
+ * the service fails to start, {@link ListenableFuture#get} will throw an
+ * {@link ExecutionException}, and the service's state will be {@link
+ * State#FAILED}. If it has already finished starting, {@link
+ * ListenableFuture#get} returns immediately. Cancelling this future has
+ * no effect on the service.
*/
ListenableFuture<State> start();
/**
- * Initiates service startup (if necessary), returning once the service has finished starting.
- * Unlike calling {@code start().get()}, this method throws no checked exceptions, and it cannot
- * be {@linkplain Thread#interrupt interrupted}.
+ * Initiates service startup (if necessary), returning once the service has
+ * finished starting. Unlike calling {@code start().get()}, this method throws
+ * no checked exceptions, and it cannot be {@linkplain Thread#interrupt
+ * interrupted}.
*
* @throws UncheckedExecutionException if startup failed
* @return the state of the service when startup finished.
@@ -88,67 +87,39 @@ public interface Service {
State state();
/**
- * If the service is {@linkplain State#STARTING starting} or {@linkplain State#RUNNING running},
- * this initiates service shutdown and returns immediately. If the service is
- * {@linkplain State#NEW new}, it is {@linkplain State#TERMINATED terminated} without having been
- * started nor stopped. If the service has already been stopped, this method returns immediately
- * without taking action.
+ * If the service is {@linkplain State#STARTING starting} or {@linkplain
+ * State#RUNNING running}, this initiates service shutdown and returns
+ * immediately. If the service is {@linkplain State#NEW new}, it is
+ * {@linkplain State#TERMINATED terminated} without having been started nor
+ * stopped. If the service has already been stopped, this method returns
+ * immediately without taking action.
*
- * @return a future for the shutdown result, regardless of whether this call initiated shutdown.
- * Calling {@link ListenableFuture#get} will block until the service has finished shutting
- * down, and either returns {@link State#TERMINATED} or throws an
- * {@link ExecutionException}. If it has already finished stopping,
- * {@link ListenableFuture#get} returns immediately. Cancelling this future has no effect
- * on the service.
+ * @return a future for the shutdown result, regardless of whether this call
+ * initiated shutdown. Calling {@link ListenableFuture#get} will block
+ * until the service has finished shutting down, and either returns
+ * {@link State#TERMINATED} or throws an {@link ExecutionException}. If
+ * it has already finished stopping, {@link ListenableFuture#get} returns
+ * immediately. Cancelling this future has no effect on the service.
*/
ListenableFuture<State> stop();
/**
- * Initiates service shutdown (if necessary), returning once the service has finished stopping. If
- * this is {@link State#STARTING}, startup will be cancelled. If this is {@link State#NEW}, it is
- * {@link State#TERMINATED terminated} without having been started nor stopped. Unlike calling
- * {@code stop().get()}, this method throws no checked exceptions.
+ * Initiates service shutdown (if necessary), returning once the service has
+ * finished stopping. If this is {@link State#STARTING}, startup will be
+ * cancelled. If this is {@link State#NEW}, it is {@link State#TERMINATED
+ * terminated} without having been started nor stopped. Unlike calling {@code
+ * stop().get()}, this method throws no checked exceptions.
*
- * @throws UncheckedExecutionException if the service has failed or fails during shutdown
+ * @throws UncheckedExecutionException if shutdown failed
* @return the state of the service when shutdown finished.
*/
State stopAndWait();
/**
- * Returns the {@link Throwable} that caused this service to fail.
- *
- * @throws IllegalStateException if this service's state isn't {@linkplain State#FAILED FAILED}.
- *
- * @since 14.0
- */
- Throwable failureCause();
-
- /**
- * Registers a {@link Listener} to be {@linkplain Executor#execute executed} on the given
- * executor. The listener will have the corresponding transition method called whenever the
- * service changes state. The listener will not have previous state changes replayed, so it is
- * suggested that listeners are added before the service starts.
- *
- * <p>There is no guaranteed ordering of execution of listeners, but any listener added through
- * this method is guaranteed to be called whenever there is a state change.
- *
- * <p>Exceptions thrown by a listener will be propagated up to the executor. Any exception thrown
- * during {@code Executor.execute} (e.g., a {@code RejectedExecutionException} or an exception
- * thrown by {@linkplain MoreExecutors#sameThreadExecutor inline execution}) will be caught and
- * logged.
- *
- * @param listener the listener to run when the service changes state is complete
- * @param executor the executor in which the the listeners callback methods will be run. For fast,
- * lightweight listeners that would be safe to execute in any thread, consider
- * {@link MoreExecutors#sameThreadExecutor}.
- * @since 13.0
- */
- void addListener(Listener listener, Executor executor);
-
- /**
* The lifecycle states of a service.
*
- * @since 9.0 (in 1.0 as {@code com.google.common.base.Service.State})
+ * @since 9.0 (in 1.0 as
+ * {@code com.google.common.base.Service.State})
*/
@Beta // should come out of Beta when Service does
enum State {
@@ -174,70 +145,15 @@ public interface Service {
STOPPING,
/**
- * A service in this state has completed execution normally. It does minimal work and consumes
- * minimal resources.
+ * A service in this state has completed execution normally. It does minimal
+ * work and consumes minimal resources.
*/
TERMINATED,
/**
- * A service in this state has encountered a problem and may not be operational. It cannot be
- * started nor stopped.
+ * A service in this state has encountered a problem and may not be
+ * operational. It cannot be started nor stopped.
*/
FAILED
}
-
- /**
- * A listener for the various state changes that a {@link Service} goes through in its lifecycle.
- *
- * @author Luke Sandberg
- * @since 13.0
- */
- @Beta // should come out of Beta when Service does
- interface Listener {
- /**
- * Called when the service transitions from {@linkplain State#NEW NEW} to
- * {@linkplain State#STARTING STARTING}. This occurs when {@link Service#start} or
- * {@link Service#startAndWait} is called the first time.
- */
- void starting();
-
- /**
- * Called when the service transitions from {@linkplain State#STARTING STARTING} to
- * {@linkplain State#RUNNING RUNNING}. This occurs when a service has successfully started.
- */
- void running();
-
- /**
- * Called when the service transitions to the {@linkplain State#STOPPING STOPPING} state. The
- * only valid values for {@code from} are {@linkplain State#STARTING STARTING} or
- * {@linkplain State#RUNNING RUNNING}. This occurs when {@link Service#stop} is called.
- *
- * @param from The previous state that is being transitioned from.
- */
- void stopping(State from);
-
- /**
- * Called when the service transitions to the {@linkplain State#TERMINATED TERMINATED} state.
- * The {@linkplain State#TERMINATED TERMINATED} state is a terminal state in the transition
- * diagram. Therefore, if this method is called, no other methods will be called on the
- * {@link Listener}.
- *
- * @param from The previous state that is being transitioned from. The only valid values for
- * this are {@linkplain State#NEW NEW}, {@linkplain State#RUNNING RUNNING} or
- * {@linkplain State#STOPPING STOPPING}.
- */
- void terminated(State from);
-
- /**
- * Called when the service transitions to the {@linkplain State#FAILED FAILED} state. The
- * {@linkplain State#FAILED FAILED} state is a terminal state in the transition diagram.
- * Therefore, if this method is called, no other methods will be called on the {@link Listener}.
- *
- * @param from The previous state that is being transitioned from. Failure can occur in any
- * state with the exception of {@linkplain State#NEW NEW} or
- * {@linkplain State#TERMINATED TERMINATED}.
- * @param failure The exception that caused the failure.
- */
- void failed(State from, Throwable failure);
- }
}
diff --git a/guava/src/com/google/common/util/concurrent/ServiceManager.java b/guava/src/com/google/common/util/concurrent/ServiceManager.java
deleted file mode 100644
index c779b23..0000000
--- a/guava/src/com/google/common/util/concurrent/ServiceManager.java
+++ /dev/null
@@ -1,724 +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.util.concurrent;
-
-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 java.util.concurrent.TimeUnit.MILLISECONDS;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Ordering;
-import com.google.common.collect.Queues;
-import com.google.common.util.concurrent.Service.State;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Queue;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.annotation.concurrent.GuardedBy;
-import javax.annotation.concurrent.Immutable;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * A manager for monitoring and controlling a set of {@link Service services}. This class provides
- * methods for {@linkplain #startAsync() starting}, {@linkplain #stopAsync() stopping} and
- * {@linkplain #servicesByState inspecting} a collection of {@linkplain Service services}.
- * Additionally, users can monitor state transitions with the {@link Listener listener} mechanism.
- *
- * <p>While it is recommended that service lifecycles be managed via this class, state transitions
- * initiated via other mechanisms do not impact the correctness of its methods. For example, if the
- * services are started by some mechanism besides {@link #startAsync}, the listeners will be invoked
- * when appropriate and {@link #awaitHealthy} will still work as expected.
- *
- * <p>Here is a simple example of how to use a {@link ServiceManager} to start a server.
- * <pre> {@code
- * class Server {
- * public static void main(String[] args) {
- * Set<Service> services = ...;
- * ServiceManager manager = new ServiceManager(services);
- * manager.addListener(new Listener() {
- * public void stopped() {}
- * public void healthy() {
- * // Services have been initialized and are healthy, start accepting requests...
- * }
- * public void failure(Service service) {
- * // Something failed, at this point we could log it, notify a load balancer, or take
- * // some other action. For now we will just exit.
- * System.exit(1);
- * }
- * },
- * MoreExecutors.sameThreadExecutor());
- *
- * Runtime.getRuntime().addShutdownHook(new Thread() {
- * public void run() {
- * // Give the services 5 seconds to stop to ensure that we are responsive to shutdown
- * // requests.
- * try {
- * manager.stopAsync().awaitStopped(5, TimeUnit.SECONDS);
- * } catch (TimeoutException timeout) {
- * // stopping timed out
- * }
- * }
- * });
- * manager.startAsync(); // start all the services asynchronously
- * }
- * }}</pre>
- *
- * This class uses the ServiceManager's methods to start all of its services, to respond to service
- * failure and to ensure that when the JVM is shutting down all the services are stopped.
- *
- * @author Luke Sandberg
- * @since 14.0
- */
-@Beta
-@Singleton
-public final class ServiceManager {
- private static final Logger logger = Logger.getLogger(ServiceManager.class.getName());
-
- /**
- * A listener for the aggregate state changes of the services that are under management. Users
- * that need to listen to more fine-grained events (such as when each particular
- * {@link Service service} starts, or terminates), should attach {@link Service.Listener service
- * listeners} to each individual service.
- *
- * @author Luke Sandberg
- * @since 14.0
- */
- @Beta // Should come out of Beta when ServiceManager does
- public static interface Listener {
- /**
- * Called when the service initially becomes healthy.
- *
- * <p>This will be called at most once after all the services have entered the
- * {@linkplain State#RUNNING running} state. If any services fail during start up or
- * {@linkplain State#FAILED fail}/{@linkplain State#TERMINATED terminate} before all other
- * services have started {@linkplain State#RUNNING running} then this method will not be called.
- */
- void healthy();
-
- /**
- * Called when the all of the component services have reached a terminal state, either
- * {@linkplain State#TERMINATED terminated} or {@linkplain State#FAILED failed}.
- */
- void stopped();
-
- /**
- * Called when a component service has {@linkplain State#FAILED failed}.
- *
- * @param service The service that failed.
- */
- void failure(Service service);
- }
-
- /**
- * An encapsulation of all of the state that is accessed by the {@linkplain ServiceListener
- * service listeners}. This is extracted into its own object so that {@link ServiceListener}
- * could be made {@code static} and its instances can be safely constructed and added in the
- * {@link ServiceManager} constructor without having to close over the partially constructed
- * {@link ServiceManager} instance (i.e. avoid leaking a pointer to {@code this}).
- */
- private final ServiceManagerState state;
- private final ImmutableMap<Service, ServiceListener> services;
-
- /**
- * Constructs a new instance for managing the given services.
- *
- * @param services The services to manage
- *
- * @throws IllegalArgumentException if not all services are {@link State#NEW new} or if there are
- * any duplicate services.
- */
- public ServiceManager(Iterable<? extends Service> services) {
- ImmutableList<Service> copy = ImmutableList.copyOf(services);
- this.state = new ServiceManagerState(copy.size());
- ImmutableMap.Builder<Service, ServiceListener> builder = ImmutableMap.builder();
- Executor executor = MoreExecutors.sameThreadExecutor();
- for (Service service : copy) {
- ServiceListener listener = new ServiceListener(service, state);
- service.addListener(listener, executor);
- // We check the state after adding the listener as a way to ensure that our listener was added
- // to a NEW service.
- checkArgument(service.state() == State.NEW, "Can only manage NEW services, %s", service);
- builder.put(service, listener);
- }
- this.services = builder.build();
- }
-
- /**
- * Constructs a new instance for managing the given services. This constructor is provided so that
- * dependency injection frameworks can inject instances of {@link ServiceManager}.
- *
- * @param services The services to manage
- *
- * @throws IllegalStateException if not all services are {@link State#NEW new}.
- */
- @Inject ServiceManager(Set<Service> services) {
- this((Iterable<Service>) services);
- }
-
- /**
- * Registers a {@link Listener} to be {@linkplain Executor#execute executed} on the given
- * executor. The listener will not have previous state changes replayed, so it is
- * suggested that listeners are added before any of the managed services are
- * {@linkplain Service#start started}.
- *
- * <p>There is no guaranteed ordering of execution of listeners, but any listener added through
- * this method is guaranteed to be called whenever there is a state change.
- *
- * <p>Exceptions thrown by a listener will be propagated up to the executor. Any exception thrown
- * during {@code Executor.execute} (e.g., a {@code RejectedExecutionException} or an exception
- * thrown by {@linkplain MoreExecutors#sameThreadExecutor inline execution}) will be caught and
- * logged.
- *
- * @param listener the listener to run when the manager changes state
- * @param executor the executor in which the the listeners callback methods will be run. For fast,
- * lightweight listeners that would be safe to execute in any thread, consider
- * {@link MoreExecutors#sameThreadExecutor}.
- */
- public void addListener(Listener listener, Executor executor) {
- state.addListener(listener, executor);
- }
-
- /**
- * Initiates service {@linkplain Service#start startup} on all the services being managed. It is
- * only valid to call this method if all of the services are {@linkplain State#NEW new}.
- *
- * @return this
- * @throws IllegalStateException if any of the Services are not {@link State#NEW new} when the
- * method is called, {@link State#TERMINATED terminated} or {@link State#FAILED failed}.
- */
- public ServiceManager startAsync() {
- for (Map.Entry<Service, ServiceListener> entry : services.entrySet()) {
- Service service = entry.getKey();
- State state = service.state();
- checkState(state == State.NEW, "Service %s is %s, cannot start it.", service,
- state);
- }
- for (ServiceListener service : services.values()) {
- service.start();
- }
- return this;
- }
-
- /**
- * Waits for the {@link ServiceManager} to become {@linkplain #isHealthy() healthy}. The manager
- * will become healthy after all the component services have reached the {@linkplain State#RUNNING
- * running} state.
- *
- * @throws IllegalStateException if the service manager reaches a state from which it cannot
- * become {@linkplain #isHealthy() healthy}.
- */
- public void awaitHealthy() {
- state.awaitHealthy();
- checkState(isHealthy(), "Expected to be healthy after starting");
- }
-
- /**
- * Waits for the {@link ServiceManager} to become {@linkplain #isHealthy() healthy} for no more
- * than the given time. The manager will become healthy after all the component services have
- * reached the {@linkplain State#RUNNING running} state.
- *
- * @param timeout the maximum time to wait
- * @param unit the time unit of the timeout argument
- * @throws TimeoutException if not all of the services have finished starting within the deadline
- * @throws IllegalStateException if the service manager reaches a state from which it cannot
- * become {@linkplain #isHealthy() healthy}.
- */
- public void awaitHealthy(long timeout, TimeUnit unit) throws TimeoutException {
- if (!state.awaitHealthy(timeout, unit)) {
- // It would be nice to tell the caller who we are still waiting on, and this information is
- // likely to be in servicesByState(), however due to race conditions we can't actually tell
- // which services are holding up healthiness. The current set of NEW or STARTING services is
- // likely to point out the culprit, but may not. If we really wanted to solve this we could
- // change state to track exactly which services have started and then we could accurately
- // report on this. But it is only for logging so we likely don't care.
- throw new TimeoutException("Timeout waiting for the services to become healthy.");
- }
- checkState(isHealthy(), "Expected to be healthy after starting");
- }
-
- /**
- * Initiates service {@linkplain Service#stop shutdown} if necessary on all the services being
- * managed.
- *
- * @return this
- */
- public ServiceManager stopAsync() {
- for (Service service : services.keySet()) {
- service.stop();
- }
- return this;
- }
-
- /**
- * Waits for the all the services to reach a terminal state. After this method returns all
- * services will either be {@link Service.State#TERMINATED terminated} or
- * {@link Service.State#FAILED failed}
- */
- public void awaitStopped() {
- state.awaitStopped();
- }
-
- /**
- * Waits for the all the services to reach a terminal state for no more than the given time. After
- * this method returns all services will either be {@link Service.State#TERMINATED terminated} or
- * {@link Service.State#FAILED failed}
- *
- * @param timeout the maximum time to wait
- * @param unit the time unit of the timeout argument
- * @throws TimeoutException if not all of the services have stopped within the deadline
- */
- public void awaitStopped(long timeout, TimeUnit unit) throws TimeoutException {
- if (!state.awaitStopped(timeout, unit)) {
- throw new TimeoutException("Timeout waiting for the services to stop.");
- }
- }
-
- /**
- * Returns true if all services are currently in the {@linkplain State#RUNNING running} state.
- *
- * <p>Users who want more detailed information should use the {@link #servicesByState} method to
- * get detailed information about which services are not running.
- */
- public boolean isHealthy() {
- for (Service service : services.keySet()) {
- if (!service.isRunning()) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Provides a snapshot of the current state of all the services under management.
- *
- * <p>N.B. This snapshot it not guaranteed to be consistent, i.e. the set of states returned may
- * not correspond to any particular point in time view of the services.
- */
- public ImmutableMultimap<State, Service> servicesByState() {
- ImmutableMultimap.Builder<State, Service> builder = ImmutableMultimap.builder();
- for (Service service : services.keySet()) {
- builder.put(service.state(), service);
- }
- return builder.build();
- }
-
- /**
- * Returns the service load times. This value will only return startup times for services that
- * have finished starting.
- *
- * @return Map of services and their corresponding startup time in millis, the map entries will be
- * ordered by startup time.
- */
- public ImmutableMap<Service, Long> startupTimes() {
- Map<Service, Long> loadTimeMap = Maps.newHashMapWithExpectedSize(services.size());
- for (Map.Entry<Service, ServiceListener> entry : services.entrySet()) {
- State state = entry.getKey().state();
- if (state != State.NEW && state != State.STARTING) {
- loadTimeMap.put(entry.getKey(), entry.getValue().startupTimeMillis());
- }
- }
- List<Entry<Service, Long>> servicesByStartTime = Ordering.<Long>natural()
- .onResultOf(new Function<Map.Entry<Service, Long>, Long>() {
- @Override public Long apply(Map.Entry<Service, Long> input) {
- return input.getValue();
- }
- })
- .sortedCopy(loadTimeMap.entrySet());
- ImmutableMap.Builder<Service, Long> builder = ImmutableMap.builder();
- for (Map.Entry<Service, Long> entry : servicesByStartTime) {
- builder.put(entry);
- }
- return builder.build();
- }
-
- @Override public String toString() {
- return Objects.toStringHelper(ServiceManager.class)
- .add("services", services.keySet())
- .toString();
- }
-
- /**
- * An encapsulation of all the mutable state of the {@link ServiceManager} that needs to be
- * accessed by instances of {@link ServiceListener}.
- */
- private static final class ServiceManagerState {
- final Monitor monitor = new Monitor();
- final int numberOfServices;
- /** The number of services that have not finished starting up. */
- @GuardedBy("monitor")
- int unstartedServices;
- /** The number of services that have not reached a terminal state. */
- @GuardedBy("monitor")
- int unstoppedServices;
- /**
- * Controls how long to wait for all the service manager to either become healthy or reach a
- * state where it is guaranteed that it can never become healthy.
- */
- final Monitor.Guard awaitHealthGuard = new Monitor.Guard(monitor) {
- @Override public boolean isSatisfied() {
- // All services have started or some service has terminated/failed.
- return unstartedServices == 0 || unstoppedServices != numberOfServices;
- }
- };
- /**
- * Controls how long to wait for all services to reach a terminal state.
- */
- final Monitor.Guard stoppedGuard = new Monitor.Guard(monitor) {
- @Override public boolean isSatisfied() {
- return unstoppedServices == 0;
- }
- };
- /** The listeners to notify during a state transition. */
- @GuardedBy("monitor")
- final List<ListenerExecutorPair> listeners = Lists.newArrayList();
- /**
- * The queue of listeners that are waiting to be executed.
- *
- * <p>Enqueue operations should be protected by {@link #monitor} while dequeue operations should
- * be protected by the implicit lock on this object. This is to ensure that listeners are
- * executed in the correct order and also so that a listener can not hold the {@link #monitor}
- * for an arbitrary amount of time (listeners can only block other listeners, not internal state
- * transitions). We use a concurrent queue implementation so that enqueues can be executed
- * concurrently with dequeues.
- */
- @GuardedBy("queuedListeners")
- final Queue<Runnable> queuedListeners = Queues.newConcurrentLinkedQueue();
-
- ServiceManagerState(int numberOfServices) {
- this.numberOfServices = numberOfServices;
- this.unstoppedServices = numberOfServices;
- this.unstartedServices = numberOfServices;
- }
-
- void addListener(Listener listener, Executor executor) {
- checkNotNull(listener, "listener");
- checkNotNull(executor, "executor");
- monitor.enter();
- try {
- // no point in adding a listener that will never be called
- if (unstartedServices > 0 || unstoppedServices > 0) {
- listeners.add(new ListenerExecutorPair(listener, executor));
- }
- } finally {
- monitor.leave();
- }
- }
-
- void awaitHealthy() {
- monitor.enter();
- try {
- monitor.waitForUninterruptibly(awaitHealthGuard);
- } finally {
- monitor.leave();
- }
- }
-
- boolean awaitHealthy(long timeout, TimeUnit unit) {
- monitor.enter();
- try {
- if (monitor.waitForUninterruptibly(awaitHealthGuard, timeout, unit)) {
- return true;
- }
- return false;
- } finally {
- monitor.leave();
- }
- }
-
- void awaitStopped() {
- monitor.enter();
- try {
- monitor.waitForUninterruptibly(stoppedGuard);
- } finally {
- monitor.leave();
- }
- }
-
- boolean awaitStopped(long timeout, TimeUnit unit) {
- monitor.enter();
- try {
- return monitor.waitForUninterruptibly(stoppedGuard, timeout, unit);
- } finally {
- monitor.leave();
- }
- }
-
- /**
- * This should be called when a service finishes starting up.
- *
- * @param currentlyHealthy whether or not the service that finished starting was healthy at the
- * time that it finished starting.
- */
- @GuardedBy("monitor")
- private void serviceFinishedStarting(Service service, boolean currentlyHealthy) {
- checkState(unstartedServices > 0,
- "All services should have already finished starting but %s just finished.", service);
- unstartedServices--;
- if (currentlyHealthy && unstartedServices == 0 && unstoppedServices == numberOfServices) {
- // This means that the manager is currently healthy, or at least it should have been
- // healthy at some point from some perspective. Calling isHealthy is not currently
- // guaranteed to return true because any service could fail right now. However, the
- // happens-before relationship enforced by the monitor ensures that this method was called
- // before either serviceTerminated or serviceFailed, so we know that the manager was at
- // least healthy for some period of time. Furthermore we are guaranteed that this call to
- // healthy() will be before any call to terminated() or failure(Service) on the listener.
- // So it is correct to execute the listener's health() callback.
- for (final ListenerExecutorPair pair : listeners) {
- queuedListeners.add(new Runnable() {
- @Override public void run() {
- pair.execute(new Runnable() {
- @Override public void run() {
- pair.listener.healthy();
- }
- });
- }
- });
- }
- }
- }
-
- /**
- * This should be called when a service is {@linkplain State#TERMINATED terminated}.
- */
- @GuardedBy("monitor")
- private void serviceTerminated(Service service) {
- serviceStopped(service);
- }
-
- /**
- * This should be called when a service is {@linkplain State#FAILED failed}.
- */
- @GuardedBy("monitor")
- private void serviceFailed(final Service service) {
- for (final ListenerExecutorPair pair : listeners) {
- queuedListeners.add(new Runnable() {
- @Override public void run() {
- pair.execute(new Runnable() {
- @Override public void run() {
- pair.listener.failure(service);
- }
- });
- }
- });
- }
- serviceStopped(service);
- }
-
- /**
- * Should be called whenever a service reaches a terminal state (
- * {@linkplain State#TERMINATED terminated} or
- * {@linkplain State#FAILED failed}).
- */
- @GuardedBy("monitor")
- private void serviceStopped(Service service) {
- checkState(unstoppedServices > 0,
- "All services should have already stopped but %s just stopped.", service);
- unstoppedServices--;
- if (unstoppedServices == 0) {
- checkState(unstartedServices == 0,
- "All services are stopped but %d services haven't finished starting",
- unstartedServices);
- for (final ListenerExecutorPair pair : listeners) {
- queuedListeners.add(new Runnable() {
- @Override public void run() {
- pair.execute(new Runnable() {
- @Override public void run() {
- pair.listener.stopped();
- }
- });
- }
- });
- }
- // no more listeners could possibly be called, so clear them out
- listeners.clear();
- }
- }
-
- /**
- * Attempts to execute all the listeners in {@link #queuedListeners}.
- */
- private void executeListeners() {
- checkState(!monitor.isOccupiedByCurrentThread(),
- "It is incorrect to execute listeners with the monitor held.");
- synchronized (queuedListeners) {
- Runnable listener;
- while ((listener = queuedListeners.poll()) != null) {
- listener.run();
- }
- }
- }
- }
-
- /**
- * A {@link Service} that wraps another service and times how long it takes for it to start and
- * also calls the {@link ServiceManagerState#serviceFinishedStarting},
- * {@link ServiceManagerState#serviceTerminated} and {@link ServiceManagerState#serviceFailed}
- * according to its current state.
- */
- private static final class ServiceListener implements Service.Listener {
- @GuardedBy("watch") // AFAICT Stopwatch is not thread safe so we need to protect accesses
- final Stopwatch watch = new Stopwatch();
- final Service service;
- final ServiceManagerState state;
-
- /**
- * @param service the service that
- */
- ServiceListener(Service service, ServiceManagerState state) {
- this.service = service;
- this.state = state;
- }
-
- @Override public void starting() {
- // This can happen if someone besides the ServiceManager starts the service, in this case
- // our timings may be inaccurate.
- startTimer();
- }
-
- @Override public void running() {
- state.monitor.enter();
- try {
- finishedStarting(true);
- } finally {
- state.monitor.leave();
- state.executeListeners();
- }
- }
-
- @Override public void stopping(State from) {
- if (from == State.STARTING) {
- state.monitor.enter();
- try {
- finishedStarting(false);
- } finally {
- state.monitor.leave();
- state.executeListeners();
- }
- }
- }
-
- @Override public void terminated(State from) {
- logger.info("Service " + service + " has terminated. Previous state was " + from + " state.");
- state.monitor.enter();
- try {
- if (from == State.NEW) {
- // startTimer is idempotent, so this is safe to call and it may be necessary if no one has
- // started the timer yet.
- startTimer();
- finishedStarting(false);
- }
- state.serviceTerminated(service);
- } finally {
- state.monitor.leave();
- state.executeListeners();
- }
- }
-
- @Override public void failed(State from, Throwable failure) {
- logger.log(Level.SEVERE, "Service " + service + " has failed in the " + from + " state.",
- failure);
- state.monitor.enter();
- try {
- if (from == State.STARTING) {
- finishedStarting(false);
- }
- state.serviceFailed(service);
- } finally {
- state.monitor.leave();
- state.executeListeners();
- }
- }
-
- /**
- * Stop the stopwatch, log the startup time and decrement the startup latch
- *
- * @param currentlyHealthy whether or not the service that finished starting is currently
- * healthy
- */
- @GuardedBy("monitor")
- void finishedStarting(boolean currentlyHealthy) {
- synchronized (watch) {
- watch.stop();
- logger.log(Level.INFO, "Started " + service + " in " + startupTimeMillis() + " ms.");
- }
- state.serviceFinishedStarting(service, currentlyHealthy);
- }
-
- void start() {
- startTimer();
- service.start();
- }
-
- /** Start the timer if it hasn't been started. */
- void startTimer() {
- synchronized (watch) {
- if (!watch.isRunning()) { // only start the watch once.
- watch.start();
- logger.log(Level.INFO, "Starting {0}", service);
- }
- }
- }
-
- /** Returns the amount of time it took for the service to finish starting in milliseconds. */
- synchronized long startupTimeMillis() {
- synchronized (watch) {
- return watch.elapsed(MILLISECONDS);
- }
- }
- }
-
- /** Simple value object binding a listener to its executor. */
- @Immutable private static final class ListenerExecutorPair {
- final Listener listener;
- final Executor executor;
-
- ListenerExecutorPair(Listener listener, Executor executor) {
- this.listener = listener;
- this.executor = executor;
- }
-
- /**
- * Executes the given {@link Runnable} on {@link #executor} logging and swallowing all
- * exceptions
- */
- void execute(Runnable runnable) {
- try {
- executor.execute(runnable);
- } catch (Exception e) {
- logger.log(Level.SEVERE, "Exception while executing listener " + listener
- + " with executor " + executor, e);
- }
- }
- }
-}
diff --git a/guava/src/com/google/common/util/concurrent/Striped.java b/guava/src/com/google/common/util/concurrent/Striped.java
deleted file mode 100644
index 3c426f0..0000000
--- a/guava/src/com/google/common/util/concurrent/Striped.java
+++ /dev/null
@@ -1,376 +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.util.concurrent;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Functions;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.MapMaker;
-import com.google.common.math.IntMath;
-import com.google.common.primitives.Ints;
-
-import java.math.RoundingMode;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * A striped {@code Lock/Semaphore/ReadWriteLock}. This offers the underlying lock striping
- * similar to that of {@code ConcurrentHashMap} in a reusable form, and extends it for
- * semaphores and read-write locks. Conceptually, lock striping is the technique of dividing a lock
- * into many <i>stripes</i>, increasing the granularity of a single lock and allowing independent
- * operations to lock different stripes and proceed concurrently, instead of creating contention
- * for a single lock.
- *
- * <p>The guarantee provided by this class is that equal keys lead to the same lock (or semaphore),
- * i.e. {@code if (key1.equals(key2))} then {@code striped.get(key1) == striped.get(key2)}
- * (assuming {@link Object#hashCode()} is correctly implemented for the keys). Note
- * that if {@code key1} is <strong>not</strong> equal to {@code key2}, it is <strong>not</strong>
- * guaranteed that {@code striped.get(key1) != striped.get(key2)}; the elements might nevertheless
- * be mapped to the same lock. The lower the number of stripes, the higher the probability of this
- * happening.
- *
- * <p>There are three flavors of this class: {@code Striped<Lock>}, {@code Striped<Semaphore>},
- * and {@code Striped<ReadWriteLock>}. For each type, two implementations are offered:
- * {@linkplain #lock(int) strong} and {@linkplain #lazyWeakLock(int) weak}
- * {@code Striped<Lock>}, {@linkplain #semaphore(int, int) strong} and {@linkplain
- * #lazyWeakSemaphore(int, int) weak} {@code Striped<Semaphore>}, and {@linkplain
- * #readWriteLock(int) strong} and {@linkplain #lazyWeakReadWriteLock(int) weak}
- * {@code Striped<ReadWriteLock>}. <i>Strong</i> means that all stripes (locks/semaphores) are
- * initialized eagerly, and are not reclaimed unless {@code Striped} itself is reclaimable.
- * <i>Weak</i> means that locks/semaphores are created lazily, and they are allowed to be reclaimed
- * if nobody is holding on to them. This is useful, for example, if one wants to create a {@code
- * Striped<Lock>} of many locks, but worries that in most cases only a small portion of these
- * would be in use.
- *
- * <p>Prior to this class, one might be tempted to use {@code Map<K, Lock>}, where {@code K}
- * represents the task. This maximizes concurrency by having each unique key mapped to a unique
- * lock, but also maximizes memory footprint. On the other extreme, one could use a single lock
- * for all tasks, which minimizes memory footprint but also minimizes concurrency. Instead of
- * choosing either of these extremes, {@code Striped} allows the user to trade between required
- * concurrency and memory footprint. For example, if a set of tasks are CPU-bound, one could easily
- * create a very compact {@code Striped<Lock>} of {@code availableProcessors() * 4} stripes,
- * instead of possibly thousands of locks which could be created in a {@code Map<K, Lock>}
- * structure.
- *
- * @author Dimitris Andreou
- * @since 13.0
- */
-@Beta
-public abstract class Striped<L> {
- private Striped() {}
-
- /**
- * Returns the stripe that corresponds to the passed key. It is always guaranteed that if
- * {@code key1.equals(key2)}, then {@code get(key1) == get(key2)}.
- *
- * @param key an arbitrary, non-null key
- * @return the stripe that the passed key corresponds to
- */
- public abstract L get(Object key);
-
- /**
- * Returns the stripe at the specified index. Valid indexes are 0, inclusively, to
- * {@code size()}, exclusively.
- *
- * @param index the index of the stripe to return; must be in {@code [0...size())}
- * @return the stripe at the specified index
- */
- public abstract L getAt(int index);
-
- /**
- * Returns the index to which the given key is mapped, so that getAt(indexFor(key)) == get(key).
- */
- abstract int indexFor(Object key);
-
- /**
- * Returns the total number of stripes in this instance.
- */
- public abstract int size();
-
- /**
- * Returns the stripes that correspond to the passed objects, in ascending (as per
- * {@link #getAt(int)}) order. Thus, threads that use the stripes in the order returned
- * by this method are guaranteed to not deadlock each other.
- *
- * <p>It should be noted that using a {@code Striped<L>} with relatively few stripes, and
- * {@code bulkGet(keys)} with a relative large number of keys can cause an excessive number
- * of shared stripes (much like the birthday paradox, where much fewer than anticipated birthdays
- * are needed for a pair of them to match). Please consider carefully the implications of the
- * number of stripes, the intended concurrency level, and the typical number of keys used in a
- * {@code bulkGet(keys)} operation. See <a href="http://www.mathpages.com/home/kmath199.htm">Balls
- * in Bins model</a> for mathematical formulas that can be used to estimate the probability of
- * collisions.
- *
- * @param keys arbitrary non-null keys
- * @return the stripes corresponding to the objects (one per each object, derived by delegating
- * to {@link #get(Object)}; may contain duplicates), in an increasing index order.
- */
- public Iterable<L> bulkGet(Iterable<?> keys) {
- // Initially using the array to store the keys, then reusing it to store the respective L's
- final Object[] array = Iterables.toArray(keys, Object.class);
- int[] stripes = new int[array.length];
- for (int i = 0; i < array.length; i++) {
- stripes[i] = indexFor(array[i]);
- }
- Arrays.sort(stripes);
- for (int i = 0; i < array.length; i++) {
- array[i] = getAt(stripes[i]);
- }
- /*
- * Note that the returned Iterable holds references to the returned stripes, to avoid
- * error-prone code like:
- *
- * Striped<Lock> stripedLock = Striped.lazyWeakXXX(...)'
- * Iterable<Lock> locks = stripedLock.bulkGet(keys);
- * for (Lock lock : locks) {
- * lock.lock();
- * }
- * operation();
- * for (Lock lock : locks) {
- * lock.unlock();
- * }
- *
- * If we only held the int[] stripes, translating it on the fly to L's, the original locks
- * might be garbage collected after locking them, ending up in a huge mess.
- */
- @SuppressWarnings("unchecked") // we carefully replaced all keys with their respective L's
- List<L> asList = (List<L>) Arrays.asList(array);
- return Collections.unmodifiableList(asList);
- }
-
- // Static factories
-
- /**
- * Creates a {@code Striped<Lock>} with eagerly initialized, strongly referenced locks, with the
- * specified fairness. Every lock is reentrant.
- *
- * @param stripes the minimum number of stripes (locks) required
- * @return a new {@code Striped<Lock>}
- */
- public static Striped<Lock> lock(int stripes) {
- return new CompactStriped<Lock>(stripes, new Supplier<Lock>() {
- public Lock get() {
- return new PaddedLock();
- }
- });
- }
-
- /**
- * Creates a {@code Striped<Lock>} with lazily initialized, weakly referenced locks, with the
- * specified fairness. Every lock is reentrant.
- *
- * @param stripes the minimum number of stripes (locks) required
- * @return a new {@code Striped<Lock>}
- */
- public static Striped<Lock> lazyWeakLock(int stripes) {
- return new LazyStriped<Lock>(stripes, new Supplier<Lock>() {
- public Lock get() {
- return new ReentrantLock(false);
- }
- });
- }
-
- /**
- * Creates a {@code Striped<Semaphore>} with eagerly initialized, strongly referenced semaphores,
- * with the specified number of permits and fairness.
- *
- * @param stripes the minimum number of stripes (semaphores) required
- * @param permits the number of permits in each semaphore
- * @return a new {@code Striped<Semaphore>}
- */
- public static Striped<Semaphore> semaphore(int stripes, final int permits) {
- return new CompactStriped<Semaphore>(stripes, new Supplier<Semaphore>() {
- public Semaphore get() {
- return new PaddedSemaphore(permits);
- }
- });
- }
-
- /**
- * Creates a {@code Striped<Semaphore>} with lazily initialized, weakly referenced semaphores,
- * with the specified number of permits and fairness.
- *
- * @param stripes the minimum number of stripes (semaphores) required
- * @param permits the number of permits in each semaphore
- * @return a new {@code Striped<Semaphore>}
- */
- public static Striped<Semaphore> lazyWeakSemaphore(int stripes, final int permits) {
- return new LazyStriped<Semaphore>(stripes, new Supplier<Semaphore>() {
- public Semaphore get() {
- return new Semaphore(permits, false);
- }
- });
- }
-
- /**
- * Creates a {@code Striped<ReadWriteLock>} with eagerly initialized, strongly referenced
- * read-write locks, with the specified fairness. Every lock is reentrant.
- *
- * @param stripes the minimum number of stripes (locks) required
- * @return a new {@code Striped<ReadWriteLock>}
- */
- public static Striped<ReadWriteLock> readWriteLock(int stripes) {
- return new CompactStriped<ReadWriteLock>(stripes, READ_WRITE_LOCK_SUPPLIER);
- }
-
- /**
- * Creates a {@code Striped<ReadWriteLock>} with lazily initialized, weakly referenced
- * read-write locks, with the specified fairness. Every lock is reentrant.
- *
- * @param stripes the minimum number of stripes (locks) required
- * @return a new {@code Striped<ReadWriteLock>}
- */
- public static Striped<ReadWriteLock> lazyWeakReadWriteLock(int stripes) {
- return new LazyStriped<ReadWriteLock>(stripes, READ_WRITE_LOCK_SUPPLIER);
- }
-
- // ReentrantReadWriteLock is large enough to make padding probably unnecessary
- private static final Supplier<ReadWriteLock> READ_WRITE_LOCK_SUPPLIER =
- new Supplier<ReadWriteLock>() {
- public ReadWriteLock get() {
- return new ReentrantReadWriteLock();
- }
- };
-
- private abstract static class PowerOfTwoStriped<L> extends Striped<L> {
- /** Capacity (power of two) minus one, for fast mod evaluation */
- final int mask;
-
- PowerOfTwoStriped(int stripes) {
- Preconditions.checkArgument(stripes > 0, "Stripes must be positive");
- this.mask = stripes > Ints.MAX_POWER_OF_TWO ? ALL_SET : ceilToPowerOfTwo(stripes) - 1;
- }
-
- @Override final int indexFor(Object key) {
- int hash = smear(key.hashCode());
- return hash & mask;
- }
-
- @Override public final L get(Object key) {
- return getAt(indexFor(key));
- }
- }
-
- /**
- * Implementation of Striped where 2^k stripes are represented as an array of the same length,
- * eagerly initialized.
- */
- private static class CompactStriped<L> extends PowerOfTwoStriped<L> {
- /** Size is a power of two. */
- private final Object[] array;
-
- private CompactStriped(int stripes, Supplier<L> supplier) {
- super(stripes);
- Preconditions.checkArgument(stripes <= Ints.MAX_POWER_OF_TWO, "Stripes must be <= 2^30)");
-
- this.array = new Object[mask + 1];
- for (int i = 0; i < array.length; i++) {
- array[i] = supplier.get();
- }
- }
-
- @SuppressWarnings("unchecked") // we only put L's in the array
- @Override public L getAt(int index) {
- return (L) array[index];
- }
-
- @Override public int size() {
- return array.length;
- }
- }
-
- /**
- * Implementation of Striped where up to 2^k stripes can be represented, using a Cache
- * where the key domain is [0..2^k). To map a user key into a stripe, we take a k-bit slice of the
- * user key's (smeared) hashCode(). The stripes are lazily initialized and are weakly referenced.
- */
- private static class LazyStriped<L> extends PowerOfTwoStriped<L> {
- final ConcurrentMap<Integer, L> cache;
- final int size;
-
- LazyStriped(int stripes, Supplier<L> supplier) {
- super(stripes);
- this.size = (mask == ALL_SET) ? Integer.MAX_VALUE : mask + 1;
- this.cache = new MapMaker().weakValues().makeComputingMap(Functions.forSupplier(supplier));
- }
-
- @Override public L getAt(int index) {
- Preconditions.checkElementIndex(index, size());
- return cache.get(index);
- }
-
- @Override public int size() {
- return size;
- }
- }
-
- /**
- * A bit mask were all bits are set.
- */
- private static final int ALL_SET = ~0;
-
- private static int ceilToPowerOfTwo(int x) {
- return 1 << IntMath.log2(x, RoundingMode.CEILING);
- }
-
- /*
- * 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.
- */
- // Copied from java/com/google/common/collect/Hashing.java
- private static int smear(int hashCode) {
- hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12);
- return hashCode ^ (hashCode >>> 7) ^ (hashCode >>> 4);
- }
-
- private static class PaddedLock extends ReentrantLock {
- /*
- * Padding from 40 into 64 bytes, same size as cache line. Might be beneficial to add
- * a fourth long here, to minimize chance of interference between consecutive locks,
- * but I couldn't observe any benefit from that.
- */
- @SuppressWarnings("unused")
- long q1, q2, q3;
-
- PaddedLock() {
- super(false);
- }
- }
-
- private static class PaddedSemaphore extends Semaphore {
- // See PaddedReentrantLock comment
- @SuppressWarnings("unused")
- long q1, q2, q3;
-
- PaddedSemaphore(int permits) {
- super(permits, false);
- }
- }
-}
diff --git a/guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java b/guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java
index a05247e..167ad11 100644
--- a/guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java
+++ b/guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java
@@ -61,12 +61,9 @@ public final class ThreadFactoryBuilder {
* @param nameFormat a {@link String#format(String, Object...)}-compatible
* format String, to which a unique integer (0, 1, etc.) will be supplied
* as the single parameter. This integer will be unique to the built
- * instance of the ThreadFactory and will be assigned sequentially. For
- * example, {@code "rpc-pool-%d"} will generate thread names like
- * {@code "rpc-pool-0"}, {@code "rpc-pool-1"}, {@code "rpc-pool-2"}, etc.
+ * instance of the ThreadFactory and will be assigned sequentially.
* @return this for the builder pattern
*/
- @SuppressWarnings("ReturnValueIgnored")
public ThreadFactoryBuilder setNameFormat(String nameFormat) {
String.format(nameFormat, 0); // fail fast if the format is bad or null
this.nameFormat = nameFormat;
diff --git a/guava/src/com/google/common/util/concurrent/UncheckedExecutionException.java b/guava/src/com/google/common/util/concurrent/UncheckedExecutionException.java
index 77afdc3..c0c99e1 100644
--- a/guava/src/com/google/common/util/concurrent/UncheckedExecutionException.java
+++ b/guava/src/com/google/common/util/concurrent/UncheckedExecutionException.java
@@ -16,10 +16,9 @@
package com.google.common.util.concurrent;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import javax.annotation.Nullable;
-
/**
* Unchecked variant of {@link java.util.concurrent.ExecutionException}. As with
* {@code ExecutionException}, the exception's {@linkplain #getCause() cause}
@@ -27,16 +26,17 @@ import javax.annotation.Nullable;
*
* <p>{@code UncheckedExecutionException} is intended as an alternative to
* {@code ExecutionException} when the exception thrown by a task is an
- * unchecked exception. However, it may also wrap a checked exception in some
- * cases.
+ * unchecked exception. This allows the client code to continue to distinguish
+ * between checked and unchecked exceptions, even when they come from other
+ * threads.
*
* <p>When wrapping an {@code Error} from another thread, prefer {@link
- * ExecutionError}. When wrapping a checked exception, prefer {@code
- * ExecutionException}.
+ * ExecutionError}.
*
* @author Charles Fry
* @since 10.0
*/
+@Beta
@GwtCompatible
public class UncheckedExecutionException extends RuntimeException {
/**
@@ -47,21 +47,21 @@ public class UncheckedExecutionException extends RuntimeException {
/**
* Creates a new instance with the given detail message.
*/
- protected UncheckedExecutionException(@Nullable String message) {
+ protected UncheckedExecutionException(String message) {
super(message);
}
/**
* Creates a new instance with the given detail message and cause.
*/
- public UncheckedExecutionException(@Nullable String message, @Nullable Throwable cause) {
+ public UncheckedExecutionException(String message, Throwable cause) {
super(message, cause);
}
/**
* Creates a new instance with the given cause.
*/
- public UncheckedExecutionException(@Nullable Throwable cause) {
+ public UncheckedExecutionException(Throwable cause) {
super(cause);
}
diff --git a/guava/src/com/google/common/util/concurrent/UncheckedTimeoutException.java b/guava/src/com/google/common/util/concurrent/UncheckedTimeoutException.java
index cefe379..d821c84 100644
--- a/guava/src/com/google/common/util/concurrent/UncheckedTimeoutException.java
+++ b/guava/src/com/google/common/util/concurrent/UncheckedTimeoutException.java
@@ -16,8 +16,6 @@
package com.google.common.util.concurrent;
-import javax.annotation.Nullable;
-
/**
* Unchecked version of {@link java.util.concurrent.TimeoutException}.
*
@@ -27,15 +25,15 @@ import javax.annotation.Nullable;
public class UncheckedTimeoutException extends RuntimeException {
public UncheckedTimeoutException() {}
- public UncheckedTimeoutException(@Nullable String message) {
+ public UncheckedTimeoutException(String message) {
super(message);
}
- public UncheckedTimeoutException(@Nullable Throwable cause) {
+ public UncheckedTimeoutException(Throwable cause) {
super(cause);
}
- public UncheckedTimeoutException(@Nullable String message, @Nullable Throwable cause) {
+ public UncheckedTimeoutException(String message, Throwable cause) {
super(message, cause);
}
diff --git a/guava/src/com/google/common/util/concurrent/Uninterruptibles.java b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
index 79d7598..89f30b8 100644
--- a/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
+++ b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
@@ -122,9 +122,6 @@ public final class Uninterruptibles {
* <p>If instead, you wish to treat {@link InterruptedException} uniformly
* with other exceptions, see {@link Futures#get(Future, Class) Futures.get}
* or {@link Futures#makeChecked}.
- *
- * @throws ExecutionException if the computation threw an exception
- * @throws CancellationException if the computation was cancelled
*/
public static <V> V getUninterruptibly(Future<V> future)
throws ExecutionException {
@@ -152,10 +149,6 @@ public final class Uninterruptibles {
* <p>If instead, you wish to treat {@link InterruptedException} uniformly
* with other exceptions, see {@link Futures#get(Future, Class) Futures.get}
* or {@link Futures#makeChecked}.
- *
- * @throws ExecutionException if the computation threw an exception
- * @throws CancellationException if the computation was cancelled
- * @throws TimeoutException if the wait timed out
*/
public static <V> V getUninterruptibly(
Future<V> future, long timeout, TimeUnit unit)
@@ -233,11 +226,6 @@ public final class Uninterruptibles {
/**
* Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)}
* uninterruptibly.
- *
- * @throws ClassCastException if the class of the specified element prevents
- * it from being added to the given queue
- * @throws IllegalArgumentException if some property of the specified element
- * prevents it from being added to the given queue
*/
public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) {
boolean interrupted = false;
diff --git a/guava/src/com/google/common/util/concurrent/package-info.java b/guava/src/com/google/common/util/concurrent/package-info.java
index 6ea5069..6281552 100644
--- a/guava/src/com/google/common/util/concurrent/package-info.java
+++ b/guava/src/com/google/common/util/concurrent/package-info.java
@@ -33,4 +33,3 @@
package com.google.common.util.concurrent;
import javax.annotation.ParametersAreNonnullByDefault;
-