summaryrefslogtreecommitdiffstats
path: root/guava
diff options
context:
space:
mode:
authorYohann Roussel <yroussel@google.com>2014-03-19 16:25:37 +0100
committerYohann Roussel <yroussel@google.com>2014-03-20 15:13:33 +0100
commit4eceb95409e844fdc33c9c706e1dc307bfd40303 (patch)
treeee9f4f3fc79f757c79081c336bce4f1782c6ccd8 /guava
parent3d2402901b1a6462e2cf47a6fd09711f327961c3 (diff)
downloadtoolchain_jack-4eceb95409e844fdc33c9c706e1dc307bfd40303.zip
toolchain_jack-4eceb95409e844fdc33c9c706e1dc307bfd40303.tar.gz
toolchain_jack-4eceb95409e844fdc33c9c706e1dc307bfd40303.tar.bz2
Initial Jack import.
Change-Id: I953cf0a520195a7187d791b2885848ad0d5a9b43
Diffstat (limited to 'guava')
-rw-r--r--guava/Android.mk40
-rw-r--r--guava/COPYING202
-rw-r--r--guava/README28
-rw-r--r--guava/README.android8
-rw-r--r--guava/README.maven29
-rw-r--r--guava/build.xml136
-rw-r--r--guava/collect-jarjar-rules.txt2
-rw-r--r--guava/guava.iml21
-rw-r--r--guava/guava.ipr1104
-rw-r--r--guava/mvn-deploy.sh40
-rw-r--r--guava/pom.xml91
-rw-r--r--guava/src/com/google/common/annotations/Beta.java50
-rw-r--r--guava/src/com/google/common/annotations/GwtCompatible.java88
-rw-r--r--guava/src/com/google/common/annotations/GwtIncompatible.java52
-rw-r--r--guava/src/com/google/common/annotations/VisibleForTesting.java27
-rw-r--r--guava/src/com/google/common/annotations/package-info.java21
-rw-r--r--guava/src/com/google/common/base/Absent.java87
-rw-r--r--guava/src/com/google/common/base/AbstractIterator.java84
-rw-r--r--guava/src/com/google/common/base/Ascii.java487
-rw-r--r--guava/src/com/google/common/base/CaseFormat.java164
-rw-r--r--guava/src/com/google/common/base/CharMatcher.java1271
-rw-r--r--guava/src/com/google/common/base/Charsets.java83
-rw-r--r--guava/src/com/google/common/base/Defaults.java60
-rw-r--r--guava/src/com/google/common/base/Enums.java128
-rw-r--r--guava/src/com/google/common/base/Equivalence.java358
-rw-r--r--guava/src/com/google/common/base/Equivalences.java65
-rw-r--r--guava/src/com/google/common/base/FinalizablePhantomReference.java44
-rw-r--r--guava/src/com/google/common/base/FinalizableReference.java33
-rw-r--r--guava/src/com/google/common/base/FinalizableReferenceQueue.java299
-rw-r--r--guava/src/com/google/common/base/FinalizableSoftReference.java42
-rw-r--r--guava/src/com/google/common/base/FinalizableWeakReference.java42
-rw-r--r--guava/src/com/google/common/base/Function.java63
-rw-r--r--guava/src/com/google/common/base/FunctionalEquivalence.java77
-rw-r--r--guava/src/com/google/common/base/Functions.java356
-rw-r--r--guava/src/com/google/common/base/Joiner.java562
-rw-r--r--guava/src/com/google/common/base/MediumCharMatcher.java133
-rw-r--r--guava/src/com/google/common/base/Objects.java440
-rw-r--r--guava/src/com/google/common/base/Optional.java245
-rw-r--r--guava/src/com/google/common/base/PairwiseEquivalence.java80
-rw-r--r--guava/src/com/google/common/base/Platform.java55
-rw-r--r--guava/src/com/google/common/base/Preconditions.java449
-rw-r--r--guava/src/com/google/common/base/Predicate.java63
-rw-r--r--guava/src/com/google/common/base/Predicates.java626
-rw-r--r--guava/src/com/google/common/base/Present.java92
-rw-r--r--guava/src/com/google/common/base/SmallCharMatcher.java128
-rw-r--r--guava/src/com/google/common/base/Splitter.java571
-rw-r--r--guava/src/com/google/common/base/Stopwatch.java226
-rw-r--r--guava/src/com/google/common/base/Strings.java238
-rw-r--r--guava/src/com/google/common/base/Supplier.java38
-rw-r--r--guava/src/com/google/common/base/Suppliers.java293
-rw-r--r--guava/src/com/google/common/base/Throwables.java220
-rw-r--r--guava/src/com/google/common/base/Ticker.java63
-rw-r--r--guava/src/com/google/common/base/internal/Finalizer.java205
-rw-r--r--guava/src/com/google/common/base/package-info.java66
-rw-r--r--guava/src/com/google/common/cache/AbstractCache.java275
-rw-r--r--guava/src/com/google/common/cache/AbstractLoadingCache.java79
-rw-r--r--guava/src/com/google/common/cache/Cache.java147
-rw-r--r--guava/src/com/google/common/cache/CacheBuilder.java888
-rw-r--r--guava/src/com/google/common/cache/CacheBuilderSpec.java455
-rw-r--r--guava/src/com/google/common/cache/CacheLoader.java194
-rw-r--r--guava/src/com/google/common/cache/CacheStats.java269
-rw-r--r--guava/src/com/google/common/cache/ForwardingCache.java146
-rw-r--r--guava/src/com/google/common/cache/ForwardingLoadingCache.java91
-rw-r--r--guava/src/com/google/common/cache/LoadingCache.java163
-rw-r--r--guava/src/com/google/common/cache/LocalCache.java4913
-rw-r--r--guava/src/com/google/common/cache/LongAdder.java207
-rw-r--r--guava/src/com/google/common/cache/RemovalCause.java97
-rw-r--r--guava/src/com/google/common/cache/RemovalListener.java46
-rw-r--r--guava/src/com/google/common/cache/RemovalListeners.java57
-rw-r--r--guava/src/com/google/common/cache/RemovalNotification.java100
-rw-r--r--guava/src/com/google/common/cache/Striped64.java344
-rw-r--r--guava/src/com/google/common/cache/Weigher.java35
-rw-r--r--guava/src/com/google/common/cache/package-info.java38
-rw-r--r--guava/src/com/google/common/collect/AbstractBiMap.java404
-rw-r--r--guava/src/com/google/common/collect/AbstractIndexedListIterator.java109
-rw-r--r--guava/src/com/google/common/collect/AbstractIterator.java173
-rw-r--r--guava/src/com/google/common/collect/AbstractLinkedIterator.java84
-rw-r--r--guava/src/com/google/common/collect/AbstractListMultimap.java120
-rw-r--r--guava/src/com/google/common/collect/AbstractMapBasedMultiset.java325
-rw-r--r--guava/src/com/google/common/collect/AbstractMapEntry.java67
-rw-r--r--guava/src/com/google/common/collect/AbstractMultimap.java1414
-rw-r--r--guava/src/com/google/common/collect/AbstractMultiset.java221
-rw-r--r--guava/src/com/google/common/collect/AbstractSequentialIterator.java80
-rw-r--r--guava/src/com/google/common/collect/AbstractSetMultimap.java132
-rw-r--r--guava/src/com/google/common/collect/AbstractSortedMultiset.java147
-rw-r--r--guava/src/com/google/common/collect/AbstractSortedSetMultimap.java124
-rw-r--r--guava/src/com/google/common/collect/AllEqualOrdering.java66
-rw-r--r--guava/src/com/google/common/collect/ArrayListMultimap.java168
-rw-r--r--guava/src/com/google/common/collect/ArrayTable.java825
-rw-r--r--guava/src/com/google/common/collect/AsynchronousComputationException.java37
-rw-r--r--guava/src/com/google/common/collect/BiMap.java110
-rw-r--r--guava/src/com/google/common/collect/BoundType.java57
-rw-r--r--guava/src/com/google/common/collect/ByFunctionOrdering.java70
-rw-r--r--guava/src/com/google/common/collect/ClassToInstanceMap.java66
-rw-r--r--guava/src/com/google/common/collect/Collections2.java703
-rw-r--r--guava/src/com/google/common/collect/ComparatorOrdering.java87
-rw-r--r--guava/src/com/google/common/collect/ComparisonChain.java225
-rw-r--r--guava/src/com/google/common/collect/CompoundOrdering.java71
-rw-r--r--guava/src/com/google/common/collect/ComputationException.java36
-rw-r--r--guava/src/com/google/common/collect/ComputingConcurrentHashMap.java454
-rw-r--r--guava/src/com/google/common/collect/ConcurrentHashMultiset.java605
-rw-r--r--guava/src/com/google/common/collect/Constraint.java67
-rw-r--r--guava/src/com/google/common/collect/Constraints.java382
-rw-r--r--guava/src/com/google/common/collect/ContiguousSet.java172
-rw-r--r--guava/src/com/google/common/collect/Count.java74
-rw-r--r--guava/src/com/google/common/collect/Cut.java347
-rw-r--r--guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java97
-rw-r--r--guava/src/com/google/common/collect/DiscreteDomain.java117
-rw-r--r--guava/src/com/google/common/collect/DiscreteDomains.java162
-rw-r--r--guava/src/com/google/common/collect/EmptyContiguousSet.java136
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableBiMap.java45
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableList.java131
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableListMultimap.java40
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableMap.java99
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableMultiset.java114
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableSet.java100
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableSetMultimap.java40
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableSortedMap.java119
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableSortedMultiset.java139
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableSortedSet.java127
-rw-r--r--guava/src/com/google/common/collect/EmptyImmutableTable.java128
-rw-r--r--guava/src/com/google/common/collect/EnumBiMap.java151
-rw-r--r--guava/src/com/google/common/collect/EnumHashBiMap.java130
-rw-r--r--guava/src/com/google/common/collect/EnumMultiset.java94
-rw-r--r--guava/src/com/google/common/collect/ExplicitOrdering.java78
-rw-r--r--guava/src/com/google/common/collect/FluentIterable.java399
-rw-r--r--guava/src/com/google/common/collect/ForwardingCollection.java265
-rw-r--r--guava/src/com/google/common/collect/ForwardingConcurrentMap.java61
-rw-r--r--guava/src/com/google/common/collect/ForwardingDeque.java136
-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/ForwardingIterator.java55
-rw-r--r--guava/src/com/google/common/collect/ForwardingList.java239
-rw-r--r--guava/src/com/google/common/collect/ForwardingListIterator.java70
-rw-r--r--guava/src/com/google/common/collect/ForwardingListMultimap.java54
-rw-r--r--guava/src/com/google/common/collect/ForwardingMap.java319
-rw-r--r--guava/src/com/google/common/collect/ForwardingMapEntry.java128
-rw-r--r--guava/src/com/google/common/collect/ForwardingMultimap.java143
-rw-r--r--guava/src/com/google/common/collect/ForwardingMultiset.java313
-rw-r--r--guava/src/com/google/common/collect/ForwardingNavigableMap.java412
-rw-r--r--guava/src/com/google/common/collect/ForwardingNavigableSet.java250
-rw-r--r--guava/src/com/google/common/collect/ForwardingObject.java76
-rw-r--r--guava/src/com/google/common/collect/ForwardingQueue.java123
-rw-r--r--guava/src/com/google/common/collect/ForwardingSet.java101
-rw-r--r--guava/src/com/google/common/collect/ForwardingSetMultimap.java56
-rw-r--r--guava/src/com/google/common/collect/ForwardingSortedMap.java171
-rw-r--r--guava/src/com/google/common/collect/ForwardingSortedSet.java166
-rw-r--r--guava/src/com/google/common/collect/ForwardingSortedSetMultimap.java60
-rw-r--r--guava/src/com/google/common/collect/ForwardingTable.java144
-rw-r--r--guava/src/com/google/common/collect/GeneralRange.java304
-rw-r--r--guava/src/com/google/common/collect/GenericMapMaker.java143
-rw-r--r--guava/src/com/google/common/collect/GwtTransient.java38
-rw-r--r--guava/src/com/google/common/collect/HashBasedTable.java148
-rw-r--r--guava/src/com/google/common/collect/HashBiMap.java118
-rw-r--r--guava/src/com/google/common/collect/HashMultimap.java142
-rw-r--r--guava/src/com/google/common/collect/HashMultiset.java101
-rw-r--r--guava/src/com/google/common/collect/Hashing.java43
-rw-r--r--guava/src/com/google/common/collect/ImmutableAsList.java84
-rw-r--r--guava/src/com/google/common/collect/ImmutableBiMap.java305
-rw-r--r--guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java154
-rw-r--r--guava/src/com/google/common/collect/ImmutableCollection.java376
-rw-r--r--guava/src/com/google/common/collect/ImmutableEntry.java52
-rw-r--r--guava/src/com/google/common/collect/ImmutableEnumSet.java116
-rw-r--r--guava/src/com/google/common/collect/ImmutableList.java749
-rw-r--r--guava/src/com/google/common/collect/ImmutableListMultimap.java388
-rw-r--r--guava/src/com/google/common/collect/ImmutableMap.java462
-rw-r--r--guava/src/com/google/common/collect/ImmutableMapEntrySet.java76
-rw-r--r--guava/src/com/google/common/collect/ImmutableMapKeySet.java92
-rw-r--r--guava/src/com/google/common/collect/ImmutableMapValues.java89
-rw-r--r--guava/src/com/google/common/collect/ImmutableMultimap.java682
-rw-r--r--guava/src/com/google/common/collect/ImmutableMultiset.java596
-rw-r--r--guava/src/com/google/common/collect/ImmutableSet.java626
-rw-r--r--guava/src/com/google/common/collect/ImmutableSetMultimap.java510
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedAsList.java86
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedMap.java705
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedMapFauxverideShim.java117
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedMultiset.java574
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java170
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedSet.java845
-rw-r--r--guava/src/com/google/common/collect/ImmutableSortedSetFauxverideShim.java167
-rw-r--r--guava/src/com/google/common/collect/ImmutableTable.java336
-rw-r--r--guava/src/com/google/common/collect/Interner.java44
-rw-r--r--guava/src/com/google/common/collect/Interners.java136
-rw-r--r--guava/src/com/google/common/collect/Iterables.java1071
-rw-r--r--guava/src/com/google/common/collect/Iterators.java1427
-rw-r--r--guava/src/com/google/common/collect/LexicographicalOrdering.java78
-rw-r--r--guava/src/com/google/common/collect/LinkedHashMultimap.java615
-rw-r--r--guava/src/com/google/common/collect/LinkedHashMultiset.java113
-rw-r--r--guava/src/com/google/common/collect/LinkedListMultimap.java995
-rw-r--r--guava/src/com/google/common/collect/ListMultimap.java96
-rw-r--r--guava/src/com/google/common/collect/Lists.java1073
-rw-r--r--guava/src/com/google/common/collect/MapConstraint.java65
-rw-r--r--guava/src/com/google/common/collect/MapConstraints.java783
-rw-r--r--guava/src/com/google/common/collect/MapDifference.java114
-rw-r--r--guava/src/com/google/common/collect/MapMaker.java887
-rw-r--r--guava/src/com/google/common/collect/MapMakerInternalMap.java4081
-rw-r--r--guava/src/com/google/common/collect/Maps.java3240
-rw-r--r--guava/src/com/google/common/collect/MinMaxPriorityQueue.java939
-rw-r--r--guava/src/com/google/common/collect/Multimap.java360
-rw-r--r--guava/src/com/google/common/collect/Multimaps.java2695
-rw-r--r--guava/src/com/google/common/collect/Multiset.java440
-rw-r--r--guava/src/com/google/common/collect/Multisets.java972
-rw-r--r--guava/src/com/google/common/collect/MutableClassToInstanceMap.java86
-rw-r--r--guava/src/com/google/common/collect/NaturalOrdering.java74
-rw-r--r--guava/src/com/google/common/collect/NullsFirstOrdering.java81
-rw-r--r--guava/src/com/google/common/collect/NullsLastOrdering.java81
-rw-r--r--guava/src/com/google/common/collect/ObjectArrays.java195
-rw-r--r--guava/src/com/google/common/collect/Ordering.java791
-rw-r--r--guava/src/com/google/common/collect/PeekingIterator.java69
-rw-r--r--guava/src/com/google/common/collect/Platform.java77
-rw-r--r--guava/src/com/google/common/collect/Queues.java341
-rw-r--r--guava/src/com/google/common/collect/Range.java438
-rw-r--r--guava/src/com/google/common/collect/RangeMap.java223
-rw-r--r--guava/src/com/google/common/collect/RangeSet.java289
-rw-r--r--guava/src/com/google/common/collect/Ranges.java255
-rw-r--r--guava/src/com/google/common/collect/RegularContiguousSet.java276
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableAsList.java91
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableBiMap.java60
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableList.java139
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableMap.java246
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableMultiset.java110
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableSet.java67
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableSortedMap.java128
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java145
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableSortedSet.java262
-rw-r--r--guava/src/com/google/common/collect/RegularImmutableTable.java559
-rw-r--r--guava/src/com/google/common/collect/ReverseNaturalOrdering.java92
-rw-r--r--guava/src/com/google/common/collect/ReverseOrdering.java100
-rw-r--r--guava/src/com/google/common/collect/RowSortedTable.java55
-rw-r--r--guava/src/com/google/common/collect/Serialization.java231
-rw-r--r--guava/src/com/google/common/collect/SetMultimap.java113
-rw-r--r--guava/src/com/google/common/collect/Sets.java1666
-rw-r--r--guava/src/com/google/common/collect/SingletonImmutableList.java128
-rw-r--r--guava/src/com/google/common/collect/SingletonImmutableMap.java105
-rw-r--r--guava/src/com/google/common/collect/SingletonImmutableSet.java125
-rw-r--r--guava/src/com/google/common/collect/SingletonImmutableTable.java149
-rw-r--r--guava/src/com/google/common/collect/SortedIterable.java42
-rw-r--r--guava/src/com/google/common/collect/SortedIterables.java60
-rw-r--r--guava/src/com/google/common/collect/SortedLists.java284
-rw-r--r--guava/src/com/google/common/collect/SortedMapDifference.java45
-rw-r--r--guava/src/com/google/common/collect/SortedMultiset.java137
-rw-r--r--guava/src/com/google/common/collect/SortedMultisets.java196
-rw-r--r--guava/src/com/google/common/collect/SortedSetMultimap.java114
-rw-r--r--guava/src/com/google/common/collect/StandardRowSortedTable.java172
-rw-r--r--guava/src/com/google/common/collect/StandardTable.java1122
-rw-r--r--guava/src/com/google/common/collect/Synchronized.java1565
-rw-r--r--guava/src/com/google/common/collect/Table.java296
-rw-r--r--guava/src/com/google/common/collect/Tables.java753
-rw-r--r--guava/src/com/google/common/collect/TransformedImmutableSet.java91
-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.java380
-rw-r--r--guava/src/com/google/common/collect/TreeMultimap.java201
-rw-r--r--guava/src/com/google/common/collect/TreeMultiset.java982
-rw-r--r--guava/src/com/google/common/collect/TreeRangeSet.java203
-rw-r--r--guava/src/com/google/common/collect/UnmodifiableIterator.java43
-rw-r--r--guava/src/com/google/common/collect/UnmodifiableListIterator.java53
-rw-r--r--guava/src/com/google/common/collect/UsingToStringOrdering.java45
-rw-r--r--guava/src/com/google/common/collect/WellBehavedMap.java98
-rw-r--r--guava/src/com/google/common/collect/package-info.java226
-rw-r--r--guava/src/com/google/common/eventbus/AllowConcurrentEvents.java41
-rw-r--r--guava/src/com/google/common/eventbus/AnnotatedHandlerFinder.java106
-rw-r--r--guava/src/com/google/common/eventbus/AsyncEventBus.java101
-rw-r--r--guava/src/com/google/common/eventbus/DeadEvent.java69
-rw-r--r--guava/src/com/google/common/eventbus/EventBus.java358
-rw-r--r--guava/src/com/google/common/eventbus/EventHandler.java109
-rw-r--r--guava/src/com/google/common/eventbus/HandlerFindingStrategy.java42
-rw-r--r--guava/src/com/google/common/eventbus/Subscribe.java46
-rw-r--r--guava/src/com/google/common/eventbus/SynchronizedEventHandler.java48
-rw-r--r--guava/src/com/google/common/eventbus/package-info.java254
-rw-r--r--guava/src/com/google/common/hash/AbstractCompositeHashFunction.java148
-rw-r--r--guava/src/com/google/common/hash/AbstractHasher.java49
-rw-r--r--guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java158
-rw-r--r--guava/src/com/google/common/hash/AbstractStreamingHashFunction.java253
-rw-r--r--guava/src/com/google/common/hash/BloomFilter.java310
-rw-r--r--guava/src/com/google/common/hash/BloomFilterStrategies.java137
-rw-r--r--guava/src/com/google/common/hash/Funnel.java38
-rw-r--r--guava/src/com/google/common/hash/Funnels.java148
-rw-r--r--guava/src/com/google/common/hash/HashCode.java120
-rw-r--r--guava/src/com/google/common/hash/HashCodes.java171
-rw-r--r--guava/src/com/google/common/hash/HashFunction.java207
-rw-r--r--guava/src/com/google/common/hash/Hasher.java75
-rw-r--r--guava/src/com/google/common/hash/Hashing.java336
-rw-r--r--guava/src/com/google/common/hash/MessageDigestHashFunction.java169
-rw-r--r--guava/src/com/google/common/hash/Murmur3_128HashFunction.java172
-rw-r--r--guava/src/com/google/common/hash/Murmur3_32HashFunction.java158
-rw-r--r--guava/src/com/google/common/hash/PrimitiveSink.java102
-rw-r--r--guava/src/com/google/common/hash/package-info.java26
-rw-r--r--guava/src/com/google/common/io/AppendableWriter.java117
-rw-r--r--guava/src/com/google/common/io/ByteArrayDataInput.java65
-rw-r--r--guava/src/com/google/common/io/ByteArrayDataOutput.java55
-rw-r--r--guava/src/com/google/common/io/ByteProcessor.java49
-rw-r--r--guava/src/com/google/common/io/ByteStreams.java871
-rw-r--r--guava/src/com/google/common/io/CharStreams.java441
-rw-r--r--guava/src/com/google/common/io/Closeables.java104
-rw-r--r--guava/src/com/google/common/io/CountingInputStream.java90
-rw-r--r--guava/src/com/google/common/io/CountingOutputStream.java59
-rw-r--r--guava/src/com/google/common/io/FileBackedOutputStream.java210
-rw-r--r--guava/src/com/google/common/io/Files.java780
-rw-r--r--guava/src/com/google/common/io/Flushables.java80
-rw-r--r--guava/src/com/google/common/io/InputSupplier.java40
-rw-r--r--guava/src/com/google/common/io/LimitInputStream.java104
-rw-r--r--guava/src/com/google/common/io/LineBuffer.java117
-rw-r--r--guava/src/com/google/common/io/LineProcessor.java45
-rw-r--r--guava/src/com/google/common/io/LineReader.java87
-rw-r--r--guava/src/com/google/common/io/LittleEndianDataInputStream.java232
-rw-r--r--guava/src/com/google/common/io/LittleEndianDataOutputStream.java164
-rw-r--r--guava/src/com/google/common/io/MultiInputStream.java115
-rw-r--r--guava/src/com/google/common/io/MultiReader.java90
-rw-r--r--guava/src/com/google/common/io/NullOutputStream.java38
-rw-r--r--guava/src/com/google/common/io/OutputSupplier.java40
-rw-r--r--guava/src/com/google/common/io/PatternFilenameFilter.java62
-rw-r--r--guava/src/com/google/common/io/Resources.java173
-rw-r--r--guava/src/com/google/common/io/package-info.java41
-rw-r--r--guava/src/com/google/common/math/BigIntegerMath.java451
-rw-r--r--guava/src/com/google/common/math/DoubleMath.java379
-rw-r--r--guava/src/com/google/common/math/DoubleUtils.java148
-rw-r--r--guava/src/com/google/common/math/IntMath.java551
-rw-r--r--guava/src/com/google/common/math/LongMath.java675
-rw-r--r--guava/src/com/google/common/math/MathPreconditions.java98
-rw-r--r--guava/src/com/google/common/math/package-info.java31
-rw-r--r--guava/src/com/google/common/net/HostAndPort.java268
-rw-r--r--guava/src/com/google/common/net/HostSpecifier.java178
-rw-r--r--guava/src/com/google/common/net/HttpHeaders.java200
-rw-r--r--guava/src/com/google/common/net/InetAddresses.java1011
-rw-r--r--guava/src/com/google/common/net/InternetDomainName.java580
-rw-r--r--guava/src/com/google/common/net/MediaType.java667
-rw-r--r--guava/src/com/google/common/net/TldPatterns.java4633
-rw-r--r--guava/src/com/google/common/net/package-info.java30
-rw-r--r--guava/src/com/google/common/primitives/AndroidInteger.java91
-rw-r--r--guava/src/com/google/common/primitives/Booleans.java471
-rw-r--r--guava/src/com/google/common/primitives/Bytes.java389
-rw-r--r--guava/src/com/google/common/primitives/Chars.java587
-rw-r--r--guava/src/com/google/common/primitives/Doubles.java534
-rw-r--r--guava/src/com/google/common/primitives/Floats.java531
-rw-r--r--guava/src/com/google/common/primitives/Ints.java620
-rw-r--r--guava/src/com/google/common/primitives/Longs.java575
-rw-r--r--guava/src/com/google/common/primitives/ParseRequest.java57
-rw-r--r--guava/src/com/google/common/primitives/Primitives.java134
-rw-r--r--guava/src/com/google/common/primitives/Shorts.java593
-rw-r--r--guava/src/com/google/common/primitives/SignedBytes.java194
-rw-r--r--guava/src/com/google/common/primitives/UnsignedBytes.java438
-rw-r--r--guava/src/com/google/common/primitives/UnsignedInteger.java240
-rw-r--r--guava/src/com/google/common/primitives/UnsignedInts.java275
-rw-r--r--guava/src/com/google/common/primitives/UnsignedLong.java243
-rw-r--r--guava/src/com/google/common/primitives/UnsignedLongs.java391
-rw-r--r--guava/src/com/google/common/primitives/package-info.java69
-rw-r--r--guava/src/com/google/common/reflect/AbstractInvocationHandler.java82
-rw-r--r--guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java138
-rw-r--r--guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java89
-rw-r--r--guava/src/com/google/common/reflect/Reflection.java103
-rw-r--r--guava/src/com/google/common/reflect/TypeCapture.java38
-rw-r--r--guava/src/com/google/common/reflect/TypeParameter.java70
-rw-r--r--guava/src/com/google/common/reflect/TypeResolver.java389
-rw-r--r--guava/src/com/google/common/reflect/TypeToInstanceMap.java92
-rw-r--r--guava/src/com/google/common/reflect/TypeToken.java1086
-rw-r--r--guava/src/com/google/common/reflect/Types.java518
-rw-r--r--guava/src/com/google/common/reflect/package-info.java23
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractCheckedFuture.java117
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java188
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractFuture.java371
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractIdleService.java132
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java163
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractScheduledService.java446
-rw-r--r--guava/src/com/google/common/util/concurrent/AbstractService.java536
-rw-r--r--guava/src/com/google/common/util/concurrent/AsyncFunction.java41
-rw-r--r--guava/src/com/google/common/util/concurrent/AtomicDouble.java257
-rw-r--r--guava/src/com/google/common/util/concurrent/AtomicDoubleArray.java271
-rw-r--r--guava/src/com/google/common/util/concurrent/AtomicLongMap.java434
-rw-r--r--guava/src/com/google/common/util/concurrent/Atomics.java76
-rw-r--r--guava/src/com/google/common/util/concurrent/Callables.java43
-rw-r--r--guava/src/com/google/common/util/concurrent/CheckedFuture.java76
-rw-r--r--guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java1034
-rw-r--r--guava/src/com/google/common/util/concurrent/ExecutionError.java64
-rw-r--r--guava/src/com/google/common/util/concurrent/ExecutionList.java159
-rw-r--r--guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java47
-rw-r--r--guava/src/com/google/common/util/concurrent/ForwardingBlockingQueue.java74
-rw-r--r--guava/src/com/google/common/util/concurrent/ForwardingCheckedFuture.java78
-rw-r--r--guava/src/com/google/common/util/concurrent/ForwardingExecutorService.java117
-rw-r--r--guava/src/com/google/common/util/concurrent/ForwardingFuture.java96
-rw-r--r--guava/src/com/google/common/util/concurrent/ForwardingListenableFuture.java74
-rw-r--r--guava/src/com/google/common/util/concurrent/ForwardingListeningExecutorService.java52
-rw-r--r--guava/src/com/google/common/util/concurrent/ForwardingService.java86
-rw-r--r--guava/src/com/google/common/util/concurrent/FutureCallback.java49
-rw-r--r--guava/src/com/google/common/util/concurrent/Futures.java1249
-rw-r--r--guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java182
-rw-r--r--guava/src/com/google/common/util/concurrent/ListenableFuture.java135
-rw-r--r--guava/src/com/google/common/util/concurrent/ListenableFutureTask.java90
-rw-r--r--guava/src/com/google/common/util/concurrent/ListeningExecutorService.java88
-rw-r--r--guava/src/com/google/common/util/concurrent/ListeningScheduledExecutorService.java40
-rw-r--r--guava/src/com/google/common/util/concurrent/Monitor.java942
-rw-r--r--guava/src/com/google/common/util/concurrent/MoreExecutors.java587
-rw-r--r--guava/src/com/google/common/util/concurrent/RateLimiter.java658
-rw-r--r--guava/src/com/google/common/util/concurrent/Service.java234
-rw-r--r--guava/src/com/google/common/util/concurrent/SettableFuture.java70
-rw-r--r--guava/src/com/google/common/util/concurrent/SimpleTimeLimiter.java195
-rw-r--r--guava/src/com/google/common/util/concurrent/Striped.java376
-rw-r--r--guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java176
-rw-r--r--guava/src/com/google/common/util/concurrent/TimeLimiter.java106
-rw-r--r--guava/src/com/google/common/util/concurrent/UncaughtExceptionHandlers.java65
-rw-r--r--guava/src/com/google/common/util/concurrent/UncheckedExecutionException.java69
-rw-r--r--guava/src/com/google/common/util/concurrent/UncheckedTimeoutException.java41
-rw-r--r--guava/src/com/google/common/util/concurrent/Uninterruptibles.java278
-rw-r--r--guava/src/com/google/common/util/concurrent/package-info.java36
-rw-r--r--guava/test/com/google/common/base/CaseFormatTest.java202
-rw-r--r--guava/test/com/google/common/base/CharMatcherTest.java613
-rw-r--r--guava/test/com/google/common/base/CharsetsTest.java52
-rw-r--r--guava/test/com/google/common/base/DefaultsTest.java39
-rw-r--r--guava/test/com/google/common/base/FinalizableReferenceQueueTest.java163
-rw-r--r--guava/test/com/google/common/base/FunctionsTest.java403
-rw-r--r--guava/test/com/google/common/base/JoinerTest.java264
-rw-r--r--guava/test/com/google/common/base/ObjectsTest.java80
-rw-r--r--guava/test/com/google/common/base/PreconditionsTest.java369
-rw-r--r--guava/test/com/google/common/base/PredicatesTest.java963
-rw-r--r--guava/test/com/google/common/base/SplitterTest.java529
-rw-r--r--guava/test/com/google/common/base/StringsTest.java132
-rw-r--r--guava/test/com/google/common/base/SuppliersTest.java274
-rw-r--r--guava/test/com/google/common/base/ThrowablesTest.java601
-rw-r--r--guava/test/com/google/common/base/ToStringHelperTest.java119
420 files changed, 120296 insertions, 0 deletions
diff --git a/guava/Android.mk b/guava/Android.mk
new file mode 100644
index 0000000..4bb7ae4
--- /dev/null
+++ b/guava/Android.mk
@@ -0,0 +1,40 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under, src/)
+
+LOCAL_MODULE := guava-jack
+
+LOCAL_JAVA_LIBRARIES := jsr305lib-jack
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+#
+# Build guava for java-allocation-tracker
+#
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/)
+LOCAL_MODULE := guava-collect-jack
+LOCAL_JARJAR_RULES := $(LOCAL_PATH)/collect-jarjar-rules.txt
+LOCAL_STATIC_JAVA_LIBRARIES := jsr305lib-jack
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/guava/COPYING b/guava/COPYING
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/guava/COPYING
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/guava/README b/guava/README
new file mode 100644
index 0000000..a0e832d
--- /dev/null
+++ b/guava/README
@@ -0,0 +1,28 @@
+Guava: Google Core Libraries for Java
+
+Requires JDK 5 or higher.
+
+Project page:
+ http://guava-libraries.googlecode.com
+
+Ask "how-to" and "why-didn't-it-work" questions at:
+ http://www.stackoverflow.com/questions/ask
+ (use the "guava" tag so we'll see it)
+
+Ask discussion questions at:
+ http://groups.google.com/group/guava-discuss
+
+Subscribe to project updates in your feed reader:
+ http://code.google.com/feeds/p/guava-libraries/updates/basic
+
+Warnings:
+
+All APIs marked @Beta at the class or method level are subject to
+change. If your code is a library or framework that users outside
+your control will include on their classpath, do not use @Beta
+APIs (at least without repackaging them somehow).
+
+Serialized forms of ALL objects are subject to change. Do not
+persist these and assume they can be read by a future version of
+the library.
+
diff --git a/guava/README.android b/guava/README.android
new file mode 100644
index 0000000..91875bc
--- /dev/null
+++ b/guava/README.android
@@ -0,0 +1,8 @@
+URL: http://code.google.com/p/guava-libraries/wiki/Release13
+Tag: v13.0.1
+License: Apache 2
+Description: The Guava project contains several of Google's core libraries that
+we rely on in our Java-based projects: collections, caching, primitives
+support, concurrency libraries, common annotations, string processing, I/O, and
+so forth.
+Local Modifications: the lib folder was not imported.
diff --git a/guava/README.maven b/guava/README.maven
new file mode 100644
index 0000000..1686138
--- /dev/null
+++ b/guava/README.maven
@@ -0,0 +1,29 @@
+These folders host the maven metadata which are used to
+build release binaries for hosting in hthe central maven
+repositories. These are not considered the "canonical"
+build, but are maintained seperately by (a) volunteer(s)
+with an interest in easy use of Guava by the Maven build
+system.
+
+As a convenience, these folders have been set up to
+provide alternate packaging of the sub-pmodules, which
+correspond to their respective java packages, with
+sources symbolically linked back to the main project.
+This will work to allow command-line builds on MacOS X
+or other Unix platforms which support symbolic linking,
+but is not known to work on Windows platforms.
+(Obviously the deployed binaries in maven repostories
+will work fine on any compliant JVM).
+
+The maintainers of these metadata have used M2Eclipse
+to import these projects directly into Eclipse. Please
+remember that this codebase uses @Override annotations
+on methods which implement an interface method, and
+therefore require a JDK 1.6 (or newer 1.5 with the
+appropriate fix) to support this behaviour. Executing
+Maven with an appropriate JAVA_HOME env is sufficient,
+and these metadata do not have toolchain restrictions
+currently set up.
+
+Christian
+cgruber@google.com
diff --git a/guava/build.xml b/guava/build.xml
new file mode 100644
index 0000000..e6a73cb
--- /dev/null
+++ b/guava/build.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+
+<!--
+
+ You must:
+ * have JAVA_HOME set to a recent JDK 6 installation
+ * have JAVA5_HOME set to a recent JDK 1.5.0 installation,
+ or specify this with -Djava5home=
+ * have unzipped $JAVA_HOME/src.zip to $JAVA_HOME/src,
+ or specify this with -Djavasrc=
+ * specify -Drelease=r09 (for example) on the ant command line
+
+-->
+
+<project name="guava" default="compile">
+
+ <property environment="env"/>
+
+ <!-- these properties can be overridden at the command line with
+ -Dname=value, or in IDEA in the ant properties dialog -->
+
+ <property name="release" value="unknown"/>
+ <property name="java5home" value="${env.JAVA5_HOME}" />
+ <property name="javasrc" value="${env.JAVA_HOME}/src" />
+
+ <target name="compile" description="Compile Java source.">
+ <mkdir dir="build/classes"/>
+
+ <property name="java5bootclasspath" value="${java5home}/jre/lib/rt.jar"/>
+
+ <available file="${java5bootclasspath}" property="isJava5HomeSetRight"/>
+ <fail unless="isJava5HomeSetRight"
+ message="JAVA5_HOME must be set to a valid JDK 1.5 installation, containing a jre/lib/rt.jar file"/>
+
+ <javac srcdir="src"
+ debug="on"
+ destdir="build/classes"
+ source="1.5"
+ target="1.5"
+ bootclasspath="${java5bootclasspath}"
+ extdirs="">
+ <compilerarg value="-Xlint:all"/>
+ <classpath>
+ <pathelement location="lib/jsr305.jar"/>
+ </classpath>
+ </javac>
+ </target>
+
+ <target name="jar" depends="compile" description="Build jar.">
+ <mkdir dir="build/dist/guava-${release}"/>
+ <jar jarfile="build/dist/guava-${release}/guava-${release}.jar">
+ <fileset dir="build/classes"/>
+ </jar>
+ </target>
+
+ <target name="javadoc" description="Generate Javadocs">
+ <delete dir="build/javadoc"/>
+ <mkdir dir="build/javadoc"/>
+
+ <javadoc packagenames="com.google.common.*"
+ destdir="build/javadoc"
+ encoding="UTF-8"
+ docencoding="UTF-8"
+ charset="UTF-8"
+ use="true"
+ author="true"
+ protected="true"
+ linksource="true"
+ windowtitle="Guava: Google Core Libraries for Java - ${release}">
+ <sourcepath>
+ <pathelement location="src"/>
+ <pathelement location="${javasrc}"/>
+ </sourcepath>
+ <!-- workaround for http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6442982 -->
+ <classpath>
+ <pathelement location="lib/jsr305.jar"/>
+ </classpath>
+ <link href="http://jsr-305.googlecode.com/svn/trunk/javadoc"/>
+ <link href="http://java.sun.com/javase/6/docs/api"/>
+ </javadoc>
+
+ <!-- remove dumb comments inserted by javadoc so that we only see svn diffs
+ when things actually change. -->
+ <replaceregexp
+ match="^.*(META NAME=.date|generated by javadoc ).*$\n"
+ replace=""
+ flags="gmi">
+ <fileset dir="build/javadoc" includes="**/*.html"/>
+ </replaceregexp>
+ </target>
+
+ <target name="jdiff" description="Generate JDiff report">
+ <mkdir dir="build/javadoc/jdiff"/>
+ <javadoc doclet="jdiff.JDiff"
+ docletpath="lib/jdiff.jar"
+ additionalparam="-apiname 'Guava ${release}' -apidir build/javadoc/jdiff"
+ packagenames="com.google.common.*"
+ destdir="build/javadoc/jdiff">
+ <sourcepath>
+ <pathelement location="src"/>
+ </sourcepath>
+ <classpath>
+ <pathelement location="lib/jsr305.jar"/>
+ </classpath>
+ </javadoc>
+
+ <!-- remove dumb comments inserted by jdiff so that we only see svn diffs when things actually change. -->
+ <replaceregexp match="^.!--\s+(on|Command line arguments) .* -->$\n"
+ replace="" flags="gm" file="build/javadoc/jdiff/Guava_${release}.xml"/>
+ </target>
+
+ <target name="zipsrc" description="Build zip of source.">
+ <mkdir dir="build/dist/guava-${release}"/>
+ <jar jarfile="build/dist/guava-${release}/guava-src-${release}.zip">
+ <fileset dir="src"/>
+ </jar>
+ </target>
+
+ <target name="dist" depends="jar, zipsrc, javadoc"
+ description="Build entire distribution.">
+ <copy toDir="build/dist/guava-${release}" file="COPYING"/>
+ <copy toDir="build/dist/guava-${release}" file="README"/>
+ <copy toDir="build/dist/guava-${release}">
+ <fileset dir="build" includes="javadoc/**/*" excludes="javadoc/jdiff/**/*"/>
+ </copy>
+
+ <zip destfile="build/guava-${release}.zip"
+ basedir="build/dist"/>
+ </target>
+
+ <target name="clean"
+ description="Remove generated files.">
+ <delete dir="build"/>
+ </target>
+
+</project>
diff --git a/guava/collect-jarjar-rules.txt b/guava/collect-jarjar-rules.txt
new file mode 100644
index 0000000..d69d803
--- /dev/null
+++ b/guava/collect-jarjar-rules.txt
@@ -0,0 +1,2 @@
+keep com.google.common.collect.MapMaker
+keep com.google.common.collect.ForwardingMap
diff --git a/guava/guava.iml b/guava/guava.iml
new file mode 100644
index 0000000..45bbe49
--- /dev/null
+++ b/guava/guava.iml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_5" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module-library">
+ <library>
+ <CLASSES>
+ <root url="jar://$MODULE_DIR$/lib/jsr305.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ </component>
+</module>
+
diff --git a/guava/guava.ipr b/guava/guava.ipr
new file mode 100644
index 0000000..1a48bef
--- /dev/null
+++ b/guava/guava.ipr
@@ -0,0 +1,1104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="AntConfiguration">
+ <defaultAnt bundledAnt="true" />
+ </component>
+ <component name="BlazePluginSettings" buildBeforeRefresh="true" blazeTestProducers="true" updater="default" />
+ <component name="ClientPropertiesManager">
+ <properties class="javax.swing.AbstractButton">
+ <property name="hideActionText" class="java.lang.Boolean" />
+ </properties>
+ <properties class="javax.swing.JComponent">
+ <property name="html.disable" class="java.lang.Boolean" />
+ </properties>
+ <properties class="javax.swing.JEditorPane">
+ <property name="JEditorPane.w3cLengthUnits" class="java.lang.Boolean" />
+ <property name="JEditorPane.honorDisplayProperties" class="java.lang.Boolean" />
+ <property name="charset" class="java.lang.String" />
+ </properties>
+ <properties class="javax.swing.JList">
+ <property name="List.isFileList" class="java.lang.Boolean" />
+ </properties>
+ <properties class="javax.swing.JPasswordField">
+ <property name="JPasswordField.cutCopyAllowed" class="java.lang.Boolean" />
+ </properties>
+ <properties class="javax.swing.JSlider">
+ <property name="Slider.paintThumbArrowShape" class="java.lang.Boolean" />
+ <property name="JSlider.isFilled" class="java.lang.Boolean" />
+ </properties>
+ <properties class="javax.swing.JTable">
+ <property name="Table.isFileList" class="java.lang.Boolean" />
+ <property name="JTable.autoStartsEdit" class="java.lang.Boolean" />
+ <property name="terminateEditOnFocusLost" class="java.lang.Boolean" />
+ </properties>
+ <properties class="javax.swing.JToolBar">
+ <property name="JToolBar.isRollover" class="java.lang.Boolean" />
+ </properties>
+ <properties class="javax.swing.JTree">
+ <property name="JTree.lineStyle" class="java.lang.String" />
+ </properties>
+ <properties class="javax.swing.text.JTextComponent">
+ <property name="caretAspectRatio" class="java.lang.Double" />
+ <property name="caretWidth" class="java.lang.Integer" />
+ </properties>
+ </component>
+ <component name="CodeStyleSettingsManager">
+ <option name="PER_PROJECT_SETTINGS">
+ <value>
+ <option name="LAYOUT_STATIC_IMPORTS_SEPARATELY" value="false" />
+ <option name="USE_FQ_CLASS_NAMES_IN_JAVADOC" value="false" />
+ <option name="INSERT_INNER_CLASS_IMPORTS" value="true" />
+ <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="59" />
+ <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="39" />
+ <option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
+ <value />
+ </option>
+ <option name="IMPORT_LAYOUT_TABLE">
+ <value>
+ <package name="com.google" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="java" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="javax" withSubpackages="true" static="false" />
+ <emptyLine />
+ <package name="" withSubpackages="true" static="false" />
+ <emptyLine />
+ </value>
+ </option>
+ <ADDITIONAL_INDENT_OPTIONS fileType="groovy">
+ <option name="INDENT_SIZE" value="2" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="java">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="js">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="jsp">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ <ADDITIONAL_INDENT_OPTIONS fileType="xml">
+ <option name="INDENT_SIZE" value="4" />
+ <option name="CONTINUATION_INDENT_SIZE" value="8" />
+ <option name="TAB_SIZE" value="4" />
+ <option name="USE_TAB_CHARACTER" value="false" />
+ <option name="SMART_TABS" value="false" />
+ <option name="LABEL_INDENT_SIZE" value="0" />
+ <option name="LABEL_INDENT_ABSOLUTE" value="false" />
+ </ADDITIONAL_INDENT_OPTIONS>
+ </value>
+ </option>
+ <option name="USE_PER_PROJECT_SETTINGS" value="true" />
+ </component>
+ <component name="CompilerConfiguration">
+ <option name="DEFAULT_COMPILER" value="Javac" />
+ <resourceExtensions>
+ <entry name=".+\.(properties|xml|html|dtd|tld)" />
+ <entry name=".+\.(gif|png|jpeg|jpg)" />
+ </resourceExtensions>
+ <wildcardResourcePatterns>
+ <entry name="?*.properties" />
+ <entry name="?*.xml" />
+ <entry name="?*.gif" />
+ <entry name="?*.png" />
+ <entry name="?*.jpeg" />
+ <entry name="?*.jpg" />
+ <entry name="?*.html" />
+ <entry name="?*.dtd" />
+ <entry name="?*.tld" />
+ <entry name="?*.ftl" />
+ <entry name="?*.properties" />
+ <entry name="?*.xml" />
+ <entry name="?*.html" />
+ <entry name="?*.dtd" />
+ <entry name="?*.tld" />
+ <entry name="?*.gif" />
+ <entry name="?*.png" />
+ <entry name="?*.jpeg" />
+ <entry name="?*.jpg" />
+ </wildcardResourcePatterns>
+ <annotationProcessing enabled="false" useClasspath="true" />
+ </component>
+ <component name="CopyrightManager" default="">
+ <copyright>
+ <option name="notice" value="Copyright (C) &amp;#36;today.year Google Inc.&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10;http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
+ <option name="keyword" value="Copyright" />
+ <option name="allowReplaceKeyword" value="Copyright" />
+ <option name="myName" value="Apache 2.0/Google" />
+ <option name="myLocal" value="true" />
+ </copyright>
+ <module2copyright />
+ </component>
+ <component name="DependencyValidationManager">
+ <option name="SKIP_IMPORT_STATEMENTS" value="false" />
+ </component>
+ <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
+ <component name="IdProvider" IDEtalkID="9D3662DDF16C2758FD5CFC5C3FF9327A" />
+ <component name="InspectionProjectProfileManager">
+ <profiles>
+ <profile version="1.0" is_locked="false">
+ <option name="myName" value="Project Default" />
+ <option name="myLocal" value="false" />
+ <inspection_tool class="AbstractClassExtendsConcreteClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AbstractClassNeverImplemented" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AbstractClassWithoutAbstractMethods" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AbstractMethodCallInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AbstractMethodOverridesAbstractMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AbstractMethodOverridesConcreteMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AbstractMethodWithMissingImplementations" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AccessToNonThreadSafeStaticFieldFromInstance" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="nonThreadSafeTypes" value="java.text.DateFormat,java.util.Calendar" />
+ </inspection_tool>
+ <inspection_tool class="AccessToStaticFieldLockedOnInstance" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AmbiguousMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AnnotationNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="AnonymousClassVariableHidesContainingMethodVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ArchaicSystemPropertyAccess" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ArithmeticOnVolatileField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssertEqualsMayBeAssertSame" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssertStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssignmentToCatchBlockParameter" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssignmentToDateFieldFromParameter" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignorePrivateMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="AssignmentToForLoopParameter" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_checkForeachParameters" value="false" />
+ </inspection_tool>
+ <inspection_tool class="AssignmentToMethodParameter" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreTransformationOfOriginalParameter" value="false" />
+ </inspection_tool>
+ <inspection_tool class="AssignmentToNull" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssignmentToStaticFieldFromInstanceMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AssignmentUsedAsCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AwaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="AwaitWithoutCorrespondingSignal" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BadExceptionCaught" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="exceptionsString" value="java.lang.NullPointerException,java.lang.IllegalMonitorStateException,java.lang.ArrayIndexOutOfBoundsException" />
+ </inspection_tool>
+ <inspection_tool class="BadExceptionThrown" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="exceptionsString" value="java.lang.Throwable,java.lang.Exception,java.lang.Error,java.lang.RuntimeException,java.lang.NullPointerException,java.lang.ClassCastException,java.lang.ArrayIndexOutOfBoundsException" />
+ </inspection_tool>
+ <inspection_tool class="BadOddness" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BeforeClassOrAfterClassIsPublicStaticVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BeforeOrAfterIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BigDecimalEquals" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BindingAnnotationWithoutInject" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="BreakStatementWithLabel" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="BusyWait" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CStyleArrayDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CachedNumberConstructorCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CallToNativeMethodWhileLocked" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CallToSimpleGetterInClass" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreGetterCallsOnOtherObjects" value="false" />
+ </inspection_tool>
+ <inspection_tool class="CallToSimpleSetterInClass" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreSetterCallsOnOtherObjects" value="false" />
+ </inspection_tool>
+ <inspection_tool class="CallToStringConcatCanBeReplacedByOperator" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CastConflictsWithInstanceof" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CastThatLosesPrecision" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreIntegerCharCasts" value="false" />
+ </inspection_tool>
+ <inspection_tool class="CastToIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CatchGenericClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ChainedEquality" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CheckDtdRefs" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="CheckEmptyScriptTag" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CheckImageSize" level="WARNING" enabled="false" />
+ <inspection_tool class="CheckNodeTest" level="WARNING" enabled="false" />
+ <inspection_tool class="CheckTagEmptyBody" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="CheckValidXmlInScriptTagBody" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="CheckXmlFileWithXercesValidator" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="CheckedExceptionClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassEscapesItsScope" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassInTopLevelPackage" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassInitializer" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassLoaderInstantiation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassMayBeInterface" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassNameDiffersFromFileName" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassNamePrefixedWithPackageName" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassNameSameAsAncestorName" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="2" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="ClassReferencesSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ClassUnconnectedToPackage" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CloneCallsConstructors" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CloneInNonCloneableClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CloneableClassInSecureContext" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CloneableImplementsClone" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreCloneableDueToInheritance" value="false" />
+ </inspection_tool>
+ <inspection_tool class="CollectionAddedToSelf" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CollectionContainsUrl" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CollectionsFieldAccessReplaceableByMethodCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ComparableImplementedButEqualsNotOverridden" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ComparatorNotSerializable" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CompareToUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ComparisonOfShortAndChar" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ComparisonToNaN" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConditionSignal" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConditionalExpressionWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConflictingAnnotations" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="ConfusingElse" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConfusingFloatingPointLiteral" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConfusingMainMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConfusingOctalEscape" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstantDeclaredInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstantDeclaredInInterface" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstantMathCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstantNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="onlyCheckImmutables" value="false" />
+ <option name="m_regex" value="[A-Z_\d]*" />
+ <option name="m_minLength" value="5" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="ConstantStringIntern" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ConstantValueVariableUse" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ContinueStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ContinueStatementWithLabel" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ControlFlowStatementWithoutBraces" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CovariantEquals" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CustomClassloader" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="CustomSecurityManager" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DeclareCollectionAsInterface" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreLocalVariables" value="false" />
+ <option name="ignorePrivateMethodsAndFields" value="false" />
+ </inspection_tool>
+ <inspection_tool class="DefaultNotLastCaseInSwitch" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DisjointPackage" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DivideByZero" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DollarSignInName" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DoubleCheckedLocking" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreOnVolatileVariables" value="false" />
+ </inspection_tool>
+ <inspection_tool class="DoubleNegation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DuplicateBooleanBranch" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="DuplicateCondition" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreMethodCalls" value="false" />
+ </inspection_tool>
+ <inspection_tool class="EmptyClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EmptyInitializer" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EmptySynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EnumSwitchStatementWhichMissesCases" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreSwitchStatementsWithDefault" value="true" />
+ </inspection_tool>
+ <inspection_tool class="EnumeratedClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="2" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="EnumeratedConstantNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[A-Z]\w+" />
+ <option name="m_minLength" value="2" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="EqualsAndHashcode" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EqualsCalledOnEnumConstant" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EqualsHashCodeCalledOnUrl" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="EqualsUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ErrorRethrown" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExceptionFromCatchWhichDoesntWrap" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreGetMessage" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ExceptionNameDoesntEndWithException" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExtendsConcreteCollection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExtendsThread" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExtendsUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ExternalizableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FallthruInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FieldAccessedSynchronizedAndUnsynchronized" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="countGettersAndSetters" value="false" />
+ </inspection_tool>
+ <inspection_tool class="FieldHidesSuperclassField" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreInvisibleFields" value="true" />
+ </inspection_tool>
+ <inspection_tool class="FieldMayBeFinal" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FieldMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FinalMethodInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="Finalize" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FinalizeNotProtected" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="FloatingPointEquality" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ForLoopReplaceableByWhile" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreLoopsWithoutConditions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ForLoopThatDoesntUseLoopVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ForLoopWithMissingComponent" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreCollectionLoops" value="false" />
+ </inspection_tool>
+ <inspection_tool class="HardcodedFileSeparators" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_recognizeExampleMediaType" value="false" />
+ </inspection_tool>
+ <inspection_tool class="HardcodedLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="HardwiredNamespacePrefix" level="WARNING" enabled="false" />
+ <inspection_tool class="HashCodeUsesNonFinalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="HtmlDeprecatedTag" level="WARNING" enabled="false" />
+ <inspection_tool class="HtmlExtraClosingTag" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="HtmlPresentationalElement" level="WARNING" enabled="false" />
+ <inspection_tool class="HtmlUnknownAttribute" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="myValues">
+ <value>
+ <list size="5">
+ <item index="0" class="java.lang.String" itemvalue="type" />
+ <item index="1" class="java.lang.String" itemvalue="wmode" />
+ <item index="2" class="java.lang.String" itemvalue="src" />
+ <item index="3" class="java.lang.String" itemvalue="width" />
+ <item index="4" class="java.lang.String" itemvalue="height" />
+ </list>
+ </value>
+ </option>
+ <option name="myCustomValuesEnabled" value="true" />
+ </inspection_tool>
+ <inspection_tool class="HtmlUnknownTag" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="myValues">
+ <value>
+ <list size="5">
+ <item index="0" class="java.lang.String" itemvalue="embed" />
+ <item index="1" class="java.lang.String" itemvalue="nobr" />
+ <item index="2" class="java.lang.String" itemvalue="noembed" />
+ <item index="3" class="java.lang.String" itemvalue="comment" />
+ <item index="4" class="java.lang.String" itemvalue="script" />
+ </list>
+ </value>
+ </option>
+ <option name="myCustomValuesEnabled" value="true" />
+ </inspection_tool>
+ <inspection_tool class="IfMayBeConditional" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IfStatementWithIdenticalBranches" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IfStatementWithTooManyBranches" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="ImplicitNumericConversion" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreWideningConversions" value="true" />
+ <option name="ignoreCharConversions" value="false" />
+ <option name="ignoreConstantConversions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ImplicitTypeConversion" level="WARNING" enabled="false">
+ <option name="BITS" value="1720" />
+ <option name="FLAG_EXPLICIT_CONVERSION" value="true" />
+ <option name="IGNORE_NODESET_TO_BOOLEAN_VIA_STRING" value="true" />
+ </inspection_tool>
+ <inspection_tool class="InconsistentResourceBundle" enabled="false" level="ERROR" enabled_by_default="false">
+ <option name="REPORT_MISSING_TRANSLATIONS" value="true" />
+ <option name="REPORT_INCONSISTENT_PROPERTIES" value="true" />
+ <option name="REPORT_DUPLICATED_PROPERTIES" value="true" />
+ </inspection_tool>
+ <inspection_tool class="IndexOfReplaceableByContains" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IndexZeroUsage" level="WARNING" enabled="false" />
+ <inspection_tool class="InjectOfNonPublicMember" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InjectionNotApplicable" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="InnerClassMayBeStatic" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InnerClassOnInterface" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreInnerInterfaces" value="false" />
+ </inspection_tool>
+ <inspection_tool class="InnerClassVariableHidesOuterClassVariable" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreInvisibleFields" value="true" />
+ </inspection_tool>
+ <inspection_tool class="InstanceMethodNamingConvention" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_regex" value="([a-z][A-Za-z\d]*|test\w*)" />
+ <option name="m_minLength" value="2" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="InstanceVariableNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="2" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="InstanceVariableUninitializedUse" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignorePrimitives" value="false" />
+ </inspection_tool>
+ <inspection_tool class="InstanceofCatchParameter" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InstanceofChain" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InstanceofIncompatibleInterface" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InstanceofThis" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InstantiationOfUtilityClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IntegerDivisionInFloatingPointContext" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IntegerMultiplicationImplicitCastToLong" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="InterceptionAnnotationWithoutRuntimeRetention" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InterfaceNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="InterfaceNeverImplemented" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreInterfacesThatOnlyDeclareConstants" value="false" />
+ </inspection_tool>
+ <inspection_tool class="InvalidImplementedBy" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InvalidProvidedBy" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="InvalidRequestParameters" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="IteratorHasNextCallsIteratorNext" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="IteratorNextDoesNotThrowNoSuchElementException" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JDBCExecuteWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JDBCPrepareStatementWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JUnit4AnnotatedMethodInJUnit3TestCase" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JUnitAbstractTestClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*TestCase" />
+ <option name="m_minLength" value="12" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="JUnitTestClassNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[A-Z][A-Za-z\d]*Test" />
+ <option name="m_minLength" value="8" />
+ <option name="m_maxLength" value="64" />
+ </inspection_tool>
+ <inspection_tool class="JavaDoc" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="TOP_LEVEL_CLASS_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="INNER_CLASS_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="METHOD_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
+ </value>
+ </option>
+ <option name="FIELD_OPTIONS">
+ <value>
+ <option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
+ <option name="REQUIRED_TAGS" value="" />
+ </value>
+ </option>
+ <option name="IGNORE_DEPRECATED" value="false" />
+ <option name="IGNORE_JAVADOC_PERIOD" value="true" />
+ <option name="IGNORE_DUPLICATED_THROWS" value="false" />
+ <option name="myAdditionalJavadocTags" value="" />
+ </inspection_tool>
+ <inspection_tool class="JavaLangImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="JavaLangReflect" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="KeySetIterationMayUseEntrySet" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LabeledStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LanguageMismatch" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="CHECK_NON_ANNOTATED_REFERENCES" value="true" />
+ </inspection_tool>
+ <inspection_tool class="LengthOneStringInIndexOf" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LimitedScopeInnerClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ListIndexOfReplaceableByContains" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LiteralAsArgToStringEquals" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LoadLibraryWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LocalVariableHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreInvisibleFields" value="true" />
+ <option name="m_ignoreStaticMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="LocalVariableNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreForLoopParameters" value="false" />
+ <option name="m_ignoreCatchParameters" value="false" />
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="1" />
+ <option name="m_maxLength" value="20" />
+ </inspection_tool>
+ <inspection_tool class="LongLiteralsEndingWithLowercaseL" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="LoopConditionNotUpdatedInsideLoop" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreIterators" value="false" />
+ </inspection_tool>
+ <inspection_tool class="LoopWithImplicitTerminationCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MalformedXPath" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MapReplaceableByEnumMap" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MethodMayBeSynchronized" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MethodNameSameAsParentName" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MethodNamesDifferOnlyByCase" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MethodOnlyUsedFromInnerClass" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreMethodsAccessedFromAnonymousClass" value="false" />
+ </inspection_tool>
+ <inspection_tool class="MethodOverloadsParentMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MethodOverridesPackageLocalMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MethodOverridesPrivateMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MethodReturnAlwaysConstant" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MisorderedAssertEqualsParameters" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MissingDeprecatedAnnotation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_requireAnnotationsFirst" value="true" />
+ </inspection_tool>
+ <inspection_tool class="MisspelledCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MisspelledEquals" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MisspelledHashcode" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MisspelledSetUp" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MisspelledTearDown" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MisspelledToString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MultipleBindingAnnotations" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MultipleDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MultipleInjectedConstructorsForClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="MultipleTopLevelClassesInFile" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="MultipleTypedDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NakedNotify" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NativeMethods" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NegatedConditional" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreNegatedNullComparison" value="true" />
+ </inspection_tool>
+ <inspection_tool class="NegatedIfElse" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreNegatedNullComparison" value="true" />
+ </inspection_tool>
+ <inspection_tool class="NestedSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NestedSynchronizedStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NestedTryStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonExceptionNameEndsWithException" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonFinalClone" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonFinalFieldOfException" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonFinalStaticVariableUsedInClassInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonProtectedConstructorInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreNonPublicClasses" value="false" />
+ </inspection_tool>
+ <inspection_tool class="NonReproducibleMathCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonSerializableObjectBoundToHttpSession" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonSerializableObjectPassedToObjectStream" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonSerializableWithSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonSerializableWithSerializationMethods" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonShortCircuitBoolean" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonStaticInnerClassInSecureContext" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonSynchronizedMethodOverridesSynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NonThreadSafeLazyInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NoopMethodInAbstractClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NotifyCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NotifyNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NotifyWithoutCorrespondingWait" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="NullableProblems" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" />
+ <option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="true" />
+ <option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true" />
+ <option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true" />
+ <option name="REPORT_NOT_ANNOTATED_GETTER" value="true" />
+ <option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true" />
+ <option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ObjectEquality" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreEnums" value="true" />
+ <option name="m_ignoreClassObjects" value="false" />
+ <option name="m_ignorePrivateConstructors" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ObjectNotify" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ObsoleteCollection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreLibraryArguments" value="false" />
+ </inspection_tool>
+ <inspection_tool class="OctalAndDecimalIntegersMixed" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="OnDemandImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="OverloadedVarargsMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="OverlyComplexArithmeticExpression" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_limit" value="6" />
+ </inspection_tool>
+ <inspection_tool class="OverlyStrongTypeCast" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreInMatchingInstanceof" value="false" />
+ </inspection_tool>
+ <inspection_tool class="OverridableMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="OverriddenMethodCallDuringObjectConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PackageInMultipleModules" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PackageWithTooFewClasses" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="limit" value="3" />
+ </inspection_tool>
+ <inspection_tool class="PackageWithTooManyClasses" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="ParameterHidingMemberVariable" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreInvisibleFields" value="true" />
+ <option name="m_ignoreStaticMethodParametersHidingInstanceFields" value="false" />
+ <option name="m_ignoreForConstructors" value="true" />
+ <option name="m_ignoreForPropertySetters" value="true" />
+ <option name="m_ignoreForAbstractMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ParameterNameDiffersFromOverriddenParameter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreSingleCharacterNames" value="true" />
+ <option name="m_ignoreOverridesOfLibraryMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ParameterNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="1" />
+ <option name="m_maxLength" value="40" />
+ </inspection_tool>
+ <inspection_tool class="PointlessBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="PointlessIndexOfComparison" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ProtectedField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ProtectedMemberInFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PublicConstructorInNonPublicClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PublicField" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreEnums" value="false" />
+ </inspection_tool>
+ <inspection_tool class="PublicFieldAccessedInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PublicStaticArrayField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="PublicStaticCollectionField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="QuestionableName" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="nameString" value="aa,abc,bad,bar,bar2,baz,baz1,baz2,baz3,bb,blah,bogus,bool,cc,dd,defau1t,dummy,dummy2,ee,fa1se,ff,foo,foo1,foo2,foo3,foobar,four,fred,fred1,fred2,gg,hh,hello,hello1,hello2,hello3,ii,nu11,one,silly,silly2,string,two,then,three,whi1e,var" />
+ </inspection_tool>
+ <inspection_tool class="RandomDoubleForRandomInteger" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ReadObjectAndWriteObjectPrivate" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ReadObjectInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ReadResolveAndWriteReplaceProtected" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantFieldInitialization" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantImplements" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreSerializable" value="false" />
+ <option name="ignoreCloneable" value="false" />
+ </inspection_tool>
+ <inspection_tool class="RedundantImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantMethodOverride" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantScopeBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantStringFormatCall" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantSuppression" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantThrowsDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RedundantToBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantToProviderBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="RedundantTypeConversion" level="WARNING" enabled="false">
+ <option name="CHECK_ANY" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ReplaceAllDot" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ReplaceAssignmentWithOperatorAssignment" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreLazyOperators" value="true" />
+ <option name="ignoreObscureOperators" value="false" />
+ </inspection_tool>
+ <inspection_tool class="RequiredAttributes" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="myAdditionalRequiredHtmlAttributes" value="" />
+ </inspection_tool>
+ <inspection_tool class="ResultOfObjectAllocationIgnored" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ReturnNull" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_reportObjectMethods" value="true" />
+ <option name="m_reportArrayMethods" value="true" />
+ <option name="m_reportCollectionMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="ReturnOfDateField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ReuseOfLocalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RuntimeExec" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="RuntimeExecWithNonConstantString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SSBasedInspection" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SafeLock" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SamePackageImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SerialPersistentFieldsWithWrongSignature" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="superClassString" value="java.awt.Component" />
+ </inspection_tool>
+ <inspection_tool class="SerializableInnerClassHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="superClassString" value="java.awt.Component" />
+ </inspection_tool>
+ <inspection_tool class="SerializableInnerClassWithNonSerializableOuterClass" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="superClassString" value="java.awt.Component" />
+ </inspection_tool>
+ <inspection_tool class="SerializableWithUnconstructableAncestor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SessionScopedInjectsRequestScoped" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SetReplaceableByEnumSet" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SetupCallsSuperSetup" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SetupIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SignalWithoutCorrespondingAwait" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SimplifiableIfStatement" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SimplifiableJUnitAssertion" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="Since15" enabled="true" level="ERROR" enabled_by_default="true">
+ <option name="FORBID_15_API" value="false" />
+ <option name="FORBID_16_API" value="true" />
+ </inspection_tool>
+ <inspection_tool class="Singleton" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SingletonInjectsScoped" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="SizeReplaceableByIsEmpty" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreNegations" value="false" />
+ </inspection_tool>
+ <inspection_tool class="SleepWhileHoldingLock" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StaticCallOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StaticCollection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreWeakCollections" value="false" />
+ </inspection_tool>
+ <inspection_tool class="StaticFieldReferenceOnSubclass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StaticInheritance" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StaticMethodNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="4" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="StaticNonFinalField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StaticSuite" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StaticVariableInitialization" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignorePrimitives" value="false" />
+ </inspection_tool>
+ <inspection_tool class="StaticVariableNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="checkMutableFinals" value="false" />
+ <option name="m_regex" value="[a-z][A-Za-z\d]*" />
+ <option name="m_minLength" value="2" />
+ <option name="m_maxLength" value="32" />
+ </inspection_tool>
+ <inspection_tool class="StaticVariableUninitializedUse" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignorePrimitives" value="false" />
+ </inspection_tool>
+ <inspection_tool class="StringBufferField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringBufferMustHaveInitialCapacity" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringBufferReplaceableByString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringBufferReplaceableByStringBuilder" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringBufferToStringInConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringEqualsEmptyString" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="StringReplaceableByStringBuffer" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="onlyWarnOnLoop" value="true" />
+ </inspection_tool>
+ <inspection_tool class="SubstringZero" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SubtractionInCompareTo" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SuspiciousIndentAfterControlStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SuspiciousMethodCalls" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="REPORT_CONVERTIBLE_METHOD_CALLS" value="true" />
+ </inspection_tool>
+ <inspection_tool class="SwitchStatementDensity" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_limit" value="20" />
+ </inspection_tool>
+ <inspection_tool class="SwitchStatementWithConfusingDeclaration" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SwitchStatementWithTooFewBranches" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_limit" value="2" />
+ </inspection_tool>
+ <inspection_tool class="SwitchStatementWithTooManyBranches" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_limit" value="10" />
+ </inspection_tool>
+ <inspection_tool class="SwitchStatementsWithoutDefault" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreFullyCoveredEnums" value="true" />
+ </inspection_tool>
+ <inspection_tool class="SynchronizeOnLock" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SynchronizeOnThis" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SynchronizedMethod" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_includeNativeMethods" value="true" />
+ </inspection_tool>
+ <inspection_tool class="SynchronizedOnLiteralObject" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SystemExit" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SystemGC" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SystemGetenv" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SystemOutErr" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SystemProperties" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SystemRunFinalizersOnExit" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="SystemSetSecurityManager" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TailRecursion" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TeardownCallsSuperTeardown" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TeardownIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TestCaseInProductCode" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TestCaseWithConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TestCaseWithNoTestMethods" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreSupers" value="false" />
+ </inspection_tool>
+ <inspection_tool class="TestMethodInProductCode" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TestMethodIsPublicVoidNoArg" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TextLabelInSwitchStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThisEscapedInConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadDeathRethrown" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadDumpStack" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadPriority" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadRun" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadStartInConstruction" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadStopSuspendResume" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadWithDefaultRunMethod" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThreadYield" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ThrowCaughtLocally" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreRethrownExceptions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="ThrowablePrintStackTrace" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="ToArrayCallWithZeroLengthArrayArgument" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="TooBroadCatch" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="onlyWarnOnRootExceptions" value="false" />
+ </inspection_tool>
+ <inspection_tool class="TooBroadScope" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_allowConstructorAsInitializer" value="false" />
+ <option name="m_onlyLookAtBlocks" value="false" />
+ </inspection_tool>
+ <inspection_tool class="TransientFieldInNonSerializableClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TransientFieldNotInitialized" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TrivialStringConcatenation" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TypeParameterExtendsFinalClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TypeParameterHidesVisibleType" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TypeParameterNamingConvention" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_regex" value="[A-Z\d]" />
+ <option name="m_minLength" value="1" />
+ <option name="m_maxLength" value="1" />
+ </inspection_tool>
+ <inspection_tool class="UNUSED_SYMBOL" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="LOCAL_VARIABLE" value="true" />
+ <option name="FIELD" value="true" />
+ <option name="METHOD" value="true" />
+ <option name="CLASS" value="true" />
+ <option name="PARAMETER" value="true" />
+ <option name="REPORT_PARAMETER_FOR_PUBLIC_METHODS" value="true" />
+ <option name="INJECTION_ANNOS">
+ <value>
+ <list size="1">
+ <item index="0" class="java.lang.String" itemvalue="com.google.caliper.Param" />
+ </list>
+ </value>
+ </option>
+ </inspection_tool>
+ <inspection_tool class="UnaryPlus" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UncheckedExceptionClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnconditionalWait" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnconstructableTestCase" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UninstantiableBinding" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UninstantiableImplementedByClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UninstantiableProvidedByClass" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnknownLanguage" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="UnnecessarilyQualifiedStaticUsage" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreStaticFieldAccesses" value="false" />
+ <option name="m_ignoreStaticMethodCalls" value="false" />
+ <option name="m_ignoreStaticAccessFromStaticContext" value="true" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryBlockStatement" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryCallToStringValueOf" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryConstantArrayCreationExpression" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryDefault" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryEnumModifier" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryFinalOnLocalVariable" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryFinalOnParameter" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="onlyWarnOnAbstractMethods" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryFullyQualifiedName" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreJavadoc" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryInterfaceModifier" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryLocalVariable" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="m_ignoreImmediatelyReturnedVariables" value="false" />
+ <option name="m_ignoreAnnotatedVariables" value="true" />
+ </inspection_tool>
+ <inspection_tool class="UnnecessaryQualifierForThis" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryStaticInjection" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UnnecessarySuperConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessarySuperQualifier" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnnecessaryUnaryMinus" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnpredictableBigDecimalConstructorCall" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreReferences" value="true" />
+ <option name="ignoreComplexLiterals" value="false" />
+ </inspection_tool>
+ <inspection_tool class="UnresolvedPropertyKey" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="UnusedCatchParameter" enabled="false" level="WARNING" enabled_by_default="false">
+ <option name="m_ignoreCatchBlocksWithComments" value="true" />
+ <option name="m_ignoreTestCases" value="true" />
+ </inspection_tool>
+ <inspection_tool class="UnusedImport" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnusedLibrary" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UnusedMessageFormatParameter" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="UpperCaseFieldNameNotConstant" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UseOfAWTPeerClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UseOfAnotherObjectsPrivateField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UseOfJDBCDriverClass" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UseOfProcessBuilder" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UseOfPropertiesAsHashtable" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UseOfSunClasses" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UtilityClassWithPublicConstructor" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="UtilityClassWithoutPrivateConstructor" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreClassesWithOnlyMain" value="false" />
+ </inspection_tool>
+ <inspection_tool class="VariableNotUsedInsideIf" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="VolatileArrayField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="VolatileLongOrDoubleField" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="WaitCalledOnCondition" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="WaitNotInLoop" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="WaitNotInSynchronizedContext" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="WaitOrAwaitWithoutTimeout" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="WaitWhileHoldingTwoLocks" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="WaitWithoutCorrespondingNotify" enabled="true" level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="WhileLoopSpinsOnField" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoreNonEmtpyLoops" value="false" />
+ </inspection_tool>
+ <inspection_tool class="XmlDuplicatedId" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="XmlUnboundNsPrefix" enabled="false" level="WARNING" enabled_by_default="false" />
+ <inspection_tool class="XmlWrongRootElement" enabled="false" level="ERROR" enabled_by_default="false" />
+ <inspection_tool class="XsltDeclarations" level="ERROR" enabled="false" />
+ <inspection_tool class="XsltTemplateInvocation" level="ERROR" enabled="false" />
+ <inspection_tool class="XsltUnusedDeclaration" level="WARNING" enabled="false" />
+ <inspection_tool class="dependsOnMethodTestNG" level="WARNING" enabled="false" />
+ <inspection_tool class="groupsTestNG" level="WARNING" enabled="false">
+ <option name="groups">
+ <value>
+ <list size="0" />
+ </value>
+ </option>
+ </inspection_tool>
+ </profile>
+ </profiles>
+ <option name="PROJECT_PROFILE" value="Project Default" />
+ <option name="USE_PROJECT_PROFILE" value="true" />
+ <version value="1.0" />
+ </component>
+ <component name="JavacSettings">
+ <option name="ADDITIONAL_OPTIONS_STRING" value="-source 1.5 -target 1.5" />
+ <option name="MAXIMUM_HEAP_SIZE" value="800" />
+ </component>
+ <component name="JavadocGenerationManager">
+ <option name="OUTPUT_DIRECTORY" />
+ <option name="OPTION_SCOPE" value="protected" />
+ <option name="OPTION_HIERARCHY" value="true" />
+ <option name="OPTION_NAVIGATOR" value="true" />
+ <option name="OPTION_INDEX" value="true" />
+ <option name="OPTION_SEPARATE_INDEX" value="true" />
+ <option name="OPTION_DOCUMENT_TAG_USE" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
+ <option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
+ <option name="OPTION_DEPRECATED_LIST" value="true" />
+ <option name="OTHER_OPTIONS" value="" />
+ <option name="HEAP_SIZE" />
+ <option name="LOCALE" />
+ <option name="OPEN_IN_BROWSER" value="true" />
+ </component>
+ <component name="Palette2">
+ <group name="Swing">
+ <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+ </item>
+ <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+ <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+ <initial-values>
+ <property name="text" value="Button" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="RadioButton" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="CheckBox" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="Label" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+ <preferred-size width="-1" height="20" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+ </item>
+ </group>
+ </component>
+ <component name="ProjectDetails">
+ <option name="projectName" value="guava" />
+ </component>
+ <component name="ProjectDictionaryState">
+ <dictionary name="kevinb" />
+ </component>
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/guava.iml" filepath="$PROJECT_DIR$/guava.iml" />
+ </modules>
+ </component>
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="JDK 6-google-v2" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/out" />
+ </component>
+ <component name="SvnBranchConfigurationManager">
+ <option name="mySupportsUserInfoFilter" value="true" />
+ </component>
+ <component name="VcsDirectoryMappings">
+ <mapping directory="" vcs="svn" />
+ </component>
+</project>
+
diff --git a/guava/mvn-deploy.sh b/guava/mvn-deploy.sh
new file mode 100644
index 0000000..4c8a5f7
--- /dev/null
+++ b/guava/mvn-deploy.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# This script checks the java version and bails if it's less
+# than Java6 (because we use @Override annotations on interface
+# overriding methods. It then proceeds to do a maven build that
+# first cleans, then builds the normal lifecycle through compilation
+# unit testing (if available) up to packaging. It then packages
+# the source, javadocs, and maven site. It then signs the
+# artifacts with whatever pgp signature is the default of the
+# user executing it, and then deploys to the repository contained
+# in the distributionManagement section of the pom.
+#
+# author: cgruber@google.com (Christian Edward Gruber)
+#
+if [[ -n ${JAVA_HOME} ]] ; then
+ JAVA_CMD=${JAVA_HOME}/bin/java
+else
+ JAVA_CMD=java
+fi
+java_version="$(${JAVA_CMD} -version 2>&1 | grep -e 'java version' | awk '{ print $3 }')"
+
+# This test sucks, but it's short term
+# TODO(cgruber) strip the quotes and patch version and do version comparison.
+greater_than_java5="$(echo ${java_version} | grep -e '^"1.[67]')"
+
+if [[ -z ${greater_than_java5} ]] ; then
+ echo "Your java version is ${java_version}."
+ echo "You must use at least a java 6 JVM to build and deploy this software."
+ exit 1
+else
+ echo "Building with java ${java_version}"
+fi
+
+if [[ $# > 0 ]]; then
+ params+=" -Dgpg.keyname=${1}"
+ gpg_sign_plugin=" gpg:sign"
+fi
+cmd="mvn clean package source:jar site:jar javadoc:jar ${gpg_sign_plugin} deploy ${params}"
+echo "Executing ${cmd}"
+${cmd}
diff --git a/guava/pom.xml b/guava/pom.xml
new file mode 100644
index 0000000..89da71d
--- /dev/null
+++ b/guava/pom.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google</groupId>
+ <artifactId>google</artifactId>
+ <version>5</version>
+ </parent>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>r06</version>
+ <packaging>jar</packaging>
+ <name>Guava (Google Common Libraries)</name>
+ <description>
+ Guava is a suite of core and expanded libraries that include
+ utility classes, google's collections, io classes, and much
+ much more.
+
+ This project is a complete packaging of all the Guava libraries
+ into a single jar. Individual portions of Guava can be used
+ by downloading the appropriate module and its dependencies.
+
+ Guava (complete) has only one code dependency - javax.annotation,
+ per the JSR-305 spec.
+ </description>
+ <url>http://code.google.com/p/guava-libraries</url>
+ <issueManagement>
+ <system>code.google.com</system>
+ <url>http://code.google.com/p/guava-libraries/issues</url>
+ </issueManagement>
+ <inceptionYear>2010</inceptionYear>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <prerequisites>
+ <maven>2.0.9</maven>
+ </prerequisites>
+ <scm>
+ <connection>scm:svn:http://guava-libraries.googlecode.com/svn/trunk/</connection>
+ <developerConnection>scm:svn:https://guava-libraries.googlecode.com/svn/trunk/</developerConnection>
+ <url>http://code.google.com/p/guava-libraries/source/browse</url>
+ </scm>
+ <developers>
+ <developer>
+ <id>kevinb9n</id>
+ <name>Kevin Bourillion</name>
+ <email>kevinb@google.com</email>
+ <organization>Google</organization>
+ <organizationUrl>http://www.google.com</organizationUrl>
+ <roles>
+ <role>owner</role>
+ <role>developer</role>
+ </roles>
+ <timezone>-8</timezone>
+ </developer>
+ </developers>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <version>1.3.7</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.5</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ <finalName>${project.artifactId}-${project.version}</finalName>
+ <sourceDirectory>src</sourceDirectory>
+ <testSourceDirectory>tests_disabled</testSourceDirectory>
+ </build>
+</project>
diff --git a/guava/src/com/google/common/annotations/Beta.java b/guava/src/com/google/common/annotations/Beta.java
new file mode 100644
index 0000000..5eefe9a
--- /dev/null
+++ b/guava/src/com/google/common/annotations/Beta.java
@@ -0,0 +1,50 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+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.
+ *
+ *
+ * @author Kevin Bourrillion
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({
+ ElementType.ANNOTATION_TYPE,
+ ElementType.CONSTRUCTOR,
+ ElementType.FIELD,
+ ElementType.METHOD,
+ ElementType.TYPE})
+@Documented
+@GwtCompatible
+public @interface Beta {}
diff --git a/guava/src/com/google/common/annotations/GwtCompatible.java b/guava/src/com/google/common/annotations/GwtCompatible.java
new file mode 100644
index 0000000..e8d62c0
--- /dev/null
+++ b/guava/src/com/google/common/annotations/GwtCompatible.java
@@ -0,0 +1,88 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The presence of this annotation on a type indicates that the type may be
+ * used with the
+ * <a href="http://code.google.com/webtoolkit/">Google Web Toolkit</a> (GWT).
+ * When applied to a method, the return type of the method is GWT compatible.
+ * It's useful to indicate that an instance created by factory methods has a GWT
+ * serializable type. In the following example,
+ *
+ * <pre style="code">
+ * {@literal @}GwtCompatible
+ * class Lists {
+ * ...
+ * {@literal @}GwtCompatible(serializable = true)
+ * static &lt;E> List&lt;E> newArrayList(E... elements) {
+ * ...
+ * }
+ * }
+ * </pre>
+ * The return value of {@code Lists.newArrayList(E[])} has GWT
+ * serializable type. It is also useful in specifying contracts of interface
+ * methods. In the following example,
+ *
+ * <pre style="code">
+ * {@literal @}GwtCompatible
+ * interface ListFactory {
+ * ...
+ * {@literal @}GwtCompatible(serializable = true)
+ * &lt;E> List&lt;E> newArrayList(E... elements);
+ * }
+ * </pre>
+ * The {@code newArrayList(E[])} method of all implementations of {@code
+ * ListFactory} is expected to return a value with a GWT serializable type.
+ *
+ * <p>Note that a {@code GwtCompatible} type may have some {@link
+ * GwtIncompatible} methods.
+ *
+ * @author Charles Fry
+ * @author Hayward Chan
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Documented
+@GwtCompatible
+public @interface GwtCompatible {
+
+ /**
+ * When {@code true}, the annotated type or the type of the method return
+ * value is GWT serializable.
+ *
+ * @see <a href="http://code.google.com/webtoolkit/doc/latest/DevGuideServerCommunication.html#DevGuideSerializableTypes">
+ * Documentation about GWT serialization</a>
+ */
+ boolean serializable() default false;
+
+ /**
+ * When {@code true}, the annotated type is emulated in GWT. The emulated
+ * source (also known as super-source) is different from the implementation
+ * used by the JVM.
+ *
+ * @see <a href="http://code.google.com/webtoolkit/doc/latest/DevGuideOrganizingProjects.html#DevGuideModules">
+ * Documentation about GWT emulated source</a>
+ */
+ boolean emulated() default false;
+}
diff --git a/guava/src/com/google/common/annotations/GwtIncompatible.java b/guava/src/com/google/common/annotations/GwtIncompatible.java
new file mode 100644
index 0000000..a56d746
--- /dev/null
+++ b/guava/src/com/google/common/annotations/GwtIncompatible.java
@@ -0,0 +1,52 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The presence of this annotation on a method indicates that the method may
+ * <em>not</em> be used with the
+ * <a href="http://code.google.com/webtoolkit/">Google Web Toolkit</a> (GWT),
+ * even though its type is annotated as {@link GwtCompatible} and accessible in
+ * GWT. They can cause GWT compilation errors or simply unexpected exceptions
+ * when used in GWT.
+ *
+ * <p>Note that this annotation should only be applied to methods, fields, or
+ * inner classes of types which are annotated as {@link GwtCompatible}.
+ *
+ * @author Charles Fry
+ */
+@Retention(RetentionPolicy.CLASS)
+@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,
+ * it is sufficient to simply reference the unsupported type/method. E.g.
+ * "Class.isInstance".
+ */
+ String value();
+}
diff --git a/guava/src/com/google/common/annotations/VisibleForTesting.java b/guava/src/com/google/common/annotations/VisibleForTesting.java
new file mode 100644
index 0000000..6f867db
--- /dev/null
+++ b/guava/src/com/google/common/annotations/VisibleForTesting.java
@@ -0,0 +1,27 @@
+/*
+ * 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.annotations;
+
+/**
+ * Annotates a program element that exists, or is more widely visible than
+ * otherwise necessary, only for use in test code.
+ *
+ * @author Johannes Henkel
+ */
+@GwtCompatible
+public @interface VisibleForTesting {
+}
diff --git a/guava/src/com/google/common/annotations/package-info.java b/guava/src/com/google/common/annotations/package-info.java
new file mode 100644
index 0000000..2bf8b21
--- /dev/null
+++ b/guava/src/com/google/common/annotations/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Common annotation types. This package is a part of the open-source
+ * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
+ */
+package com.google.common.annotations;
diff --git a/guava/src/com/google/common/base/Absent.java b/guava/src/com/google/common/base/Absent.java
new file mode 100644
index 0000000..852fa20
--- /dev/null
+++ b/guava/src/com/google/common/base/Absent.java
@@ -0,0 +1,87 @@
+/*
+ * 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();
+
+ @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 <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/AbstractIterator.java b/guava/src/com/google/common/base/AbstractIterator.java
new file mode 100644
index 0000000..d171af2
--- /dev/null
+++ b/guava/src/com/google/common/base/AbstractIterator.java
@@ -0,0 +1,84 @@
+/*
+ * 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.base;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Note this class is a copy of
+ * {@link com.google.common.collect.AbstractIterator} (for dependency reasons).
+ */
+@GwtCompatible
+abstract class AbstractIterator<T> implements Iterator<T> {
+ private State state = State.NOT_READY;
+
+ protected AbstractIterator() {}
+
+ private enum State {
+ READY, NOT_READY, DONE, FAILED,
+ }
+
+ private T next;
+
+ protected abstract T computeNext();
+
+ protected final T endOfData() {
+ state = State.DONE;
+ return null;
+ }
+
+ @Override
+ public final boolean hasNext() {
+ checkState(state != State.FAILED);
+ switch (state) {
+ case DONE:
+ return false;
+ case READY:
+ return true;
+ default:
+ }
+ return tryToComputeNext();
+ }
+
+ private boolean tryToComputeNext() {
+ state = State.FAILED; // temporary pessimism
+ next = computeNext();
+ if (state != State.DONE) {
+ state = State.READY;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public final T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ state = State.NOT_READY;
+ return next;
+ }
+
+ @Override public final void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/guava/src/com/google/common/base/Ascii.java b/guava/src/com/google/common/base/Ascii.java
new file mode 100644
index 0000000..792856d
--- /dev/null
+++ b/guava/src/com/google/common/base/Ascii.java
@@ -0,0 +1,487 @@
+/*
+ * 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.GwtCompatible;
+
+/**
+ * Static methods pertaining to ASCII characters (those in the range of values
+ * {@code 0x00} through {@code 0x7F}), and to strings containing such
+ * characters.
+ *
+ * <p>ASCII utilities also exist in other classes of this package:
+ * <ul>
+ * <!-- TODO(kevinb): how can we make this not produce a warning when building gwt javadoc? -->
+ * <li>{@link Charsets#US_ASCII} specifies the {@code Charset} of ASCII characters.
+ * <li>{@link CharMatcher#ASCII} matches ASCII characters and provides text processing methods
+ * which operate only on the ASCII characters of a string.
+ * </ul>
+ *
+ * @author Craig Berry
+ * @author Gregory Kick
+ * @since 7.0
+ */
+@GwtCompatible
+public final class Ascii {
+
+ private Ascii() {}
+
+ /* The ASCII control characters, per RFC 20. */
+ /**
+ * Null ('\0'): The all-zeros character which may serve to accomplish
+ * time fill and media fill. Normally used as a C string terminator.
+ * <p>Although RFC 20 names this as "Null", note that it is distinct
+ * from the C/C++ "NULL" pointer.
+ *
+ * @since 8.0
+ */
+ public static final byte NUL = 0;
+
+ /**
+ * Start of Heading: A communication control character used at
+ * the beginning of a sequence of characters which constitute a
+ * machine-sensible address or routing information. Such a sequence is
+ * referred to as the "heading." An STX character has the effect of
+ * terminating a heading.
+ *
+ * @since 8.0
+ */
+ public static final byte SOH = 1;
+
+ /**
+ * Start of Text: A communication control character which
+ * precedes a sequence of characters that is to be treated as an entity
+ * and entirely transmitted through to the ultimate destination. Such a
+ * sequence is referred to as "text." STX may be used to terminate a
+ * sequence of characters started by SOH.
+ *
+ * @since 8.0
+ */
+ public static final byte STX = 2;
+
+ /**
+ * End of Text: A communication control character used to
+ * terminate a sequence of characters started with STX and transmitted
+ * as an entity.
+ *
+ * @since 8.0
+ */
+ public static final byte ETX = 3;
+
+ /**
+ * End of Transmission: A communication control character used
+ * to indicate the conclusion of a transmission, which may have
+ * contained one or more texts and any associated headings.
+ *
+ * @since 8.0
+ */
+ public static final byte EOT = 4;
+
+ /**
+ * Enquiry: A communication control character used in data
+ * communication systems as a request for a response from a remote
+ * station. It may be used as a "Who Are You" (WRU) to obtain
+ * identification, or may be used to obtain station status, or both.
+ *
+ * @since 8.0
+ */
+ public static final byte ENQ = 5;
+
+ /**
+ * Acknowledge: A communication control character transmitted
+ * by a receiver as an affirmative response to a sender.
+ *
+ * @since 8.0
+ */
+ public static final byte ACK = 6;
+
+ /**
+ * Bell ('\a'): A character for use when there is a need to call for
+ * human attention. It may control alarm or attention devices.
+ *
+ * @since 8.0
+ */
+ public static final byte BEL = 7;
+
+ /**
+ * Backspace ('\b'): A format effector which controls the movement of
+ * the printing position one printing space backward on the same
+ * printing line. (Applicable also to display devices.)
+ *
+ * @since 8.0
+ */
+ public static final byte BS = 8;
+
+ /**
+ * Horizontal Tabulation ('\t'): A format effector which controls the
+ * movement of the printing position to the next in a series of
+ * predetermined positions along the printing line. (Applicable also to
+ * display devices and the skip function on punched cards.)
+ *
+ * @since 8.0
+ */
+ public static final byte HT = 9;
+
+ /**
+ * Line Feed ('\n'): A format effector which controls the movement of
+ * the printing position to the next printing line. (Applicable also to
+ * display devices.) Where appropriate, this character may have the
+ * meaning "New Line" (NL), a format effector which controls the
+ * movement of the printing point to the first printing position on the
+ * next printing line. Use of this convention requires agreement
+ * between sender and recipient of data.
+ *
+ * @since 8.0
+ */
+ public static final byte LF = 10;
+
+ /**
+ * Alternate name for {@link #LF}. ({@code LF} is preferred.)
+ *
+ * @since 8.0
+ */
+ public static final byte NL = 10;
+
+ /**
+ * Vertical Tabulation ('\v'): A format effector which controls the
+ * movement of the printing position to the next in a series of
+ * predetermined printing lines. (Applicable also to display devices.)
+ *
+ * @since 8.0
+ */
+ public static final byte VT = 11;
+
+ /**
+ * Form Feed ('\f'): A format effector which controls the movement of
+ * the printing position to the first pre-determined printing line on
+ * the next form or page. (Applicable also to display devices.)
+ *
+ * @since 8.0
+ */
+ public static final byte FF = 12;
+
+ /**
+ * Carriage Return ('\r'): A format effector which controls the
+ * movement of the printing position to the first printing position on
+ * the same printing line. (Applicable also to display devices.)
+ *
+ * @since 8.0
+ */
+ public static final byte CR = 13;
+
+ /**
+ * Shift Out: A control character indicating that the code
+ * combinations which follow shall be interpreted as outside of the
+ * character set of the standard code table until a Shift In character
+ * is reached.
+ *
+ * @since 8.0
+ */
+ public static final byte SO = 14;
+
+ /**
+ * Shift In: A control character indicating that the code
+ * combinations which follow shall be interpreted according to the
+ * standard code table.
+ *
+ * @since 8.0
+ */
+ public static final byte SI = 15;
+
+ /**
+ * Data Link Escape: A communication control character which
+ * will change the meaning of a limited number of contiguously following
+ * characters. It is used exclusively to provide supplementary controls
+ * in data communication networks.
+ *
+ * @since 8.0
+ */
+ public static final byte DLE = 16;
+
+ /**
+ * Device Control 1. 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.)
+ *
+ * @since 8.0
+ */
+ public static final byte DC1 = 17; // aka XON
+
+ /**
+ * Transmission On: 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
+ * control code.
+ *
+ * @since 8.0
+ */
+ 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.)
+ *
+ * @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.)
+ *
+ * @since 8.0
+ */
+ public static final byte DC3 = 19; // aka XOFF
+
+ /**
+ * Transmission off. See {@link #XON} for explanation.
+ *
+ * @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.)
+ *
+ * @since 8.0
+ */
+ public static final byte DC4 = 20;
+
+ /**
+ * Negative Acknowledge: A communication control character
+ * transmitted by a receiver as a negative response to the sender.
+ *
+ * @since 8.0
+ */
+ public static final byte NAK = 21;
+
+ /**
+ * Synchronous Idle: A communication control character used by
+ * a synchronous transmission system in the absence of any other
+ * character to provide a signal from which synchronism may be achieved
+ * or retained.
+ *
+ * @since 8.0
+ */
+ public static final byte SYN = 22;
+
+ /**
+ * End of Transmission Block: A communication control character
+ * used to indicate the end of a block of data for communication
+ * purposes. ETB is used for blocking data where the block structure is
+ * not necessarily related to the processing format.
+ *
+ * @since 8.0
+ */
+ public static final byte ETB = 23;
+
+ /**
+ * Cancel: A control character used to indicate that the data
+ * with which it is sent is in error or is to be disregarded.
+ *
+ * @since 8.0
+ */
+ public static final byte CAN = 24;
+
+ /**
+ * End of Medium: A control character associated with the sent
+ * data which may be used to identify the physical end of the medium, or
+ * the end of the used, or wanted, portion of information recorded on a
+ * medium. (The position of this character does not necessarily
+ * correspond to the physical end of the medium.)
+ *
+ * @since 8.0
+ */
+ public static final byte EM = 25;
+
+ /**
+ * Substitute: A character that may be substituted for a
+ * character which is determined to be invalid or in error.
+ *
+ * @since 8.0
+ */
+ public static final byte SUB = 26;
+
+ /**
+ * Escape: A control character intended to provide code
+ * extension (supplementary characters) in general information
+ * interchange. The Escape character itself is a prefix affecting the
+ * interpretation of a limited number of contiguously following
+ * characters.
+ *
+ * @since 8.0
+ */
+ public static final byte ESC = 27;
+
+ /**
+ * File 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.)
+ *
+ * @since 8.0
+ */
+ 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.)
+ *
+ * @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.)
+ *
+ * @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.)
+ *
+ * @since 8.0
+ */
+ public static final byte US = 31;
+
+ /**
+ * Space: A normally non-printing graphic character used to
+ * separate words. It is also a format effector which controls the
+ * movement of the printing position, one printing position forward.
+ * (Applicable also to display devices.)
+ *
+ * @since 8.0
+ */
+ public static final byte SP = 32;
+
+ /**
+ * Alternate name for {@link #SP}.
+ *
+ * @since 8.0
+ */
+ public static final byte SPACE = 32;
+
+ /**
+ * Delete: This character is used primarily to "erase" or
+ * "obliterate" erroneous or unwanted characters in perforated tape.
+ *
+ * @since 8.0
+ */
+ public static final byte DEL = 127;
+
+ /**
+ * The minimum value of an ASCII character.
+ *
+ * @since 9.0 (was type {@code int} before 12.0)
+ */
+ public static final char MIN = 0;
+
+ /**
+ * The maximum value of an ASCII character.
+ *
+ * @since 9.0 (was type {@code int} before 12.0)
+ */
+ public static final char MAX = 127;
+
+ /**
+ * Returns a copy of the input string in which all {@linkplain #isUpperCase(char) uppercase ASCII
+ * characters} have been converted to lowercase. All other characters are copied without
+ * modification.
+ */
+ public static String toLowerCase(String string) {
+ int length = string.length();
+ StringBuilder builder = new StringBuilder(length);
+ for (int i = 0; i < length; i++) {
+ builder.append(toLowerCase(string.charAt(i)));
+ }
+ return builder.toString();
+ }
+
+ /**
+ * If the argument is an {@linkplain #isUpperCase(char) uppercase ASCII character} returns the
+ * lowercase equivalent. Otherwise returns the argument.
+ */
+ 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) {
+ int length = string.length();
+ StringBuilder builder = new StringBuilder(length);
+ for (int i = 0; i < length; i++) {
+ builder.append(toUpperCase(string.charAt(i)));
+ }
+ return builder.toString();
+ }
+
+ /**
+ * If the argument is a {@linkplain #isLowerCase(char) lowercase ASCII character} returns the
+ * uppercase equivalent. Otherwise returns the argument.
+ */
+ public static char toUpperCase(char c) {
+ return isLowerCase(c) ? (char) (c & 0x5f) : c;
+ }
+
+ /**
+ * Indicates whether {@code c} is one of the twenty-six lowercase ASCII alphabetic characters
+ * between {@code 'a'} and {@code 'z'} inclusive. All others (including non-ASCII characters)
+ * return {@code false}.
+ */
+ public static boolean isLowerCase(char c) {
+ return (c >= 'a') && (c <= 'z');
+ }
+
+ /**
+ * Indicates whether {@code c} is one of the twenty-six uppercase ASCII alphabetic characters
+ * between {@code 'A'} and {@code 'Z'} inclusive. All others (including non-ASCII characters)
+ * return {@code false}.
+ */
+ public static boolean isUpperCase(char c) {
+ return (c >= 'A') && (c <= 'Z');
+ }
+}
diff --git a/guava/src/com/google/common/base/CaseFormat.java b/guava/src/com/google/common/base/CaseFormat.java
new file mode 100644
index 0000000..8ef7c5c
--- /dev/null
+++ b/guava/src/com/google/common/base/CaseFormat.java
@@ -0,0 +1,164 @@
+/*
+ * 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.base;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * Utility class for converting between various ASCII case formats.
+ *
+ * @author Mike Bostock
+ * @since 1.0
+ */
+@GwtCompatible
+public enum CaseFormat {
+ /**
+ * Hyphenated variable naming convention, e.g., "lower-hyphen".
+ */
+ LOWER_HYPHEN(CharMatcher.is('-'), "-"),
+
+ /**
+ * C++ variable naming convention, e.g., "lower_underscore".
+ */
+ LOWER_UNDERSCORE(CharMatcher.is('_'), "_"),
+
+ /**
+ * Java variable naming convention, e.g., "lowerCamel".
+ */
+ LOWER_CAMEL(CharMatcher.inRange('A', 'Z'), ""),
+
+ /**
+ * Java and C++ class naming convention, e.g., "UpperCamel".
+ */
+ UPPER_CAMEL(CharMatcher.inRange('A', 'Z'), ""),
+
+ /**
+ * Java and C++ constant naming convention, e.g., "UPPER_UNDERSCORE".
+ */
+ UPPER_UNDERSCORE(CharMatcher.is('_'), "_");
+
+ private final CharMatcher wordBoundary;
+ private final String wordSeparator;
+
+ CaseFormat(CharMatcher wordBoundary, String wordSeparator) {
+ this.wordBoundary = wordBoundary;
+ this.wordSeparator = wordSeparator;
+ }
+
+ /**
+ * 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 String to(CaseFormat format, String s) {
+ if (format == null) {
+ throw new NullPointerException();
+ }
+ if (s == null) {
+ throw new NullPointerException();
+ }
+
+ 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;
+ while ((j = wordBoundary.indexIn(s, ++j)) != -1) {
+ if (i == 0) {
+ // include some extra space for separators
+ out = new StringBuilder(s.length() + 4 * wordSeparator.length());
+ out.append(format.normalizeFirstWord(s.substring(i, j)));
+ } else {
+ out.append(format.normalizeWord(s.substring(i, j)));
+ }
+ out.append(format.wordSeparator);
+ i = j + wordSeparator.length();
+ }
+ if (i == 0) {
+ return format.normalizeFirstWord(s);
+ }
+ out.append(format.normalizeWord(s.substring(i)));
+ return out.toString();
+ }
+
+ private String normalizeFirstWord(String 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) {
+ 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
new file mode 100644
index 0000000..64a70b7
--- /dev/null
+++ b/guava/src/com/google/common/base/CharMatcher.java
@@ -0,0 +1,1271 @@
+/*
+ * 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.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 java.util.Arrays;
+import javax.annotation.CheckReturnValue;
+
+/**
+ * Determines a true or false value for any Java {@code char} value, just as {@link Predicate} does
+ * for any {@link Object}. Also offers basic text processing methods based on this function.
+ * Implementations are strongly encouraged to be side-effect-free and immutable.
+ *
+ * <p>Throughout the documentation of this class, the phrase "matching character" is used to mean
+ * "any character {@code c} for which {@code this.matches(c)} returns {@code true}".
+ *
+ * <p><b>Note:</b> This class deals only with {@code char} values; it does not understand
+ * supplementary Unicode code points in the range {@code 0x10000} to {@code 0x10FFFF}. Such logical
+ * characters are encoded into a {@code String} using surrogate pairs, and a {@code CharMatcher}
+ * treats these just as two separate characters.
+ *
+ * <p>Example usages: <pre>
+ * 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
+public abstract class CharMatcher implements Predicate<Character> {
+ // Constants
+ /**
+ * 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
+ * discussion of that term.
+ *
+ * @since 2.0
+ */
+ public static final CharMatcher BREAKING_WHITESPACE =
+ anyOf("\t\n\013\f\r \u0085\u1680\u2028\u2029\u205f\u3000")
+ .or(inRange('\u2000', '\u2006'))
+ .or(inRange('\u2008', '\u200a'))
+ .withToString("CharMatcher.BREAKING_WHITESPACE")
+ .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");
+
+ /**
+ * 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;
+
+ 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.withToString("CharMatcher.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") {
+ @Override public boolean matches(char c) {
+ return Character.isDigit(c);
+ }
+ };
+
+ /**
+ * Determines whether a character is a letter according to {@link Character#isLetter(char) Java's
+ * 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") {
+ @Override public boolean matches(char c) {
+ return Character.isLetter(c);
+ }
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
+ };
+
+ /**
+ * 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") {
+ @Override public boolean matches(char c) {
+ return Character.isLetterOrDigit(c);
+ }
+ };
+
+ /**
+ * 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") {
+ @Override public boolean matches(char c) {
+ return Character.isUpperCase(c);
+ }
+ };
+
+ /**
+ * 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") {
+ @Override public boolean matches(char c) {
+ return Character.isLowerCase(c);
+ }
+ };
+
+ /**
+ * Determines whether a character is an ISO control character as specified by {@link
+ * Character#isISOControl(char)}.
+ */
+ public static final CharMatcher JAVA_ISO_CONTROL =
+ inRange('\u0000', '\u001f')
+ .or(inRange('\u007f', '\u009f'))
+ .withToString("CharMatcher.JAVA_ISO_CONTROL");
+
+ /**
+ * 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 = inRange('\u0000', '\u0020')
+ .or(inRange('\u007f', '\u00a0'))
+ .or(is('\u00ad'))
+ .or(inRange('\u0600', '\u0604'))
+ .or(anyOf("\u06dd\u070f\u1680\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"))
+ .withToString("CharMatcher.INVISIBLE")
+ .precomputed();
+
+ /**
+ * Determines whether a character is single-width (not double-width). When in doubt, this matcher
+ * errs on the side of returning {@code false} (that is, it tends to assume a character is
+ * double-width).
+ *
+ * <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 = 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'))
+ .withToString("CharMatcher.SINGLE_WIDTH")
+ .precomputed();
+
+ /** Matches any character. */
+ public static final CharMatcher ANY =
+ new CharMatcher("CharMatcher.ANY") {
+ @Override public boolean matches(char c) {
+ return true;
+ }
+
+ @Override public int indexIn(CharSequence sequence) {
+ return (sequence.length() == 0) ? -1 : 0;
+ }
+
+ @Override public int indexIn(CharSequence sequence, int start) {
+ int length = sequence.length();
+ Preconditions.checkPositionIndex(start, length);
+ return (start == length) ? -1 : start;
+ }
+
+ @Override public int lastIndexIn(CharSequence sequence) {
+ return sequence.length() - 1;
+ }
+
+ @Override public boolean matchesAllOf(CharSequence sequence) {
+ checkNotNull(sequence);
+ return true;
+ }
+
+ @Override public boolean matchesNoneOf(CharSequence sequence) {
+ return sequence.length() == 0;
+ }
+
+ @Override public String removeFrom(CharSequence sequence) {
+ checkNotNull(sequence);
+ return "";
+ }
+
+ @Override public String replaceFrom(CharSequence sequence, char replacement) {
+ char[] array = new char[sequence.length()];
+ Arrays.fill(array, replacement);
+ return new String(array);
+ }
+
+ @Override public String replaceFrom(CharSequence sequence, CharSequence replacement) {
+ StringBuilder retval = new StringBuilder(sequence.length() * replacement.length());
+ for (int i = 0; i < sequence.length(); i++) {
+ retval.append(replacement);
+ }
+ return retval.toString();
+ }
+
+ @Override public String collapseFrom(CharSequence sequence, char replacement) {
+ return (sequence.length() == 0) ? "" : String.valueOf(replacement);
+ }
+
+ @Override public String trimFrom(CharSequence sequence) {
+ checkNotNull(sequence);
+ return "";
+ }
+
+ @Override public int countIn(CharSequence sequence) {
+ return sequence.length();
+ }
+
+ @Override public CharMatcher and(CharMatcher other) {
+ return checkNotNull(other);
+ }
+
+ @Override public CharMatcher or(CharMatcher other) {
+ checkNotNull(other);
+ return this;
+ }
+
+ @Override public CharMatcher negate() {
+ return NONE;
+ }
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
+ };
+
+ /** Matches no characters. */
+ public static final CharMatcher NONE =
+ new CharMatcher("CharMatcher.NONE") {
+ @Override public boolean matches(char c) {
+ return false;
+ }
+
+ @Override public int indexIn(CharSequence sequence) {
+ checkNotNull(sequence);
+ return -1;
+ }
+
+ @Override public int indexIn(CharSequence sequence, int start) {
+ int length = sequence.length();
+ Preconditions.checkPositionIndex(start, length);
+ return -1;
+ }
+
+ @Override public int lastIndexIn(CharSequence sequence) {
+ checkNotNull(sequence);
+ return -1;
+ }
+
+ @Override public boolean matchesAllOf(CharSequence sequence) {
+ return sequence.length() == 0;
+ }
+
+ @Override public boolean matchesNoneOf(CharSequence sequence) {
+ checkNotNull(sequence);
+ return true;
+ }
+
+ @Override public String removeFrom(CharSequence sequence) {
+ return sequence.toString();
+ }
+
+ @Override public String replaceFrom(CharSequence sequence, char replacement) {
+ return sequence.toString();
+ }
+
+ @Override public String replaceFrom(CharSequence sequence, CharSequence replacement) {
+ checkNotNull(replacement);
+ return sequence.toString();
+ }
+
+ @Override public String collapseFrom(CharSequence sequence, char replacement) {
+ return sequence.toString();
+ }
+
+ @Override public String trimFrom(CharSequence sequence) {
+ return sequence.toString();
+ }
+
+ @Override public int countIn(CharSequence sequence) {
+ checkNotNull(sequence);
+ return 0;
+ }
+
+ @Override public CharMatcher and(CharMatcher other) {
+ checkNotNull(other);
+ return this;
+ }
+
+ @Override public CharMatcher or(CharMatcher other) {
+ return checkNotNull(other);
+ }
+
+ @Override public CharMatcher negate() {
+ return ANY;
+ }
+
+ @Override void setBits(LookupTable table) {}
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
+ };
+
+ // Static factories
+
+ /**
+ * Returns a {@code char} matcher that matches only one specified character.
+ */
+ public static CharMatcher is(final char match) {
+ String description = new StringBuilder("CharMatcher.is(")
+ .append(Integer.toHexString(match))
+ .append(")")
+ .toString();
+ return new CharMatcher(description) {
+ @Override public boolean matches(char c) {
+ return c == match;
+ }
+
+ @Override public String replaceFrom(CharSequence sequence, char replacement) {
+ return sequence.toString().replace(match, replacement);
+ }
+
+ @Override public CharMatcher and(CharMatcher other) {
+ return other.matches(match) ? this : NONE;
+ }
+
+ @Override public CharMatcher or(CharMatcher other) {
+ return other.matches(match) ? other : super.or(other);
+ }
+
+ @Override public CharMatcher negate() {
+ return isNot(match);
+ }
+
+ @Override void setBits(LookupTable table) {
+ table.set(match);
+ }
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
+ };
+ }
+
+ /**
+ * Returns a {@code char} matcher that matches any character except the one specified.
+ *
+ * <p>To negate another {@code CharMatcher}, use {@link #negate()}.
+ */
+ public static CharMatcher isNot(final char match) {
+ String description = new StringBuilder("CharMatcher.isNot(")
+ .append(Integer.toHexString(match))
+ .append(")")
+ .toString();
+ return new CharMatcher(description) {
+ @Override public boolean matches(char c) {
+ return c != match;
+ }
+
+ @Override public CharMatcher and(CharMatcher other) {
+ return other.matches(match) ? super.and(other) : other;
+ }
+
+ @Override public CharMatcher or(CharMatcher other) {
+ return other.matches(match) ? ANY : this;
+ }
+
+ @Override public CharMatcher negate() {
+ return is(match);
+ }
+ };
+ }
+
+ /**
+ * Returns a {@code char} matcher that matches any character present in the given character
+ * sequence.
+ */
+ public static CharMatcher anyOf(final CharSequence sequence) {
+ switch (sequence.length()) {
+ case 0:
+ return NONE;
+ case 1:
+ return is(sequence.charAt(0));
+ case 2:
+ final char match1 = sequence.charAt(0);
+ final char match2 = sequence.charAt(1);
+ return new CharMatcher(
+ new StringBuilder("CharMatcher.anyOf(\"").append(sequence).append("\")").toString()) {
+ @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;
+ }
+ };
+ }
+ final char[] chars = sequence.toString().toCharArray();
+ Arrays.sort(chars);
+
+ return new CharMatcher(new StringBuilder("CharMatcher.anyOf(\"").append(chars)
+ .append("\")").toString()) {
+ @Override public boolean matches(char c) {
+ return Arrays.binarySearch(chars, c) >= 0;
+ }
+ };
+ }
+
+ /**
+ * Returns a {@code char} matcher that matches any character not present in the given character
+ * sequence.
+ */
+ public static CharMatcher noneOf(CharSequence sequence) {
+ return anyOf(sequence).negate();
+ }
+
+ /**
+ * Returns a {@code char} matcher that matches any character in a given range (both endpoints are
+ * inclusive). For example, to match any lowercase letter of the English alphabet, use {@code
+ * CharMatcher.inRange('a', 'z')}.
+ *
+ * @throws IllegalArgumentException if {@code endInclusive < startInclusive}
+ */
+ public static CharMatcher inRange(final char startInclusive, final char endInclusive) {
+ checkArgument(endInclusive >= startInclusive);
+ String description = new StringBuilder("CharMatcher.inRange(")
+ .append(Integer.toHexString(startInclusive))
+ .append(", ")
+ .append(Integer.toHexString(endInclusive))
+ .append(")")
+ .toString();
+ return inRange(startInclusive, endInclusive, description);
+ }
+
+ static CharMatcher inRange(final char startInclusive, final char endInclusive,
+ String description) {
+ return new CharMatcher(description) {
+ @Override public boolean matches(char c) {
+ return startInclusive <= c && c <= endInclusive;
+ }
+
+ @Override void setBits(LookupTable table) {
+ char c = startInclusive;
+ while (true) {
+ table.set(c);
+ if (c++ == endInclusive) {
+ break;
+ }
+ }
+ }
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
+ };
+ }
+
+ /**
+ * Returns a matcher with identical behavior to the given {@link Character}-based predicate, but
+ * which operates on primitive {@code char} instances instead.
+ */
+ public static CharMatcher forPredicate(final Predicate<? super Character> predicate) {
+ checkNotNull(predicate);
+ if (predicate instanceof CharMatcher) {
+ return (CharMatcher) predicate;
+ }
+ String description = new StringBuilder("CharMatcher.forPredicate(")
+ .append(predicate)
+ .append(')')
+ .toString();
+ return new CharMatcher(description) {
+ @Override public boolean matches(char c) {
+ return predicate.apply(c);
+ }
+
+ @Override public boolean apply(Character character) {
+ return predicate.apply(checkNotNull(character));
+ }
+ };
+ }
+
+ // State
+ final String description;
+
+ // Constructors
+
+ /**
+ * Sets the {@code toString()} from the given description.
+ */
+ 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 = "UnknownCharMatcher";
+ }
+
+ // Abstract methods
+
+ /** Determines a true or false value for the given character. */
+ public abstract boolean matches(char c);
+
+ // Non-static factories
+
+ /**
+ * Returns a matcher that matches any character not matched by this matcher.
+ */
+ public CharMatcher negate() {
+ final CharMatcher original = this;
+ return new CharMatcher(original + ".negate()") {
+ @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);
+ }
+
+ @Override public int countIn(CharSequence sequence) {
+ return sequence.length() - original.countIn(sequence);
+ }
+
+ @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));
+ }
+
+ private static class And extends CharMatcher {
+ final CharMatcher first;
+ final CharMatcher second;
+
+ And(CharMatcher a, CharMatcher b) {
+ this(a, b, "CharMatcher.and(" + a + ", " + b + ")");
+ }
+
+ And(CharMatcher a, CharMatcher b, String description) {
+ super(description);
+ first = checkNotNull(a);
+ second = checkNotNull(b);
+ }
+
+ @Override
+ public CharMatcher and(CharMatcher other) {
+ return new And(this, other);
+ }
+
+ @Override
+ public boolean matches(char c) {
+ return first.matches(c) && second.matches(c);
+ }
+
+ @Override
+ CharMatcher withToString(String description) {
+ return new And(first, second, description);
+ }
+ }
+
+ /**
+ * 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));
+ }
+
+ 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);
+ }
+
+ Or(CharMatcher a, CharMatcher b) {
+ this(a, b, "CharMatcher.or(" + a + ", " + b + ")");
+ }
+
+ @Override
+ public CharMatcher or(CharMatcher other) {
+ return new Or(this, checkNotNull(other));
+ }
+
+ @Override
+ public boolean matches(char c) {
+ return first.matches(c) || second.matches(c);
+ }
+
+ @Override
+ CharMatcher withToString(String description) {
+ return new Or(first, second, description);
+ }
+ }
+
+ /**
+ * Returns a {@code char} matcher functionally equivalent to this one, but which may be faster to
+ * query than the original; your mileage may vary. Precomputation takes time and is likely to be
+ * worthwhile only if the precomputed matcher is queried many thousands of times.
+ *
+ * <p>This method has no effect (returns {@code this}) when called in GWT: it's unclear whether a
+ * precomputed matcher is faster, but it certainly consumes more memory, which doesn't seem like a
+ * worthwhile tradeoff in a browser.
+ */
+ public CharMatcher precomputed() {
+ return Platform.precomputeCharMatcher(this);
+ }
+
+ /**
+ * Construct an array of all possible chars in the slowest way possible.
+ */
+ char[] slowGetChars() {
+ char[] allChars = new char[65536];
+ int size = 0;
+ for (int c = Character.MIN_VALUE; c <= Character.MAX_VALUE; c++) {
+ if (matches((char) c)) {
+ allChars[size++] = (char) c;
+ }
+ }
+ char[] retValue = new char[size];
+ System.arraycopy(allChars, 0, retValue, 0, size);
+ return retValue;
+ }
+
+ /**
+ * 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>If the number of matched characters is small enough, we try to build a small hash
+ * table to contain all of the characters. Otherwise, we record the characters in eight-kilobyte
+ * bit array. In many situations this produces a matcher which is faster to query
+ * than the original.
+ */
+ CharMatcher precomputedInternal() {
+ final char[] chars = slowGetChars();
+ int totalCharacters = chars.length;
+ if (totalCharacters == 0) {
+ return NONE;
+ } else if (totalCharacters == 1) {
+ return is(chars[0]);
+ } else if (totalCharacters < SmallCharMatcher.MAX_SIZE) {
+ return SmallCharMatcher.from(chars, toString());
+ } else if (totalCharacters < MediumCharMatcher.MAX_SIZE) {
+ return MediumCharMatcher.from(chars, toString());
+ }
+ // Otherwise, make the full lookup table.
+ final LookupTable table = new LookupTable();
+ setBits(table);
+ final CharMatcher outer = this;
+
+ return new CharMatcher(outer.toString()) {
+ @Override public boolean matches(char c) {
+ return table.get(c);
+ }
+
+ // TODO(kevinb): make methods like negate() smart?
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
+ };
+ }
+
+ /**
+ * Subclasses should provide a new CharMatcher with the same characteristics as {@code this},
+ * but with their {@code toString} method overridden with the new description.
+ *
+ * <p>This is unsupported by default.
+ */
+ CharMatcher withToString(String description) {
+ throw new UnsupportedOperationException();
+
+ }
+
+ /**
+ * 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.
+ */
+ void setBits(LookupTable table) {
+ char c = Character.MIN_VALUE;
+ while (true) {
+ if (matches(c)) {
+ table.set(c);
+ }
+ if (c++ == Character.MAX_VALUE) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * 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.
+ */
+ 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;
+ }
+ }
+
+ // Text processing routines
+
+ /**
+ * Returns {@code true} if a character sequence contains at least one matching character.
+ * Equivalent to {@code !matchesNoneOf(sequence)}.
+ *
+ * <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
+ * character, until this returns {@code true} or the end is reached.
+ *
+ * @param sequence the character sequence to examine, possibly empty
+ * @return {@code true} if this matcher matches at least one character in the sequence
+ * @since 8.0
+ */
+ public boolean matchesAnyOf(CharSequence sequence) {
+ return !matchesNoneOf(sequence);
+ }
+
+ /**
+ * Returns {@code true} if a character sequence contains only matching characters.
+ *
+ * <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
+ * character, until this returns {@code false} or the end is reached.
+ *
+ * @param sequence the character sequence to examine, possibly empty
+ * @return {@code true} if this matcher matches every character in the sequence, including when
+ * the sequence is empty
+ */
+ public boolean matchesAllOf(CharSequence sequence) {
+ for (int i = sequence.length() - 1; i >= 0; i--) {
+ if (!matches(sequence.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if a character sequence contains no matching characters. Equivalent to
+ * {@code !matchesAnyOf(sequence)}.
+ *
+ * <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
+ * character, until this returns {@code false} or the end is reached.
+ *
+ * @param sequence the character sequence to examine, possibly empty
+ * @return {@code true} if this matcher matches every character in the sequence, including when
+ * the sequence is empty
+ */
+ public boolean matchesNoneOf(CharSequence sequence) {
+ return indexIn(sequence) == -1;
+ }
+
+ /**
+ * Returns the index of the first matching character in a character sequence, or {@code -1} if no
+ * matching character is present.
+ *
+ * <p>The default implementation iterates over the sequence in forward order calling {@link
+ * #matches} for each character.
+ *
+ * @param sequence the character sequence to examine from the beginning
+ * @return an index, or {@code -1} if no character matches
+ */
+ public int indexIn(CharSequence sequence) {
+ int length = sequence.length();
+ for (int i = 0; i < length; i++) {
+ if (matches(sequence.charAt(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the index of the first matching character in a character sequence, starting from a
+ * given position, or {@code -1} if no character matches after that position.
+ *
+ * <p>The default implementation iterates over the sequence in forward order, beginning at {@code
+ * start}, calling {@link #matches} for each character.
+ *
+ * @param sequence the character sequence to examine
+ * @param start the first index to examine; must be nonnegative and no greater than {@code
+ * sequence.length()}
+ * @return the index of the first matching character, guaranteed to be no less than {@code start},
+ * or {@code -1} if no character matches
+ * @throws IndexOutOfBoundsException if start is negative or greater than {@code
+ * sequence.length()}
+ */
+ public int indexIn(CharSequence sequence, int start) {
+ int length = sequence.length();
+ Preconditions.checkPositionIndex(start, length);
+ for (int i = start; i < length; i++) {
+ if (matches(sequence.charAt(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the index of the last matching character in a character sequence, or {@code -1} if no
+ * matching character is present.
+ *
+ * <p>The default implementation iterates over the sequence in reverse order calling {@link
+ * #matches} for each character.
+ *
+ * @param sequence the character sequence to examine from the end
+ * @return an index, or {@code -1} if no character matches
+ */
+ public int lastIndexIn(CharSequence sequence) {
+ for (int i = sequence.length() - 1; i >= 0; i--) {
+ if (matches(sequence.charAt(i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the number of matching characters found in a character sequence.
+ */
+ public int countIn(CharSequence sequence) {
+ int count = 0;
+ for (int i = 0; i < sequence.length(); i++) {
+ if (matches(sequence.charAt(i))) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Returns a string containing all non-matching characters of a character sequence, in order. For
+ * example: <pre> {@code
+ *
+ * CharMatcher.is('a').removeFrom("bazaar")}</pre>
+ *
+ * ... returns {@code "bzr"}.
+ */
+ @CheckReturnValue
+ public String removeFrom(CharSequence sequence) {
+ String string = sequence.toString();
+ int pos = indexIn(string);
+ if (pos == -1) {
+ return string;
+ }
+
+ char[] chars = string.toCharArray();
+ int spread = 1;
+
+ // This unusual loop comes from extensive benchmarking
+ OUT: while (true) {
+ pos++;
+ while (true) {
+ if (pos == chars.length) {
+ break OUT;
+ }
+ if (matches(chars[pos])) {
+ break;
+ }
+ chars[pos - spread] = chars[pos];
+ pos++;
+ }
+ spread++;
+ }
+ return new String(chars, 0, pos - spread);
+ }
+
+ /**
+ * Returns a string containing all matching characters of a character sequence, in order. For
+ * example: <pre> {@code
+ *
+ * CharMatcher.is('a').retainFrom("bazaar")}</pre>
+ *
+ * ... returns {@code "aaa"}.
+ */
+ @CheckReturnValue
+ public String retainFrom(CharSequence sequence) {
+ return negate().removeFrom(sequence);
+ }
+
+ /**
+ * Returns a string copy of the input character sequence, with each character that matches this
+ * matcher replaced by a given replacement character. For example: <pre> {@code
+ *
+ * CharMatcher.is('a').replaceFrom("radar", 'o')}</pre>
+ *
+ * ... returns {@code "rodor"}.
+ *
+ * <p>The default implementation uses {@link #indexIn(CharSequence)} to find the first matching
+ * character, then iterates the remainder of the sequence calling {@link #matches(char)} for each
+ * character.
+ *
+ * @param sequence the character sequence to replace matching characters in
+ * @param replacement the character to append to the result string in place of each matching
+ * character in {@code sequence}
+ * @return the new string
+ */
+ @CheckReturnValue
+ public String replaceFrom(CharSequence sequence, char replacement) {
+ String string = sequence.toString();
+ int pos = indexIn(string);
+ if (pos == -1) {
+ return string;
+ }
+ char[] chars = string.toCharArray();
+ chars[pos] = replacement;
+ for (int i = pos + 1; i < chars.length; i++) {
+ if (matches(chars[i])) {
+ chars[i] = replacement;
+ }
+ }
+ return new String(chars);
+ }
+
+ /**
+ * Returns a string copy of the input character sequence, with each character that matches this
+ * matcher replaced by a given replacement sequence. For example: <pre> {@code
+ *
+ * CharMatcher.is('a').replaceFrom("yaha", "oo")}</pre>
+ *
+ * ... returns {@code "yoohoo"}.
+ *
+ * <p><b>Note:</b> If the replacement is a fixed string with only one character, you are better
+ * off calling {@link #replaceFrom(CharSequence, char)} directly.
+ *
+ * @param sequence the character sequence to replace matching characters in
+ * @param replacement the characters to append to the result string in place of each matching
+ * character in {@code sequence}
+ * @return the new string
+ */
+ @CheckReturnValue
+ public String replaceFrom(CharSequence sequence, CharSequence replacement) {
+ int replacementLen = replacement.length();
+ if (replacementLen == 0) {
+ return removeFrom(sequence);
+ }
+ if (replacementLen == 1) {
+ return replaceFrom(sequence, replacement.charAt(0));
+ }
+
+ String string = sequence.toString();
+ int pos = indexIn(string);
+ if (pos == -1) {
+ return string;
+ }
+
+ int len = string.length();
+ StringBuilder buf = new StringBuilder((len * 3 / 2) + 16);
+
+ int oldpos = 0;
+ do {
+ buf.append(string, oldpos, pos);
+ buf.append(replacement);
+ oldpos = pos + 1;
+ pos = indexIn(string, oldpos);
+ } while (pos != -1);
+
+ buf.append(string, oldpos, len);
+ return buf.toString();
+ }
+
+ /**
+ * Returns a substring of the input character sequence that omits all characters this matcher
+ * matches from the beginning and from the end of the string. For example: <pre> {@code
+ *
+ * CharMatcher.anyOf("ab").trimFrom("abacatbab")}</pre>
+ *
+ * ... returns {@code "cat"}.
+ *
+ * <p>Note that: <pre> {@code
+ *
+ * CharMatcher.inRange('\0', ' ').trimFrom(str)}</pre>
+ *
+ * ... is equivalent to {@link String#trim()}.
+ */
+ @CheckReturnValue
+ public String trimFrom(CharSequence sequence) {
+ int len = sequence.length();
+ int first;
+ int last;
+
+ for (first = 0; first < len; first++) {
+ if (!matches(sequence.charAt(first))) {
+ break;
+ }
+ }
+ for (last = len - 1; last > first; last--) {
+ if (!matches(sequence.charAt(last))) {
+ break;
+ }
+ }
+
+ return sequence.subSequence(first, last + 1).toString();
+ }
+
+ /**
+ * Returns a substring of the input character sequence that omits all characters this matcher
+ * matches from the beginning of the string. For example: <pre> {@code
+ *
+ * CharMatcher.anyOf("ab").trimLeadingFrom("abacatbab")}</pre>
+ *
+ * ... returns {@code "catbab"}.
+ */
+ @CheckReturnValue
+ public String trimLeadingFrom(CharSequence sequence) {
+ int len = sequence.length();
+ int first;
+
+ for (first = 0; first < len; first++) {
+ if (!matches(sequence.charAt(first))) {
+ break;
+ }
+ }
+
+ return sequence.subSequence(first, len).toString();
+ }
+
+ /**
+ * Returns a substring of the input character sequence that omits all characters this matcher
+ * matches from the end of the string. For example: <pre> {@code
+ *
+ * CharMatcher.anyOf("ab").trimTrailingFrom("abacatbab")}</pre>
+ *
+ * ... returns {@code "abacat"}.
+ */
+ @CheckReturnValue
+ public String trimTrailingFrom(CharSequence sequence) {
+ int len = sequence.length();
+ int last;
+
+ for (last = len - 1; last >= 0; last--) {
+ if (!matches(sequence.charAt(last))) {
+ break;
+ }
+ }
+
+ return sequence.subSequence(0, last + 1).toString();
+ }
+
+ /**
+ * Returns a string copy of the input character sequence, with each group of consecutive
+ * characters that match this matcher replaced by a single replacement character. For example:
+ * <pre> {@code
+ *
+ * CharMatcher.anyOf("eko").collapseFrom("bookkeeper", '-')}</pre>
+ *
+ * ... returns {@code "b-p-r"}.
+ *
+ * <p>The default implementation uses {@link #indexIn(CharSequence)} to find the first matching
+ * character, then iterates the remainder of the sequence calling {@link #matches(char)} for each
+ * character.
+ *
+ * @param sequence the character sequence to replace matching groups of characters in
+ * @param replacement the character to append to the result string in place of each group of
+ * matching characters in {@code sequence}
+ * @return the new string
+ */
+ @CheckReturnValue
+ public String collapseFrom(CharSequence sequence, char replacement) {
+ 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 (!in) {
+ builder.append(replacement);
+ in = true;
+ }
+ } else {
+ builder.append(c);
+ in = false;
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Collapses groups of matching characters exactly as {@link #collapseFrom} does, except that
+ * groups of matching characters at the start or end of the sequence are removed without
+ * replacement.
+ */
+ @CheckReturnValue
+ public String trimAndCollapseFrom(CharSequence sequence, char replacement) {
+ 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)) {
+ inMatchingGroup = true;
+ } else {
+ if (inMatchingGroup) {
+ builder.append(replacement);
+ inMatchingGroup = false;
+ }
+ builder.append(c);
+ }
+ }
+ return builder.toString();
+ }
+
+ // Predicate interface
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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 CharMatcher("CharMatcher.WHITESPACE") {
+ /**
+ * 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.
+ */
+
+ // Mod-79 lookup table.
+ private final char[] table = {1, 0, 160, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 0, 0,
+ 8232, 8233, 0, 0, 0, 0, 0, 8239, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 12288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199,
+ 8200, 8201, 8202, 0, 0, 0, 0, 0, 8287, 5760, 0, 0, 6158, 0, 0, 0};
+
+ @Override public boolean matches(char c) {
+ return table[c % 79] == c;
+ }
+
+ @Override public CharMatcher precomputed() {
+ return this;
+ }
+ };
+}
diff --git a/guava/src/com/google/common/base/Charsets.java b/guava/src/com/google/common/base/Charsets.java
new file mode 100644
index 0000000..79c9128
--- /dev/null
+++ b/guava/src/com/google/common/base/Charsets.java
@@ -0,0 +1,83 @@
+/*
+ * 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.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");
+
+ /**
+ * UTF-8: eight-bit UCS Transformation Format.
+ */
+ public static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ /**
+ * 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");
+
+ /*
+ * Please do not add new Charset references to this class, unless those character encodings are
+ * part of the set required to be supported by all Java platform implementations! Any Charsets
+ * initialized here may cause unexpected delays when this class is loaded. See the Charset
+ * Javadocs for the list of built-in character encodings.
+ */
+}
diff --git a/guava/src/com/google/common/base/Defaults.java b/guava/src/com/google/common/base/Defaults.java
new file mode 100644
index 0000000..b3e8555
--- /dev/null
+++ b/guava/src/com/google/common/base/Defaults.java
@@ -0,0 +1,60 @@
+/*
+ * 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.base;
+
+import java.util.Collections;
+import java.util.HashMap;
+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() {}
+
+ private static final Map<Class<?>, Object> DEFAULTS;
+
+ static {
+ Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
+ put(map, boolean.class, false);
+ put(map, char.class, '\0');
+ put(map, byte.class, (byte) 0);
+ put(map, short.class, (short) 0);
+ put(map, int.class, 0);
+ put(map, long.class, 0L);
+ put(map, float.class, 0f);
+ put(map, double.class, 0d);
+ DEFAULTS = Collections.unmodifiableMap(map);
+ }
+
+ private static <T> void put(Map<Class<?>, Object> map, Class<T> type, T value) {
+ map.put(type, value);
+ }
+
+ /**
+ * Returns the default value of {@code type} as defined by JLS --- {@code 0} for numbers, {@code
+ * false} for {@code boolean} and {@code '\0'} for {@code char}. For non-primitive types and
+ * {@code void}, null is returned.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T defaultValue(Class<T> 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
new file mode 100644
index 0000000..6105410
--- /dev/null
+++ b/guava/src/com/google/common/base/Enums.java
@@ -0,0 +1,128 @@
+/*
+ * 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.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;
+
+/**
+ * Utility methods for working with {@link Enum} instances.
+ *
+ * @author Steve McKay
+ *
+ * @since 9.0
+ */
+@GwtCompatible(emulated = true)
+@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.
+ *
+ * @param enumClass the {@link Class} of the {@code Enum} declaring the
+ * constant values.
+ */
+ public static <T extends Enum<T>> Function<String, T> valueOfFunction(Class<T> enumClass) {
+ return new ValueOfFunction<T>(enumClass);
+ }
+
+ /**
+ * A {@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 final Class<T> enumClass;
+
+ private ValueOfFunction(Class<T> enumClass) {
+ this.enumClass = checkNotNull(enumClass);
+ }
+
+ @Override
+ public T apply(String value) {
+ try {
+ return Enum.valueOf(enumClass, value);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ return obj instanceof ValueOfFunction &&
+ enumClass.equals(((ValueOfFunction) obj).enumClass);
+ }
+
+ @Override public int hashCode() {
+ return enumClass.hashCode();
+ }
+
+ @Override public String toString() {
+ return "Enums.valueOf(" + enumClass + ")";
+ }
+
+ 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
new file mode 100644
index 0000000..d039283
--- /dev/null
+++ b/guava/src/com/google/common/base/Equivalence.java
@@ -0,0 +1,358 @@
+/*
+ * 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 static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+
+import javax.annotation.Nullable;
+
+/**
+ * A strategy for determining whether two instances are considered equivalent. Examples of
+ * equivalences are the {@link Equivalences#identity() identity equivalence} and {@link
+ * Equivalences#equals equals equivalence}.
+ *
+ * @author Bob Lee
+ * @author Ben Yu
+ * @author Gregory Kick
+ * @since 10.0 (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility"
+ * >mostly source-compatible</a> since 4.0)
+ */
+@GwtCompatible
+public abstract class Equivalence<T> {
+ /**
+ * Constructor for use by subclasses.
+ */
+ protected Equivalence() {}
+
+ /**
+ * Returns {@code true} if the given objects are considered equivalent.
+ *
+ * <p>The {@code equivalent} method implements an equivalence relation on object references:
+ *
+ * <ul>
+ * <li>It is <i>reflexive</i>: for any reference {@code x}, including null, {@code
+ * equivalent(x, x)} returns {@code true}.
+ * <li>It is <i>symmetric</i>: for any references {@code x} and {@code y}, {@code
+ * equivalent(x, y) == equivalent(y, x)}.
+ * <li>It is <i>transitive</i>: for any references {@code x}, {@code y}, and {@code z}, if
+ * {@code equivalent(x, y)} returns {@code true} and {@code equivalent(y, z)} returns {@code
+ * true}, then {@code equivalent(x, z)} returns {@code true}.
+ * <li>It is <i>consistent</i>: for any references {@code x} and {@code y}, multiple invocations
+ * of {@code equivalent(x, y)} consistently return {@code true} or consistently return {@code
+ * false} (provided that neither {@code x} nor {@code y} is modified).
+ * </ul>
+ */
+ public final boolean equivalent(@Nullable T a, @Nullable T b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ return doEquivalent(a, b);
+ }
+
+ /**
+ * Returns {@code true} if {@code a} and {@code b} are considered equivalent.
+ *
+ * <p>Called by {@link #equivalent}. {@code a} and {@code b} are not the same
+ * object and are not nulls.
+ *
+ * @since 10.0 (previously, subclasses would override equivalent())
+ */
+ protected abstract boolean doEquivalent(T a, T b);
+
+ /**
+ * Returns a hash code for {@code t}.
+ *
+ * <p>The {@code hash} has the following properties:
+ * <ul>
+ * <li>It is <i>consistent</i>: for any reference {@code x}, multiple invocations of
+ * {@code hash(x}} consistently return the same value provided {@code x} remains unchanged
+ * according to the definition of the equivalence. The hash need not remain consistent from
+ * one execution of an application to another execution of the same application.
+ * <li>It is <i>distributable accross equivalence</i>: for any references {@code x} and {@code y},
+ * if {@code equivalent(x, y)}, then {@code hash(x) == hash(y)}. It is <i>not</i> necessary
+ * that the hash be distributable accorss <i>inequivalence</i>. If {@code equivalence(x, y)}
+ * is false, {@code hash(x) == hash(y)} may still be true.
+ * <li>{@code hash(null)} is {@code 0}.
+ * </ul>
+ */
+ public final int hash(@Nullable T t) {
+ if (t == null) {
+ return 0;
+ }
+ return doHash(t);
+ }
+
+ /**
+ * Returns a hash code for non-null object {@code t}.
+ *
+ * <p>Called by {@link #hash}.
+ *
+ * @since 10.0 (previously, subclasses would override hash())
+ */
+ protected abstract int doHash(T t);
+
+ /**
+ * Returns a new equivalence relation for {@code F} which evaluates equivalence by first applying
+ * {@code function} to the argument, then evaluating using {@code this}. That is, for any pair of
+ * non-null objects {@code x} and {@code y}, {@code
+ * equivalence.onResultOf(function).equivalent(a, b)} is true if and only if {@code
+ * equivalence.equivalent(function.apply(a), function.apply(b))} is true.
+ *
+ * <p>For example: <pre> {@code
+ *
+ * Equivalence<Person> SAME_AGE = Equivalences.equals().onResultOf(GET_PERSON_AGE);
+ * }</pre>
+ *
+ * <p>{@code function} will never be invoked with a null value.
+ *
+ * <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 Equivalences.identity().onResultOf(Functions.toStringFunction())} is broken
+ * because it's not guaranteed that {@link Object#toString}) always returns the same string
+ * instance.
+ *
+ * @since 10.0
+ */
+ public final <F> Equivalence<F> onResultOf(Function<F, ? extends T> function) {
+ return new FunctionalEquivalence<F, T>(function, this);
+ }
+
+ /**
+ * Returns a wrapper of {@code reference} that implements
+ * {@link Wrapper#equals(Object) Object.equals()} such that
+ * {@code wrap(this, a).equals(wrap(this, b))} if and only if {@code this.equivalent(a, b)}.
+ *
+ * @since 10.0
+ */
+ public final <S extends T> Wrapper<S> wrap(@Nullable S reference) {
+ return new Wrapper<S>(this, reference);
+ }
+
+ /**
+ * Wraps an object so that {@link #equals(Object)} and {@link #hashCode()} delegate to an
+ * {@link Equivalence}.
+ *
+ * <p>For example, given an {@link Equivalence} for {@link String strings} named {@code equiv}
+ * that tests equivalence using their lengths:
+ *
+ * <pre> {@code
+ * equiv.wrap("a").equals(equiv.wrap("b")) // true
+ * equiv.wrap("a").equals(equiv.wrap("hello")) // false
+ * }</pre>
+ *
+ * <p>Note in particular that an equivalence wrapper is never equal to the object it wraps.
+ *
+ * <pre> {@code
+ * equiv.wrap(obj).equals(obj) // always false
+ * }</pre>
+ *
+ * @since 10.0
+ */
+ public static final class Wrapper<T> implements Serializable {
+ private final Equivalence<? super T> equivalence;
+ @Nullable private final T reference;
+
+ private Wrapper(Equivalence<? super T> equivalence, @Nullable T reference) {
+ this.equivalence = checkNotNull(equivalence);
+ this.reference = reference;
+ }
+
+ /** Returns the (possibly null) reference wrapped by this instance. */
+ @Nullable public T get() {
+ return reference;
+ }
+
+ /**
+ * Returns {@code true} if {@link Equivalence#equivalent(Object, Object)} applied to the wrapped
+ * references is {@code true} and both wrappers use the {@link Object#equals(Object) same}
+ * equivalence.
+ */
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof Wrapper) {
+ Wrapper<?> that = (Wrapper<?>) obj;
+ /*
+ * We cast to Equivalence<Object> here because we can't check the type of the reference held
+ * by the other wrapper. But, by checking that the Equivalences are equal, we know that
+ * whatever type it is, it is assignable to the type handled by this wrapper's equivalence.
+ */
+ @SuppressWarnings("unchecked")
+ Equivalence<Object> equivalence = (Equivalence<Object>) this.equivalence;
+ return equivalence.equals(that.equivalence)
+ && equivalence.equivalent(this.reference, that.reference);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the result of {@link Equivalence#hash(Object)} applied to the the wrapped reference.
+ */
+ @Override public int hashCode() {
+ return equivalence.hash(reference);
+ }
+
+ /**
+ * Returns a string representation for this equivalence wrapper. The form of this string
+ * representation is not specified.
+ */
+ @Override public String toString() {
+ return equivalence + ".wrap(" + reference + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns an equivalence over iterables based on the equivalence of their elements. More
+ * specifically, two iterables are considered equivalent if they both contain the same number of
+ * elements, and each pair of corresponding elements is equivalent according to
+ * {@code this}. Null iterables are equivalent to one another.
+ *
+ * <p>Note that this method performs a similar function for equivalences as {@link
+ * com.google.common.collect.Ordering#lexicographical} does for orderings.
+ *
+ * @since 10.0
+ */
+ @GwtCompatible(serializable = true)
+ public final <S extends T> Equivalence<Iterable<S>> pairwise() {
+ // Ideally, the returned equivalence would support Iterable<? extends T>. However,
+ // the need for this is so rare that it's not worth making callers deal with the ugly wildcard.
+ return new PairwiseEquivalence<S>(this);
+ }
+
+ /**
+ * Returns a predicate that evaluates to true if and only if the input is
+ * equivalent to {@code target} according to this equivalence relation.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public final Predicate<T> equivalentTo(@Nullable T target) {
+ return new EquivalentToPredicate<T>(this, target);
+ }
+
+ private static final class EquivalentToPredicate<T> implements Predicate<T>, Serializable {
+
+ private final Equivalence<T> equivalence;
+ @Nullable private final T target;
+
+ EquivalentToPredicate(Equivalence<T> equivalence, @Nullable T target) {
+ this.equivalence = checkNotNull(equivalence);
+ this.target = target;
+ }
+
+ @Override public boolean apply(@Nullable T input) {
+ return equivalence.equivalent(input, target);
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof EquivalentToPredicate) {
+ EquivalentToPredicate<?> that = (EquivalentToPredicate<?>) obj;
+ return equivalence.equals(that.equivalence)
+ && Objects.equal(target, that.target);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(equivalence, target);
+ }
+
+ @Override public String toString() {
+ return equivalence + ".equivalentTo(" + target + ")";
+ }
+
+ 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..23f947c
--- /dev/null
+++ b/guava/src/com/google/common/base/Equivalences.java
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+/**
+ * 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)
+ * @deprecated This method has been moved to {@link Equivalence#equals}. This method is scheduled
+ * to be removed in Guava release 14.0.
+ */
+ @Deprecated
+ public static Equivalence<Object> equals() {
+ return Equivalence.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.
+ *
+ * @deprecated This method has been moved to {@link Equivalence#identity}. This method is schedule
+ * to be removed in Guava release 14.0.
+ */
+ @Deprecated
+ public static Equivalence<Object> identity() {
+ return Equivalence.Identity.INSTANCE;
+ }
+}
diff --git a/guava/src/com/google/common/base/FinalizablePhantomReference.java b/guava/src/com/google/common/base/FinalizablePhantomReference.java
new file mode 100644
index 0000000..c694bc9
--- /dev/null
+++ b/guava/src/com/google/common/base/FinalizablePhantomReference.java
@@ -0,0 +1,44 @@
+/*
+ * 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.base;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+
+/**
+ * Phantom reference with a {@code finalizeReferent()} method which a background thread invokes
+ * after the garbage collector reclaims the referent. This is a simpler alternative to using a
+ * {@link ReferenceQueue}.
+ *
+ * <p>Unlike a normal phantom reference, this reference will be cleared automatically.
+ *
+ * @author Bob Lee
+ * @since 2.0 (imported from Google Collections Library)
+ */
+public abstract class FinalizablePhantomReference<T> extends PhantomReference<T>
+ implements FinalizableReference {
+ /**
+ * Constructs a new finalizable phantom reference.
+ *
+ * @param referent to phantom reference
+ * @param queue that should finalize the referent
+ */
+ protected FinalizablePhantomReference(T referent, FinalizableReferenceQueue queue) {
+ super(referent, queue.queue);
+ queue.cleanUp();
+ }
+}
diff --git a/guava/src/com/google/common/base/FinalizableReference.java b/guava/src/com/google/common/base/FinalizableReference.java
new file mode 100644
index 0000000..ab2dec3
--- /dev/null
+++ b/guava/src/com/google/common/base/FinalizableReference.java
@@ -0,0 +1,33 @@
+/*
+ * 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.base;
+
+/**
+ * Implemented by references that have code to run after garbage collection of their referents.
+ *
+ * @see FinalizableReferenceQueue
+ * @author Bob Lee
+ * @since 2.0 (imported from Google Collections Library)
+ */
+public interface FinalizableReference {
+ /**
+ * Invoked on a background thread after the referent has been garbage collected unless security
+ * restrictions prevented starting a background thread, in which case this method is invoked when
+ * new references are created.
+ */
+ void finalizeReferent();
+}
diff --git a/guava/src/com/google/common/base/FinalizableReferenceQueue.java b/guava/src/com/google/common/base/FinalizableReferenceQueue.java
new file mode 100644
index 0000000..aaa5f76
--- /dev/null
+++ b/guava/src/com/google/common/base/FinalizableReferenceQueue.java
@@ -0,0 +1,299 @@
+/*
+ * 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.base;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A reference queue with an associated background thread that dequeues references and invokes
+ * {@link FinalizableReference#finalizeReferent()} on them.
+ *
+ * <p>Keep a strong reference to this object until all of the associated referents have been
+ * finalized. If this object is garbage collected earlier, the backing thread will not invoke {@code
+ * finalizeReferent()} on the remaining references.
+ *
+ * @author Bob Lee
+ * @since 2.0 (imported from Google Collections Library)
+ */
+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
+ * will reclaim it and enqueue the phantom reference. The enqueued reference will trigger the
+ * Finalizer to stop.
+ *
+ * If this library is loaded in the system class loader, FinalizableReferenceQueue can load
+ * Finalizer directly with no problems.
+ *
+ * If this library is loaded in an application class loader, it's important that Finalizer not
+ * have a strong reference back to the class loader. Otherwise, you could have a graph like this:
+ *
+ * Finalizer Thread runs instance of -> Finalizer.class loaded by -> Application class loader
+ * which loaded -> ReferenceMap.class which has a static -> FinalizableReferenceQueue instance
+ *
+ * Even if no other references to classes from the application class loader remain, the Finalizer
+ * thread keeps an indirect strong reference to the queue in ReferenceMap, which keeps the
+ * Finalizer running, and as a result, the application class loader can never be reclaimed.
+ *
+ * This means that dynamically loaded web applications and OSGi bundles can't be unloaded.
+ *
+ * If the library is loaded in an application class loader, we try to break the cycle by loading
+ * Finalizer in its own independent class loader:
+ *
+ * System class loader -> Application class loader -> ReferenceMap -> FinalizableReferenceQueue
+ * -> etc. -> Decoupled class loader -> Finalizer
+ *
+ * Now, Finalizer no longer keeps an indirect strong reference to the static
+ * FinalizableReferenceQueue field in ReferenceMap. The application class loader can be reclaimed
+ * at which point the Finalizer thread will stop and its decoupled class loader can also be
+ * reclaimed.
+ *
+ * If any of this fails along the way, we fall back to loading Finalizer directly in the
+ * application class loader.
+ */
+
+ private static final Logger logger = Logger.getLogger(FinalizableReferenceQueue.class.getName());
+
+ private static final String FINALIZER_CLASS_NAME = "com.google.common.base.internal.Finalizer";
+
+ /** Reference to Finalizer.startFinalizer(). */
+ private static final Method startFinalizer;
+ static {
+ Class<?> finalizer = loadFinalizer(
+ new SystemLoader(), new DecoupledLoader(), new DirectLoader());
+ startFinalizer = getStartFinalizer(finalizer);
+ }
+
+ /**
+ * The actual reference queue that our background thread will poll.
+ */
+ final ReferenceQueue<Object> queue;
+
+ /**
+ * Whether or not the background thread started successfully.
+ */
+ final boolean threadStarted;
+
+ /**
+ * Constructs a new queue.
+ */
+ @SuppressWarnings("unchecked")
+ public FinalizableReferenceQueue() {
+ // We could start the finalizer lazily, but I'd rather it blow up early.
+ ReferenceQueue<Object> queue;
+ boolean threadStarted = false;
+ try {
+ 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;
+ }
+
+ /**
+ * Repeatedly dequeues references from the queue and invokes {@link
+ * FinalizableReference#finalizeReferent()} on them until the queue is empty. This method is a
+ * no-op if the background thread was created successfully.
+ */
+ void cleanUp() {
+ if (threadStarted) {
+ return;
+ }
+
+ Reference<?> reference;
+ while ((reference = queue.poll()) != null) {
+ /*
+ * This is for the benefit of phantom references. Weak and soft references will have already
+ * been cleared by this point.
+ */
+ reference.clear();
+ try {
+ ((FinalizableReference) reference).finalizeReferent();
+ } catch (Throwable t) {
+ logger.log(Level.SEVERE, "Error cleaning up after reference.", t);
+ }
+ }
+ }
+
+ /**
+ * Iterates through the given loaders until it finds one that can load Finalizer.
+ *
+ * @return Finalizer.class
+ */
+ private static Class<?> loadFinalizer(FinalizerLoader... loaders) {
+ for (FinalizerLoader loader : loaders) {
+ Class<?> finalizer = loader.loadFinalizer();
+ if (finalizer != null) {
+ return finalizer;
+ }
+ }
+
+ throw new AssertionError();
+ }
+
+ /**
+ * Loads Finalizer.class.
+ */
+ interface FinalizerLoader {
+
+ /**
+ * Returns Finalizer.class or null if this loader shouldn't or can't load it.
+ *
+ * @throws SecurityException if we don't have the appropriate privileges
+ */
+ Class<?> loadFinalizer();
+ }
+
+ /**
+ * Tries to load Finalizer from the system class loader. If Finalizer is in the system class path,
+ * 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();
+ } catch (SecurityException e) {
+ logger.info("Not allowed to access system class loader.");
+ return null;
+ }
+ if (systemLoader != null) {
+ try {
+ return systemLoader.loadClass(FINALIZER_CLASS_NAME);
+ } catch (ClassNotFoundException e) {
+ // Ignore. Finalizer is simply in a child class loader.
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+ }
+
+ /**
+ * Try to load Finalizer in its own class loader. If Finalizer's thread had a direct reference to
+ * our class loader (which could be that of a dynamically loaded web application or OSGi bundle),
+ * it would prevent our class loader from getting garbage collected.
+ */
+ static class DecoupledLoader implements FinalizerLoader {
+ private static final String LOADING_ERROR = "Could not load Finalizer in its own class loader."
+ + "Loading Finalizer in the current class loader instead. As a result, you will not be able"
+ + "to garbage collect this class loader. To support reclaiming this class loader, either"
+ + "resolve the underlying issue, or move Google Collections to your system class path.";
+
+ @Override
+ public Class<?> loadFinalizer() {
+ try {
+ /*
+ * We use URLClassLoader because it's the only concrete class loader implementation in the
+ * JDK. If we used our own ClassLoader subclass, Finalizer would indirectly reference this
+ * class loader:
+ *
+ * Finalizer.class -> CustomClassLoader -> CustomClassLoader.class -> This class loader
+ *
+ * System class loader will (and must) be the parent.
+ */
+ ClassLoader finalizerLoader = newLoader(getBaseUrl());
+ return finalizerLoader.loadClass(FINALIZER_CLASS_NAME);
+ } catch (Exception e) {
+ logger.log(Level.WARNING, LOADING_ERROR, e);
+ return null;
+ }
+ }
+
+ /**
+ * Gets URL for base of path containing Finalizer.class.
+ */
+ URL getBaseUrl() throws IOException {
+ // Find URL pointing to Finalizer.class file.
+ String finalizerPath = FINALIZER_CLASS_NAME.replace('.', '/') + ".class";
+ URL finalizerUrl = getClass().getClassLoader().getResource(finalizerPath);
+ if (finalizerUrl == null) {
+ throw new FileNotFoundException(finalizerPath);
+ }
+
+ // Find URL pointing to base of class path.
+ String urlString = finalizerUrl.toString();
+ if (!urlString.endsWith(finalizerPath)) {
+ throw new IOException("Unsupported path style: " + urlString);
+ }
+ urlString = urlString.substring(0, urlString.length() - finalizerPath.length());
+ return new URL(finalizerUrl, urlString);
+ }
+
+ /** 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);
+ }
+ }
+
+ /**
+ * Loads Finalizer directly using the current class loader. We won't be able to garbage collect
+ * this class loader, but at least the world doesn't end.
+ */
+ static class DirectLoader implements FinalizerLoader {
+ @Override
+ public Class<?> loadFinalizer() {
+ try {
+ return Class.forName(FINALIZER_CLASS_NAME);
+ } catch (ClassNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ /**
+ * Looks up Finalizer.startFinalizer().
+ */
+ static Method getStartFinalizer(Class<?> finalizer) {
+ try {
+ return finalizer.getMethod("startFinalizer", Class.class, Object.class);
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/base/FinalizableSoftReference.java b/guava/src/com/google/common/base/FinalizableSoftReference.java
new file mode 100644
index 0000000..88607f4
--- /dev/null
+++ b/guava/src/com/google/common/base/FinalizableSoftReference.java
@@ -0,0 +1,42 @@
+/*
+ * 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.base;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+
+/**
+ * Soft reference with a {@code finalizeReferent()} method which a background thread invokes after
+ * the garbage collector reclaims the referent. This is a simpler alternative to using a {@link
+ * ReferenceQueue}.
+ *
+ * @author Bob Lee
+ * @since 2.0 (imported from Google Collections Library)
+ */
+public abstract class FinalizableSoftReference<T> extends SoftReference<T>
+ implements FinalizableReference {
+ /**
+ * Constructs a new finalizable soft reference.
+ *
+ * @param referent to softly reference
+ * @param queue that should finalize the referent
+ */
+ protected FinalizableSoftReference(T referent, FinalizableReferenceQueue queue) {
+ super(referent, queue.queue);
+ queue.cleanUp();
+ }
+}
diff --git a/guava/src/com/google/common/base/FinalizableWeakReference.java b/guava/src/com/google/common/base/FinalizableWeakReference.java
new file mode 100644
index 0000000..b14d023
--- /dev/null
+++ b/guava/src/com/google/common/base/FinalizableWeakReference.java
@@ -0,0 +1,42 @@
+/*
+ * 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.base;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+/**
+ * Weak reference with a {@code finalizeReferent()} method which a background thread invokes after
+ * the garbage collector reclaims the referent. This is a simpler alternative to using a {@link
+ * ReferenceQueue}.
+ *
+ * @author Bob Lee
+ * @since 2.0 (imported from Google Collections Library)
+ */
+public abstract class FinalizableWeakReference<T> extends WeakReference<T>
+ implements FinalizableReference {
+ /**
+ * Constructs a new finalizable weak reference.
+ *
+ * @param referent to weakly reference
+ * @param queue that should finalize the referent
+ */
+ protected FinalizableWeakReference(T referent, FinalizableReferenceQueue queue) {
+ super(referent, queue.queue);
+ queue.cleanUp();
+ }
+}
diff --git a/guava/src/com/google/common/base/Function.java b/guava/src/com/google/common/base/Function.java
new file mode 100644
index 0000000..9c29264
--- /dev/null
+++ b/guava/src/com/google/common/base/Function.java
@@ -0,0 +1,63 @@
+/*
+ * 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.base;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * Determines an output value based on an input value.
+ *
+ * <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)
+ */
+@GwtCompatible
+public interface Function<F, T> {
+ /**
+ * Returns the result of applying this function to {@code input}. This method is <i>generally
+ * expected</i>, but not absolutely required, to have the following properties:
+ *
+ * <ul>
+ * <li>Its execution does not cause any observable side effects.
+ * <li>The computation is <i>consistent with equals</i>; that is, {@link Objects#equal
+ * Objects.equal}{@code (a, b)} implies that {@code Objects.equal(function.apply(a),
+ * function.apply(b))}.
+ * </ul>
+ *
+ * @throws NullPointerException if {@code input} is null and this function does not accept null
+ * arguments
+ */
+ @Nullable T apply(@Nullable F input);
+
+ /**
+ * Indicates whether another object is equal to this function.
+ *
+ * <p>Most implementations will have no reason to override the behavior of {@link Object#equals}.
+ * However, an implementation may also choose to return {@code true} whenever {@code object} is a
+ * {@link Function} that it considers <i>interchangeable</i> with this one. "Interchangeable"
+ * <i>typically</i> means that {@code Objects.equal(this.apply(f), that.apply(f))} is true for all
+ * {@code f} of type {@code F}. Note that a {@code false} result from this method does not imply
+ * that the functions are known <i>not</i> to be interchangeable.
+ */
+ @Override
+ boolean equals(@Nullable Object object);
+}
diff --git a/guava/src/com/google/common/base/FunctionalEquivalence.java b/guava/src/com/google/common/base/FunctionalEquivalence.java
new file mode 100644
index 0000000..a5e9c13
--- /dev/null
+++ b/guava/src/com/google/common/base/FunctionalEquivalence.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.base;
+
+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 javax.annotation.Nullable;
+
+/**
+ * Equivalence applied on functional result.
+ *
+ * @author Bob Lee
+ * @since 10.0
+ */
+@Beta
+@GwtCompatible
+final class FunctionalEquivalence<F, T> extends Equivalence<F>
+ implements Serializable {
+
+ private static final long serialVersionUID = 0;
+
+ private final Function<F, ? extends T> function;
+ private final Equivalence<T> resultEquivalence;
+
+ FunctionalEquivalence(
+ Function<F, ? extends T> function, Equivalence<T> resultEquivalence) {
+ this.function = checkNotNull(function);
+ this.resultEquivalence = checkNotNull(resultEquivalence);
+ }
+
+ @Override protected boolean doEquivalent(F a, F b) {
+ return resultEquivalence.equivalent(function.apply(a), function.apply(b));
+ }
+
+ @Override protected int doHash(F a) {
+ return resultEquivalence.hash(function.apply(a));
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof FunctionalEquivalence) {
+ FunctionalEquivalence<?, ?> that = (FunctionalEquivalence<?, ?>) obj;
+ return function.equals(that.function)
+ && resultEquivalence.equals(that.resultEquivalence);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(function, resultEquivalence);
+ }
+
+ @Override public String toString() {
+ return resultEquivalence + ".onResultOf(" + function + ")";
+ }
+}
diff --git a/guava/src/com/google/common/base/Functions.java b/guava/src/com/google/common/base/Functions.java
new file mode 100644
index 0000000..65fc2c6
--- /dev/null
+++ b/guava/src/com/google/common/base/Functions.java
@@ -0,0 +1,356 @@
+/*
+ * 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.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 java.io.Serializable;
+import java.util.Map;
+
+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>.
+ *
+ * @author Mike Bostock
+ * @author Jared Levy
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public final class Functions {
+ private Functions() {}
+
+ /**
+ * Returns a function that calls {@code toString()} on its argument. The function does not accept
+ * nulls; it will throw a {@link NullPointerException} when applied to {@code null}.
+ *
+ * <p><b>Warning:</b> The returned function may not be <i>consistent with equals</i> (as
+ * documented at {@link Function#apply}). For example, this function yields different results for
+ * the two equal instances {@code ImmutableSet.of(1, 2)} and {@code ImmutableSet.of(2, 1)}.
+ */
+ public static Function<Object, String> toStringFunction() {
+ return ToStringFunction.INSTANCE;
+ }
+
+ // enum singleton pattern
+ private enum ToStringFunction implements Function<Object, String> {
+ INSTANCE;
+
+ @Override
+ public String apply(Object o) {
+ checkNotNull(o); // eager for GWT.
+ return o.toString();
+ }
+
+ @Override public String toString() {
+ return "toString";
+ }
+ }
+
+ /**
+ * Returns the identity function.
+ */
+ @SuppressWarnings("unchecked")
+ public static <E> Function<E, E> identity() {
+ return (Function<E, E>) IdentityFunction.INSTANCE;
+ }
+
+ // enum singleton pattern
+ private enum IdentityFunction implements Function<Object, Object> {
+ INSTANCE;
+
+ @Override
+ public Object apply(Object o) {
+ return o;
+ }
+
+ @Override public String toString() {
+ return "identity";
+ }
+ }
+
+ /**
+ * Returns a function which performs a map lookup. The returned function throws an {@link
+ * IllegalArgumentException} if given a key that does not exist in the map.
+ */
+ public static <K, V> Function<K, V> forMap(Map<K, V> map) {
+ return new FunctionForMapNoDefault<K, V>(map);
+ }
+
+ private static class FunctionForMapNoDefault<K, V> implements Function<K, V>, Serializable {
+ final Map<K, V> map;
+
+ FunctionForMapNoDefault(Map<K, V> map) {
+ this.map = checkNotNull(map);
+ }
+
+ @Override
+ 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;
+ }
+
+ @Override public boolean equals(@Nullable Object o) {
+ if (o instanceof FunctionForMapNoDefault) {
+ FunctionForMapNoDefault<?, ?> that = (FunctionForMapNoDefault<?, ?>) o;
+ return map.equals(that.map);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return map.hashCode();
+ }
+
+ @Override public String toString() {
+ return "forMap(" + map + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a function which performs a map lookup with a default value. The function created by
+ * this method returns {@code defaultValue} for all inputs that do not belong to the map's key
+ * set.
+ *
+ * @param map source map that determines the function behavior
+ * @param defaultValue the value to return for inputs that aren't map keys
+ * @return function that returns {@code map.get(a)} when {@code a} is a key, or {@code
+ * defaultValue} otherwise
+ */
+ public static <K, V> Function<K, V> forMap(Map<K, ? extends V> map, @Nullable V defaultValue) {
+ return new ForMapWithDefault<K, V>(map, defaultValue);
+ }
+
+ private static class ForMapWithDefault<K, V> implements Function<K, V>, Serializable {
+ final Map<K, ? extends V> map;
+ final V defaultValue;
+
+ ForMapWithDefault(Map<K, ? extends V> map, @Nullable V defaultValue) {
+ this.map = checkNotNull(map);
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public V apply(K key) {
+ V result = map.get(key);
+ return (result != null || map.containsKey(key)) ? result : defaultValue;
+ }
+
+ @Override public boolean equals(@Nullable Object o) {
+ if (o instanceof ForMapWithDefault) {
+ ForMapWithDefault<?, ?> that = (ForMapWithDefault<?, ?>) o;
+ return map.equals(that.map) && Objects.equal(defaultValue, that.defaultValue);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(map, defaultValue);
+ }
+
+ @Override public String toString() {
+ return "forMap(" + map + ", defaultValue=" + defaultValue + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns the composition of two functions. For {@code f: A->B} and {@code g: B->C}, composition
+ * is defined as the function h such that {@code h(a) == g(f(a))} for each {@code a}.
+ *
+ * @param g the second function to apply
+ * @param f the first function to apply
+ * @return the composition of {@code f} and {@code g}
+ * @see <a href="//en.wikipedia.org/wiki/Function_composition">function composition</a>
+ */
+ public static <A, B, C> Function<A, C> compose(Function<B, C> g, Function<A, ? extends B> f) {
+ return new FunctionComposition<A, B, C>(g, f);
+ }
+
+ private static class FunctionComposition<A, B, C> implements Function<A, C>, Serializable {
+ private final Function<B, C> g;
+ private final Function<A, ? extends B> f;
+
+ public FunctionComposition(Function<B, C> g, Function<A, ? extends B> f) {
+ this.g = checkNotNull(g);
+ this.f = checkNotNull(f);
+ }
+
+ @Override
+ public C apply(A a) {
+ return g.apply(f.apply(a));
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof FunctionComposition) {
+ FunctionComposition<?, ?, ?> that = (FunctionComposition<?, ?, ?>) obj;
+ return f.equals(that.f) && g.equals(that.g);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return f.hashCode() ^ g.hashCode();
+ }
+
+ @Override public String toString() {
+ return g.toString() + "(" + f.toString() + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Creates a function that returns the same boolean output as the given predicate for all inputs.
+ *
+ * <p>The returned function is <i>consistent with equals</i> (as documented at {@link
+ * Function#apply}) if and only if {@code predicate} is itself consistent with equals.
+ */
+ public static <T> Function<T, Boolean> forPredicate(Predicate<T> predicate) {
+ return new PredicateFunction<T>(predicate);
+ }
+
+ /** @see Functions#forPredicate */
+ private static class PredicateFunction<T> implements Function<T, Boolean>, Serializable {
+ private final Predicate<T> predicate;
+
+ private PredicateFunction(Predicate<T> predicate) {
+ this.predicate = checkNotNull(predicate);
+ }
+
+ @Override
+ public Boolean apply(T t) {
+ return predicate.apply(t);
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof PredicateFunction) {
+ PredicateFunction<?> that = (PredicateFunction<?>) obj;
+ return predicate.equals(that.predicate);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return predicate.hashCode();
+ }
+
+ @Override public String toString() {
+ return "forPredicate(" + predicate + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Creates a function that returns {@code value} for any input.
+ *
+ * @param value the constant value for the function to return
+ * @return a function that always returns {@code value}
+ */
+ public static <E> Function<Object, E> constant(@Nullable E value) {
+ return new ConstantFunction<E>(value);
+ }
+
+ private static class ConstantFunction<E> implements Function<Object, E>, Serializable {
+ private final E value;
+
+ public ConstantFunction(@Nullable E value) {
+ this.value = value;
+ }
+
+ @Override
+ public E apply(@Nullable Object from) {
+ return value;
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof ConstantFunction) {
+ ConstantFunction<?> that = (ConstantFunction<?>) obj;
+ return Objects.equal(value, that.value);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return (value == null) ? 0 : value.hashCode();
+ }
+
+ @Override public String toString() {
+ return "constant(" + value + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a function that always returns the result of invoking {@link Supplier#get} on {@code
+ * supplier}, regardless of its input.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public static <T> Function<Object, T> forSupplier(Supplier<T> supplier) {
+ return new SupplierFunction<T>(supplier);
+ }
+
+ /** @see Functions#forSupplier*/
+ private static class SupplierFunction<T> implements Function<Object, T>, Serializable {
+
+ private final Supplier<T> supplier;
+
+ private SupplierFunction(Supplier<T> supplier) {
+ this.supplier = checkNotNull(supplier);
+ }
+
+ @Override public T apply(@Nullable Object input) {
+ return supplier.get();
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof SupplierFunction) {
+ SupplierFunction<?> that = (SupplierFunction<?>) obj;
+ return this.supplier.equals(that.supplier);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return supplier.hashCode();
+ }
+
+ @Override public String toString() {
+ return "forSupplier(" + supplier + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/guava/src/com/google/common/base/Joiner.java b/guava/src/com/google/common/base/Joiner.java
new file mode 100644
index 0000000..9391550
--- /dev/null
+++ b/guava/src/com/google/common/base/Joiner.java
@@ -0,0 +1,562 @@
+/*
+ * 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.base;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.io.IOException;
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.CheckReturnValue;
+import javax.annotation.Nullable;
+
+/**
+ * An object which joins pieces of text (specified as an array, {@link Iterable}, varargs or even a
+ * {@link Map}) with a separator. It either appends the results to an {@link Appendable} or returns
+ * them as a {@link String}. Example: <pre> {@code
+ *
+ * Joiner joiner = Joiner.on("; ").skipNulls();
+ * . . .
+ * return joiner.join("Harry", null, "Ron", "Hermione");}</pre>
+ *
+ * This returns the string {@code "Harry; Ron; Hermione"}. Note that all input elements are
+ * converted to strings using {@link Object#toString()} before being appended.
+ *
+ * <p>If neither {@link #skipNulls()} nor {@link #useForNull(String)} is specified, the joining
+ * methods will throw {@link NullPointerException} if any given element is null.
+ *
+ * <p><b>Warning: joiner instances are always immutable</b>; a configuration method such as {@code
+ * useForNull} has no effect on the instance it is invoked on! You must store and use the new joiner
+ * instance returned by the method. This makes joiners thread-safe, and safe to store as {@code
+ * static final} constants. <pre> {@code
+ *
+ * // Bad! Do not do this!
+ * Joiner joiner = Joiner.on(',');
+ * 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)
+ */
+@GwtCompatible
+public class Joiner {
+ /**
+ * Returns a joiner which automatically places {@code separator} between consecutive elements.
+ */
+ public static Joiner on(String separator) {
+ return new Joiner(separator);
+ }
+
+ /**
+ * Returns a joiner which automatically places {@code separator} between consecutive elements.
+ */
+ public static Joiner on(char separator) {
+ return new Joiner(String.valueOf(separator));
+ }
+
+ private final String separator;
+
+ private Joiner(String separator) {
+ this.separator = checkNotNull(separator);
+ }
+
+ private Joiner(Joiner prototype) {
+ this.separator = prototype.separator;
+ }
+
+ /**
+ * <b>Deprecated.</b>
+ *
+ * @since 11.0
+ * @deprecated use {@link #appendTo(Appendable, Iterator)} by casting {@code parts} to
+ * {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not
+ * {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b>
+ */
+ @Beta
+ @Deprecated
+ public
+ final <A extends Appendable, I extends Object & Iterable<?> & Iterator<?>> A
+ appendTo(A appendable, I parts) throws IOException {
+ return appendTo(appendable, (Iterator<?>) parts);
+ }
+
+ /**
+ * Appends the string representation of each of {@code parts}, using the previously configured
+ * separator between each, to {@code appendable}.
+ */
+ public <A extends Appendable> A appendTo(A appendable, Iterable<?> parts) throws IOException {
+ return appendTo(appendable, parts.iterator());
+ }
+
+ /**
+ * Appends the string representation of each of {@code parts}, using the previously configured
+ * separator between each, to {@code appendable}.
+ *
+ * @since 11.0
+ */
+ public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {
+ checkNotNull(appendable);
+ if (parts.hasNext()) {
+ appendable.append(toString(parts.next()));
+ while (parts.hasNext()) {
+ appendable.append(separator);
+ appendable.append(toString(parts.next()));
+ }
+ }
+ return appendable;
+ }
+
+ /**
+ * Appends the string representation of each of {@code parts}, using the previously configured
+ * separator between each, to {@code appendable}.
+ */
+ public final <A extends Appendable> A appendTo(A appendable, Object[] parts) throws IOException {
+ return appendTo(appendable, Arrays.asList(parts));
+ }
+
+ /**
+ * Appends to {@code appendable} the string representation of each of the remaining arguments.
+ */
+ public final <A extends Appendable> A appendTo(
+ A appendable, @Nullable Object first, @Nullable Object second, Object... rest)
+ throws IOException {
+ return appendTo(appendable, iterable(first, second, rest));
+ }
+
+ /**
+ * <b>Deprecated.</b>
+ *
+ * @since 11.0
+ * @deprecated use {@link #appendTo(StringBuilder, Iterator)} by casting {@code parts} to
+ * {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not
+ * {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b>
+ */
+ @Beta
+ @Deprecated
+ public
+ final <I extends Object & Iterable<?> & Iterator<?>> StringBuilder
+ appendTo(StringBuilder builder, I parts) {
+ return appendTo(builder, (Iterator<?>) parts);
+ }
+
+ /**
+ * Appends the string representation of each of {@code parts}, using the previously configured
+ * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
+ * Iterable)}, except that it does not throw {@link IOException}.
+ */
+ public final StringBuilder appendTo(StringBuilder builder, Iterable<?> parts) {
+ return appendTo(builder, parts.iterator());
+ }
+
+ /**
+ * Appends the string representation of each of {@code parts}, using the previously configured
+ * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
+ * Iterable)}, except that it does not throw {@link IOException}.
+ *
+ * @since 11.0
+ */
+ public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) {
+ try {
+ appendTo((Appendable) builder, parts);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ return builder;
+ }
+
+ /**
+ * Appends the string representation of each of {@code parts}, using the previously configured
+ * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable,
+ * Iterable)}, except that it does not throw {@link IOException}.
+ */
+ public final StringBuilder appendTo(StringBuilder builder, Object[] parts) {
+ return appendTo(builder, Arrays.asList(parts));
+ }
+
+ /**
+ * Appends to {@code builder} the string representation of each of the remaining arguments.
+ * Identical to {@link #appendTo(Appendable, Object, Object, Object...)}, except that it does not
+ * throw {@link IOException}.
+ */
+ public final StringBuilder appendTo(
+ StringBuilder builder, @Nullable Object first, @Nullable Object second, Object... rest) {
+ return appendTo(builder, iterable(first, second, rest));
+ }
+
+ /**
+ * <b>Deprecated.</b>
+ *
+ * @since 11.0
+ * @deprecated use {@link #join(Iterator)} by casting {@code parts} to
+ * {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not
+ * {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b>
+ */
+ @Beta
+ @Deprecated
+ public
+ final <I extends Object & Iterable<?> & Iterator<?>> String join(I parts) {
+ return join((Iterator<?>) parts);
+ }
+
+ /**
+ * Returns a string containing the string representation of each of {@code parts}, using the
+ * previously configured separator between each.
+ */
+ public final String join(Iterable<?> parts) {
+ return join(parts.iterator());
+ }
+
+ /**
+ * Returns a string containing the string representation of each of {@code parts}, using the
+ * previously configured separator between each.
+ *
+ * @since 11.0
+ */
+ public final String join(Iterator<?> parts) {
+ return appendTo(new StringBuilder(), parts).toString();
+ }
+
+ /**
+ * Returns a string containing the string representation of each of {@code parts}, using the
+ * previously configured separator between each.
+ */
+ public final String join(Object[] parts) {
+ return join(Arrays.asList(parts));
+ }
+
+ /**
+ * Returns a string containing the string representation of each argument, using the previously
+ * configured separator between each.
+ */
+ public final String join(@Nullable Object first, @Nullable Object second, Object... rest) {
+ return join(iterable(first, second, rest));
+ }
+
+ /**
+ * Returns a joiner with the same behavior as this one, except automatically substituting {@code
+ * nullText} for any provided null elements.
+ */
+ @CheckReturnValue
+ public Joiner useForNull(final String nullText) {
+ checkNotNull(nullText);
+ return new Joiner(this) {
+ @Override CharSequence toString(Object part) {
+ return (part == null) ? nullText : Joiner.this.toString(part);
+ }
+
+ @Override public Joiner useForNull(String nullText) {
+ checkNotNull(nullText); // weird: just to satisfy NullPointerTester.
+ throw new UnsupportedOperationException("already specified useForNull");
+ }
+
+ @Override public Joiner skipNulls() {
+ throw new UnsupportedOperationException("already specified useForNull");
+ }
+ };
+ }
+
+ /**
+ * Returns a joiner with the same behavior as this joiner, except automatically skipping over any
+ * provided null elements.
+ */
+ @CheckReturnValue
+ public Joiner skipNulls() {
+ return new Joiner(this) {
+ @Override public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts)
+ throws IOException {
+ checkNotNull(appendable, "appendable");
+ checkNotNull(parts, "parts");
+ while (parts.hasNext()) {
+ Object part = parts.next();
+ if (part != null) {
+ appendable.append(Joiner.this.toString(part));
+ break;
+ }
+ }
+ while (parts.hasNext()) {
+ Object part = parts.next();
+ if (part != null) {
+ appendable.append(separator);
+ appendable.append(Joiner.this.toString(part));
+ }
+ }
+ return appendable;
+ }
+
+ @Override public Joiner useForNull(String nullText) {
+ checkNotNull(nullText); // weird: just to satisfy NullPointerTester.
+ throw new UnsupportedOperationException("already specified skipNulls");
+ }
+
+ @Override public MapJoiner withKeyValueSeparator(String kvs) {
+ checkNotNull(kvs); // weird: just to satisfy NullPointerTester.
+ throw new UnsupportedOperationException("can't use .skipNulls() with maps");
+ }
+ };
+ }
+
+ /**
+ * Returns a {@code MapJoiner} using the given key-value separator, and the same configuration as
+ * this {@code Joiner} otherwise.
+ */
+ @CheckReturnValue
+ public MapJoiner withKeyValueSeparator(String keyValueSeparator) {
+ return new MapJoiner(this, keyValueSeparator);
+ }
+
+ /**
+ * An object that joins map entries in the same manner as {@code Joiner} joins iterables and
+ * arrays. Like {@code Joiner}, it is thread-safe and immutable.
+ *
+ * <p>In addition to operating on {@code Map} instances, {@code MapJoiner} can operate on {@code
+ * Multimap} entries in two distinct modes:
+ *
+ * <ul>
+ * <li>To output a separate entry for each key-value pair, pass {@code multimap.entries()} to a
+ * {@code MapJoiner} method that accepts entries as input, and receive output of the form
+ * {@code key1=A&key1=B&key2=C}.
+ * <li>To output a single entry for each key, pass {@code multimap.asMap()} to a {@code MapJoiner}
+ * method that accepts a map as input, and receive output of the form {@code
+ * key1=[A, B]&key2=C}.
+ * </ul>
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public final static class MapJoiner {
+ private final Joiner joiner;
+ private final String keyValueSeparator;
+
+ private MapJoiner(Joiner joiner, String keyValueSeparator) {
+ this.joiner = joiner; // only "this" is ever passed, so don't checkNotNull
+ this.keyValueSeparator = checkNotNull(keyValueSeparator);
+ }
+
+ /**
+ * Appends the string representation of each entry of {@code map}, using the previously
+ * configured separator and key-value separator, to {@code appendable}.
+ */
+ public <A extends Appendable> A appendTo(A appendable, Map<?, ?> map) throws IOException {
+ return appendTo(appendable, map.entrySet());
+ }
+
+ /**
+ * Appends the string representation of each entry of {@code map}, using the previously
+ * configured separator and key-value separator, to {@code builder}. Identical to {@link
+ * #appendTo(Appendable, Map)}, except that it does not throw {@link IOException}.
+ */
+ public StringBuilder appendTo(StringBuilder builder, Map<?, ?> map) {
+ return appendTo(builder, map.entrySet());
+ }
+
+ /**
+ * Returns a string containing the string representation of each entry of {@code map}, using the
+ * previously configured separator and key-value separator.
+ */
+ public String join(Map<?, ?> map) {
+ return join(map.entrySet());
+ }
+
+ /**
+ * <b>Deprecated.</b>
+ *
+ * @since 11.0
+ * @deprecated use {@link #appendTo(Appendable, Iterator)} by casting {@code entries} to
+ * {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only
+ * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion
+ * in June 2013.</b>
+ */
+ @Beta
+ @Deprecated
+ 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;
+ return appendTo(appendable, iterator);
+ }
+
+ /**
+ * Appends the string representation of each entry in {@code entries}, using the previously
+ * configured separator and key-value separator, to {@code appendable}.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public <A extends Appendable> A appendTo(A appendable, Iterable<? extends Entry<?, ?>> entries)
+ throws IOException {
+ return appendTo(appendable, entries.iterator());
+ }
+
+ /**
+ * Appends the string representation of each entry in {@code entries}, using the previously
+ * configured separator and key-value separator, to {@code appendable}.
+ *
+ * @since 11.0
+ */
+ @Beta
+ public <A extends Appendable> A appendTo(A appendable, Iterator<? extends Entry<?, ?>> parts)
+ throws IOException {
+ checkNotNull(appendable);
+ if (parts.hasNext()) {
+ Entry<?, ?> entry = parts.next();
+ appendable.append(joiner.toString(entry.getKey()));
+ appendable.append(keyValueSeparator);
+ appendable.append(joiner.toString(entry.getValue()));
+ while (parts.hasNext()) {
+ appendable.append(joiner.separator);
+ Entry<?, ?> e = parts.next();
+ appendable.append(joiner.toString(e.getKey()));
+ appendable.append(keyValueSeparator);
+ appendable.append(joiner.toString(e.getValue()));
+ }
+ }
+ return appendable;
+ }
+
+ /**
+ * <b>Deprecated.</b>
+ *
+ * @since 11.0
+ * @deprecated use {@link #appendTo(StringBuilder, Iterator)} by casting {@code entries} to
+ * {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only
+ * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion
+ * in June 2013.</b>
+ */
+ @Beta
+ @Deprecated
+ 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);
+ }
+
+ /**
+ * Appends the string representation of each entry in {@code entries}, using the previously
+ * configured separator and key-value separator, to {@code builder}. Identical to {@link
+ * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public StringBuilder appendTo(StringBuilder builder, Iterable<? extends Entry<?, ?>> entries) {
+ return appendTo(builder, entries.iterator());
+ }
+
+ /**
+ * Appends the string representation of each entry in {@code entries}, using the previously
+ * configured separator and key-value separator, to {@code builder}. Identical to {@link
+ * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}.
+ *
+ * @since 11.0
+ */
+ @Beta
+ public StringBuilder appendTo(StringBuilder builder, Iterator<? extends Entry<?, ?>> entries) {
+ try {
+ appendTo((Appendable) builder, entries);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ return builder;
+ }
+
+ /**
+ * <b>Deprecated.</b>
+ *
+ * @since 11.0
+ * @deprecated use {@link #join(Iterator)} by casting {@code entries} to
+ * {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only
+ * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion
+ * in June 2013.</b>
+ */
+ @Beta
+ @Deprecated
+ public
+ <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>>
+ String join(I entries) throws IOException {
+ Iterator<? extends Entry<?, ?>> iterator = entries;
+ return join(iterator);
+ }
+
+ /**
+ * Returns a string containing the string representation of each entry in {@code entries}, using
+ * the previously configured separator and key-value separator.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public String join(Iterable<? extends Entry<?, ?>> entries) {
+ return join(entries.iterator());
+ }
+
+ /**
+ * Returns a string containing the string representation of each entry in {@code entries}, using
+ * the previously configured separator and key-value separator.
+ *
+ * @since 11.0
+ */
+ @Beta
+ public String join(Iterator<? extends Entry<?, ?>> entries) {
+ return appendTo(new StringBuilder(), entries).toString();
+ }
+
+ /**
+ * Returns a map joiner with the same behavior as this one, except automatically substituting
+ * {@code nullText} for any provided null keys or values.
+ */
+ @CheckReturnValue
+ public MapJoiner useForNull(String nullText) {
+ return new MapJoiner(joiner.useForNull(nullText), keyValueSeparator);
+ }
+ }
+
+ CharSequence toString(Object part) {
+ checkNotNull(part); // checkNotNull for GWT (do not optimize).
+ return (part instanceof CharSequence) ? (CharSequence) part : part.toString();
+ }
+
+ private static Iterable<Object> iterable(
+ final Object first, final Object second, final Object[] rest) {
+ checkNotNull(rest);
+ return new AbstractList<Object>() {
+ @Override public int size() {
+ return rest.length + 2;
+ }
+
+ @Override public Object get(int index) {
+ switch (index) {
+ case 0:
+ return first;
+ case 1:
+ return second;
+ default:
+ return rest[index - 2];
+ }
+ }
+ };
+ }
+}
diff --git a/guava/src/com/google/common/base/MediumCharMatcher.java b/guava/src/com/google/common/base/MediumCharMatcher.java
new file mode 100644
index 0000000..f55ad5d
--- /dev/null
+++ b/guava/src/com/google/common/base/MediumCharMatcher.java
@@ -0,0 +1,133 @@
+/*
+ * 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.GwtCompatible;
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * An immutable version of CharMatcher for medium-sized sets of characters that uses a hash table
+ * with linear probing to check for matches.
+ *
+ * @author Christopher Swenson
+ */
+@GwtCompatible
+final class MediumCharMatcher extends CharMatcher {
+ static final int MAX_SIZE = 1023;
+ private final char[] table;
+ private final boolean containsZero;
+ private final long filter;
+
+ private MediumCharMatcher(char[] table, long filter, boolean containsZero,
+ String description) {
+ super(description);
+ this.table = table;
+ this.filter = filter;
+ this.containsZero = containsZero;
+ }
+
+ 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;
+ }
+
+ // This method is thread-safe, since if any two threads execute it simultaneously, all
+ // that will happen is that they compute the same data structure twice, but nothing will ever
+ // be incorrect.
+ @Override
+ public CharMatcher precomputed() {
+ return this;
+ }
+
+ static CharMatcher from(char[] chars, String description) {
+ // Compute the filter.
+ long filter = 0;
+ int size = chars.length;
+ boolean containsZero = (chars[0] == 0);
+ // Compute the filter.
+ for (char c : chars) {
+ filter |= 1L << c;
+ }
+ // Compute the hash table.
+ char[] table = new char[chooseTableSize(size)];
+ int mask = table.length - 1;
+ for (char c : chars) {
+ int index = c & mask;
+ while (true) {
+ // Check for empty.
+ if (table[index] == 0) {
+ table[index] = c;
+ break;
+ }
+ // Linear probing.
+ index = (index + 1) & mask;
+ }
+ }
+ return new MediumCharMatcher(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 = 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;
+ }
+}
diff --git a/guava/src/com/google/common/base/Objects.java b/guava/src/com/google/common/base/Objects.java
new file mode 100644
index 0000000..e1c79a3
--- /dev/null
+++ b/guava/src/com/google/common/base/Objects.java
@@ -0,0 +1,440 @@
+/*
+ * 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.base;
+
+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.LinkedList;
+import java.util.List;
+
+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)
+ */
+@GwtCompatible
+public final class Objects {
+ private Objects() {}
+
+ /**
+ * Determines whether two possibly-null objects are equal. Returns:
+ *
+ * <ul>
+ * <li>{@code true} if {@code a} and {@code b} are both null.
+ * <li>{@code true} if {@code a} and {@code b} are both non-null and they are
+ * equal according to {@link Object#equals(Object)}.
+ * <li>{@code false} in all other situations.
+ * </ul>
+ *
+ * <p>This assumes that any non-null objects passed to this function conform
+ * to the {@code equals()} contract.
+ */
+ public static boolean equal(@Nullable Object a, @Nullable Object b) {
+ return a == b || (a != null && a.equals(b));
+ }
+
+ /**
+ * Generates a hash code for multiple values. The hash code is generated by
+ * calling {@link Arrays#hashCode(Object[])}.
+ *
+ * <p>This is useful for implementing {@link Object#hashCode()}. For example,
+ * in an object that has three properties, {@code x}, {@code y}, and
+ * {@code z}, one could write:
+ * <pre>
+ * public int hashCode() {
+ * return Objects.hashCode(getX(), getY(), getZ());
+ * }</pre>
+ *
+ * <b>Warning</b>: When a single object is supplied, the returned hash code
+ * does not equal the hash code of that object.
+ */
+ public static int hashCode(@Nullable Object... objects) {
+ return Arrays.hashCode(objects);
+ }
+
+ /**
+ * Creates an instance of {@link ToStringHelper}.
+ *
+ * <p>This is helpful for implementing {@link Object#toString()}.
+ * Specification by example: <pre> {@code
+ * // Returns "ClassName{}"
+ * Objects.toStringHelper(this)
+ * .toString();
+ *
+ * // Returns "ClassName{x=1}"
+ * Objects.toStringHelper(this)
+ * .add("x", 1)
+ * .toString();
+ *
+ * // Returns "MyObject{x=1}"
+ * Objects.toStringHelper("MyObject")
+ * .add("x", 1)
+ * .toString();
+ *
+ * // Returns "ClassName{x=1, y=foo}"
+ * Objects.toStringHelper(this)
+ * .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.
+ *
+ * @param self the object to generate the string for (typically {@code this}),
+ * used only for its class name
+ * @since 2.0
+ */
+ public static ToStringHelper toStringHelper(Object self) {
+ return new ToStringHelper(simpleName(self.getClass()));
+ }
+
+ /**
+ * Creates an instance of {@link ToStringHelper} in the same manner as
+ * {@link Objects#toStringHelper(Object)}, but using the name of {@code clazz}
+ * instead of using an instance's {@link Object#getClass()}.
+ *
+ * <p>Note that in GWT, class names are often obfuscated.
+ *
+ * @param clazz the {@link Class} of the instance
+ * @since 7.0 (source-compatible since 2.0)
+ */
+ public static ToStringHelper toStringHelper(Class<?> clazz) {
+ return new ToStringHelper(simpleName(clazz));
+ }
+
+ /**
+ * Creates an instance of {@link ToStringHelper} in the same manner as
+ * {@link Objects#toStringHelper(Object)}, but using {@code className} instead
+ * of using an instance's {@link Object#getClass()}.
+ *
+ * @param className the name of the instance type
+ * @since 7.0 (source-compatible since 2.0)
+ */
+ public static ToStringHelper toStringHelper(String className) {
+ return new ToStringHelper(className);
+ }
+
+ /**
+ * {@link Class#getSimpleName()} is not GWT compatible yet, so we
+ * provide our own implementation.
+ */
+ private static String simpleName(Class<?> clazz) {
+ String name = clazz.getName();
+
+ // the nth anonymous class has a class name ending in "Outer$n"
+ // and local inner classes have names ending in "Outer.$1Inner"
+ name = name.replaceAll("\\$[0-9]+", "\\$");
+
+ // we want the name of the inner class all by its lonesome
+ int start = name.lastIndexOf('$');
+
+ // if this isn't an inner class, just find the start of the
+ // top level class name.
+ if (start == -1) {
+ start = name.lastIndexOf('.');
+ }
+ return name.substring(start + 1);
+ }
+
+ /**
+ * Returns the first of two given parameters that is not {@code null}, if
+ * either is, or otherwise throws a {@link NullPointerException}.
+ *
+ * <p><b>Note:</b> if {@code first} is represented as an {@code Optional<T>},
+ * this can be accomplished with {@code first.or(second)}. That approach also
+ * allows for lazy evaluation of the fallback instance, using
+ * {@code first.or(Supplier)}.
+ *
+ * @return {@code first} if {@code first} is not {@code null}, or
+ * {@code second} if {@code first} is {@code null} and {@code second} is
+ * not {@code null}
+ * @throws NullPointerException if both {@code first} and {@code second} were
+ * {@code null}
+ * @since 3.0
+ */
+ public static <T> T firstNonNull(@Nullable T first, @Nullable T second) {
+ return first != null ? first : checkNotNull(second);
+ }
+
+ /**
+ * Support class for {@link Objects#toStringHelper}.
+ *
+ * @author Jason Lee
+ * @since 2.0
+ */
+ public static final class ToStringHelper {
+ private final String className;
+ private final List<ValueHolder> valueHolders =
+ new LinkedList<ValueHolder>();
+ private boolean omitNullValues = false;
+
+ /**
+ * Use {@link Objects#toStringHelper(Object)} to create an instance.
+ */
+ private ToStringHelper(String className) {
+ this.className = checkNotNull(className);
+ }
+
+ /**
+ * When called, the formatted output returned by {@link #toString()} will
+ * ignore {@code null} values.
+ *
+ * @since 12.0
+ */
+ @Beta
+ public ToStringHelper omitNullValues() {
+ omitNullValues = true;
+ return this;
+ }
+
+ /**
+ * 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.
+ */
+ public ToStringHelper add(String name, @Nullable Object value) {
+ checkNotNull(name);
+ addHolder(value).builder.append(name).append('=').append(value);
+ return this;
+ }
+
+ /**
+ * Adds a name/value pair to the formatted output in {@code name=value}
+ * format.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper add(String name, boolean value) {
+ checkNameAndAppend(name).append(value);
+ return this;
+ }
+
+ /**
+ * Adds a name/value pair to the formatted output in {@code name=value}
+ * format.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper add(String name, char value) {
+ checkNameAndAppend(name).append(value);
+ return this;
+ }
+
+ /**
+ * Adds a name/value pair to the formatted output in {@code name=value}
+ * format.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper add(String name, double value) {
+ checkNameAndAppend(name).append(value);
+ return this;
+ }
+
+ /**
+ * Adds a name/value pair to the formatted output in {@code name=value}
+ * format.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper add(String name, float value) {
+ checkNameAndAppend(name).append(value);
+ return this;
+ }
+
+ /**
+ * Adds a name/value pair to the formatted output in {@code name=value}
+ * format.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper add(String name, int value) {
+ checkNameAndAppend(name).append(value);
+ return this;
+ }
+
+ /**
+ * Adds a name/value pair to the formatted output in {@code name=value}
+ * format.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper add(String name, long value) {
+ checkNameAndAppend(name).append(value);
+ return this;
+ }
+
+ private StringBuilder checkNameAndAppend(String name) {
+ checkNotNull(name);
+ return addHolder().builder.append(name).append('=');
+ }
+
+ /**
+ * Adds an unnamed value to the formatted output.
+ *
+ * <p>It is strongly encouraged to use {@link #add(String, Object)} instead
+ * and give value a readable name.
+ */
+ public ToStringHelper addValue(@Nullable Object value) {
+ addHolder(value).builder.append(value);
+ return this;
+ }
+
+ /**
+ * Adds an unnamed value to the formatted output.
+ *
+ * <p>It is strongly encouraged to use {@link #add(String, boolean)} instead
+ * and give value a readable name.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper addValue(boolean value) {
+ addHolder().builder.append(value);
+ return this;
+ }
+
+ /**
+ * Adds an unnamed value to the formatted output.
+ *
+ * <p>It is strongly encouraged to use {@link #add(String, char)} instead
+ * and give value a readable name.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper addValue(char value) {
+ addHolder().builder.append(value);
+ return this;
+ }
+
+ /**
+ * Adds an unnamed value to the formatted output.
+ *
+ * <p>It is strongly encouraged to use {@link #add(String, double)} instead
+ * and give value a readable name.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper addValue(double value) {
+ addHolder().builder.append(value);
+ return this;
+ }
+
+ /**
+ * Adds an unnamed value to the formatted output.
+ *
+ * <p>It is strongly encouraged to use {@link #add(String, float)} instead
+ * and give value a readable name.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper addValue(float value) {
+ addHolder().builder.append(value);
+ return this;
+ }
+
+ /**
+ * Adds an unnamed value to the formatted output.
+ *
+ * <p>It is strongly encouraged to use {@link #add(String, int)} instead
+ * and give value a readable name.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper addValue(int value) {
+ addHolder().builder.append(value);
+ return this;
+ }
+
+ /**
+ * Adds an unnamed value to the formatted output.
+ *
+ * <p>It is strongly encouraged to use {@link #add(String, long)} instead
+ * and give value a readable name.
+ *
+ * @since 11.0 (source-compatible since 2.0)
+ */
+ public ToStringHelper addValue(long value) {
+ addHolder().builder.append(value);
+ return this;
+ }
+
+ /**
+ * Returns a string in the format specified by {@link
+ * Objects#toStringHelper(Object)}.
+ */
+ @Override public String toString() {
+ // create a copy to keep it consistent in case value changes
+ boolean omitNullValuesSnapshot = omitNullValues;
+ boolean needsSeparator = false;
+ StringBuilder builder = new StringBuilder(32).append(className)
+ .append('{');
+ for (ValueHolder valueHolder : valueHolders) {
+ if (!omitNullValuesSnapshot || !valueHolder.isNull) {
+ if (needsSeparator) {
+ builder.append(", ");
+ } else {
+ needsSeparator = true;
+ }
+ // must explicitly cast it, otherwise GWT tests might fail because
+ // it tries to access StringBuilder.append(StringBuilder), which is
+ // a private method
+ // TODO(user): change once 5904010 is fixed
+ CharSequence sequence = valueHolder.builder;
+ builder.append(sequence);
+ }
+ }
+ return builder.append('}').toString();
+ }
+
+ private ValueHolder addHolder() {
+ ValueHolder valueHolder = new ValueHolder();
+ valueHolders.add(valueHolder);
+ return valueHolder;
+ }
+
+ private ValueHolder addHolder(@Nullable Object value) {
+ ValueHolder valueHolder = addHolder();
+ valueHolder.isNull = (value == null);
+ return valueHolder;
+ }
+
+ private static final class ValueHolder {
+ final StringBuilder builder = new StringBuilder();
+ boolean isNull;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/base/Optional.java b/guava/src/com/google/common/base/Optional.java
new file mode 100644
index 0000000..8cd7cda
--- /dev/null
+++ b/guava/src/com/google/common/base/Optional.java
@@ -0,0 +1,245 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable object that may contain a non-null reference to another object. Each
+ * instance of this type either contains a non-null reference, or contains nothing (in
+ * which case we say that the reference is "absent"); it is never said to "contain {@code
+ * null}".
+ *
+ * <p>A non-null {@code Optional<T>} reference can be used as a replacement for a nullable
+ * {@code T} reference. It allows you to represent "a {@code T} that must be present" and
+ * a "a {@code T} that might be absent" as two distinct types in your program, which can
+ * aid clarity.
+ *
+ * <p>Some uses of this class include
+ *
+ * <ul>
+ * <li>As a method return type, as an alternative to returning {@code null} to indicate
+ * that no value was available
+ * <li>To distinguish between "unknown" (for example, not present in a map) and "known to
+ * have no value" (present in the map, with value {@code Optional.absent()})
+ * <li>To wrap nullable references for storage in a collection that does not support
+ * {@code null} (though there are
+ * <a href="http://code.google.com/p/guava-libraries/wiki/LivingWithNullHostileCollections">
+ * several other approaches to this</a> that should be considered first)
+ * </ul>
+ *
+ * <p>A common alternative to using this class is to find or create a suitable
+ * <a href="http://en.wikipedia.org/wiki/Null_Object_pattern">null object</a> for the
+ * type in question.
+ *
+ * <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}.
+ * @author Kurt Alfred Kluever
+ * @author Kevin Bourrillion
+ * @since 10.0
+ */
+@GwtCompatible(serializable = true)
+public abstract class Optional<T> implements Serializable {
+ /**
+ * Returns an {@code Optional} instance with no contained reference.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Optional<T> absent() {
+ return (Optional<T>) Absent.INSTANCE;
+ }
+
+ /**
+ * Returns an {@code Optional} instance containing the given non-null reference.
+ */
+ public static <T> Optional<T> of(T reference) {
+ return new Present<T>(checkNotNull(reference));
+ }
+
+ /**
+ * If {@code nullableReference} is non-null, returns an {@code Optional} instance containing that
+ * reference; otherwise returns {@link Optional#absent}.
+ */
+ public static <T> Optional<T> fromNullable(@Nullable T nullableReference) {
+ return (nullableReference == null)
+ ? Optional.<T>absent()
+ : new Present<T>(nullableReference);
+ }
+
+ Optional() {}
+
+ /**
+ * Returns {@code true} if this holder contains a (non-null) instance.
+ */
+ public abstract boolean isPresent();
+
+ /**
+ * Returns the contained instance, which must be present. If the instance might be
+ * absent, use {@link #or(Object)} or {@link #orNull} instead.
+ *
+ * @throws IllegalStateException if the instance is absent ({@link #isPresent} returns
+ * {@code false})
+ */
+ public abstract T get();
+
+ /**
+ * 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);
+
+ /**
+ * Returns this {@code Optional} if it has a value present; {@code secondChoice}
+ * otherwise.
+ */
+ @Beta
+ public abstract Optional<T> or(Optional<? extends T> secondChoice);
+
+ /**
+ * Returns the contained instance if it is present; {@code supplier.get()} otherwise. If the
+ * supplier returns {@code null}, a {@link NullPointerException} is 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();
+
+ /**
+ * 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
+ */
+ @Beta
+ 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);
+
+ /**
+ * Returns a hash code for this instance.
+ */
+ @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();
+
+ /**
+ * 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)
+ */
+ @Beta
+ public static <T> Iterable<T> presentInstances(
+ final Iterable<? extends Optional<? extends T>> optionals) {
+ checkNotNull(optionals);
+ return new Iterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return new AbstractIterator<T>() {
+ private final Iterator<? extends Optional<? extends T>> iterator =
+ checkNotNull(optionals.iterator());
+
+ @Override
+ protected T computeNext() {
+ while (iterator.hasNext()) {
+ Optional<? extends T> optional = iterator.next();
+ if (optional.isPresent()) {
+ return optional.get();
+ }
+ }
+ return endOfData();
+ }
+ };
+ };
+ };
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/base/PairwiseEquivalence.java b/guava/src/com/google/common/base/PairwiseEquivalence.java
new file mode 100644
index 0000000..23ab539
--- /dev/null
+++ b/guava/src/com/google/common/base/PairwiseEquivalence.java
@@ -0,0 +1,80 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import javax.annotation.Nullable;
+
+@GwtCompatible(serializable = true)
+final class PairwiseEquivalence<T> extends Equivalence<Iterable<T>>
+ implements Serializable {
+
+ final Equivalence<? super T> elementEquivalence;
+
+ PairwiseEquivalence(Equivalence<? super T> elementEquivalence) {
+ this.elementEquivalence = Preconditions.checkNotNull(elementEquivalence);
+ }
+
+ @Override
+ protected boolean doEquivalent(Iterable<T> iterableA, Iterable<T> iterableB) {
+ Iterator<T> iteratorA = iterableA.iterator();
+ Iterator<T> iteratorB = iterableB.iterator();
+
+ while (iteratorA.hasNext() && iteratorB.hasNext()) {
+ if (!elementEquivalence.equivalent(iteratorA.next(), iteratorB.next())) {
+ return false;
+ }
+ }
+
+ return !iteratorA.hasNext() && !iteratorB.hasNext();
+ }
+
+ @Override
+ protected int doHash(Iterable<T> iterable) {
+ int hash = 78721;
+ for (T element : iterable) {
+ hash = hash * 24943 + elementEquivalence.hash(element);
+ }
+ return hash;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object instanceof PairwiseEquivalence) {
+ PairwiseEquivalence<?> that = (PairwiseEquivalence<?>) object;
+ return this.elementEquivalence.equals(that.elementEquivalence);
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return elementEquivalence.hashCode() ^ 0x46a3eb07;
+ }
+
+ @Override
+ public String toString() {
+ return elementEquivalence + ".pairwise()";
+ }
+
+ private static final long serialVersionUID = 1;
+}
diff --git a/guava/src/com/google/common/base/Platform.java b/guava/src/com/google/common/base/Platform.java
new file mode 100644
index 0000000..dcbe06c
--- /dev/null
+++ b/guava/src/com/google/common/base/Platform.java
@@ -0,0 +1,55 @@
+/*
+ * 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.base;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * Methods factored out so that they can be emulated differently in GWT.
+ *
+ * @author Jesse Wilson
+ */
+@GwtCompatible(emulated = true)
+final class Platform {
+ private Platform() {}
+
+ /** Returns a thread-local 1024-char array. */
+ static char[] charBufferFromThreadLocal() {
+ return DEST_TL.get();
+ }
+
+ /** Calls {@link System#nanoTime()}. */
+ static long systemNanoTime() {
+ return System.nanoTime();
+ }
+
+ /**
+ * A thread-local destination buffer to keep us from creating new buffers.
+ * The starting size is 1024 characters. If we grow past this we don't
+ * put it back in the threadlocal, we just keep going and grow as needed.
+ */
+ private static final ThreadLocal<char[]> DEST_TL = new ThreadLocal<char[]>() {
+ @Override
+ protected char[] initialValue() {
+ return new char[1024];
+ }
+ };
+
+ static CharMatcher precomputeCharMatcher(CharMatcher matcher) {
+ return matcher.precomputedInternal();
+ }
+}
diff --git a/guava/src/com/google/common/base/Preconditions.java b/guava/src/com/google/common/base/Preconditions.java
new file mode 100644
index 0000000..802a309
--- /dev/null
+++ b/guava/src/com/google/common/base/Preconditions.java
@@ -0,0 +1,449 @@
+/*
+ * 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.base;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.util.NoSuchElementException;
+
+import javax.annotation.Nullable;
+
+/**
+ * Simple static methods to be called at the start of your own methods to verify
+ * correct arguments and state. This allows constructs such as
+ * <pre>
+ * if (count <= 0) {
+ * throw new IllegalArgumentException("must be positive: " + count);
+ * }</pre>
+ *
+ * to be replaced with the more compact
+ * <pre>
+ * checkArgument(count > 0, "must be positive: %s", count);</pre>
+ *
+ * Note that the sense of the expression is inverted; with {@code Preconditions}
+ * you declare what you expect to be <i>true</i>, just as you do with an
+ * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html">
+ * {@code assert}</a> or a JUnit {@code assertTrue} call.
+ *
+ * <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a
+ * placeholder in these messages, not the full range of {@link
+ * String#format(String, Object[])} specifiers.
+ *
+ * <p>Take care not to confuse precondition checking with other similar types
+ * of checks! Precondition exceptions -- including those provided here, but also
+ * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link
+ * UnsupportedOperationException} and others -- are used to signal that the
+ * <i>calling method</i> has made an error. This tells the caller that it should
+ * not have invoked the method when it did, with the arguments it did, or
+ * 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)
+ */
+@GwtCompatible
+public final class Preconditions {
+ private Preconditions() {}
+
+ /**
+ * Ensures the truth of an expression involving one or more parameters to the
+ * calling method.
+ *
+ * @param expression a boolean expression
+ * @throws IllegalArgumentException if {@code expression} is false
+ */
+ public static void checkArgument(boolean expression) {
+ if (!expression) {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Ensures the truth of an expression involving one or more parameters to the
+ * calling method.
+ *
+ * @param expression a boolean expression
+ * @param errorMessage the exception message to use if the check fails; will
+ * be converted to a string using {@link String#valueOf(Object)}
+ * @throws IllegalArgumentException if {@code expression} is false
+ */
+ public static void checkArgument(
+ boolean expression, @Nullable Object errorMessage) {
+ if (!expression) {
+ throw new IllegalArgumentException(String.valueOf(errorMessage));
+ }
+ }
+
+ /**
+ * Ensures the truth of an expression involving one or more parameters to the
+ * calling method.
+ *
+ * @param expression a boolean expression
+ * @param errorMessageTemplate a template for the exception message should the
+ * check fail. The message is formed by replacing each {@code %s}
+ * placeholder in the template with an argument. These are matched by
+ * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
+ * Unmatched arguments will be appended to the formatted message in square
+ * braces. Unmatched placeholders will be left as-is.
+ * @param errorMessageArgs the arguments to be substituted into the message
+ * template. Arguments are converted to strings using
+ * {@link String#valueOf(Object)}.
+ * @throws IllegalArgumentException if {@code expression} is false
+ * @throws NullPointerException if the check fails and either {@code
+ * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
+ * this happen)
+ */
+ public static void checkArgument(boolean expression,
+ @Nullable String errorMessageTemplate,
+ @Nullable Object... errorMessageArgs) {
+ if (!expression) {
+ throw new IllegalArgumentException(
+ format(errorMessageTemplate, errorMessageArgs));
+ }
+ }
+
+ /**
+ * Ensures the truth of an expression involving the state of the calling
+ * instance, but not involving any parameters to the calling method.
+ *
+ * @param expression a boolean expression
+ * @throws IllegalStateException if {@code expression} is false
+ */
+ public static void checkState(boolean expression) {
+ if (!expression) {
+ throw new IllegalStateException();
+ }
+ }
+
+ /**
+ * Ensures the truth of an expression involving the state of the calling
+ * instance, but not involving any parameters to the calling method.
+ *
+ * @param expression a boolean expression
+ * @param errorMessage the exception message to use if the check fails; will
+ * be converted to a string using {@link String#valueOf(Object)}
+ * @throws IllegalStateException if {@code expression} is false
+ */
+ public static void checkState(
+ boolean expression, @Nullable Object errorMessage) {
+ if (!expression) {
+ throw new IllegalStateException(String.valueOf(errorMessage));
+ }
+ }
+
+ /**
+ * Ensures the truth of an expression involving the state of the calling
+ * instance, but not involving any parameters to the calling method.
+ *
+ * @param expression a boolean expression
+ * @param errorMessageTemplate a template for the exception message should the
+ * check fail. The message is formed by replacing each {@code %s}
+ * placeholder in the template with an argument. These are matched by
+ * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
+ * Unmatched arguments will be appended to the formatted message in square
+ * braces. Unmatched placeholders will be left as-is.
+ * @param errorMessageArgs the arguments to be substituted into the message
+ * template. Arguments are converted to strings using
+ * {@link String#valueOf(Object)}.
+ * @throws IllegalStateException if {@code expression} is false
+ * @throws NullPointerException if the check fails and either {@code
+ * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let
+ * this happen)
+ */
+ public static void checkState(boolean expression,
+ @Nullable String errorMessageTemplate,
+ @Nullable Object... errorMessageArgs) {
+ if (!expression) {
+ throw new IllegalStateException(
+ format(errorMessageTemplate, errorMessageArgs));
+ }
+ }
+
+ /**
+ * Ensures that an object reference passed as a parameter to the calling
+ * method is not null.
+ *
+ * @param reference an object reference
+ * @return the non-null reference that was validated
+ * @throws NullPointerException if {@code reference} is null
+ */
+ public static <T> T checkNotNull(T reference) {
+ if (reference == null) {
+ throw new NullPointerException();
+ }
+ return reference;
+ }
+
+ /**
+ * Ensures that an object reference passed as a parameter to the calling
+ * method is not null.
+ *
+ * @param reference an object reference
+ * @param errorMessage the exception message to use if the check fails; will
+ * be converted to a string using {@link String#valueOf(Object)}
+ * @return the non-null reference that was validated
+ * @throws NullPointerException if {@code reference} is null
+ */
+ public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
+ if (reference == null) {
+ throw new NullPointerException(String.valueOf(errorMessage));
+ }
+ return reference;
+ }
+
+ /**
+ * Ensures that an object reference passed as a parameter to the calling
+ * method is not null.
+ *
+ * @param reference an object reference
+ * @param errorMessageTemplate a template for the exception message should the
+ * check fail. The message is formed by replacing each {@code %s}
+ * placeholder in the template with an argument. These are matched by
+ * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc.
+ * Unmatched arguments will be appended to the formatted message in square
+ * braces. Unmatched placeholders will be left as-is.
+ * @param errorMessageArgs the arguments to be substituted into the message
+ * template. Arguments are converted to strings using
+ * {@link String#valueOf(Object)}.
+ * @return the non-null reference that was validated
+ * @throws NullPointerException if {@code reference} is null
+ */
+ public static <T> T checkNotNull(T reference,
+ @Nullable String errorMessageTemplate,
+ @Nullable Object... errorMessageArgs) {
+ if (reference == null) {
+ // If either of these parameters is null, the right thing happens anyway
+ throw new NullPointerException(
+ format(errorMessageTemplate, errorMessageArgs));
+ }
+ return reference;
+ }
+
+ /*
+ * All recent hotspots (as of 2009) *really* like to have the natural code
+ *
+ * if (guardExpression) {
+ * throw new BadException(messageExpression);
+ * }
+ *
+ * refactored so that messageExpression is moved to a separate
+ * String-returning method.
+ *
+ * if (guardExpression) {
+ * throw new BadException(badMsg(...));
+ * }
+ *
+ * The alternative natural refactorings into void or Exception-returning
+ * methods are much slower. This is a big deal - we're talking factors of
+ * 2-8 in microbenchmarks, not just 10-20%. (This is a hotspot optimizer
+ * bug, which should be fixed, but that's a separate, big project).
+ *
+ * The coding pattern above is heavily used in java.util, e.g. in ArrayList.
+ * There is a RangeCheckMicroBenchmark in the JDK that was used to test this.
+ *
+ * But the methods in this class want to throw different exceptions,
+ * depending on the args, so it appears that this pattern is not directly
+ * applicable. But we can use the ridiculous, devious trick of throwing an
+ * exception in the middle of the construction of another exception.
+ * Hotspot is fine with that.
+ */
+
+ /**
+ * Ensures that {@code index} specifies a valid <i>element</i> in an array,
+ * list or string of size {@code size}. An element index may range from zero,
+ * inclusive, to {@code size}, exclusive.
+ *
+ * @param index a user-supplied index identifying an element of an array, list
+ * or string
+ * @param size the size of that array, list or string
+ * @return the value of {@code index}
+ * @throws IndexOutOfBoundsException if {@code index} is negative or is not
+ * less than {@code size}
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ public static int checkElementIndex(int index, int size) {
+ return checkElementIndex(index, size, "index");
+ }
+
+ /**
+ * Ensures that {@code index} specifies a valid <i>element</i> in an array,
+ * list or string of size {@code size}. An element index may range from zero,
+ * inclusive, to {@code size}, exclusive.
+ *
+ * @param index a user-supplied index identifying an element of an array, list
+ * or string
+ * @param size the size of that array, list or string
+ * @param desc the text to use to describe this index in an error message
+ * @return the value of {@code index}
+ * @throws IndexOutOfBoundsException if {@code index} is negative or is not
+ * less than {@code size}
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ public static int checkElementIndex(
+ int index, int size, @Nullable String desc) {
+ // Carefully optimized for execution by hotspot (explanatory comment above)
+ if (index < 0 || index >= size) {
+ throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
+ }
+ return index;
+ }
+
+ private static String badElementIndex(int index, int size, String desc) {
+ if (index < 0) {
+ return format("%s (%s) must not be negative", desc, index);
+ } else if (size < 0) {
+ throw new IllegalArgumentException("negative size: " + size);
+ } else { // index >= size
+ return format("%s (%s) must be less than size (%s)", desc, index, size);
+ }
+ }
+
+ /**
+ * Ensures that {@code index} specifies a valid <i>position</i> in an array,
+ * list or string of size {@code size}. A position index may range from zero
+ * to {@code size}, inclusive.
+ *
+ * @param index a user-supplied index identifying a position in an array, list
+ * or string
+ * @param size the size of that array, list or string
+ * @return the value of {@code index}
+ * @throws IndexOutOfBoundsException if {@code index} is negative or is
+ * greater than {@code size}
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ public static int checkPositionIndex(int index, int size) {
+ return checkPositionIndex(index, size, "index");
+ }
+
+ /**
+ * Ensures that {@code index} specifies a valid <i>position</i> in an array,
+ * list or string of size {@code size}. A position index may range from zero
+ * to {@code size}, inclusive.
+ *
+ * @param index a user-supplied index identifying a position in an array, list
+ * or string
+ * @param size the size of that array, list or string
+ * @param desc the text to use to describe this index in an error message
+ * @return the value of {@code index}
+ * @throws IndexOutOfBoundsException if {@code index} is negative or is
+ * greater than {@code size}
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ public static int checkPositionIndex(
+ int index, int size, @Nullable String desc) {
+ // Carefully optimized for execution by hotspot (explanatory comment above)
+ if (index < 0 || index > size) {
+ throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
+ }
+ return index;
+ }
+
+ private static String badPositionIndex(int index, int size, String desc) {
+ if (index < 0) {
+ return format("%s (%s) must not be negative", desc, index);
+ } else if (size < 0) {
+ throw new IllegalArgumentException("negative size: " + size);
+ } else { // index > size
+ return format("%s (%s) must not be greater than size (%s)",
+ desc, index, size);
+ }
+ }
+
+ /**
+ * Ensures that {@code start} and {@code end} specify a valid <i>positions</i>
+ * in an array, list or string of size {@code size}, and are in order. A
+ * position index may range from zero to {@code size}, inclusive.
+ *
+ * @param start a user-supplied index identifying a starting position in an
+ * array, list or string
+ * @param end a user-supplied index identifying a ending position in an array,
+ * list or string
+ * @param size the size of that array, list or string
+ * @throws IndexOutOfBoundsException if either index is negative or is
+ * greater than {@code size}, or if {@code end} is less than {@code start}
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ public static void checkPositionIndexes(int start, int end, int size) {
+ // Carefully optimized for execution by hotspot (explanatory comment above)
+ if (start < 0 || end < start || end > size) {
+ throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
+ }
+ }
+
+ private static String badPositionIndexes(int start, int end, int size) {
+ if (start < 0 || start > size) {
+ return badPositionIndex(start, size, "start index");
+ }
+ if (end < 0 || end > size) {
+ return badPositionIndex(end, size, "end index");
+ }
+ // end < start
+ return format("end index (%s) must not be less than start index (%s)",
+ end, start);
+ }
+
+ /**
+ * Substitutes each {@code %s} in {@code template} with an argument. These
+ * are matched by position - the first {@code %s} gets {@code args[0]}, etc.
+ * If there are more arguments than placeholders, the unmatched arguments will
+ * be appended to the end of the formatted message in square braces.
+ *
+ * @param template a non-null string containing 0 or more {@code %s}
+ * placeholders.
+ * @param args the arguments to be substituted into the message
+ * template. Arguments are converted to strings using
+ * {@link String#valueOf(Object)}. Arguments can be null.
+ */
+ @VisibleForTesting static String format(String template,
+ @Nullable Object... args) {
+ template = String.valueOf(template); // null -> "null"
+
+ // start substituting the arguments into the '%s' placeholders
+ StringBuilder builder = new StringBuilder(
+ template.length() + 16 * args.length);
+ int templateStart = 0;
+ int i = 0;
+ while (i < args.length) {
+ int placeholderStart = template.indexOf("%s", templateStart);
+ if (placeholderStart == -1) {
+ break;
+ }
+ builder.append(template.substring(templateStart, placeholderStart));
+ builder.append(args[i++]);
+ templateStart = placeholderStart + 2;
+ }
+ builder.append(template.substring(templateStart));
+
+ // if we run out of placeholders, append the extra args in square braces
+ if (i < args.length) {
+ builder.append(" [");
+ builder.append(args[i++]);
+ while (i < args.length) {
+ builder.append(", ");
+ builder.append(args[i++]);
+ }
+ builder.append(']');
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/guava/src/com/google/common/base/Predicate.java b/guava/src/com/google/common/base/Predicate.java
new file mode 100644
index 0000000..89a8c36
--- /dev/null
+++ b/guava/src/com/google/common/base/Predicate.java
@@ -0,0 +1,63 @@
+/*
+ * 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.base;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * Determines a true or false value for a given input.
+ *
+ * <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)
+ */
+@GwtCompatible
+public interface Predicate<T> {
+ /**
+ * Returns the result of applying this predicate to {@code input}. This method is <i>generally
+ * expected</i>, but not absolutely required, to have the following properties:
+ *
+ * <ul>
+ * <li>Its execution does not cause any observable side effects.
+ * <li>The computation is <i>consistent with equals</i>; that is, {@link Objects#equal
+ * Objects.equal}{@code (a, b)} implies that {@code predicate.apply(a) ==
+ * predicate.apply(b))}.
+ * </ul>
+ *
+ * @throws NullPointerException if {@code input} is null and this predicate does not accept null
+ * arguments
+ */
+ boolean apply(@Nullable T input);
+
+ /**
+ * Indicates whether another object is equal to this predicate.
+ *
+ * <p>Most implementations will have no reason to override the behavior of {@link Object#equals}.
+ * However, an implementation may also choose to return {@code true} whenever {@code object} is a
+ * {@link Predicate} that it considers <i>interchangeable</i> with this one. "Interchangeable"
+ * <i>typically</i> means that {@code this.apply(t) == that.apply(t)} for all {@code t} of type
+ * {@code T}). Note that a {@code false} result from this method does not imply that the
+ * predicates are known <i>not</i> to be interchangeable.
+ */
+ @Override
+ boolean equals(@Nullable Object object);
+}
diff --git a/guava/src/com/google/common/base/Predicates.java b/guava/src/com/google/common/base/Predicates.java
new file mode 100644
index 0000000..5c42c55
--- /dev/null
+++ b/guava/src/com/google/common/base/Predicates.java
@@ -0,0 +1,626 @@
+/*
+ * 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.base;
+
+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.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nullable;
+
+/**
+ * Static utility methods pertaining to {@code Predicate} instances.
+ *
+ * <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)
+ */
+@GwtCompatible(emulated = true)
+public final class Predicates {
+ private Predicates() {}
+
+ // TODO(kevinb): considering having these implement a VisitablePredicate
+ // interface which specifies an accept(PredicateVisitor) method.
+
+ /**
+ * Returns a predicate that always evaluates to {@code true}.
+ */
+ @GwtCompatible(serializable = true)
+ public static <T> Predicate<T> alwaysTrue() {
+ return ObjectPredicate.ALWAYS_TRUE.withNarrowedType();
+ }
+
+ /**
+ * Returns a predicate that always evaluates to {@code false}.
+ */
+ @GwtCompatible(serializable = true)
+ public static <T> Predicate<T> alwaysFalse() {
+ return ObjectPredicate.ALWAYS_FALSE.withNarrowedType();
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the object reference
+ * being tested is null.
+ */
+ @GwtCompatible(serializable = true)
+ public static <T> Predicate<T> isNull() {
+ return ObjectPredicate.IS_NULL.withNarrowedType();
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the object reference
+ * being tested is not null.
+ */
+ @GwtCompatible(serializable = true)
+ public static <T> Predicate<T> notNull() {
+ return ObjectPredicate.NOT_NULL.withNarrowedType();
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the given predicate
+ * evaluates to {@code false}.
+ */
+ public static <T> Predicate<T> not(Predicate<T> predicate) {
+ return new NotPredicate<T>(predicate);
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if each of its
+ * components evaluates to {@code true}. The components are evaluated in
+ * order, and evaluation will be "short-circuited" as soon as a false
+ * predicate is found. It defensively copies the iterable passed in, so future
+ * changes to it won't alter the behavior of this predicate. If {@code
+ * components} is empty, the returned predicate will always evaluate to {@code
+ * true}.
+ */
+ public static <T> Predicate<T> and(
+ Iterable<? extends Predicate<? super T>> components) {
+ return new AndPredicate<T>(defensiveCopy(components));
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if each of its
+ * components evaluates to {@code true}. The components are evaluated in
+ * order, and evaluation will be "short-circuited" as soon as a false
+ * predicate is found. It defensively copies the array passed in, so future
+ * changes to it won't alter the behavior of this predicate. If {@code
+ * components} is empty, the returned predicate will always evaluate to {@code
+ * true}.
+ */
+ public static <T> Predicate<T> and(Predicate<? super T>... components) {
+ return new AndPredicate<T>(defensiveCopy(components));
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if both of its
+ * components evaluate to {@code true}. The components are evaluated in
+ * order, and evaluation will be "short-circuited" as soon as a false
+ * predicate is found.
+ */
+ public static <T> Predicate<T> and(Predicate<? super T> first,
+ Predicate<? super T> second) {
+ return new AndPredicate<T>(Predicates.<T>asList(
+ checkNotNull(first), checkNotNull(second)));
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if any one of its
+ * components evaluates to {@code true}. The components are evaluated in
+ * order, and evaluation will be "short-circuited" as soon as a
+ * true predicate is found. It defensively copies the iterable passed in, so
+ * future changes to it won't alter the behavior of this predicate. If {@code
+ * components} is empty, the returned predicate will always evaluate to {@code
+ * false}.
+ */
+ public static <T> Predicate<T> or(
+ Iterable<? extends Predicate<? super T>> components) {
+ return new OrPredicate<T>(defensiveCopy(components));
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if any one of its
+ * components evaluates to {@code true}. The components are evaluated in
+ * order, and evaluation will be "short-circuited" as soon as a
+ * true predicate is found. It defensively copies the array passed in, so
+ * future changes to it won't alter the behavior of this predicate. If {@code
+ * components} is empty, the returned predicate will always evaluate to {@code
+ * false}.
+ */
+ public static <T> Predicate<T> or(Predicate<? super T>... components) {
+ return new OrPredicate<T>(defensiveCopy(components));
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if either of its
+ * components evaluates to {@code true}. The components are evaluated in
+ * order, and evaluation will be "short-circuited" as soon as a
+ * true predicate is found.
+ */
+ public static <T> Predicate<T> or(
+ Predicate<? super T> first, Predicate<? super T> second) {
+ return new OrPredicate<T>(Predicates.<T>asList(
+ checkNotNull(first), checkNotNull(second)));
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the object being
+ * tested {@code equals()} the given target or both are null.
+ */
+ public static <T> Predicate<T> equalTo(@Nullable T target) {
+ return (target == null)
+ ? Predicates.<T>isNull()
+ : new IsEqualToPredicate<T>(target);
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the object being
+ * tested is an instance of the given class. If the object being tested
+ * is {@code null} this predicate evaluates to {@code false}.
+ *
+ * <p>If you want to filter an {@code Iterable} to narrow its type, consider
+ * using {@link com.google.common.collect.Iterables#filter(Iterable, Class)}
+ * in preference.
+ *
+ * <p><b>Warning:</b> contrary to the typical assumptions about predicates (as
+ * documented at {@link Predicate#apply}), the returned predicate may not be
+ * <i>consistent with equals</i>. For example, {@code
+ * instanceOf(ArrayList.class)} will yield different results for the two equal
+ * instances {@code Lists.newArrayList(1)} and {@code Arrays.asList(1)}.
+ */
+ @GwtIncompatible("Class.isInstance")
+ 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")
+ @Beta
+ public static Predicate<Class<?>> assignableFrom(Class<?> clazz) {
+ return new AssignableFromPredicate(clazz);
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the object reference
+ * being tested is a member of the given collection. It does not defensively
+ * copy the collection passed in, so future changes to it will alter the
+ * behavior of the predicate.
+ *
+ * <p>This method can technically accept any {@code Collection<?>}, but using
+ * a typed collection helps prevent bugs. This approach doesn't block any
+ * potential users since it is always possible to use {@code
+ * Predicates.<Object>in()}.
+ *
+ * @param target the collection that may contain the function input
+ */
+ public static <T> Predicate<T> in(Collection<? extends T> target) {
+ return new InPredicate<T>(target);
+ }
+
+ /**
+ * Returns the composition of a function and a predicate. For every {@code x},
+ * the generated predicate returns {@code predicate(function(x))}.
+ *
+ * @return the composition of the provided function and predicate
+ */
+ public static <A, B> Predicate<A> compose(
+ Predicate<B> predicate, Function<A, ? extends B> function) {
+ return new CompositionPredicate<A, B>(predicate, function);
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the
+ * {@code CharSequence} being tested contains any match for the given
+ * regular expression pattern. The test used is equivalent to
+ * {@code Pattern.compile(pattern).matcher(arg).find()}
+ *
+ * @throws java.util.regex.PatternSyntaxException if the pattern is invalid
+ * @since 3.0
+ */
+ @GwtIncompatible(value = "java.util.regex.Pattern")
+ public static Predicate<CharSequence> containsPattern(String pattern) {
+ return new ContainsPatternPredicate(pattern);
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the
+ * {@code CharSequence} being tested contains any match for the given
+ * regular expression pattern. The test used is equivalent to
+ * {@code pattern.matcher(arg).find()}
+ *
+ * @since 3.0
+ */
+ @GwtIncompatible(value = "java.util.regex.Pattern")
+ public static Predicate<CharSequence> contains(Pattern pattern) {
+ return new ContainsPatternPredicate(pattern);
+ }
+
+ // End public API, begin private implementation classes.
+
+ // Package private for GWT serialization.
+ enum ObjectPredicate implements Predicate<Object> {
+ ALWAYS_TRUE {
+ @Override public boolean apply(@Nullable Object o) {
+ return true;
+ }
+ },
+ ALWAYS_FALSE {
+ @Override public boolean apply(@Nullable Object o) {
+ return false;
+ }
+ },
+ IS_NULL {
+ @Override public boolean apply(@Nullable Object o) {
+ return o == null;
+ }
+ },
+ NOT_NULL {
+ @Override public boolean apply(@Nullable Object o) {
+ return o != null;
+ }
+ };
+
+ @SuppressWarnings("unchecked") // these Object predicates work for any T
+ <T> Predicate<T> withNarrowedType() {
+ return (Predicate<T>) this;
+ }
+ }
+
+ /** @see Predicates#not(Predicate) */
+ private static class NotPredicate<T> implements Predicate<T>, Serializable {
+ final Predicate<T> predicate;
+
+ NotPredicate(Predicate<T> predicate) {
+ this.predicate = checkNotNull(predicate);
+ }
+ @Override
+ public boolean apply(T t) {
+ return !predicate.apply(t);
+ }
+ @Override public int hashCode() {
+ return ~predicate.hashCode();
+ }
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof NotPredicate) {
+ NotPredicate<?> that = (NotPredicate<?>) obj;
+ return predicate.equals(that.predicate);
+ }
+ return false;
+ }
+ @Override public String toString() {
+ return "Not(" + predicate.toString() + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ private static final Joiner COMMA_JOINER = Joiner.on(",");
+
+ /** @see Predicates#and(Iterable) */
+ private static class AndPredicate<T> implements Predicate<T>, Serializable {
+ private final List<? extends Predicate<? super T>> components;
+
+ private AndPredicate(List<? extends Predicate<? super T>> components) {
+ this.components = components;
+ }
+ @Override
+ public boolean apply(T t) {
+ // Avoid using the Iterator to avoid generating garbage (issue 820).
+ for (int i = 0; i < components.size(); i++) {
+ if (!components.get(i).apply(t)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ @Override public int hashCode() {
+ // add a random number to avoid collisions with OrPredicate
+ return components.hashCode() + 0x12472c2c;
+ }
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof AndPredicate) {
+ AndPredicate<?> that = (AndPredicate<?>) obj;
+ return components.equals(that.components);
+ }
+ return false;
+ }
+ @Override public String toString() {
+ return "And(" + COMMA_JOINER.join(components) + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** @see Predicates#or(Iterable) */
+ private static class OrPredicate<T> implements Predicate<T>, Serializable {
+ private final List<? extends Predicate<? super T>> components;
+
+ private OrPredicate(List<? extends Predicate<? super T>> components) {
+ this.components = components;
+ }
+ @Override
+ public boolean apply(T t) {
+ // Avoid using the Iterator to avoid generating garbage (issue 820).
+ for (int i = 0; i < components.size(); i++) {
+ if (components.get(i).apply(t)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ @Override public int hashCode() {
+ // add a random number to avoid collisions with AndPredicate
+ return components.hashCode() + 0x053c91cf;
+ }
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof OrPredicate) {
+ OrPredicate<?> that = (OrPredicate<?>) obj;
+ return components.equals(that.components);
+ }
+ return false;
+ }
+ @Override public String toString() {
+ return "Or(" + COMMA_JOINER.join(components) + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** @see Predicates#equalTo(Object) */
+ private static class IsEqualToPredicate<T>
+ implements Predicate<T>, Serializable {
+ private final T target;
+
+ private IsEqualToPredicate(T target) {
+ this.target = target;
+ }
+ @Override
+ public boolean apply(T t) {
+ return target.equals(t);
+ }
+ @Override public int hashCode() {
+ return target.hashCode();
+ }
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof IsEqualToPredicate) {
+ IsEqualToPredicate<?> that = (IsEqualToPredicate<?>) obj;
+ return target.equals(that.target);
+ }
+ return false;
+ }
+ @Override public String toString() {
+ return "IsEqualTo(" + target + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** @see Predicates#instanceOf(Class) */
+ @GwtIncompatible("Class.isInstance")
+ private static class InstanceOfPredicate
+ implements Predicate<Object>, Serializable {
+ private final Class<?> clazz;
+
+ private InstanceOfPredicate(Class<?> clazz) {
+ this.clazz = checkNotNull(clazz);
+ }
+ @Override
+ public boolean apply(@Nullable Object o) {
+ return clazz.isInstance(o);
+ }
+ @Override public int hashCode() {
+ return clazz.hashCode();
+ }
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof InstanceOfPredicate) {
+ InstanceOfPredicate that = (InstanceOfPredicate) obj;
+ return clazz == that.clazz;
+ }
+ return false;
+ }
+ @Override public String toString() {
+ return "IsInstanceOf(" + clazz.getName() + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** @see Predicates#assignableFrom(Class) */
+ @GwtIncompatible("Class.isAssignableFrom")
+ private static class AssignableFromPredicate
+ implements Predicate<Class<?>>, Serializable {
+ private final Class<?> clazz;
+
+ private AssignableFromPredicate(Class<?> clazz) {
+ this.clazz = checkNotNull(clazz);
+ }
+ @Override
+ public boolean apply(Class<?> input) {
+ return clazz.isAssignableFrom(input);
+ }
+ @Override public int hashCode() {
+ return clazz.hashCode();
+ }
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof AssignableFromPredicate) {
+ AssignableFromPredicate that = (AssignableFromPredicate) obj;
+ return clazz == that.clazz;
+ }
+ return false;
+ }
+ @Override public String toString() {
+ return "IsAssignableFrom(" + clazz.getName() + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** @see Predicates#in(Collection) */
+ private static class InPredicate<T> implements Predicate<T>, Serializable {
+ private final Collection<?> target;
+
+ private InPredicate(Collection<?> target) {
+ this.target = checkNotNull(target);
+ }
+
+ @Override
+ public boolean apply(T t) {
+ try {
+ return target.contains(t);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof InPredicate) {
+ InPredicate<?> that = (InPredicate<?>) obj;
+ return target.equals(that.target);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return target.hashCode();
+ }
+
+ @Override public String toString() {
+ return "In(" + target + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** @see Predicates#compose(Predicate, Function) */
+ private static class CompositionPredicate<A, B>
+ implements Predicate<A>, Serializable {
+ final Predicate<B> p;
+ final Function<A, ? extends B> f;
+
+ private CompositionPredicate(Predicate<B> p, Function<A, ? extends B> f) {
+ this.p = checkNotNull(p);
+ this.f = checkNotNull(f);
+ }
+
+ @Override
+ public boolean apply(A a) {
+ return p.apply(f.apply(a));
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof CompositionPredicate) {
+ CompositionPredicate<?, ?> that = (CompositionPredicate<?, ?>) obj;
+ return f.equals(that.f) && p.equals(that.p);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return f.hashCode() ^ p.hashCode();
+ }
+
+ @Override public String toString() {
+ return p.toString() + "(" + f.toString() + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * @see Predicates#contains(Pattern)
+ * @see Predicates#containsPattern(String)
+ */
+ @GwtIncompatible("Only used by other GWT-incompatible code.")
+ private static class ContainsPatternPredicate
+ implements Predicate<CharSequence>, Serializable {
+ final Pattern pattern;
+
+ ContainsPatternPredicate(Pattern pattern) {
+ this.pattern = checkNotNull(pattern);
+ }
+
+ ContainsPatternPredicate(String patternStr) {
+ this(Pattern.compile(patternStr));
+ }
+
+ @Override
+ public boolean apply(CharSequence t) {
+ return pattern.matcher(t).find();
+ }
+
+ @Override public int hashCode() {
+ // Pattern uses Object.hashCode, so we have to reach
+ // inside to build a hashCode consistent with equals.
+
+ return Objects.hashCode(pattern.pattern(), pattern.flags());
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof ContainsPatternPredicate) {
+ ContainsPatternPredicate that = (ContainsPatternPredicate) obj;
+
+ // Pattern uses Object (identity) equality, so we have to reach
+ // inside to compare individual fields.
+ return Objects.equal(pattern.pattern(), that.pattern.pattern())
+ && Objects.equal(pattern.flags(), that.pattern.flags());
+ }
+ return false;
+ }
+
+ @Override public String toString() {
+ return Objects.toStringHelper(this)
+ .add("pattern", pattern)
+ .add("pattern.flags", Integer.toHexString(pattern.flags()))
+ .toString();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> List<Predicate<? super T>> asList(
+ Predicate<? super T> first, Predicate<? super T> second) {
+ return Arrays.<Predicate<? super T>>asList(first, second);
+ }
+
+ private static <T> List<T> defensiveCopy(T... array) {
+ return defensiveCopy(Arrays.asList(array));
+ }
+
+ static <T> List<T> defensiveCopy(Iterable<T> iterable) {
+ ArrayList<T> list = new ArrayList<T>();
+ for (T element : iterable) {
+ list.add(checkNotNull(element));
+ }
+ return list;
+ }
+}
diff --git a/guava/src/com/google/common/base/Present.java b/guava/src/com/google/common/base/Present.java
new file mode 100644
index 0000000..aa1ddc5
--- /dev/null
+++ b/guava/src/com/google/common/base/Present.java
@@ -0,0 +1,92 @@
+/*
+ * 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 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 <V> Optional<V> transform(Function<? super T, V> function) {
+ return new Present<V>(checkNotNull(function.apply(reference),
+ "Transformation function cannot 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
new file mode 100644
index 0000000..b62a488
--- /dev/null
+++ b/guava/src/com/google/common/base/SmallCharMatcher.java
@@ -0,0 +1,128 @@
+/*
+ * 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.GwtCompatible;
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * An immutable small version of CharMatcher that uses an efficient hash table implementation, with
+ * non-power-of-2 sizing to try to use no reprobing, if possible.
+ *
+ * @author Christopher Swenson
+ */
+@GwtCompatible
+final class SmallCharMatcher extends CharMatcher {
+ static final int MAX_SIZE = 63;
+ static final int MAX_TABLE_SIZE = 128;
+ private final boolean reprobe;
+ private final char[] table;
+ private final boolean containsZero;
+ final long filter;
+
+ private SmallCharMatcher(char[] table, long filter, boolean containsZero,
+ boolean reprobe, String description) {
+ super(description);
+ this.table = table;
+ this.filter = filter;
+ this.containsZero = containsZero;
+ this.reprobe = reprobe;
+ }
+
+ private boolean checkFilter(int c) {
+ return 1 == (1 & (filter >> c));
+ }
+
+ @Override
+ public CharMatcher precomputed() {
+ return this;
+ }
+
+ @VisibleForTesting
+ static char[] buildTable(int modulus, char[] allChars, boolean reprobe) {
+ char[] table = new char[modulus];
+ for (int i = 0; i < allChars.length; i++) {
+ char c = allChars[i];
+ int index = c % modulus;
+ if (index < 0) {
+ index += modulus;
+ }
+ if ((table[index] != 0) && !reprobe) {
+ return null;
+ } else if (reprobe) {
+ while (table[index] != 0) {
+ index = (index + 1) % modulus;
+ }
+ }
+ table[index] = c;
+ }
+ return table;
+ }
+
+ static CharMatcher from(char[] chars, String description) {
+ long filter = 0;
+ int size = chars.length;
+ boolean containsZero = false;
+ boolean reprobe = false;
+ containsZero = chars[0] == 0;
+
+ // Compute the filter.
+ for (char c : chars) {
+ filter |= 1L << c;
+ }
+ char[] table = null;
+ for (int i = size; i < MAX_TABLE_SIZE; i++) {
+ table = buildTable(i, chars, false);
+ if (table != null) {
+ break;
+ }
+ }
+ // Compute the hash table.
+ if (table == null) {
+ table = buildTable(MAX_TABLE_SIZE, chars, true);
+ reprobe = true;
+ }
+ return new SmallCharMatcher(table, filter, containsZero, reprobe, description);
+ }
+
+ @Override
+ public boolean matches(char c) {
+ if (c == 0) {
+ return containsZero;
+ }
+ if (!checkFilter(c)) {
+ return false;
+ }
+ int index = c % table.length;
+ if (index < 0) {
+ index += table.length;
+ }
+ while (true) {
+ // Check for empty.
+ if (table[index] == 0) {
+ return false;
+ } else if (table[index] == c) {
+ return true;
+ } else if (reprobe) {
+ // Linear probing will terminate eventually.
+ index = (index + 1) % table.length;
+ } else {
+ return false;
+ }
+ }
+ }
+}
diff --git a/guava/src/com/google/common/base/Splitter.java b/guava/src/com/google/common/base/Splitter.java
new file mode 100644
index 0000000..a1c236c
--- /dev/null
+++ b/guava/src/com/google/common/base/Splitter.java
@@ -0,0 +1,571 @@
+/*
+ * 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.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.GwtIncompatible;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.CheckReturnValue;
+
+/**
+ * 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>Here is the most basic example of {@code Splitter} usage: <pre> {@code
+ *
+ * Splitter.on(',').split("foo,bar")}</pre>
+ *
+ * This invocation returns an {@code Iterable<String>} containing {@code "foo"}
+ * and {@code "bar"}, in that order.
+ *
+ * <p>By default {@code Splitter}'s behavior is very simplistic: <pre> {@code
+ *
+ * Splitter.on(',').split("foo,,bar, quux")}</pre>
+ *
+ * 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, 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: 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
+ *
+ * // Bad! Do not do this!
+ * Splitter splitter = Splitter.on('/');
+ * splitter.trimResults(); // does nothing!
+ * return splitter.split("wrong / wrong / wrong");}</pre>
+ *
+ * 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><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}.
+ *
+ * <p>See the Guava User Guide article on <a href=
+ * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#Splitter">
+ * {@code Splitter}</a>.
+ *
+ * @author Julien Silland
+ * @author Jesse Wilson
+ * @author Kevin Bourrillion
+ * @author Louis Wasserman
+ * @since 1.0
+ */
+@GwtCompatible(emulated = true)
+public final class Splitter {
+ private final CharMatcher trimmer;
+ private final boolean omitEmptyStrings;
+ private final Strategy strategy;
+ private final int limit;
+
+ private Splitter(Strategy strategy) {
+ this(strategy, false, CharMatcher.NONE, Integer.MAX_VALUE);
+ }
+
+ private Splitter(Strategy strategy, boolean omitEmptyStrings,
+ CharMatcher trimmer, int limit) {
+ this.strategy = strategy;
+ this.omitEmptyStrings = omitEmptyStrings;
+ this.trimmer = trimmer;
+ this.limit = limit;
+ }
+
+ /**
+ * Returns a splitter that uses the given single-character separator. For
+ * example, {@code Splitter.on(',').split("foo,,bar")} returns an iterable
+ * containing {@code ["foo", "", "bar"]}.
+ *
+ * @param separator the character to recognize as a separator
+ * @return a splitter, with default settings, that recognizes that separator
+ */
+ public static Splitter on(char separator) {
+ return on(CharMatcher.is(separator));
+ }
+
+ /**
+ * Returns a splitter that considers any single character matched by the
+ * given {@code CharMatcher} to be a separator. For example, {@code
+ * Splitter.on(CharMatcher.anyOf(";,")).split("foo,;bar,quux")} returns an
+ * iterable containing {@code ["foo", "", "bar", "quux"]}.
+ *
+ * @param separatorMatcher a {@link CharMatcher} that determines whether a
+ * character is a separator
+ * @return a splitter, with default settings, that uses this matcher
+ */
+ public static Splitter on(final CharMatcher separatorMatcher) {
+ checkNotNull(separatorMatcher);
+
+ return new Splitter(new Strategy() {
+ @Override public SplittingIterator iterator(
+ Splitter splitter, final CharSequence toSplit) {
+ return new SplittingIterator(splitter, toSplit) {
+ @Override int separatorStart(int start) {
+ return separatorMatcher.indexIn(toSplit, start);
+ }
+
+ @Override int separatorEnd(int separatorPosition) {
+ return separatorPosition + 1;
+ }
+ };
+ }
+ });
+ }
+
+ /**
+ * Returns a splitter that uses the given fixed string as a separator. For
+ * 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
+ */
+ public static Splitter on(final String separator) {
+ checkArgument(separator.length() != 0,
+ "The separator may not be the empty string.");
+
+ return new Splitter(new Strategy() {
+ @Override public SplittingIterator iterator(
+ Splitter splitter, CharSequence toSplit) {
+ return new SplittingIterator(splitter, toSplit) {
+ @Override public int separatorStart(int start) {
+ int delimeterLength = separator.length();
+
+ positions:
+ for (int p = start, last = toSplit.length() - delimeterLength;
+ p <= last; p++) {
+ for (int i = 0; i < delimeterLength; i++) {
+ if (toSplit.charAt(i + p) != separator.charAt(i)) {
+ continue positions;
+ }
+ }
+ return p;
+ }
+ return -1;
+ }
+
+ @Override public int separatorEnd(int separatorPosition) {
+ return separatorPosition + separator.length();
+ }
+ };
+ }
+ });
+ }
+
+ /**
+ * Returns a splitter that considers any subsequence matching {@code
+ * pattern} to be a separator. For example, {@code
+ * Splitter.on(Pattern.compile("\r?\n")).split(entireFile)} splits a string
+ * into lines whether it uses DOS-style or UNIX-style line terminators.
+ *
+ * @param separatorPattern the pattern that determines whether a subsequence
+ * is a separator. This pattern may not match the empty string.
+ * @return a splitter, with default settings, that uses this pattern
+ * @throws IllegalArgumentException if {@code separatorPattern} matches the
+ * empty string
+ */
+ @GwtIncompatible("java.util.regex")
+ public static Splitter on(final Pattern separatorPattern) {
+ checkNotNull(separatorPattern);
+ checkArgument(!separatorPattern.matcher("").matches(),
+ "The pattern may not match the empty string: %s", separatorPattern);
+
+ return new Splitter(new Strategy() {
+ @Override public SplittingIterator iterator(
+ final Splitter splitter, CharSequence toSplit) {
+ final Matcher matcher = separatorPattern.matcher(toSplit);
+ return new SplittingIterator(splitter, toSplit) {
+ @Override public int separatorStart(int start) {
+ return matcher.find(start) ? matcher.start() : -1;
+ }
+
+ @Override public int separatorEnd(int separatorPosition) {
+ return matcher.end();
+ }
+ };
+ }
+ });
+ }
+
+ /**
+ * Returns a splitter that considers any subsequence matching a given
+ * pattern (regular expression) to be a separator. For example, {@code
+ * Splitter.onPattern("\r?\n").split(entireFile)} splits a string into lines
+ * whether it uses DOS-style or UNIX-style line terminators. This is
+ * equivalent to {@code Splitter.on(Pattern.compile(pattern))}.
+ *
+ * @param separatorPattern the pattern that determines whether a subsequence
+ * is a separator. This pattern may not match the empty string.
+ * @return a splitter, with default settings, that uses this pattern
+ * @throws java.util.regex.PatternSyntaxException if {@code separatorPattern}
+ * is a malformed expression
+ * @throws IllegalArgumentException if {@code separatorPattern} matches the
+ * empty string
+ */
+ @GwtIncompatible("java.util.regex")
+ public static Splitter onPattern(String separatorPattern) {
+ return on(Pattern.compile(separatorPattern));
+ }
+
+ /**
+ * Returns a splitter that divides strings into pieces of the given length.
+ * For example, {@code Splitter.fixedLength(2).split("abcde")} returns an
+ * iterable containing {@code ["ab", "cd", "e"]}. The last piece can be
+ * smaller than {@code length} but will never be empty.
+ *
+ * @param length the desired length of pieces after splitting
+ * @return a splitter, with default settings, that can split into fixed sized
+ * pieces
+ */
+ public static Splitter fixedLength(final int length) {
+ checkArgument(length > 0, "The length may not be less than 1");
+
+ return new Splitter(new Strategy() {
+ @Override public SplittingIterator iterator(
+ final Splitter splitter, CharSequence toSplit) {
+ return new SplittingIterator(splitter, toSplit) {
+ @Override public int separatorStart(int start) {
+ int nextChunkStart = start + length;
+ return (nextChunkStart < toSplit.length() ? nextChunkStart : -1);
+ }
+
+ @Override public int separatorEnd(int separatorPosition) {
+ return separatorPosition;
+ }
+ };
+ }
+ });
+ }
+
+ /**
+ * Returns a splitter that behaves equivalently to {@code this} splitter, but
+ * automatically omits empty strings from the results. For example, {@code
+ * Splitter.on(',').omitEmptyStrings().split(",a,,,b,c,,")} returns an
+ * iterable containing only {@code ["a", "b", "c"]}.
+ *
+ * <p>If either {@code trimResults} option is also specified when creating a
+ * splitter, that splitter always trims results first before checking for
+ * emptiness. So, for example, {@code
+ * Splitter.on(':').omitEmptyStrings().trimResults().split(": : : ")} returns
+ * an empty iterable.
+ *
+ * <p>Note that it is ordinarily not possible for {@link #split(CharSequence)}
+ * to return an empty iterable, but when using this option, it can (if the
+ * input sequence consists of nothing but separators).
+ *
+ * @return a splitter with the desired configuration
+ */
+ @CheckReturnValue
+ public Splitter omitEmptyStrings() {
+ return new Splitter(strategy, true, trimmer, limit);
+ }
+
+ /**
+ * Returns a splitter that behaves equivalently to {@code this} splitter but
+ * stops splitting after it reaches the limit.
+ * The limit defines the maximum number of items returned by the iterator.
+ *
+ * <p>For example,
+ * {@code Splitter.on(',').limit(3).split("a,b,c,d")} returns an iterable
+ * containing {@code ["a", "b", "c,d"]}. When omitting empty strings, the
+ * omitted strings do no count. Hence,
+ * {@code Splitter.on(',').limit(3).omitEmptyStrings().split("a,,,b,,,c,d")}
+ * returns an iterable containing {@code ["a", "b", "c,d"}.
+ * When trim is requested, all entries, including the last are trimmed. Hence
+ * {@code Splitter.on(',').limit(3).trimResults().split(" a , b , c , d ")}
+ * results in @{code ["a", "b", "c , d"]}.
+ *
+ * @param limit the maximum number of items returns
+ * @return a splitter with the desired configuration
+ * @since 9.0
+ */
+ @CheckReturnValue
+ public Splitter limit(int limit) {
+ checkArgument(limit > 0, "must be greater than zero: %s", limit);
+ return new Splitter(strategy, omitEmptyStrings, trimmer, limit);
+ }
+
+ /**
+ * Returns a splitter that behaves equivalently to {@code this} splitter, but
+ * automatically removes leading and trailing {@linkplain
+ * CharMatcher#WHITESPACE whitespace} from each returned substring; equivalent
+ * to {@code trimResults(CharMatcher.WHITESPACE)}. For example, {@code
+ * Splitter.on(',').trimResults().split(" a, b ,c ")} returns an iterable
+ * containing {@code ["a", "b", "c"]}.
+ *
+ * @return a splitter with the desired configuration
+ */
+ @CheckReturnValue
+ public Splitter trimResults() {
+ return trimResults(CharMatcher.WHITESPACE);
+ }
+
+ /**
+ * Returns a splitter that behaves equivalently to {@code this} splitter, but
+ * removes all leading or trailing characters matching the given {@code
+ * CharMatcher} from each returned substring. For example, {@code
+ * Splitter.on(',').trimResults(CharMatcher.is('_')).split("_a ,_b_ ,c__")}
+ * returns an iterable containing {@code ["a ", "b_ ", "c"]}.
+ *
+ * @param trimmer a {@link CharMatcher} that determines whether a character
+ * should be removed from the beginning/end of a subsequence
+ * @return a splitter with the desired configuration
+ */
+ // TODO(kevinb): throw if a trimmer was already specified!
+ @CheckReturnValue
+ public Splitter trimResults(CharMatcher trimmer) {
+ checkNotNull(trimmer);
+ return new Splitter(strategy, omitEmptyStrings, trimmer, limit);
+ }
+
+ /**
+ * Splits {@code sequence} into string components and makes them available
+ * through an {@link Iterator}, which may be lazily evaluated.
+ *
+ * @param sequence the sequence of characters to split
+ * @return an iteration over the segments split from the parameter.
+ */
+ public Iterable<String> split(final CharSequence sequence) {
+ checkNotNull(sequence);
+
+ return new Iterable<String>() {
+ @Override public Iterator<String> iterator() {
+ return spliterator(sequence);
+ }
+ @Override public String toString() {
+ return Joiner.on(", ")
+ .appendTo(new StringBuilder().append('['), this)
+ .append(']')
+ .toString();
+ }
+ };
+ }
+
+ private Iterator<String> spliterator(CharSequence sequence) {
+ return strategy.iterator(this, sequence);
+ }
+
+ /**
+ * Returns a {@code MapSplitter} which splits entries based on this splitter,
+ * and splits entries into keys and values using the specified separator.
+ *
+ * @since 10.0
+ */
+ @CheckReturnValue
+ @Beta
+ public MapSplitter withKeyValueSeparator(String 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.
+ *
+ * @since 10.0
+ */
+ @CheckReturnValue
+ @Beta
+ public MapSplitter withKeyValueSeparator(Splitter keyValueSplitter) {
+ return new MapSplitter(this, keyValueSplitter);
+ }
+
+ /**
+ * An object that splits strings into maps as {@code Splitter} splits
+ * iterables and lists. Like {@code Splitter}, it is thread-safe and
+ * immutable.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public static final class MapSplitter {
+ private static final String INVALID_ENTRY_MESSAGE =
+ "Chunk [%s] is not a valid entry";
+ private final Splitter outerSplitter;
+ private final Splitter entrySplitter;
+
+ private MapSplitter(Splitter outerSplitter, Splitter entrySplitter) {
+ this.outerSplitter = outerSplitter; // only "this" is passed
+ this.entrySplitter = checkNotNull(entrySplitter);
+ }
+
+ /**
+ * Splits {@code sequence} into substrings, splits each substring into
+ * an entry, and returns an unmodifiable map with each of the entries. For
+ * example, <code>
+ * Splitter.on(';').trimResults().withKeyValueSeparator("=>")
+ * .split("a=>b ; c=>b")
+ * </code> will return a mapping from {@code "a"} to {@code "b"} and
+ * {@code "c"} to {@code b}.
+ *
+ * <p>The returned map preserves the order of the entries from
+ * {@code sequence}.
+ *
+ * @throws IllegalArgumentException if the specified sequence does not split
+ * into valid map entries, or if there are duplicate keys
+ */
+ public Map<String, String> split(CharSequence sequence) {
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ for (String entry : outerSplitter.split(sequence)) {
+ Iterator<String> entryFields = entrySplitter.spliterator(entry);
+
+ checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
+ String key = entryFields.next();
+ checkArgument(!map.containsKey(key), "Duplicate key [%s] found.", key);
+
+ checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
+ String value = entryFields.next();
+ map.put(key, value);
+
+ checkArgument(!entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
+ }
+ return Collections.unmodifiableMap(map);
+ }
+ }
+
+ private interface Strategy {
+ Iterator<String> iterator(Splitter splitter, CharSequence toSplit);
+ }
+
+ private abstract static class SplittingIterator extends AbstractIterator<String> {
+ final CharSequence toSplit;
+ final CharMatcher trimmer;
+ final boolean omitEmptyStrings;
+
+ /**
+ * Returns the first index in {@code toSplit} at or after {@code start}
+ * that contains the separator.
+ */
+ abstract int separatorStart(int start);
+
+ /**
+ * Returns the first index in {@code toSplit} after {@code
+ * separatorPosition} that does not contain a separator. This method is only
+ * invoked after a call to {@code separatorStart}.
+ */
+ abstract int separatorEnd(int separatorPosition);
+
+ int offset = 0;
+ int limit;
+
+ protected SplittingIterator(Splitter splitter, CharSequence toSplit) {
+ this.trimmer = splitter.trimmer;
+ this.omitEmptyStrings = splitter.omitEmptyStrings;
+ this.limit = splitter.limit;
+ this.toSplit = toSplit;
+ }
+
+ @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 end;
+
+ int separatorPosition = separatorStart(offset);
+ if (separatorPosition == -1) {
+ end = toSplit.length();
+ offset = -1;
+ } else {
+ 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++;
+ }
+ while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
+ end--;
+ }
+
+ if (omitEmptyStrings && start == end) {
+ // Don't include the (unused) separator in next split string.
+ nextStart = offset;
+ continue;
+ }
+
+ if (limit == 1) {
+ // The limit has been reached, return the rest of the string as the
+ // final item. This is tested after empty string removal so that
+ // empty strings do not count towards the limit.
+ end = toSplit.length();
+ offset = -1;
+ // Since we may have changed the end, we need to trim it again.
+ while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
+ end--;
+ }
+ } else {
+ limit--;
+ }
+
+ return toSplit.subSequence(start, end).toString();
+ }
+ return endOfData();
+ }
+ }
+}
diff --git a/guava/src/com/google/common/base/Stopwatch.java b/guava/src/com/google/common/base/Stopwatch.java
new file mode 100644
index 0000000..9e1b6f6
--- /dev/null
+++ b/guava/src/com/google/common/base/Stopwatch.java
@@ -0,0 +1,226 @@
+/*
+ * 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.base;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An object that measures elapsed time in nanoseconds. It is useful to measure
+ * elapsed time using this class instead of direct calls to {@link
+ * System#nanoTime} for a few reasons:
+ *
+ * <ul>
+ * <li>An alternate time source can be substituted, for testing or performance
+ * reasons.
+ * <li>As documented by {@code nanoTime}, the value returned has no absolute
+ * meaning, and can only be interpreted as relative to another timestamp
+ * returned by {@code nanoTime} at a different time. {@code Stopwatch} is a
+ * more effective abstraction because it exposes only these relative values,
+ * not the absolute ones.
+ * </ul>
+ *
+ * <p>Basic usage:
+ * <pre>
+ * Stopwatch stopwatch = new Stopwatch().{@link #start start}();
+ * doSomething();
+ * stopwatch.{@link #stop stop}(); // optional
+ *
+ * long millis = stopwatch.{@link #elapsedMillis elapsedMillis}();
+ *
+ * log.info("that took: " + stopwatch); // formatted string like "12.3 ms"
+ * </pre>
+ *
+ * <p>Stopwatch methods are not idempotent; it is an error to start or stop a
+ * stopwatch that is already in the desired state.
+ *
+ * <p>When testing code that uses this class, use the {@linkplain
+ * #Stopwatch(Ticker) alternate constructor} to supply a fake or mock ticker.
+ * <!-- TODO(kevinb): restore the "such as" --> This allows you to
+ * simulate any valid behavior of the stopwatch.
+ *
+ * <p><b>Note:</b> This class is not thread-safe.
+ *
+ * @author Kevin Bourrillion
+ * @since 10.0
+ */
+@Beta
+@GwtCompatible(emulated=true)
+public final class Stopwatch {
+ private final Ticker ticker;
+ private boolean isRunning;
+ private long elapsedNanos;
+ private long startTick;
+
+ /**
+ * Creates (but does not start) a new stopwatch using {@link System#nanoTime}
+ * as its time source.
+ */
+ public Stopwatch() {
+ this(Ticker.systemTicker());
+ }
+
+ /**
+ * Creates (but does not start) a new stopwatch, using the specified time
+ * source.
+ */
+ public Stopwatch(Ticker ticker) {
+ this.ticker = checkNotNull(ticker);
+ }
+
+ /**
+ * Returns {@code true} if {@link #start()} has been called on this stopwatch,
+ * and {@link #stop()} has not been called since the last call to {@code
+ * start()}.
+ */
+ public boolean isRunning() {
+ return isRunning;
+ }
+
+ /**
+ * Starts the stopwatch.
+ *
+ * @return this {@code Stopwatch} instance
+ * @throws IllegalStateException if the stopwatch is already running.
+ */
+ public Stopwatch start() {
+ checkState(!isRunning);
+ isRunning = true;
+ startTick = ticker.read();
+ return this;
+ }
+
+ /**
+ * Stops the stopwatch. Future reads will return the fixed duration that had
+ * elapsed up to this point.
+ *
+ * @return this {@code Stopwatch} instance
+ * @throws IllegalStateException if the stopwatch is already stopped.
+ */
+ public Stopwatch stop() {
+ long tick = ticker.read();
+ checkState(isRunning);
+ isRunning = false;
+ elapsedNanos += tick - startTick;
+ return this;
+ }
+
+ /**
+ * Sets the elapsed time for this stopwatch to zero,
+ * and places it in a stopped state.
+ *
+ * @return this {@code Stopwatch} instance
+ */
+ public Stopwatch reset() {
+ elapsedNanos = 0;
+ isRunning = false;
+ return this;
+ }
+
+ private long elapsedNanos() {
+ return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
+ }
+
+ /**
+ * 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.
+ */
+ public long elapsedTime(TimeUnit 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 elapsedTime(TimeUnit.MILLISECONDS}.
+ */
+ public long elapsedMillis() {
+ return elapsedTime(MILLISECONDS);
+ }
+
+ /**
+ * Returns a string representation of the current elapsed time.
+ */
+ @GwtIncompatible("String.format()")
+ @Override public String toString() {
+ return toString(4);
+ }
+
+ /**
+ * 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 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();
+
+ TimeUnit unit = chooseUnit(nanos);
+ double value = (double) nanos / NANOSECONDS.convert(1, unit);
+
+ // Too bad this functionality is not exposed as a regular method call
+ return String.format("%." + significantDigits + "g %s",
+ value, abbreviate(unit));
+ }
+
+ private static TimeUnit chooseUnit(long nanos) {
+ if (SECONDS.convert(nanos, NANOSECONDS) > 0) {
+ return SECONDS;
+ }
+ if (MILLISECONDS.convert(nanos, NANOSECONDS) > 0) {
+ return MILLISECONDS;
+ }
+ if (MICROSECONDS.convert(nanos, NANOSECONDS) > 0) {
+ return MICROSECONDS;
+ }
+ return NANOSECONDS;
+ }
+
+ private static String abbreviate(TimeUnit unit) {
+ switch (unit) {
+ case NANOSECONDS:
+ return "ns";
+ case MICROSECONDS:
+ return "\u03bcs"; // μs
+ case MILLISECONDS:
+ return "ms";
+ case SECONDS:
+ return "s";
+ default:
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/guava/src/com/google/common/base/Strings.java b/guava/src/com/google/common/base/Strings.java
new file mode 100644
index 0000000..45007fd
--- /dev/null
+++ b/guava/src/com/google/common/base/Strings.java
@@ -0,0 +1,238 @@
+/*
+ * 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 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 java.util.Formatter;
+
+import javax.annotation.Nullable;
+
+/**
+ * Static utility methods pertaining to {@code String} or {@code CharSequence}
+ * instances.
+ *
+ * @author Kevin Bourrillion
+ * @since 3.0
+ */
+@GwtCompatible
+public final class Strings {
+ private Strings() {}
+
+ /**
+ * Returns the given string if it is non-null; the empty string otherwise.
+ *
+ * @param string the string to test and possibly return
+ * @return {@code string} itself if it is non-null; {@code ""} if it is null
+ */
+ public static String nullToEmpty(@Nullable String string) {
+ return (string == null) ? "" : string;
+ }
+
+ /**
+ * Returns the given string if it is nonempty; {@code null} otherwise.
+ *
+ * @param string the string to test and possibly return
+ * @return {@code string} itself if it is nonempty; {@code null} if it is
+ * empty or null
+ */
+ public static @Nullable String emptyToNull(@Nullable String string) {
+ return isNullOrEmpty(string) ? null : string;
+ }
+
+ /**
+ * Returns {@code true} if the given string is null or is the empty string.
+ *
+ * <p>Consider normalizing your string references with {@link #nullToEmpty}.
+ * If you do, you can use {@link String#isEmpty()} instead of this
+ * method, and you won't need special null-safe forms of methods like {@link
+ * String#toUpperCase} either. Or, if you'd like to normalize "in the other
+ * direction," converting empty strings to {@code null}, you can use {@link
+ * #emptyToNull}.
+ *
+ * @param string a string reference to check
+ * @return {@code true} if the string is null or is the empty string
+ */
+ public static boolean isNullOrEmpty(@Nullable String string) {
+ return string == null || string.length() == 0; // string.isEmpty() in Java 6
+ }
+
+ /**
+ * Returns a string, of length at least {@code minLength}, consisting of
+ * {@code string} prepended with as many copies of {@code padChar} as are
+ * necessary to reach that length. For example,
+ *
+ * <ul>
+ * <li>{@code padStart("7", 3, '0')} returns {@code "007"}
+ * <li>{@code padStart("2010", 3, '0')} returns {@code "2010"}
+ * </ul>
+ *
+ * <p>See {@link Formatter} for a richer set of formatting capabilities.
+ *
+ * @param string the string which should appear at the end of the result
+ * @param minLength the minimum length the resulting string must have. Can be
+ * zero or negative, in which case the input string is always returned.
+ * @param padChar the character to insert at the beginning of the result until
+ * the minimum length is reached
+ * @return the padded string
+ */
+ public static String padStart(String string, int minLength, char padChar) {
+ checkNotNull(string); // eager for GWT.
+ if (string.length() >= minLength) {
+ return string;
+ }
+ StringBuilder sb = new StringBuilder(minLength);
+ for (int i = string.length(); i < minLength; i++) {
+ sb.append(padChar);
+ }
+ sb.append(string);
+ return sb.toString();
+ }
+
+ /**
+ * Returns a string, of length at least {@code minLength}, consisting of
+ * {@code string} appended with as many copies of {@code padChar} as are
+ * necessary to reach that length. For example,
+ *
+ * <ul>
+ * <li>{@code padEnd("4.", 5, '0')} returns {@code "4.000"}
+ * <li>{@code padEnd("2010", 3, '!')} returns {@code "2010"}
+ * </ul>
+ *
+ * <p>See {@link Formatter} for a richer set of formatting capabilities.
+ *
+ * @param string the string which should appear at the beginning of the result
+ * @param minLength the minimum length the resulting string must have. Can be
+ * zero or negative, in which case the input string is always returned.
+ * @param padChar the character to append to the end of the result until the
+ * minimum length is reached
+ * @return the padded string
+ */
+ public static String padEnd(String string, int minLength, char padChar) {
+ checkNotNull(string); // eager for GWT.
+ if (string.length() >= minLength) {
+ return string;
+ }
+ StringBuilder sb = new StringBuilder(minLength);
+ sb.append(string);
+ for (int i = string.length(); i < minLength; i++) {
+ sb.append(padChar);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns a string consisting of a specific number of concatenated copies of
+ * an input string. For example, {@code repeat("hey", 3)} returns the string
+ * {@code "heyheyhey"}.
+ *
+ * @param string any non-null string
+ * @param count the number of times to repeat it; a nonnegative integer
+ * @return a string containing {@code string} repeated {@code count} times
+ * (the empty string if {@code count} is zero)
+ * @throws IllegalArgumentException if {@code count} is negative
+ */
+ public static String repeat(String string, int count) {
+ checkNotNull(string); // eager for GWT.
+
+ if (count <= 1) {
+ checkArgument(count >= 0, "invalid count: %s", count);
+ return (count == 0) ? "" : string;
+ }
+
+ // IF YOU MODIFY THE CODE HERE, you must update StringsRepeatBenchmark
+ final int len = string.length();
+ final long longSize = (long) len * (long) count;
+ final int size = (int) longSize;
+ if (size != longSize) {
+ throw new ArrayIndexOutOfBoundsException("Required array size too large: "
+ + String.valueOf(longSize));
+ }
+
+ final char[] array = new char[size];
+ string.getChars(0, len, array, 0);
+ int n;
+ for (n = len; n < size - n; n <<= 1) {
+ System.arraycopy(array, 0, array, n, n);
+ }
+ System.arraycopy(array, 0, array, n, size - n);
+ return new String(array);
+ }
+
+ /**
+ * Returns the longest string {@code prefix} such that
+ * {@code a.toString().startsWith(prefix) && b.toString().startsWith(prefix)},
+ * taking care not to split surrogate pairs. If {@code a} and {@code b} have
+ * no common prefix, returns the empty string.
+ *
+ * @since 11.0
+ */
+ public static String commonPrefix(CharSequence a, CharSequence b) {
+ checkNotNull(a);
+ checkNotNull(b);
+
+ int maxPrefixLength = Math.min(a.length(), b.length());
+ int p = 0;
+ while (p < maxPrefixLength && a.charAt(p) == b.charAt(p)) {
+ p++;
+ }
+ if (validSurrogatePairAt(a, p - 1) || validSurrogatePairAt(b, p - 1)) {
+ p--;
+ }
+ return a.subSequence(0, p).toString();
+ }
+
+ /**
+ * Returns the longest string {@code suffix} such that
+ * {@code a.toString().endsWith(suffix) && b.toString().endsWith(suffix)},
+ * taking care not to split surrogate pairs. If {@code a} and {@code b} have
+ * no common suffix, returns the empty string.
+ *
+ * @since 11.0
+ */
+ public static String commonSuffix(CharSequence a, CharSequence b) {
+ checkNotNull(a);
+ checkNotNull(b);
+
+ int maxSuffixLength = Math.min(a.length(), b.length());
+ int s = 0;
+ while (s < maxSuffixLength
+ && a.charAt(a.length() - s - 1) == b.charAt(b.length() - s - 1)) {
+ s++;
+ }
+ if (validSurrogatePairAt(a, a.length() - s - 1)
+ || validSurrogatePairAt(b, b.length() - s - 1)) {
+ s--;
+ }
+ return a.subSequence(a.length() - s, a.length()).toString();
+ }
+
+ /**
+ * True when a valid surrogate pair starts at the given {@code index} in the
+ * given {@code string}. Out-of-range indexes return false.
+ */
+ @VisibleForTesting
+ static boolean validSurrogatePairAt(CharSequence string, int index) {
+ return index >= 0 && index <= (string.length() - 2)
+ && Character.isHighSurrogate(string.charAt(index))
+ && Character.isLowSurrogate(string.charAt(index + 1));
+ }
+}
diff --git a/guava/src/com/google/common/base/Supplier.java b/guava/src/com/google/common/base/Supplier.java
new file mode 100644
index 0000000..ab8b908
--- /dev/null
+++ b/guava/src/com/google/common/base/Supplier.java
@@ -0,0 +1,38 @@
+/*
+ * 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.base;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * A class that can supply objects of a single type. Semantically, this could
+ * be a factory, generator, builder, closure, or something else entirely. No
+ * guarantees are implied by this interface.
+ *
+ * @author Harry Heymann
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public interface Supplier<T> {
+ /**
+ * Retrieves an instance of the appropriate type. The returned object may or
+ * may not be a new instance, depending on the implementation.
+ *
+ * @return an instance of the appropriate type
+ */
+ T get();
+}
diff --git a/guava/src/com/google/common/base/Suppliers.java b/guava/src/com/google/common/base/Suppliers.java
new file mode 100644
index 0000000..add5117
--- /dev/null
+++ b/guava/src/com/google/common/base/Suppliers.java
@@ -0,0 +1,293 @@
+/*
+ * 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.base;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.Serializable;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nullable;
+
+/**
+ * Useful suppliers.
+ *
+ * <p>All methods return serializable suppliers as long as they're given
+ * serializable parameters.
+ *
+ * @author Laurence Gonsalves
+ * @author Harry Heymann
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public final class Suppliers {
+ private Suppliers() {}
+
+ /**
+ * Returns a new supplier which is the composition of the provided function
+ * and supplier. In other words, the new supplier's value will be computed by
+ * retrieving the value from {@code supplier}, and then applying
+ * {@code function} to that value. Note that the resulting supplier will not
+ * call {@code supplier} or invoke {@code function} until it is called.
+ */
+ public static <F, T> Supplier<T> compose(
+ Function<? super F, T> function, Supplier<F> supplier) {
+ Preconditions.checkNotNull(function);
+ Preconditions.checkNotNull(supplier);
+ return new SupplierComposition<F, T>(function, supplier);
+ }
+
+ private static class SupplierComposition<F, T>
+ implements Supplier<T>, Serializable {
+ final Function<? super F, T> function;
+ final Supplier<F> supplier;
+
+ SupplierComposition(Function<? super F, T> function, Supplier<F> supplier) {
+ this.function = function;
+ this.supplier = supplier;
+ }
+
+ @Override
+ public T get() {
+ return function.apply(supplier.get());
+ }
+
+ @Override
+ public String toString() {
+ return "Suppliers.compose(" + function + ", " + supplier + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a supplier which caches the instance retrieved during the first
+ * call to {@code get()} and returns that value on subsequent calls to
+ * {@code get()}. See:
+ * <a href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
+ *
+ * <p>The returned supplier is thread-safe. The supplier's serialized form
+ * does not contain the cached value, which will be recalculated when {@code
+ * get()} is called on the reserialized instance.
+ *
+ * <p>If {@code delegate} is an instance created by an earlier call to {@code
+ * memoize}, it is returned directly.
+ */
+ public static <T> Supplier<T> memoize(Supplier<T> delegate) {
+ return (delegate instanceof MemoizingSupplier)
+ ? delegate
+ : new MemoizingSupplier<T>(Preconditions.checkNotNull(delegate));
+ }
+
+ @VisibleForTesting
+ static class MemoizingSupplier<T> implements Supplier<T>, Serializable {
+ final Supplier<T> delegate;
+ transient volatile boolean initialized;
+ // "value" does not need to be volatile; visibility piggy-backs
+ // on volatile read of "initialized".
+ transient T value;
+
+ MemoizingSupplier(Supplier<T> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public T get() {
+ // A 2-field variant of Double Checked Locking.
+ if (!initialized) {
+ synchronized (this) {
+ if (!initialized) {
+ T t = delegate.get();
+ value = t;
+ initialized = true;
+ return t;
+ }
+ }
+ }
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return "Suppliers.memoize(" + delegate + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a supplier that caches the instance supplied by the delegate and
+ * removes the cached value after the specified time has passed. Subsequent
+ * calls to {@code get()} return the cached value if the expiration time has
+ * not passed. After the expiration time, a new value is retrieved, cached,
+ * and returned. See:
+ * <a href="http://en.wikipedia.org/wiki/Memoization">memoization</a>
+ *
+ * <p>The returned supplier is thread-safe. The supplier's serialized form
+ * does not contain the cached value, which will be recalculated when {@code
+ * get()} is called on the reserialized instance.
+ *
+ * @param duration the length of time after a value is created that it
+ * should stop being returned by subsequent {@code get()} calls
+ * @param unit the unit that {@code duration} is expressed in
+ * @throws IllegalArgumentException if {@code duration} is not positive
+ * @since 2.0
+ */
+ public static <T> Supplier<T> memoizeWithExpiration(
+ Supplier<T> delegate, long duration, TimeUnit unit) {
+ return new ExpiringMemoizingSupplier<T>(delegate, duration, unit);
+ }
+
+ @VisibleForTesting static class ExpiringMemoizingSupplier<T>
+ implements Supplier<T>, Serializable {
+ final Supplier<T> delegate;
+ final long durationNanos;
+ transient volatile T value;
+ // The special value 0 means "not yet initialized".
+ transient volatile long expirationNanos;
+
+ ExpiringMemoizingSupplier(
+ Supplier<T> delegate, long duration, TimeUnit unit) {
+ this.delegate = Preconditions.checkNotNull(delegate);
+ this.durationNanos = unit.toNanos(duration);
+ Preconditions.checkArgument(duration > 0);
+ }
+
+ @Override
+ public T get() {
+ // Another variant of Double Checked Locking.
+ //
+ // We use two volatile reads. We could reduce this to one by
+ // putting our fields into a holder class, but (at least on x86)
+ // the extra memory consumption and indirection are more
+ // expensive than the extra volatile reads.
+ long nanos = expirationNanos;
+ long now = Platform.systemNanoTime();
+ if (nanos == 0 || now - nanos >= 0) {
+ synchronized (this) {
+ if (nanos == expirationNanos) { // recheck for lost race
+ T t = delegate.get();
+ value = t;
+ nanos = now + durationNanos;
+ // In the very unlikely event that nanos is 0, set it to 1;
+ // no one will notice 1 ns of tardiness.
+ expirationNanos = (nanos == 0) ? 1 : nanos;
+ return t;
+ }
+ }
+ }
+ 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;
+ }
+
+ /**
+ * Returns a supplier that always supplies {@code instance}.
+ */
+ public static <T> Supplier<T> ofInstance(@Nullable T instance) {
+ return new SupplierOfInstance<T>(instance);
+ }
+
+ private static class SupplierOfInstance<T>
+ implements Supplier<T>, Serializable {
+ final T instance;
+
+ SupplierOfInstance(@Nullable T instance) {
+ this.instance = instance;
+ }
+
+ @Override
+ public T get() {
+ return instance;
+ }
+
+ @Override
+ public String toString() {
+ return "Suppliers.ofInstance(" + instance + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a supplier whose {@code get()} method synchronizes on
+ * {@code delegate} before calling it, making it thread-safe.
+ */
+ public static <T> Supplier<T> synchronizedSupplier(Supplier<T> delegate) {
+ return new ThreadSafeSupplier<T>(Preconditions.checkNotNull(delegate));
+ }
+
+ private static class ThreadSafeSupplier<T>
+ implements Supplier<T>, Serializable {
+ final Supplier<T> delegate;
+
+ ThreadSafeSupplier(Supplier<T> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public T get() {
+ synchronized (delegate) {
+ return delegate.get();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Suppliers.synchronizedSupplier(" + delegate + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a function that accepts a supplier and returns the result of
+ * invoking {@link Supplier#get} on that supplier.
+ *
+ * @since 8.0
+ */
+ @Beta
+ @SuppressWarnings("unchecked") // SupplierFunction works for any T.
+ public static <T> Function<Supplier<T>, T> supplierFunction() {
+ return (Function) SupplierFunction.INSTANCE;
+ }
+
+ private enum SupplierFunction implements Function<Supplier<?>, Object> {
+ INSTANCE;
+
+ @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
new file mode 100644
index 0000000..5e4d6ec
--- /dev/null
+++ b/guava/src/com/google/common/base/Throwables.java
@@ -0,0 +1,220 @@
+/*
+ * 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.base;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+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
+ */
+public final class Throwables {
+ private Throwables() {}
+
+ /**
+ * Propagates {@code throwable} exactly as-is, if and only if it is an
+ * instance of {@code declaredType}. Example usage:
+ * <pre>
+ * try {
+ * someMethodThatCouldThrowAnything();
+ * } catch (IKnowWhatToDoWithThisException e) {
+ * handle(e);
+ * } catch (Throwable t) {
+ * Throwables.propagateIfInstanceOf(t, IOException.class);
+ * Throwables.propagateIfInstanceOf(t, SQLException.class);
+ * throw Throwables.propagate(t);
+ * }
+ * </pre>
+ */
+ public static <X extends Throwable> void propagateIfInstanceOf(
+ @Nullable Throwable throwable, Class<X> declaredType) throws X {
+ // Check for null is needed to avoid frequent JNI calls to isInstance().
+ if (throwable != null && declaredType.isInstance(throwable)) {
+ throw declaredType.cast(throwable);
+ }
+ }
+
+ /**
+ * Propagates {@code throwable} exactly as-is, if and only if it is an
+ * instance of {@link RuntimeException} or {@link Error}. Example usage:
+ * <pre>
+ * try {
+ * someMethodThatCouldThrowAnything();
+ * } catch (IKnowWhatToDoWithThisException e) {
+ * handle(e);
+ * } catch (Throwable t) {
+ * Throwables.propagateIfPossible(t);
+ * throw new RuntimeException("unexpected", t);
+ * }
+ * </pre>
+ */
+ public static void propagateIfPossible(@Nullable Throwable throwable) {
+ propagateIfInstanceOf(throwable, Error.class);
+ propagateIfInstanceOf(throwable, RuntimeException.class);
+ }
+
+ /**
+ * Propagates {@code throwable} exactly as-is, if and only if it is an
+ * instance of {@link RuntimeException}, {@link Error}, or
+ * {@code declaredType}. Example usage:
+ * <pre>
+ * try {
+ * someMethodThatCouldThrowAnything();
+ * } catch (IKnowWhatToDoWithThisException e) {
+ * handle(e);
+ * } catch (Throwable t) {
+ * Throwables.propagateIfPossible(t, OtherException.class);
+ * throw new RuntimeException("unexpected", t);
+ * }
+ * </pre>
+ *
+ * @param throwable the Throwable to possibly propagate
+ * @param declaredType the single checked exception type declared by the
+ * calling method
+ */
+ public static <X extends Throwable> void propagateIfPossible(
+ @Nullable Throwable throwable, Class<X> declaredType) throws X {
+ propagateIfInstanceOf(throwable, declaredType);
+ propagateIfPossible(throwable);
+ }
+
+ /**
+ * Propagates {@code throwable} exactly as-is, if and only if it is an
+ * instance of {@link RuntimeException}, {@link Error}, {@code declaredType1},
+ * or {@code declaredType2}. In the unlikely case that you have three or more
+ * declared checked exception types, you can handle them all by invoking these
+ * methods repeatedly. See usage example in {@link
+ * #propagateIfPossible(Throwable, Class)}.
+ *
+ * @param throwable the Throwable to possibly propagate
+ * @param declaredType1 any checked exception type declared by the calling
+ * method
+ * @param declaredType2 any other checked exception type declared by the
+ * calling method
+ */
+ public static <X1 extends Throwable, X2 extends Throwable>
+ void propagateIfPossible(@Nullable Throwable throwable,
+ Class<X1> declaredType1, Class<X2> declaredType2) throws X1, X2 {
+ checkNotNull(declaredType2);
+ propagateIfInstanceOf(throwable, declaredType1);
+ propagateIfPossible(throwable, declaredType2);
+ }
+
+ /**
+ * Propagates {@code throwable} as-is if it is an instance of
+ * {@link RuntimeException} or {@link Error}, or else as a last resort, wraps
+ * it in a {@code RuntimeException} then propagates.
+ * <p>
+ * This method always throws an exception. The {@code RuntimeException} return
+ * type is only for client code to make Java type system happy in case a
+ * return value is required by the enclosing method. Example usage:
+ * <pre>
+ * T doSomething() {
+ * try {
+ * return someMethodThatCouldThrowAnything();
+ * } catch (IKnowWhatToDoWithThisException e) {
+ * return handle(e);
+ * } catch (Throwable t) {
+ * throw Throwables.propagate(t);
+ * }
+ * }
+ * </pre>
+ *
+ * @param throwable the Throwable to propagate
+ * @return nothing will ever be returned; this return type is only for your
+ * convenience, as illustrated in the example above
+ */
+ public static RuntimeException propagate(Throwable throwable) {
+ propagateIfPossible(checkNotNull(throwable));
+ throw new RuntimeException(throwable);
+ }
+
+ /**
+ * Returns the innermost cause of {@code throwable}. The first throwable in a
+ * chain provides context from when the error or exception was initially
+ * detected. Example usage:
+ * <pre>
+ * assertEquals("Unable to assign a customer id",
+ * Throwables.getRootCause(e).getMessage());
+ * </pre>
+ */
+ public static Throwable getRootCause(Throwable throwable) {
+ Throwable cause;
+ while ((cause = throwable.getCause()) != null) {
+ throwable = cause;
+ }
+ return throwable;
+ }
+
+ /**
+ * Gets a {@code Throwable} cause chain as a list. The first entry in the
+ * list will be {@code throwable} followed by its cause hierarchy. Note
+ * that this is a snapshot of the cause chain and will not reflect
+ * any subsequent changes to the cause chain.
+ *
+ * <p>Here's an example of how it can be used to find specific types
+ * of exceptions in the cause chain:
+ *
+ * <pre>
+ * Iterables.filter(Throwables.getCausalChain(e), IOException.class));
+ * </pre>
+ *
+ * @param throwable the non-null {@code Throwable} to extract causes from
+ * @return an unmodifiable list containing the cause chain starting with
+ * {@code throwable}
+ */
+ @Beta // TODO(kevinb): decide best return type
+ public static List<Throwable> getCausalChain(Throwable throwable) {
+ checkNotNull(throwable);
+ List<Throwable> causes = new ArrayList<Throwable>(4);
+ while (throwable != null) {
+ causes.add(throwable);
+ throwable = throwable.getCause();
+ }
+ return Collections.unmodifiableList(causes);
+ }
+
+ /**
+ * Returns a string containing the result of
+ * {@link Throwable#toString() toString()}, followed by the full, recursive
+ * stack trace of {@code throwable}. Note that you probably should not be
+ * parsing the resulting string; if you need programmatic access to the stack
+ * frames, you can call {@link Throwable#getStackTrace()}.
+ */
+ public static String getStackTraceAsString(Throwable throwable) {
+ StringWriter stringWriter = new StringWriter();
+ throwable.printStackTrace(new PrintWriter(stringWriter));
+ return stringWriter.toString();
+ }
+}
diff --git a/guava/src/com/google/common/base/Ticker.java b/guava/src/com/google/common/base/Ticker.java
new file mode 100644
index 0000000..6c34aef
--- /dev/null
+++ b/guava/src/com/google/common/base/Ticker.java
@@ -0,0 +1,63 @@
+/*
+ * 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 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.
+ *
+ * @author Kevin Bourrillion
+ * @since 10.0
+ * (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility"
+ * >mostly source-compatible</a> since 9.0)
+ */
+@Beta
+@GwtCompatible
+public abstract class Ticker {
+ /**
+ * Constructor for use by subclasses.
+ */
+ protected Ticker() {}
+
+ /**
+ * Returns the number of nanoseconds elapsed since this ticker's fixed
+ * point of reference.
+ */
+ public abstract long read();
+
+ /**
+ * A ticker that reads the current time using {@link System#nanoTime}.
+ *
+ * @since 10.0
+ */
+ public static Ticker systemTicker() {
+ return SYSTEM_TICKER;
+ }
+
+ private static final Ticker SYSTEM_TICKER = new Ticker() {
+ @Override
+ public long read() {
+ return Platform.systemNanoTime();
+ }
+ };
+}
diff --git a/guava/src/com/google/common/base/internal/Finalizer.java b/guava/src/com/google/common/base/internal/Finalizer.java
new file mode 100644
index 0000000..0934aa6
--- /dev/null
+++ b/guava/src/com/google/common/base/internal/Finalizer.java
@@ -0,0 +1,205 @@
+/*
+ * 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.base.internal;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Thread that finalizes referents. All references should implement
+ * {@code com.google.common.base.FinalizableReference}.
+ *
+ * <p>While this class is public, we consider it to be *internal* and not part
+ * of our published API. It is public so we can access it reflectively across
+ * class loaders in secure environments.
+ *
+ * <p>This class can't depend on other Google Collections code. If we were
+ * to load this class in the same class loader as the rest of
+ * Google Collections, this thread would keep an indirect strong reference
+ * to the class loader and prevent it from being garbage collected. This
+ * poses a problem for environments where you want to throw away the class
+ * loader. For example, dynamically reloading a web application or unloading
+ * an OSGi bundle.
+ *
+ * <p>{@code com.google.common.base.FinalizableReferenceQueue} loads this class
+ * in its own class loader. That way, this class doesn't prevent the main
+ * 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 {
+
+ private static final Logger logger
+ = Logger.getLogger(Finalizer.class.getName());
+
+ /** Name of FinalizableReference.class. */
+ private static final String FINALIZABLE_REFERENCE
+ = "com.google.common.base.FinalizableReference";
+
+ /**
+ * Starts the Finalizer thread. FinalizableReferenceQueue calls this method
+ * reflectively.
+ *
+ * @param finalizableReferenceClass FinalizableReference.class
+ * @param frq reference to instance of FinalizableReferenceQueue that started
+ * this thread
+ * @return ReferenceQueue which Finalizer will poll
+ */
+ public static ReferenceQueue<Object> startFinalizer(
+ Class<?> finalizableReferenceClass, Object frq) {
+ /*
+ * We use FinalizableReference.class for two things:
+ *
+ * 1) To invoke FinalizableReference.finalizeReferent()
+ *
+ * 2) To detect when FinalizableReference's class loader has to be garbage
+ * collected, at which point, Finalizer can stop running
+ */
+ if (!finalizableReferenceClass.getName().equals(FINALIZABLE_REFERENCE)) {
+ throw new IllegalArgumentException(
+ "Expected " + FINALIZABLE_REFERENCE + ".");
+ }
+
+ Finalizer finalizer = new Finalizer(finalizableReferenceClass, frq);
+ 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();
+ return finalizer.queue;
+ }
+
+ private final WeakReference<Class<?>> finalizableReferenceClassReference;
+ private final PhantomReference<Object> frqReference;
+ private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+
+ private static final Field inheritableThreadLocals
+ = getInheritableThreadLocalsField();
+
+ /** Constructs a new finalizer thread. */
+ private Finalizer(Class<?> finalizableReferenceClass, Object frq) {
+ this.finalizableReferenceClassReference
+ = new WeakReference<Class<?>>(finalizableReferenceClass);
+
+ // Keep track of the FRQ that started us so we know when to stop.
+ this.frqReference = new PhantomReference<Object>(frq, queue);
+ }
+
+ /**
+ * Loops continuously, pulling references off the queue and cleaning them up.
+ */
+ @SuppressWarnings("InfiniteLoopStatement")
+ @Override
+ public void run() {
+ try {
+ while (true) {
+ try {
+ cleanUp(queue.remove());
+ } catch (InterruptedException e) { /* ignore */ }
+ }
+ } catch (ShutDown shutDown) { /* ignore */ }
+ }
+
+ /**
+ * Cleans up a single reference. Catches and logs all throwables.
+ */
+ private void cleanUp(Reference<?> reference) throws ShutDown {
+ Method finalizeReferentMethod = getFinalizeReferentMethod();
+ do {
+ /*
+ * This is for the benefit of phantom references. Weak and soft
+ * references will have already been cleared by this point.
+ */
+ reference.clear();
+
+ if (reference == frqReference) {
+ /*
+ * The client no longer has a reference to the
+ * FinalizableReferenceQueue. We can stop.
+ */
+ throw new ShutDown();
+ }
+
+ try {
+ finalizeReferentMethod.invoke(reference);
+ } catch (Throwable t) {
+ logger.log(Level.SEVERE, "Error cleaning up after reference.", t);
+ }
+
+ /*
+ * Loop as long as we have references available so as not to waste
+ * CPU looking up the Method over and over again.
+ */
+ } while ((reference = queue.poll()) != null);
+ }
+
+ /**
+ * Looks up FinalizableReference.finalizeReferent() method.
+ */
+ private Method getFinalizeReferentMethod() throws ShutDown {
+ Class<?> finalizableReferenceClass
+ = finalizableReferenceClassReference.get();
+ if (finalizableReferenceClass == null) {
+ /*
+ * FinalizableReference's class loader was reclaimed. While there's a
+ * chance that other finalizable references could be enqueued
+ * subsequently (at which point the class loader would be resurrected
+ * by virtue of us having a strong reference to it), we should pretty
+ * much just shut down and make sure we don't keep it alive any longer
+ * than necessary.
+ */
+ throw new ShutDown();
+ }
+ try {
+ return finalizableReferenceClass.getMethod("finalizeReferent");
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static Field getInheritableThreadLocalsField() {
+ try {
+ Field inheritableThreadLocals
+ = Thread.class.getDeclaredField("inheritableThreadLocals");
+ inheritableThreadLocals.setAccessible(true);
+ return inheritableThreadLocals;
+ } catch (Throwable t) {
+ logger.log(Level.INFO, "Couldn't access Thread.inheritableThreadLocals."
+ + " Reference finalizer threads will inherit thread local"
+ + " values.");
+ return null;
+ }
+ }
+
+ /** 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 {}
+}
diff --git a/guava/src/com/google/common/base/package-info.java b/guava/src/com/google/common/base/package-info.java
new file mode 100644
index 0000000..66e7177
--- /dev/null
+++ b/guava/src/com/google/common/base/package-info.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/**
+ * Basic utility libraries and interfaces.
+ *
+ * <p>This package is a part of the open-source
+ * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
+ *
+ * <h2>Contents</h2>
+ *
+ * <h3>String-related utilities</h3>
+ *
+ * <ul>
+ * <li>{@link com.google.common.base.Ascii}
+ * <li>{@link com.google.common.base.CaseFormat}
+ * <li>{@link com.google.common.base.CharMatcher}
+ * <li>{@link com.google.common.base.Charsets}
+ * <li>{@link com.google.common.base.Joiner}
+ * <li>{@link com.google.common.base.Splitter}
+ * <li>{@link com.google.common.base.Strings}
+ * </ul>
+ *
+ * <h3>Function types</h3>
+ *
+ * <ul>
+ * <li>{@link com.google.common.base.Function},
+ * {@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},
+ * {@link com.google.common.base.Equivalences}
+ * <li>{@link com.google.common.base.Supplier},
+ * {@link com.google.common.base.Suppliers}
+ * </ul>
+ *
+ * <h3>Other</h3>
+ *
+ * <ul>
+ * <li>{@link com.google.common.base.Defaults}
+ * <li>{@link com.google.common.base.Enums}
+ * <li>{@link com.google.common.base.Objects}
+ * <li>{@link com.google.common.base.Optional}
+ * <li>{@link com.google.common.base.Preconditions}
+ * <li>{@link com.google.common.base.Stopwatch}
+ * <li>{@link com.google.common.base.Throwables}
+ * </ul>
+ *
+ */
+@ParametersAreNonnullByDefault
+package com.google.common.base;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/guava/src/com/google/common/cache/AbstractCache.java b/guava/src/com/google/common/cache/AbstractCache.java
new file mode 100644
index 0000000..0d98a2d
--- /dev/null
+++ b/guava/src/com/google/common/cache/AbstractCache.java
@@ -0,0 +1,275 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * 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
+ * {@link UnsupportedOperationException}.
+ *
+ * @author Charles Fry
+ * @since 10.0
+ */
+@Beta
+@GwtCompatible
+public abstract class AbstractCache<K, V> implements Cache<K, V> {
+
+ /** Constructor for use by subclasses. */
+ protected AbstractCache() {}
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ public V get(K key, Callable<? extends V> valueLoader) throws ExecutionException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * 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) {
+ Map<K, V> result = Maps.newLinkedHashMap();
+ for (Object key : keys) {
+ if (!result.containsKey(key)) {
+ @SuppressWarnings("unchecked")
+ K castKey = (K) key;
+ result.put(castKey, getIfPresent(key));
+ }
+ }
+ return ImmutableMap.copyOf(result);
+ }
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ public void put(K key, V value) {
+ 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() {}
+
+ @Override
+ public long size() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ public void invalidateAll(Iterable<?> keys) {
+ for (Object key : keys) {
+ invalidate(key);
+ }
+ }
+
+ @Override
+ public void invalidateAll() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public CacheStats stats() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ConcurrentMap<K, V> asMap() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * 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.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public interface StatsCounter {
+ /**
+ * Records cache hits. This should be called when a cache request returns a cached value.
+ *
+ * @param count the number of hits to record
+ * @since 11.0
+ */
+ public void recordHits(int count);
+
+ /**
+ * Records cache misses. This should be called when a cache request returns a value that was
+ * not found in the cache. This method should be called by the loading thread, as well as by
+ * threads blocking on the load. Multiple concurrent calls to {@link Cache} lookup methods with
+ * the same key on an absent value should result in a single call to either
+ * {@code recordLoadSuccess} or {@code recordLoadException} and multiple calls to this method,
+ * despite all being served by the results of a single load operation.
+ *
+ * @param count the number of misses to record
+ * @since 11.0
+ */
+ public void recordMisses(int count);
+
+ /**
+ * 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.
+ *
+ * @param loadTime the number of nanoseconds the cache spent computing or retrieving the new
+ * value
+ */
+ public void recordLoadSuccess(long loadTime);
+
+ /**
+ * 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.
+ *
+ * @param loadTime the number of nanoseconds the cache spent computing or retrieving the new
+ * value prior to an exception being thrown
+ */
+ public void recordLoadException(long loadTime);
+
+ /**
+ * Records the eviction of an entry from the cache. This should only been called when an entry
+ * is evicted due to the cache's eviction strategy, and not as a result of manual {@linkplain
+ * Cache#invalidate invalidations}.
+ */
+ public void recordEviction();
+
+ /**
+ * Returns a snapshot of this counter's values. Note that this may be an inconsistent view, as
+ * it may be interleaved with update operations.
+ */
+ public CacheStats snapshot();
+ }
+
+ /**
+ * A thread-safe {@link StatsCounter} implementation for use by {@link Cache} implementors.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public static final class SimpleStatsCounter implements StatsCounter {
+ private final LongAdder hitCount = new LongAdder();
+ private final LongAdder missCount = new LongAdder();
+ private final LongAdder loadSuccessCount = new LongAdder();
+ private final LongAdder loadExceptionCount = new LongAdder();
+ private final LongAdder totalLoadTime = new LongAdder();
+ private final LongAdder evictionCount = new LongAdder();
+
+ /**
+ * Constructs an instance with all counts initialized to zero.
+ */
+ public SimpleStatsCounter() {}
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ public void recordHits(int count) {
+ hitCount.add(count);
+ }
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ public void recordMisses(int count) {
+ missCount.add(count);
+ }
+
+ @Override
+ public void recordLoadSuccess(long loadTime) {
+ loadSuccessCount.increment();
+ totalLoadTime.add(loadTime);
+ }
+
+ @Override
+ public void recordLoadException(long loadTime) {
+ loadExceptionCount.increment();
+ totalLoadTime.add(loadTime);
+ }
+
+ @Override
+ public void recordEviction() {
+ evictionCount.increment();
+ }
+
+ @Override
+ public CacheStats snapshot() {
+ return new CacheStats(
+ hitCount.sum(),
+ missCount.sum(),
+ loadSuccessCount.sum(),
+ loadExceptionCount.sum(),
+ totalLoadTime.sum(),
+ evictionCount.sum());
+ }
+
+ /**
+ * Increments all counters by the values in {@code other}.
+ */
+ 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());
+ }
+ }
+}
diff --git a/guava/src/com/google/common/cache/AbstractLoadingCache.java b/guava/src/com/google/common/cache/AbstractLoadingCache.java
new file mode 100644
index 0000000..6a12c40
--- /dev/null
+++ b/guava/src/com/google/common/cache/AbstractLoadingCache.java
@@ -0,0 +1,79 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+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.ExecutionException;
+
+/**
+ * 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 #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
+ * methods throw an {@link UnsupportedOperationException}.
+ *
+ * @author Charles Fry
+ * @since 11.0
+ */
+@Beta
+public abstract class AbstractLoadingCache<K, V>
+ extends AbstractCache<K, V> implements LoadingCache<K, V> {
+
+ /** Constructor for use by subclasses. */
+ protected AbstractLoadingCache() {}
+
+ @Override
+ public V getUnchecked(K key) {
+ try {
+ return get(key);
+ } catch (ExecutionException e) {
+ throw new UncheckedExecutionException(e.getCause());
+ }
+ }
+
+ @Override
+ public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
+ Map<K, V> result = Maps.newLinkedHashMap();
+ for (K key : keys) {
+ if (!result.containsKey(key)) {
+ result.put(key, get(key));
+ }
+ }
+ return ImmutableMap.copyOf(result);
+ }
+
+ @Override
+ public final V apply(K key) {
+ return getUnchecked(key);
+ }
+
+ @Override
+ public void refresh(K key) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/guava/src/com/google/common/cache/Cache.java b/guava/src/com/google/common/cache/Cache.java
new file mode 100644
index 0000000..cfe5764
--- /dev/null
+++ b/guava/src/com/google/common/cache/Cache.java
@@ -0,0 +1,147 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+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;
+
+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.
+ *
+ * <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.
+ *
+ * @author Charles Fry
+ * @since 10.0
+ */
+@Beta
+@GwtCompatible
+public interface Cache<K, V> {
+
+ /**
+ * Returns the value associated with {@code key} in this cache, or {@code null} if there is no
+ * cached value for {@code key}.
+ *
+ * @since 11.0
+ */
+ @Nullable
+ V getIfPresent(Object key);
+
+ /**
+ * Returns the value associated with {@code key} in this cache, obtaining that value from
+ * {@code valueLoader} if necessary. No observable state associated with this cache is modified
+ * until loading completes. This method provides a simple substitute for the conventional
+ * "if cached, return; otherwise create, cache and return" pattern.
+ *
+ * <p><b>Warning:</b> as with {@link CacheLoader#load}, {@code valueLoader} <b>must not</b> return
+ * {@code null}; it may either return a non-null value or throw an exception.
+ *
+ * @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
+ *
+ * @since 11.0
+ */
+ V get(K key, Callable<? extends V> valueLoader) throws ExecutionException;
+
+ /**
+ * Returns a map of the values associated with {@code keys} in this cache. The returned map will
+ * only contain entries which are already present in the cache.
+ *
+ * @since 11.0
+ */
+ ImmutableMap<K, V> getAllPresent(Iterable<?> keys);
+
+ /**
+ * Associates {@code value} with {@code key} in this cache. If the cache previously contained a
+ * value associated with {@code key}, the old value is replaced by {@code value}.
+ *
+ * <p>Prefer {@link #get(Object, Callable)} when using the conventional "if cached, return;
+ * otherwise create, cache and return" pattern.
+ *
+ * @since 11.0
+ */
+ 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);
+
+ /**
+ * Discards any cached values for keys {@code keys}.
+ *
+ * @since 11.0
+ */
+ void invalidateAll(Iterable<?> keys);
+
+ /**
+ * Discards all entries in the cache.
+ */
+ void invalidateAll();
+
+ /**
+ * Returns the approximate number of entries in this cache.
+ */
+ long size();
+
+ /**
+ * Returns a current snapshot of this cache's cumulative statistics. All stats are initialized
+ * to zero, and are monotonically increasing over the lifetime of the cache.
+ */
+ CacheStats stats();
+
+ /**
+ * Returns a view of the entries stored in this cache as a thread-safe map. Modifications made to
+ * the map directly affect the cache.
+ */
+ ConcurrentMap<K, V> asMap();
+
+ /**
+ * Performs any pending maintenance operations needed by the cache. Exactly which activities are
+ * performed -- if any -- is implementation-dependent.
+ */
+ void cleanUp();
+}
diff --git a/guava/src/com/google/common/cache/CacheBuilder.java b/guava/src/com/google/common/cache/CacheBuilder.java
new file mode 100644
index 0000000..28a056f
--- /dev/null
+++ b/guava/src/com/google/common/cache/CacheBuilder.java
@@ -0,0 +1,888 @@
+/*
+ * 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.cache;
+
+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 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.Equivalence;
+import com.google.common.base.Objects;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.base.Ticker;
+import com.google.common.cache.AbstractCache.SimpleStatsCounter;
+import com.google.common.cache.AbstractCache.StatsCounter;
+import com.google.common.cache.LocalCache.Strength;
+
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.ConcurrentModificationException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.annotation.CheckReturnValue;
+
+/**
+ * <p>A builder of {@link LoadingCache} and {@link Cache} instances having any combination of the
+ * following features:
+ *
+ * <ul>
+ * <li>automatic loading of entries into the cache
+ * <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>keys automatically wrapped in {@linkplain WeakReference weak} references
+ * <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()
+ * .maximumSize(10000)
+ * .expireAfterWrite(10, TimeUnit.MINUTES)
+ * .removalListener(MY_LISTENER)
+ * .build(
+ * new CacheLoader<Key, Graph>() {
+ * public Graph load(Key key) throws AnyException {
+ * return createExpensiveGraph(key);
+ * }
+ * });}</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>
+ *
+ * <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
+ * {@link Cache} interfaces. The {@code asMap} view (and its collection views) have <i>weakly
+ * consistent iterators</i>. This means that they are safe for concurrent use, but if other threads
+ * modify the cache after the iterator is created, it is undefined which of these changes, if any,
+ * are reflected in that iterator. These iterators never throw {@link
+ * ConcurrentModificationException}.
+ *
+ * <p><b>Note:</b> by default, the returned cache uses equality comparisons (the
+ * {@link Object#equals equals} method) to determine equality for keys or values. However, if
+ * {@link #weakKeys} was specified, the cache uses identity ({@code ==})
+ * comparisons instead for keys. Likewise, if {@link #weakValues} or {@link #softValues} was
+ * specified, the cache uses identity comparisons for values.
+ *
+ * <p>Entries are automatically evicted from the cache when any of
+ * {@linkplain #maximumSize(long) maximumSize}, {@linkplain #maximumWeight(long) maximumWeight},
+ * {@linkplain #expireAfterWrite expireAfterWrite},
+ * {@linkplain #expireAfterAccess expireAfterAccess}, {@linkplain #weakKeys weakKeys},
+ * {@linkplain #weakValues weakValues}, or {@linkplain #softValues softValues} are requested.
+ *
+ * <p>If {@linkplain #maximumSize(long) maximumSize} or
+ * {@linkplain #maximumWeight(long) maximumWeight} is requested entries may be evicted on each cache
+ * modification.
+ *
+ * <p>If {@linkplain #expireAfterWrite expireAfterWrite} or
+ * {@linkplain #expireAfterAccess expireAfterAccess} is requested entries may be evicted on each
+ * cache modification, on occasional cache accesses, or on calls to {@link Cache#cleanUp}. Expired
+ * entries may be counted in {@link Cache#size}, but will never be visible to read or write
+ * operations.
+ *
+ * <p>If {@linkplain #weakKeys weakKeys}, {@linkplain #weakValues weakValues}, or
+ * {@linkplain #softValues softValues} are requested, it is possible for a key or value present in
+ * the cache to be reclaimed by the garbage collector. Entries with reclaimed keys or values may be
+ * removed from the cache on each cache modification, on occasional cache accesses, or on calls to
+ * {@link Cache#cleanUp}; such entries may be counted in {@link Cache#size}, but will never be
+ * visible to read or write operations.
+ *
+ * <p>Certain cache configurations will result in the accrual of periodic maintenance tasks which
+ * will be performed during write operations, or during occasional read operations in the absense of
+ * writes. The {@link Cache#cleanUp} method of the returned cache will also perform maintenance, but
+ * calling it should not be necessary with a high throughput cache. Only caches built with
+ * {@linkplain #removalListener removalListener}, {@linkplain #expireAfterWrite expireAfterWrite},
+ * {@linkplain #expireAfterAccess expireAfterAccess}, {@linkplain #weakKeys weakKeys},
+ * {@linkplain #weakValues weakValues}, or {@linkplain #softValues softValues} perform periodic
+ * maintenance.
+ *
+ * <p>The caches produced by {@code CacheBuilder} are serializable, and the deserialized caches
+ * 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
+ */
+@GwtCompatible(emulated = true)
+public final class CacheBuilder<K, V> {
+ private static final int DEFAULT_INITIAL_CAPACITY = 16;
+ private static final int DEFAULT_CONCURRENCY_LEVEL = 4;
+ private static final int DEFAULT_EXPIRATION_NANOS = 0;
+ private static final int DEFAULT_REFRESH_NANOS = 0;
+
+ static final Supplier<? extends StatsCounter> NULL_STATS_COUNTER = Suppliers.ofInstance(
+ new StatsCounter() {
+ @Override
+ public void recordHits(int count) {}
+
+ @Override
+ public void recordMisses(int count) {}
+
+ @Override
+ public void recordLoadSuccess(long loadTime) {}
+
+ @Override
+ public void recordLoadException(long loadTime) {}
+
+ @Override
+ public void recordEviction() {}
+
+ @Override
+ public CacheStats snapshot() {
+ return EMPTY_STATS;
+ }
+ });
+ static final CacheStats EMPTY_STATS = new CacheStats(0, 0, 0, 0, 0, 0);
+
+ static final Supplier<StatsCounter> CACHE_STATS_COUNTER =
+ new Supplier<StatsCounter>() {
+ @Override
+ public StatsCounter get() {
+ return new SimpleStatsCounter();
+ }
+ };
+
+ enum NullListener implements RemovalListener<Object, Object> {
+ INSTANCE;
+
+ @Override
+ public void onRemoval(RemovalNotification<Object, Object> notification) {}
+ }
+
+ enum OneWeigher implements Weigher<Object, Object> {
+ INSTANCE;
+
+ @Override
+ public int weigh(Object key, Object value) {
+ return 1;
+ }
+ }
+
+ static final Ticker NULL_TICKER = new Ticker() {
+ @Override
+ public long read() {
+ return 0;
+ }
+ };
+
+ private static final Logger logger = Logger.getLogger(CacheBuilder.class.getName());
+
+ static final int UNSET_INT = -1;
+
+ boolean strictParsing = true;
+
+ int initialCapacity = UNSET_INT;
+ int concurrencyLevel = UNSET_INT;
+ long maximumSize = UNSET_INT;
+ long maximumWeight = UNSET_INT;
+ Weigher<? super K, ? super V> weigher;
+
+ Strength keyStrength;
+ Strength valueStrength;
+
+ long expireAfterWriteNanos = UNSET_INT;
+ long expireAfterAccessNanos = UNSET_INT;
+ long refreshNanos = UNSET_INT;
+
+ Equivalence<Object> keyEquivalence;
+ Equivalence<Object> valueEquivalence;
+
+ RemovalListener<? super K, ? super V> removalListener;
+ Ticker ticker;
+
+ Supplier<? extends StatsCounter> statsCounterSupplier = NULL_STATS_COUNTER;
+
+ // TODO(fry): make constructor private and update tests to use newBuilder
+ CacheBuilder() {}
+
+ /**
+ * Constructs a new {@code CacheBuilder} instance with default settings, including strong keys,
+ * strong values, and no automatic eviction of any kind.
+ */
+ public static CacheBuilder<Object, Object> newBuilder() {
+ return new CacheBuilder<Object, Object>();
+ }
+
+ /**
+ * 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.
+ */
+ CacheBuilder<K, V> lenientParsing() {
+ strictParsing = false;
+ return this;
+ }
+
+ /**
+ * 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.
+ */
+ CacheBuilder<K, V> keyEquivalence(Equivalence<Object> equivalence) {
+ checkState(keyEquivalence == null, "key equivalence was already set to %s", keyEquivalence);
+ keyEquivalence = checkNotNull(equivalence);
+ return this;
+ }
+
+ Equivalence<Object> getKeyEquivalence() {
+ return firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
+ }
+
+ /**
+ * 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()}
+ * otherwise.
+ */
+ CacheBuilder<K, V> valueEquivalence(Equivalence<Object> equivalence) {
+ checkState(valueEquivalence == null,
+ "value equivalence was already set to %s", valueEquivalence);
+ this.valueEquivalence = checkNotNull(equivalence);
+ 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
+ * avoids the need for expensive resizing operations later, but setting this value unnecessarily
+ * high wastes memory.
+ *
+ * @throws IllegalArgumentException if {@code initialCapacity} is negative
+ * @throws IllegalStateException if an initial capacity was already set
+ */
+ public CacheBuilder<K, V> initialCapacity(int initialCapacity) {
+ checkState(this.initialCapacity == UNSET_INT, "initial capacity was already set to %s",
+ this.initialCapacity);
+ checkArgument(initialCapacity >= 0);
+ this.initialCapacity = initialCapacity;
+ return this;
+ }
+
+ int getInitialCapacity() {
+ return (initialCapacity == UNSET_INT) ? DEFAULT_INITIAL_CAPACITY : initialCapacity;
+ }
+
+ /**
+ * Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The
+ * table is internally partitioned to try to permit the indicated number of concurrent updates
+ * without contention. Because assignment of entries to these partitions is not necessarily
+ * uniform, the actual concurrency observed may vary. Ideally, you should choose a value to
+ * accommodate as many threads as will ever concurrently modify the table. Using a significantly
+ * 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.
+ *
+ * <p>Note that future implementations may abandon segment locking in favor of more advanced
+ * concurrency controls.
+ *
+ * @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive
+ * @throws IllegalStateException if a concurrency level was already set
+ */
+ public CacheBuilder<K, V> concurrencyLevel(int concurrencyLevel) {
+ checkState(this.concurrencyLevel == UNSET_INT, "concurrency level was already set to %s",
+ this.concurrencyLevel);
+ checkArgument(concurrencyLevel > 0);
+ this.concurrencyLevel = concurrencyLevel;
+ return this;
+ }
+
+ int getConcurrencyLevel() {
+ return (concurrencyLevel == UNSET_INT) ? DEFAULT_CONCURRENCY_LEVEL : concurrencyLevel;
+ }
+
+ /**
+ * Specifies the maximum number of entries the cache may contain. Note that the cache <b>may evict
+ * an entry before this limit is exceeded</b>. As the cache size grows close to the maximum, the
+ * cache evicts entries that are less likely to be used again. For example, the cache may evict an
+ * entry because it hasn't been used recently or very often.
+ *
+ * <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
+ */
+ public CacheBuilder<K, V> maximumSize(long size) {
+ checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
+ this.maximumSize);
+ checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s",
+ this.maximumWeight);
+ checkState(this.weigher == null, "maximum size can not be combined with weigher");
+ checkArgument(size >= 0, "maximum size must not be negative");
+ this.maximumSize = size;
+ return this;
+ }
+
+ /**
+ * Specifies the maximum weight of entries the cache may contain. Weight is determined using the
+ * {@link Weigher} specified with {@link #weigher}, and use of this method requires a
+ * corresponding call to {@link #weigher} prior to calling {@link #build}.
+ *
+ * <p>Note that the cache <b>may evict an entry before this limit is exceeded</b>. As the cache
+ * size grows close to the maximum, the cache evicts entries that are less likely to be used
+ * again. For example, the cache may evict an entry because it hasn't been used recently or very
+ * often.
+ *
+ * <p>When {@code weight} is zero, elements will be evicted immediately after being loaded into
+ * 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
+ * @since 11.0
+ */
+ public CacheBuilder<K, V> maximumWeight(long weight) {
+ checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s",
+ this.maximumWeight);
+ checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
+ this.maximumSize);
+ this.maximumWeight = weight;
+ checkArgument(weight >= 0, "maximum weight must not be negative");
+ return this;
+ }
+
+ /**
+ * Specifies the weigher to use in determining the weight of entries. Entry weight is taken
+ * into consideration by {@link #maximumWeight(long)} when determining which entries to evict, and
+ * use of this method requires a corresponding call to {@link #maximumWeight(long)} prior to
+ * calling {@link #build}. Weights are measured and recorded when entries are inserted into the
+ * cache, and are thus effectively static during the lifetime of a cache entry.
+ *
+ * <p>When the weight of an entry is zero it will not be considered for size-based eviction
+ * (though it still may be evicted by other means).
+ *
+ * <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
+ * weigher 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 weigher, you will likely experience
+ * a {@link ClassCastException} at some <i>undefined</i> point in the future.
+ *
+ * @param weigher the weigher to use in calculating the weight of cache entries
+ * @throws IllegalArgumentException if {@code size} is negative
+ * @throws IllegalStateException if a maximum size was already set
+ * @since 11.0
+ */
+ public <K1 extends K, V1 extends V> CacheBuilder<K1, V1> weigher(
+ Weigher<? super K1, ? super V1> weigher) {
+ checkState(this.weigher == null);
+ if (strictParsing) {
+ checkState(this.maximumSize == UNSET_INT, "weigher can not be combined with maximum size",
+ this.maximumSize);
+ }
+
+ // safely limiting the kinds of caches this can produce
+ @SuppressWarnings("unchecked")
+ CacheBuilder<K1, V1> me = (CacheBuilder<K1, V1>) this;
+ me.weigher = checkNotNull(weigher);
+ return me;
+ }
+
+ long getMaximumWeight() {
+ if (expireAfterWriteNanos == 0 || expireAfterAccessNanos == 0) {
+ return 0;
+ }
+ return (weigher == null) ? maximumSize : maximumWeight;
+ }
+
+ // Make a safe contravariant cast now so we don't have to do it over and over.
+ @SuppressWarnings("unchecked")
+ <K1 extends K, V1 extends V> Weigher<K1, V1> getWeigher() {
+ return (Weigher<K1, V1>) Objects.firstNonNull(weigher, OneWeigher.INSTANCE);
+ }
+
+ /**
+ * 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).
+ *
+ * <p><b>Warning:</b> when this method is used, the resulting cache will use identity ({@code ==})
+ * comparison to determine equality of keys.
+ *
+ * <p>Entries with keys that have been garbage collected may be counted in {@link Cache#size},
+ * but will never be visible to read or write operations; such entries are cleaned up as part of
+ * the routine maintenance described in the class javadoc.
+ *
+ * @throws IllegalStateException if the key strength was already set
+ */
+ @GwtIncompatible("java.lang.ref.WeakReference")
+ public CacheBuilder<K, V> weakKeys() {
+ return setKeyStrength(Strength.WEAK);
+ }
+
+ CacheBuilder<K, V> setKeyStrength(Strength strength) {
+ checkState(keyStrength == null, "Key strength was already set to %s", keyStrength);
+ keyStrength = checkNotNull(strength);
+ return this;
+ }
+
+ Strength getKeyStrength() {
+ return firstNonNull(keyStrength, Strength.STRONG);
+ }
+
+ /**
+ * 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).
+ *
+ * <p>Weak values will be garbage collected once they are weakly reachable. This makes them a poor
+ * candidate for caching; consider {@link #softValues} instead.
+ *
+ * <p><b>Note:</b> when this method is used, the resulting cache will use identity ({@code ==})
+ * comparison to determine equality of values.
+ *
+ * <p>Entries with values that have been garbage collected may be counted in {@link Cache#size},
+ * but will never be visible to read or write operations; such entries are cleaned up as part of
+ * the routine maintenance described in the class javadoc.
+ *
+ * @throws IllegalStateException if the value strength was already set
+ */
+ @GwtIncompatible("java.lang.ref.WeakReference")
+ public CacheBuilder<K, V> weakValues() {
+ return setValueStrength(Strength.WEAK);
+ }
+
+ /**
+ * Specifies that each value (not key) stored in the cache 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> in most circumstances it is better to set a per-cache {@linkplain
+ * #maximumSize(long) maximum size} instead of using soft references. You should only use this
+ * method if you are well familiar with the practical consequences of soft references.
+ *
+ * <p><b>Note:</b> when this method is used, the resulting cache will use identity ({@code ==})
+ * comparison to determine equality of values.
+ *
+ * <p>Entries with values that have been garbage collected may be counted in {@link Cache#size},
+ * but will never be visible to read or write operations; such entries are cleaned up as part of
+ * the routine maintenance described in the class javadoc.
+ *
+ * @throws IllegalStateException if the value strength was already set
+ */
+ @GwtIncompatible("java.lang.ref.SoftReference")
+ public CacheBuilder<K, V> softValues() {
+ return setValueStrength(Strength.SOFT);
+ }
+
+ CacheBuilder<K, V> setValueStrength(Strength strength) {
+ checkState(valueStrength == null, "Value strength was already set to %s", valueStrength);
+ valueStrength = checkNotNull(strength);
+ return this;
+ }
+
+ Strength getValueStrength() {
+ return firstNonNull(valueStrength, Strength.STRONG);
+ }
+
+ /**
+ * Specifies that each entry should be automatically removed from the cache once a fixed duration
+ * has elapsed after the entry's creation, or the most recent replacement of its value.
+ *
+ * <p>When {@code duration} is zero, this method hands off to
+ * {@link #maximumSize(long) maximumSize}{@code (0)}, ignoring any otherwise-specificed maximum
+ * size or weight. This can be useful in testing, or to disable caching temporarily without a code
+ * change.
+ *
+ * <p>Expired entries may be counted in {@link Cache#size}, but will never be visible to read or
+ * write operations. Expired entries are cleaned up as part of the routine maintenance described
+ * in the class javadoc.
+ *
+ * @param duration the length of time after an entry is created that it should be automatically
+ * removed
+ * @param unit the unit that {@code duration} is expressed in
+ * @throws IllegalArgumentException if {@code duration} is negative
+ * @throws IllegalStateException if the time to live or time to idle was already set
+ */
+ public CacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
+ checkState(expireAfterWriteNanos == UNSET_INT, "expireAfterWrite was already set to %s ns",
+ expireAfterWriteNanos);
+ checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
+ this.expireAfterWriteNanos = unit.toNanos(duration);
+ return this;
+ }
+
+ long getExpireAfterWriteNanos() {
+ return (expireAfterWriteNanos == UNSET_INT) ? DEFAULT_EXPIRATION_NANOS : expireAfterWriteNanos;
+ }
+
+ /**
+ * Specifies that each entry should be automatically removed from the cache once a fixed duration
+ * has elapsed after the entry's creation, the most recent replacement of its value, or its last
+ * access. Access time is reset by all cache read and write operations (including
+ * {@code Cache.asMap().get(Object)} and {@code Cache.asMap().put(K, V)}), but not by operations
+ * on the collection-views of {@link Cache#asMap}.
+ *
+ * <p>When {@code duration} is zero, this method hands off to
+ * {@link #maximumSize(long) maximumSize}{@code (0)}, ignoring any otherwise-specificed maximum
+ * size or weight. This can be useful in testing, or to disable caching temporarily without a code
+ * change.
+ *
+ * <p>Expired entries may be counted in {@link Cache#size}, but will never be visible to read or
+ * write operations. Expired entries are cleaned up as part of the routine maintenance described
+ * in the class javadoc.
+ *
+ * @param duration the length of time after an entry is last accessed that it should be
+ * automatically removed
+ * @param unit the unit that {@code duration} is expressed in
+ * @throws IllegalArgumentException if {@code duration} is negative
+ * @throws IllegalStateException if the time to idle or time to live was already set
+ */
+ public CacheBuilder<K, V> expireAfterAccess(long duration, TimeUnit unit) {
+ checkState(expireAfterAccessNanos == UNSET_INT, "expireAfterAccess was already set to %s ns",
+ expireAfterAccessNanos);
+ checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
+ this.expireAfterAccessNanos = unit.toNanos(duration);
+ return this;
+ }
+
+ long getExpireAfterAccessNanos() {
+ return (expireAfterAccessNanos == UNSET_INT)
+ ? DEFAULT_EXPIRATION_NANOS : expireAfterAccessNanos;
+ }
+
+ /**
+ * Specifies that active entries are eligible for automatic refresh once a fixed duration has
+ * elapsed after the entry's creation, or the most recent replacement of its value. The semantics
+ * of refreshes are specified in {@link LoadingCache#refresh}, and are performed by calling
+ * {@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.
+ *
+ * <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}
+ * and immediately return the new value if the returned future is complete, and the old value
+ * otherwise.
+ *
+ * <p><b>Note:</b> <i>all exceptions thrown during refresh will be logged and then swallowed</i>.
+ *
+ * @param duration the length of time after an entry is created that it should be considered
+ * stale, and thus eligible for refresh
+ * @param unit the unit that {@code duration} is expressed in
+ * @throws IllegalArgumentException if {@code duration} is negative
+ * @throws IllegalStateException if the refresh interval was already set
+ * @since 11.0
+ */
+ @Beta
+ @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);
+ checkArgument(duration > 0, "duration must be positive: %s %s", duration, unit);
+ this.refreshNanos = unit.toNanos(duration);
+ return this;
+ }
+
+ long getRefreshNanos() {
+ return (refreshNanos == UNSET_INT) ? DEFAULT_REFRESH_NANOS : refreshNanos;
+ }
+
+ /**
+ * Specifies a nanosecond-precision time source for use in determining when entries should be
+ * expired. By default, {@link System#nanoTime} is used.
+ *
+ * <p>The primary intent of this method is to facilitate testing of caches which have been
+ * configured with {@link #expireAfterWrite} or {@link #expireAfterAccess}.
+ *
+ * @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);
+ return this;
+ }
+
+ Ticker getTicker(boolean recordsTime) {
+ if (ticker != null) {
+ return ticker;
+ }
+ return recordsTime ? Ticker.systemTicker() : NULL_TICKER;
+ }
+
+ /**
+ * 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);
+
+ // safely limiting the kinds of caches this can produce
+ @SuppressWarnings("unchecked")
+ CacheBuilder<K1, V1> me = (CacheBuilder<K1, V1>) this;
+ me.removalListener = checkNotNull(listener);
+ return me;
+ }
+
+ // Make a safe contravariant cast now so we don't have to do it over and over.
+ @SuppressWarnings("unchecked")
+ <K1 extends K, V1 extends V> RemovalListener<K1, V1> getRemovalListener() {
+ return (RemovalListener<K1, V1>) Objects.firstNonNull(removalListener, NullListener.INSTANCE);
+ }
+
+ /**
+ * 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)
+ */
+ public CacheBuilder<K, V> recordStats() {
+ statsCounterSupplier = CACHE_STATS_COUNTER;
+ return this;
+ }
+
+ Supplier<? extends StatsCounter> getStatsCounterSupplier() {
+ return statsCounterSupplier;
+ }
+
+ /**
+ * Builds a cache, which either returns an already-loaded value for a given key or atomically
+ * computes or retrieves it using the supplied {@code CacheLoader}. If another thread is currently
+ * loading the value for this key, simply waits for that thread to finish and returns its
+ * loaded value. Note that multiple threads can concurrently load values for distinct keys.
+ *
+ * <p>This method does not alter the state of this {@code CacheBuilder} instance, so it can be
+ * invoked again to create multiple independent caches.
+ *
+ * @param loader the cache loader used to obtain new values
+ * @return a cache having the requested features
+ */
+ public <K1 extends K, V1 extends V> LoadingCache<K1, V1> build(
+ CacheLoader<? super K1, V1> loader) {
+ checkWeightWithWeigher();
+ return new LocalCache.LocalLoadingCache<K1, V1>(this, loader);
+ }
+
+ /**
+ * Builds a cache which does not automatically load values when keys are requested.
+ *
+ * <p>Consider {@link #build(CacheLoader)} instead, if it is feasible to implement a
+ * {@code CacheLoader}.
+ *
+ * <p>This method does not alter the state of this {@code CacheBuilder} instance, so it can be
+ * invoked again to create multiple independent caches.
+ *
+ * @return a cache having the requested features
+ * @since 11.0
+ */
+ public <K1 extends K, V1 extends V> Cache<K1, V1> build() {
+ checkWeightWithWeigher();
+ checkNonLoadingCache();
+ return new LocalCache.LocalManualCache<K1, V1>(this);
+ }
+
+ private void checkNonLoadingCache() {
+ checkState(refreshNanos == UNSET_INT, "refreshAfterWrite requires a LoadingCache");
+ }
+
+ private void checkWeightWithWeigher() {
+ if (weigher == null) {
+ checkState(maximumWeight == UNSET_INT, "maximumWeight requires weigher");
+ } else {
+ if (strictParsing) {
+ checkState(maximumWeight != UNSET_INT, "weigher requires maximumWeight");
+ } else {
+ if (maximumWeight == UNSET_INT) {
+ logger.log(Level.WARNING, "ignoring weigher specified without maximumWeight");
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns a string representation for this CacheBuilder instance. The exact form of the returned
+ * string is not specified.
+ */
+ @Override
+ public String toString() {
+ Objects.ToStringHelper s = Objects.toStringHelper(this);
+ if (initialCapacity != UNSET_INT) {
+ s.add("initialCapacity", initialCapacity);
+ }
+ if (concurrencyLevel != UNSET_INT) {
+ s.add("concurrencyLevel", concurrencyLevel);
+ }
+ if (maximumWeight != UNSET_INT) {
+ if (weigher == null) {
+ s.add("maximumSize", maximumWeight);
+ } else {
+ s.add("maximumWeight", maximumWeight);
+ }
+ }
+ if (expireAfterWriteNanos != UNSET_INT) {
+ s.add("expireAfterWrite", expireAfterWriteNanos + "ns");
+ }
+ if (expireAfterAccessNanos != UNSET_INT) {
+ s.add("expireAfterAccess", expireAfterAccessNanos + "ns");
+ }
+ if (keyStrength != null) {
+ s.add("keyStrength", Ascii.toLowerCase(keyStrength.toString()));
+ }
+ if (valueStrength != null) {
+ s.add("valueStrength", Ascii.toLowerCase(valueStrength.toString()));
+ }
+ if (keyEquivalence != null) {
+ s.addValue("keyEquivalence");
+ }
+ if (valueEquivalence != null) {
+ s.addValue("valueEquivalence");
+ }
+ if (removalListener != null) {
+ s.addValue("removalListener");
+ }
+ return s.toString();
+ }
+}
diff --git a/guava/src/com/google/common/cache/CacheBuilderSpec.java b/guava/src/com/google/common/cache/CacheBuilderSpec.java
new file mode 100644
index 0000000..9dfaf4d
--- /dev/null
+++ b/guava/src/com/google/common/cache/CacheBuilderSpec.java
@@ -0,0 +1,455 @@
+/*
+ * 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(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
new file mode 100644
index 0000000..5f77001
--- /dev/null
+++ b/guava/src/com/google/common/cache/CacheLoader.java
@@ -0,0 +1,194 @@
+/*
+ * 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.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.Supplier;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Computes or retrieves values, based on a key, for use in populating a {@link LoadingCache}.
+ *
+ * <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
+ */
+@GwtCompatible(emulated = true)
+public abstract class CacheLoader<K, V> {
+ /**
+ * Constructor for use by subclasses.
+ */
+ protected CacheLoader() {}
+
+ /**
+ * Computes or retrieves the value corresponding to {@code key}.
+ *
+ * @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}.
+ *
+ * <p>This implementation synchronously delegates to {@link #load}. It is recommended that it be
+ * overridden with an asynchronous implementation when using
+ * {@link CacheBuilder#refreshAfterWrite}.
+ *
+ * <p><b>Note:</b> <i>all exceptions thrown by this method will be logged and then swallowed</i>.
+ *
+ * @param key the non-null key whose value should be loaded
+ * @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 {
+ return Futures.immediateFuture(load(key));
+ }
+
+ /**
+ * Computes or retrieves the values corresponding to {@code keys}. This method is called by
+ * {@link LoadingCache#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
+ * contains extra keys not present in {@code keys} then all returned entries will be cached,
+ * 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.
+ *
+ * @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
+ 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}
+ */
+ @Beta
+ public static <K, V> CacheLoader<K, V> from(Function<K, V> function) {
+ return new FunctionToCacheLoader<K, V>(function);
+ }
+
+ private static final class FunctionToCacheLoader<K, V>
+ extends CacheLoader<K, V> implements Serializable {
+ private final Function<K, V> computingFunction;
+
+ public FunctionToCacheLoader(Function<K, V> computingFunction) {
+ this.computingFunction = checkNotNull(computingFunction);
+ }
+
+ @Override
+ public V load(K 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
+ */
+ @Beta
+ public static <V> CacheLoader<Object, V> from(Supplier<V> supplier) {
+ return new SupplierToCacheLoader<V>(supplier);
+ }
+
+ private static final class SupplierToCacheLoader<V>
+ extends CacheLoader<Object, V> implements Serializable {
+ private final Supplier<V> computingSupplier;
+
+ public SupplierToCacheLoader(Supplier<V> computingSupplier) {
+ this.computingSupplier = checkNotNull(computingSupplier);
+ }
+
+ @Override
+ public V load(Object key) {
+ return computingSupplier.get();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ static final class UnsupportedLoadingOperationException extends UnsupportedOperationException {}
+
+ /**
+ * Thrown to indicate that an invalid response was returned from a call to {@link CacheLoader}.
+ *
+ * @since 11.0
+ */
+ public static final class InvalidCacheLoadException extends RuntimeException {
+ public InvalidCacheLoadException(String message) {
+ super(message);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/cache/CacheStats.java b/guava/src/com/google/common/cache/CacheStats.java
new file mode 100644
index 0000000..04d442c
--- /dev/null
+++ b/guava/src/com/google/common/cache/CacheStats.java
@@ -0,0 +1,269 @@
+/*
+ * 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.GwtCompatible;
+import com.google.common.base.Objects;
+
+import javax.annotation.Nullable;
+
+/**
+ * Statistics about the performance of a {@link Cache}. Instances of this class are immutable.
+ *
+ * <p>Cache statistics are incremented according to the following rules:
+ *
+ * <ul>
+ * <li>When a cache lookup encounters an existing cache entry {@code hitCount} is incremented.
+ * <li>When a cache lookup first encounters a missing cache entry, a new entry is loaded.
+ * <ul>
+ * <li>After successfully loading an entry {@code missCount} and {@code loadSuccessCount} are
+ * incremented, and the total loading time, in nanoseconds, is added to
+ * {@code totalLoadTime}.
+ * <li>When an exception is thrown while loading an entry, {@code missCount} and {@code
+ * loadExceptionCount} are incremented, and the total loading time, in nanoseconds, is
+ * added to {@code totalLoadTime}.
+ * <li>Cache lookups that encounter a missing cache entry that is still loading will wait
+ * for loading to complete (whether successful or not) and then increment {@code missCount}.
+ * </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 by operations invoked on the {@linkplain Cache#asMap asMap} view of
+ * the cache.
+ * </ul>
+ *
+ * @author Charles Fry
+ * @since 10.0
+ */
+@Beta
+@GwtCompatible
+public final class CacheStats {
+ private final long hitCount;
+ private final long missCount;
+ private final long loadSuccessCount;
+ private final long loadExceptionCount;
+ private final long totalLoadTime;
+ private final long evictionCount;
+
+ /**
+ * Constructs a new {@code CacheStats} instance.
+ *
+ * <p>Five parameters of the same type in a row is a bad thing, but this class is not constructed
+ * by end users and is too fine-grained for a builder.
+ */
+ public CacheStats(long hitCount, long missCount, long loadSuccessCount,
+ long loadExceptionCount, long totalLoadTime, long evictionCount) {
+ checkArgument(hitCount >= 0);
+ checkArgument(missCount >= 0);
+ checkArgument(loadSuccessCount >= 0);
+ checkArgument(loadExceptionCount >= 0);
+ checkArgument(totalLoadTime >= 0);
+ checkArgument(evictionCount >= 0);
+
+ this.hitCount = hitCount;
+ this.missCount = missCount;
+ this.loadSuccessCount = loadSuccessCount;
+ this.loadExceptionCount = loadExceptionCount;
+ this.totalLoadTime = totalLoadTime;
+ this.evictionCount = evictionCount;
+ }
+
+ /**
+ * Returns the number of times {@link Cache} lookup methods have returned either a cached or
+ * uncached value. This is defined as {@code hitCount + missCount}.
+ */
+ public long requestCount() {
+ return hitCount + missCount;
+ }
+
+ /**
+ * Returns the number of times {@link Cache} lookup methods have returned a cached value.
+ */
+ public long hitCount() {
+ return hitCount;
+ }
+
+ /**
+ * Returns the ratio of cache requests which were hits. This is defined as
+ * {@code hitCount / requestCount}, or {@code 1.0} when {@code requestCount == 0}.
+ * Note that {@code hitRate + missRate =~ 1.0}.
+ */
+ public double hitRate() {
+ long requestCount = requestCount();
+ return (requestCount == 0) ? 1.0 : (double) hitCount / requestCount;
+ }
+
+ /**
+ * Returns the number of times {@link Cache} lookup methods have returned an uncached (newly
+ * loaded) value, or null. Multiple concurrent calls to {@link Cache} lookup methods on an absent
+ * value can result in multiple misses, all returning the results of a single cache load
+ * operation.
+ */
+ public long missCount() {
+ return missCount;
+ }
+
+ /**
+ * Returns the ratio of cache requests which were misses. This is defined as
+ * {@code missCount / requestCount}, or {@code 0.0} when {@code requestCount == 0}.
+ * Note that {@code hitRate + missRate =~ 1.0}. Cache misses include all requests which
+ * weren't cache hits, including requests which resulted in either successful or failed loading
+ * attempts, and requests which waited for other threads to finish loading. It is thus the case
+ * that {@code missCount &gt;= loadSuccessCount + loadExceptionCount}. Multiple
+ * concurrent misses for the same key will result in a single load operation.
+ */
+ public double missRate() {
+ long requestCount = requestCount();
+ return (requestCount == 0) ? 0.0 : (double) missCount / requestCount;
+ }
+
+ /**
+ * Returns the total number of times that {@link Cache} lookup methods attempted to load new
+ * values. This includes both successful load operations, as well as those that threw
+ * exceptions. This is defined as {@code loadSuccessCount + loadExceptionCount}.
+ */
+ public long loadCount() {
+ return loadSuccessCount + loadExceptionCount;
+ }
+
+ /**
+ * Returns the number of times {@link Cache} lookup methods have successfully loaded a new value.
+ * This is always incremented in conjunction with {@link #missCount}, though {@code missCount}
+ * is also incremented when an exception is encountered during cache loading (see
+ * {@link #loadExceptionCount}). Multiple concurrent misses for the same key will result in a
+ * single load operation.
+ */
+ public long loadSuccessCount() {
+ return loadSuccessCount;
+ }
+
+ /**
+ * Returns the number of times {@link Cache} lookup methods threw an exception while loading a
+ * new value. This is always incremented in conjunction with {@code missCount}, though
+ * {@code missCount} is also incremented when cache loading completes successfully (see
+ * {@link #loadSuccessCount}). Multiple concurrent misses for the same key will result in a
+ * single load operation.
+ */
+ public long loadExceptionCount() {
+ return loadExceptionCount;
+ }
+
+ /**
+ * Returns the ratio of cache loading attempts which threw exceptions. This is defined as
+ * {@code loadExceptionCount / (loadSuccessCount + loadExceptionCount)}, or
+ * {@code 0.0} when {@code loadSuccessCount + loadExceptionCount == 0}.
+ */
+ public double loadExceptionRate() {
+ long totalLoadCount = loadSuccessCount + loadExceptionCount;
+ return (totalLoadCount == 0)
+ ? 0.0
+ : (double) loadExceptionCount / totalLoadCount;
+ }
+
+ /**
+ * Returns the total number of nanoseconds the cache has spent loading new values. This can be
+ * used to calculate the miss penalty. This value is increased every time
+ * {@code loadSuccessCount} or {@code loadExceptionCount} is incremented.
+ */
+ public long totalLoadTime() {
+ return totalLoadTime;
+ }
+
+ /**
+ * Returns the average time spent loading new values. This is defined as
+ * {@code totalLoadTime / (loadSuccessCount + loadExceptionCount)}.
+ */
+ public double averageLoadPenalty() {
+ long totalLoadCount = loadSuccessCount + loadExceptionCount;
+ return (totalLoadCount == 0)
+ ? 0.0
+ : (double) totalLoadTime / totalLoadCount;
+ }
+
+ /**
+ * Returns the number of times an entry has been evicted. This count does not include manual
+ * {@linkplain Cache#invalidate invalidations}.
+ */
+ public long evictionCount() {
+ return evictionCount;
+ }
+
+ /**
+ * Returns a new {@code CacheStats} representing the difference between this {@code CacheStats}
+ * and {@code other}. Negative values, which aren't supported by {@code CacheStats} will be
+ * rounded up to zero.
+ */
+ public CacheStats minus(CacheStats other) {
+ return new CacheStats(
+ Math.max(0, hitCount - other.hitCount),
+ Math.max(0, missCount - other.missCount),
+ Math.max(0, loadSuccessCount - other.loadSuccessCount),
+ Math.max(0, loadExceptionCount - other.loadExceptionCount),
+ Math.max(0, totalLoadTime - other.totalLoadTime),
+ Math.max(0, evictionCount - other.evictionCount));
+ }
+
+ /**
+ * Returns a new {@code CacheStats} representing the sum of this {@code CacheStats}
+ * and {@code other}.
+ *
+ * @since 11.0
+ */
+ public CacheStats plus(CacheStats other) {
+ return new CacheStats(
+ hitCount + other.hitCount,
+ missCount + other.missCount,
+ loadSuccessCount + other.loadSuccessCount,
+ loadExceptionCount + other.loadExceptionCount,
+ totalLoadTime + other.totalLoadTime,
+ evictionCount + other.evictionCount);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(hitCount, missCount, loadSuccessCount, loadExceptionCount,
+ totalLoadTime, evictionCount);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object instanceof CacheStats) {
+ CacheStats other = (CacheStats) object;
+ return hitCount == other.hitCount
+ && missCount == other.missCount
+ && loadSuccessCount == other.loadSuccessCount
+ && loadExceptionCount == other.loadExceptionCount
+ && totalLoadTime == other.totalLoadTime
+ && evictionCount == other.evictionCount;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this)
+ .add("hitCount", hitCount)
+ .add("missCount", missCount)
+ .add("loadSuccessCount", loadSuccessCount)
+ .add("loadExceptionCount", loadExceptionCount)
+ .add("totalLoadTime", totalLoadTime)
+ .add("evictionCount", evictionCount)
+ .toString();
+ }
+}
diff --git a/guava/src/com/google/common/cache/ForwardingCache.java b/guava/src/com/google/common/cache/ForwardingCache.java
new file mode 100644
index 0000000..44fe683
--- /dev/null
+++ b/guava/src/com/google/common/cache/ForwardingCache.java
@@ -0,0 +1,146 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+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;
+
+import javax.annotation.Nullable;
+
+/**
+ * A cache which forwards all its method calls to another cache. Subclasses should override one or
+ * more methods to modify the behavior of the backing cache as desired per the
+ * <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Charles Fry
+ * @since 10.0
+ */
+@Beta
+public abstract class ForwardingCache<K, V> extends ForwardingObject implements Cache<K, V> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingCache() {}
+
+ @Override
+ protected abstract Cache<K, V> delegate();
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ @Nullable
+ public V getIfPresent(Object key) {
+ return delegate().getIfPresent(key);
+ }
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ public V get(K key, Callable<? extends V> valueLoader) throws ExecutionException {
+ return delegate().get(key, valueLoader);
+ }
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) {
+ return delegate().getAllPresent(keys);
+ }
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ public void put(K key, V value) {
+ 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);
+ }
+
+ /**
+ * @since 11.0
+ */
+ @Override
+ public void invalidateAll(Iterable<?> keys) {
+ delegate().invalidateAll(keys);
+ }
+
+ @Override
+ public void invalidateAll() {
+ delegate().invalidateAll();
+ }
+
+ @Override
+ public long size() {
+ return delegate().size();
+ }
+
+ @Override
+ public CacheStats stats() {
+ return delegate().stats();
+ }
+
+ @Override
+ public ConcurrentMap<K, V> asMap() {
+ return delegate().asMap();
+ }
+
+ @Override
+ public void cleanUp() {
+ delegate().cleanUp();
+ }
+
+ /**
+ * A simplified version of {@link ForwardingCache} where subclasses can pass in an already
+ * constructed {@link Cache} as the delegete.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public abstract static class SimpleForwardingCache<K, V> extends ForwardingCache<K, V> {
+ private final Cache<K, V> delegate;
+
+ protected SimpleForwardingCache(Cache<K, V> delegate) {
+ this.delegate = Preconditions.checkNotNull(delegate);
+ }
+
+ @Override
+ protected final Cache<K, V> delegate() {
+ return delegate;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/cache/ForwardingLoadingCache.java b/guava/src/com/google/common/cache/ForwardingLoadingCache.java
new file mode 100644
index 0000000..93732ff
--- /dev/null
+++ b/guava/src/com/google/common/cache/ForwardingLoadingCache.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * A cache which forwards all its method calls to another cache. Subclasses should override one or
+ * more methods to modify the behavior of the backing cache as desired per the
+ * <a href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p>Note that {@link #get}, {@link #getUnchecked}, and {@link #apply} all expose the same
+ * underlying functionality, so should probably be overridden as a group.
+ *
+ * @author Charles Fry
+ * @since 11.0
+ */
+@Beta
+public abstract class ForwardingLoadingCache<K, V>
+ extends ForwardingCache<K, V> implements LoadingCache<K, V> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingLoadingCache() {}
+
+ @Override
+ protected abstract LoadingCache<K, V> delegate();
+
+ @Override
+ public V get(K key) throws ExecutionException {
+ return delegate().get(key);
+ }
+
+ @Override
+ public V getUnchecked(K key) {
+ return delegate().getUnchecked(key);
+ }
+
+ @Override
+ public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
+ return delegate().getAll(keys);
+ }
+
+ @Override
+ public V apply(K key) {
+ return delegate().apply(key);
+ }
+
+ @Override
+ public void refresh(K key) {
+ delegate().refresh(key);
+ }
+
+ /**
+ * A simplified version of {@link ForwardingLoadingCache} where subclasses can pass in an already
+ * constructed {@link LoadingCache} as the delegete.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public abstract static class SimpleForwardingLoadingCache<K, V>
+ extends ForwardingLoadingCache<K, V> {
+ private final LoadingCache<K, V> delegate;
+
+ protected SimpleForwardingLoadingCache(LoadingCache<K, V> delegate) {
+ this.delegate = Preconditions.checkNotNull(delegate);
+ }
+
+ @Override
+ protected final LoadingCache<K, V> delegate() {
+ return delegate;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/cache/LoadingCache.java b/guava/src/com/google/common/cache/LoadingCache.java
new file mode 100644
index 0000000..05b1312
--- /dev/null
+++ b/guava/src/com/google/common/cache/LoadingCache.java
@@ -0,0 +1,163 @@
+/*
+ * 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 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.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * A semi-persistent mapping from keys to values. Values are automatically loaded by the cache,
+ * and are stored in the cache until either evicted or manually invalidated.
+ *
+ * <p>Implementations of this interface are expected to be thread-safe, and can be safely accessed
+ * by multiple concurrent threads.
+ *
+ * <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
+ */
+@Beta
+@GwtCompatible
+public interface LoadingCache<K, V> extends Cache<K, V>, Function<K, V> {
+
+ /**
+ * 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.
+ *
+ * <p>If another call to {@link #get} or {@link #getUnchecked} is currently loading the value for
+ * {@code key}, simply waits for that thread to finish and returns its loaded value. Note that
+ * multiple threads can concurrently load values for distinct keys.
+ *
+ * <p>Caches loaded by a {@link CacheLoader} will call {@link CacheLoader#load} to load new values
+ * into the cache. Newly loaded values are added to the cache using
+ * {@code Cache.asMap().putIfAbsent} after loading has completed; if another value was associated
+ * with {@code key} while the new value was loading then a removal notification will be sent for
+ * the new value.
+ *
+ * <p>If the cache loader associated with this cache is known not to throw checked
+ * exceptions, then prefer {@link #getUnchecked} over this method.
+ *
+ * @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
+ */
+ 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 loading
+ * 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>If another call to {@link #get} or {@link #getUnchecked} is currently loading the value for
+ * {@code key}, simply waits for that thread to finish and returns its loaded value. Note that
+ * multiple threads can concurrently load values for distinct keys.
+ *
+ * <p>Caches loaded by a {@link CacheLoader} will call {@link CacheLoader#load} to load new values
+ * into the cache. Newly loaded values are added to the cache using
+ * {@code Cache.asMap().putIfAbsent} after loading has completed; if another value was associated
+ * with {@code key} while the new value was loading then a removal notification will be sent for
+ * the new value.
+ *
+ * <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. In such cases use
+ * {@link #get} 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
+ */
+ V getUnchecked(K key);
+
+ /**
+ * Returns a map of the values associated with {@code keys}, creating or retrieving those values
+ * if necessary. The returned map contains entries that were already cached, combined with newly
+ * loaded entries; it will never contain null keys or values.
+ *
+ * <p>Caches loaded by a {@link CacheLoader} will issue a single request to
+ * {@link CacheLoader#loadAll} for all keys which are not already present in the cache. All
+ * entries returned by {@link CacheLoader#loadAll} will be stored in the cache, over-writing
+ * any previously cached values. This method will throw an exception if
+ * {@link CacheLoader#loadAll} returns {@code null}, returns a map containing null keys or values,
+ * or fails to return an entry for each requested key.
+ *
+ * <p>Note that duplicate elements in {@code keys}, as determined by {@link Object#equals}, will
+ * be ignored.
+ *
+ * @throws ExecutionException if a checked exception was thrown while loading the values
+ * @throws UncheckedExecutionException if an unchecked exception was thrown while loading the
+ * values
+ * @throws ExecutionError if an error was thrown while loading the values
+ * @since 11.0
+ */
+ ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException;
+
+ /**
+ * 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
+ */
+ @Override
+ V apply(K key);
+
+ /**
+ * Loads a new value for key {@code key}, possibly asynchronously. While the new value is loading
+ * the previous value (if any) will continue to be returned by {@code get(key)} unless it is
+ * evicted. If the new value is loaded successfully it will replace the previous value in the
+ * cache; if an exception is thrown while refreshing the previous value will remain, <i>and the
+ * exception will be logged (using {@link java.util.logging.Logger}) and swallowed</i>.
+ *
+ * <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
+ * then this method may return before refresh completes.
+ *
+ * @since 11.0
+ */
+ void refresh(K key);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p><b>Note that although the view <i>is</i> modifiable, no method on the returned map will ever
+ * cause entries to be automatically loaded.</b>
+ */
+ @Override
+ ConcurrentMap<K, V> asMap();
+}
diff --git a/guava/src/com/google/common/cache/LocalCache.java b/guava/src/com/google/common/cache/LocalCache.java
new file mode 100644
index 0000000..6079b9b
--- /dev/null
+++ b/guava/src/com/google/common/cache/LocalCache.java
@@ -0,0 +1,4913 @@
+/*
+ * 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.cache;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.cache.CacheBuilder.NULL_TICKER;
+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.VisibleForTesting;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Stopwatch;
+import com.google.common.base.Ticker;
+import com.google.common.cache.AbstractCache.SimpleStatsCounter;
+import com.google.common.cache.AbstractCache.StatsCounter;
+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.ImmutableMap;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.primitives.Ints;
+import com.google.common.util.concurrent.ExecutionError;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+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;
+import java.io.Serializable;
+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;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+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;
+
+/**
+ * The concurrent hash map implementation built by {@link CacheBuilder}.
+ *
+ * <p>This implementation is heavily derived from revision 1.96 of <a
+ * href="http://tinyurl.com/ConcurrentHashMap">ConcurrentHashMap.java</a>.
+ *
+ * @author Charles Fry
+ * @author Bob Lee ({@code com.google.common.collect.MapMaker})
+ * @author Doug Lea ({@code ConcurrentHashMap})
+ */
+class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> {
+
+ /*
+ * The basic strategy is to subdivide the table among Segments, each of which itself is a
+ * concurrently readable hash table. The map supports non-blocking reads and concurrent writes
+ * across different segments.
+ *
+ * If a maximum size is specified, a best-effort bounding is performed per segment, using a
+ * page-replacement algorithm to determine which entries to evict when the capacity has been
+ * exceeded.
+ *
+ * The page replacement algorithm's data structures are kept casually consistent with the map. The
+ * ordering of writes to a segment is sequentially consistent. An update to the map and recording
+ * of reads may not be immediately reflected on the algorithm's data structures. These structures
+ * are guarded by a lock and operations are applied in batches to avoid lock contention. The
+ * penalty of applying the batches is spread across threads so that the amortized cost is slightly
+ * higher than performing just the operation without enforcing the capacity constraint.
+ *
+ * This implementation uses a per-segment queue to record a memento of the additions, removals,
+ * and accesses that were performed on the map. The queue is drained on writes and when it exceeds
+ * its capacity threshold.
+ *
+ * The Least Recently Used page replacement algorithm was chosen due to its simplicity, high hit
+ * rate, and ability to be implemented with O(1) time complexity. The initial LRU implementation
+ * operates per-segment rather than globally for increased implementation simplicity. We expect
+ * the cache hit rate to be similar to that of a global LRU algorithm.
+ */
+
+ // Constants
+
+ /**
+ * The maximum capacity, used if a higher value is implicitly specified by either of the
+ * constructors with arguments. MUST be a power of two <= 1<<30 to ensure that entries are
+ * indexable using ints.
+ */
+ static final int MAXIMUM_CAPACITY = 1 << 30;
+
+ /** The maximum number of segments to allow; used to bound constructor arguments. */
+ static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
+
+ /** Number of (unsynchronized) retries in the containsValue method. */
+ static final int CONTAINS_VALUE_RETRIES = 3;
+
+ /**
+ * Number of cache access operations that can be buffered per segment before the cache's recency
+ * ordering information is updated. This is used to avoid lock contention by recording a memento
+ * of reads and delaying a lock acquisition until the threshold is crossed or a mutation occurs.
+ *
+ * <p>This must be a (2^n)-1 as it is used as a mask.
+ */
+ static final int DRAIN_THRESHOLD = 0x3F;
+
+ /**
+ * Maximum number of entries to be drained in a single cleanup run. This applies independently to
+ * the cleanup queue and both reference queues.
+ */
+ // TODO(fry): empirically optimize this
+ static final int DRAIN_MAX = 16;
+
+ // Fields
+
+ static final Logger logger = Logger.getLogger(LocalCache.class.getName());
+
+ static final ListeningExecutorService sameThreadExecutor = MoreExecutors.sameThreadExecutor();
+
+ /**
+ * Mask value for indexing into segments. The upper bits of a key's hash code are used to choose
+ * the segment.
+ */
+ final int segmentMask;
+
+ /**
+ * Shift value for indexing within segments. Helps prevent entries that end up in the same segment
+ * from also ending up in the same bucket.
+ */
+ final int segmentShift;
+
+ /** The segments, each of which is a specialized hash table. */
+ final Segment<K, V>[] segments;
+
+ /** The concurrency level. */
+ final int concurrencyLevel;
+
+ /** Strategy for comparing keys. */
+ final Equivalence<Object> keyEquivalence;
+
+ /** Strategy for comparing values. */
+ final Equivalence<Object> valueEquivalence;
+
+ /** Strategy for referencing keys. */
+ final Strength keyStrength;
+
+ /** Strategy for referencing values. */
+ final Strength valueStrength;
+
+ /** The maximum weight of this map. UNSET_INT if there is no maximum. */
+ final long maxWeight;
+
+ /** Weigher to weigh cache entries. */
+ final Weigher<K, V> weigher;
+
+ /** How long after the last access to an entry the map will retain that entry. */
+ final long expireAfterAccessNanos;
+
+ /** How long after the last write to an entry the map will retain that entry. */
+ final long expireAfterWriteNanos;
+
+ /** How long after the last write an entry becomes a candidate for refresh. */
+ final long refreshNanos;
+
+ /** Entries waiting to be consumed by the removal listener. */
+ // TODO(fry): define a new type which creates event objects and automates the clear logic
+ final Queue<RemovalNotification<K, V>> removalNotificationQueue;
+
+ /**
+ * A listener that is invoked when an entry is removed due to expiration or garbage collection of
+ * soft/weak entries.
+ */
+ final RemovalListener<K, V> removalListener;
+
+ /** Measures time in a testable way. */
+ final Ticker ticker;
+
+ /** Factory used to create new entries. */
+ final EntryFactory entryFactory;
+
+ /**
+ * Accumulates global cache statistics. Note that there are also per-segments stats counters
+ * which must be aggregated to obtain a global stats view.
+ */
+ final StatsCounter globalStatsCounter;
+
+ /**
+ * The default cache loader to use on loading operations.
+ */
+ @Nullable
+ final CacheLoader<? super K, V> defaultLoader;
+
+ /**
+ * 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) {
+ concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS);
+
+ keyStrength = builder.getKeyStrength();
+ valueStrength = builder.getValueStrength();
+
+ keyEquivalence = builder.getKeyEquivalence();
+ valueEquivalence = builder.getValueEquivalence();
+
+ maxWeight = builder.getMaximumWeight();
+ weigher = builder.getWeigher();
+ expireAfterAccessNanos = builder.getExpireAfterAccessNanos();
+ expireAfterWriteNanos = builder.getExpireAfterWriteNanos();
+ refreshNanos = builder.getRefreshNanos();
+
+ removalListener = builder.getRemovalListener();
+ removalNotificationQueue = (removalListener == NullListener.INSTANCE)
+ ? LocalCache.<RemovalNotification<K, V>>discardingQueue()
+ : new ConcurrentLinkedQueue<RemovalNotification<K, V>>();
+
+ ticker = builder.getTicker(recordsTime());
+ entryFactory = EntryFactory.getFactory(keyStrength, usesAccessEntries(), usesWriteEntries());
+ globalStatsCounter = builder.getStatsCounterSupplier().get();
+ defaultLoader = loader;
+
+ int initialCapacity = Math.min(builder.getInitialCapacity(), MAXIMUM_CAPACITY);
+ if (evictsBySize() && !customWeigher()) {
+ 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.
+ int segmentShift = 0;
+ int segmentCount = 1;
+ while (segmentCount < concurrencyLevel
+ && (!evictsBySize() || segmentCount * 20 <= maxWeight)) {
+ ++segmentShift;
+ segmentCount <<= 1;
+ }
+ this.segmentShift = 32 - segmentShift;
+ segmentMask = segmentCount - 1;
+
+ this.segments = newSegmentArray(segmentCount);
+
+ int segmentCapacity = initialCapacity / segmentCount;
+ if (segmentCapacity * segmentCount < initialCapacity) {
+ ++segmentCapacity;
+ }
+
+ int segmentSize = 1;
+ while (segmentSize < segmentCapacity) {
+ segmentSize <<= 1;
+ }
+
+ if (evictsBySize()) {
+ // Ensure sum of segment max weights = overall max weights
+ long maxSegmentWeight = maxWeight / segmentCount + 1;
+ long remainder = maxWeight % segmentCount;
+ for (int i = 0; i < this.segments.length; ++i) {
+ if (i == remainder) {
+ maxSegmentWeight--;
+ }
+ this.segments[i] =
+ createSegment(segmentSize, maxSegmentWeight, builder.getStatsCounterSupplier().get());
+ }
+ } else {
+ for (int i = 0; i < this.segments.length; ++i) {
+ this.segments[i] =
+ createSegment(segmentSize, UNSET_INT, builder.getStatsCounterSupplier().get());
+ }
+ }
+ }
+
+ boolean evictsBySize() {
+ return maxWeight >= 0;
+ }
+
+ boolean customWeigher() {
+ return weigher != OneWeigher.INSTANCE;
+ }
+
+ boolean expires() {
+ return expiresAfterWrite() || expiresAfterAccess();
+ }
+
+ boolean expiresAfterWrite() {
+ return expireAfterWriteNanos > 0;
+ }
+
+ boolean expiresAfterAccess() {
+ return expireAfterAccessNanos > 0;
+ }
+
+ boolean refreshes() {
+ return refreshNanos > 0;
+ }
+
+ boolean usesAccessQueue() {
+ return expiresAfterAccess() || evictsBySize();
+ }
+
+ boolean usesWriteQueue() {
+ return expiresAfterWrite();
+ }
+
+ boolean recordsWrite() {
+ return expiresAfterWrite() || refreshes();
+ }
+
+ boolean recordsAccess() {
+ return expiresAfterAccess();
+ }
+
+ boolean recordsTime() {
+ return recordsWrite() || recordsAccess();
+ }
+
+ boolean usesWriteEntries() {
+ return usesWriteQueue() || recordsWrite();
+ }
+
+ boolean usesAccessEntries() {
+ return usesAccessQueue() || recordsAccess();
+ }
+
+ boolean usesKeyReferences() {
+ return keyStrength != Strength.STRONG;
+ }
+
+ boolean usesValueReferences() {
+ return valueStrength != Strength.STRONG;
+ }
+
+ enum Strength {
+ /*
+ * TODO(kevinb): If we strongly reference the value and aren't loading, we needn't wrap the
+ * value. This could save ~8 bytes per entry.
+ */
+
+ STRONG {
+ @Override
+ <K, V> ValueReference<K, V> referenceValue(
+ Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight) {
+ return (weight == 1)
+ ? new StrongValueReference<K, V>(value)
+ : new WeightedStrongValueReference<K, V>(value, weight);
+ }
+
+ @Override
+ Equivalence<Object> defaultEquivalence() {
+ return Equivalence.equals();
+ }
+ },
+
+ SOFT {
+ @Override
+ <K, V> ValueReference<K, V> referenceValue(
+ Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight) {
+ return (weight == 1)
+ ? new SoftValueReference<K, V>(segment.valueReferenceQueue, value, entry)
+ : new WeightedSoftValueReference<K, V>(
+ segment.valueReferenceQueue, value, entry, weight);
+ }
+
+ @Override
+ Equivalence<Object> defaultEquivalence() {
+ return Equivalence.identity();
+ }
+ },
+
+ WEAK {
+ @Override
+ <K, V> ValueReference<K, V> referenceValue(
+ Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight) {
+ return (weight == 1)
+ ? new WeakValueReference<K, V>(segment.valueReferenceQueue, value, entry)
+ : new WeightedWeakValueReference<K, V>(
+ segment.valueReferenceQueue, value, entry, weight);
+ }
+
+ @Override
+ Equivalence<Object> defaultEquivalence() {
+ return Equivalence.identity();
+ }
+ };
+
+ /**
+ * Creates a reference for the given value according to this value strength.
+ */
+ abstract <K, V> ValueReference<K, V> referenceValue(
+ Segment<K, V> segment, ReferenceEntry<K, V> entry, V value, int weight);
+
+ /**
+ * Returns the default equivalence strategy used to compare and hash keys or values referenced
+ * at this strength. This strategy will be used unless the user explicitly specifies an
+ * alternate strategy.
+ */
+ abstract Equivalence<Object> defaultEquivalence();
+ }
+
+ /**
+ * Creates new entries.
+ */
+ enum EntryFactory {
+ STRONG {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new StrongEntry<K, V>(key, hash, next);
+ }
+ },
+ STRONG_ACCESS {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new StrongAccessEntry<K, V>(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);
+ copyAccessEntry(original, newEntry);
+ return newEntry;
+ }
+ },
+ STRONG_WRITE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new StrongWriteEntry<K, V>(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);
+ copyWriteEntry(original, newEntry);
+ return newEntry;
+ }
+ },
+ STRONG_ACCESS_WRITE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new StrongAccessWriteEntry<K, V>(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);
+ copyAccessEntry(original, newEntry);
+ copyWriteEntry(original, newEntry);
+ return newEntry;
+ }
+ },
+
+ WEAK {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new WeakEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
+ }
+ },
+ WEAK_ACCESS {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new WeakAccessEntry<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);
+ copyAccessEntry(original, newEntry);
+ return newEntry;
+ }
+ },
+ WEAK_WRITE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new WeakWriteEntry<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);
+ copyWriteEntry(original, newEntry);
+ return newEntry;
+ }
+ },
+ WEAK_ACCESS_WRITE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new WeakAccessWriteEntry<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);
+ copyAccessEntry(original, newEntry);
+ copyWriteEntry(original, newEntry);
+ return newEntry;
+ }
+ };
+
+ /**
+ * Masks used to compute indices in the following table.
+ */
+ static final int ACCESS_MASK = 1;
+ static final int WRITE_MASK = 2;
+ static final int WEAK_MASK = 4;
+
+ /**
+ * Look-up table for factories.
+ */
+ static final EntryFactory[] factories = {
+ STRONG, STRONG_ACCESS, STRONG_WRITE, STRONG_ACCESS_WRITE,
+ WEAK, WEAK_ACCESS, WEAK_WRITE, WEAK_ACCESS_WRITE,
+ };
+
+ static EntryFactory getFactory(Strength keyStrength, boolean usesAccessQueue,
+ boolean usesWriteQueue) {
+ int flags = ((keyStrength == Strength.WEAK) ? WEAK_MASK : 0)
+ | (usesAccessQueue ? ACCESS_MASK : 0)
+ | (usesWriteQueue ? WRITE_MASK : 0);
+ return factories[flags];
+ }
+
+ /**
+ * Creates a new entry.
+ *
+ * @param segment to create the entry for
+ * @param key of the entry
+ * @param hash of the key
+ * @param next entry in the same bucket
+ */
+ abstract <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next);
+
+ /**
+ * Copies an entry, assigning it a new {@code next} entry.
+ *
+ * @param original the entry to copy
+ * @param newNext entry in the same bucket
+ */
+ @GuardedBy("Segment.this")
+ <K, V> ReferenceEntry<K, V> copyEntry(
+ Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
+ return newEntry(segment, original.getKey(), original.getHash(), newNext);
+ }
+
+ @GuardedBy("Segment.this")
+ <K, V> void copyAccessEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
+ // TODO(fry): when we link values instead of entries this method can go
+ // away, as can connectAccessOrder, nullifyAccessOrder.
+ newEntry.setAccessTime(original.getAccessTime());
+
+ connectAccessOrder(original.getPreviousInAccessQueue(), newEntry);
+ connectAccessOrder(newEntry, original.getNextInAccessQueue());
+
+ nullifyAccessOrder(original);
+ }
+
+ @GuardedBy("Segment.this")
+ <K, V> void copyWriteEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
+ // TODO(fry): when we link values instead of entries this method can go
+ // away, as can connectWriteOrder, nullifyWriteOrder.
+ newEntry.setWriteTime(original.getWriteTime());
+
+ connectWriteOrder(original.getPreviousInWriteQueue(), newEntry);
+ connectWriteOrder(newEntry, original.getNextInWriteQueue());
+
+ nullifyWriteOrder(original);
+ }
+ }
+
+ /**
+ * A reference to a value.
+ */
+ interface ValueReference<K, V> {
+ /**
+ * Returns the value. Does not block or throw exceptions.
+ */
+ @Nullable
+ V get();
+
+ /**
+ * Waits for a value that may still be loading. Unlike get(), this method can block (in the
+ * case of FutureValueReference).
+ *
+ * @throws ExecutionException if the loading thread throws an exception
+ * @throws ExecutionError if the loading thread throws an error
+ */
+ V waitForValue() throws ExecutionException;
+
+ /**
+ * Returns the weight of this entry. This is assumed to be static between calls to setValue.
+ */
+ int getWeight();
+
+ /**
+ * Returns the entry associated with this value reference, or {@code null} if this value
+ * reference is independent of any entry.
+ */
+ @Nullable
+ ReferenceEntry<K, V> getEntry();
+
+ /**
+ * 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);
+
+ /**
+ * Notifify pending loads that a new value was set. This is only relevant to loading
+ * value references.
+ */
+ void notifyNewValue(@Nullable V newValue);
+
+ /**
+ * Returns true if a new value is currently loading, regardless of whether or not there is an
+ * existing value. It is assumed that the return value of this method is constant for any given
+ * ValueReference instance.
+ */
+ boolean isLoading();
+
+ /**
+ * Returns true if this reference contains an active value, meaning one that is still considered
+ * present in the cache. Active values consist of live values, which are returned by cache
+ * lookups, and dead values, which have been evicted but awaiting removal. Non-active values
+ * consist strictly of loading values, though during refresh a value may be both active and
+ * loading.
+ */
+ boolean isActive();
+ }
+
+ /**
+ * Placeholder. Indicates that the value hasn't been set yet.
+ */
+ static final ValueReference<Object, Object> UNSET = new ValueReference<Object, Object>() {
+ @Override
+ public Object get() {
+ return null;
+ }
+
+ @Override
+ public int getWeight() {
+ return 0;
+ }
+
+ @Override
+ public ReferenceEntry<Object, Object> getEntry() {
+ return null;
+ }
+
+ @Override
+ public ValueReference<Object, Object> copyFor(ReferenceQueue<Object> queue,
+ @Nullable Object value, ReferenceEntry<Object, Object> entry) {
+ return this;
+ }
+
+ @Override
+ public boolean isLoading() {
+ return false;
+ }
+
+ @Override
+ public boolean isActive() {
+ return false;
+ }
+
+ @Override
+ public Object waitForValue() {
+ return null;
+ }
+
+ @Override
+ public void notifyNewValue(Object newValue) {}
+ };
+
+ /**
+ * Singleton placeholder that indicates a value is being loaded.
+ */
+ @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value
+ static <K, V> ValueReference<K, V> unset() {
+ return (ValueReference<K, V>) UNSET;
+ }
+
+ /**
+ * An entry in a reference map.
+ *
+ * Entries in the map can be in the following states:
+ *
+ * Valid:
+ * - Live: valid key/value are set
+ * - Loading: loading is pending
+ *
+ * Invalid:
+ * - Expired: time expired (key/value may still be set)
+ * - Collected: key/value was partially collected, but not yet cleaned up
+ * - Unset: marked as unset, awaiting cleanup or reuse
+ */
+ interface ReferenceEntry<K, V> {
+ /**
+ * Returns the value reference from this entry.
+ */
+ ValueReference<K, V> getValueReference();
+
+ /**
+ * Sets the value reference for this entry.
+ */
+ void setValueReference(ValueReference<K, V> valueReference);
+
+ /**
+ * Returns the next entry in the chain.
+ */
+ @Nullable
+ ReferenceEntry<K, V> getNext();
+
+ /**
+ * Returns the entry's hash.
+ */
+ int getHash();
+
+ /**
+ * Returns the key for this entry.
+ */
+ @Nullable
+ K getKey();
+
+ /*
+ * Used by entries that use access order. Access entries are maintained in a doubly-linked list.
+ * New entries are added at the tail of the list at write time; stale entries are expired from
+ * the head of the list.
+ */
+
+ /**
+ * Returns the time that this entry was last accessed, in ns.
+ */
+ long getAccessTime();
+
+ /**
+ * Sets the entry access time in ns.
+ */
+ void setAccessTime(long time);
+
+ /**
+ * Returns the next entry in the access queue.
+ */
+ ReferenceEntry<K, V> getNextInAccessQueue();
+
+ /**
+ * Sets the next entry in the access queue.
+ */
+ void setNextInAccessQueue(ReferenceEntry<K, V> next);
+
+ /**
+ * Returns the previous entry in the access queue.
+ */
+ ReferenceEntry<K, V> getPreviousInAccessQueue();
+
+ /**
+ * Sets the previous entry in the access queue.
+ */
+ void setPreviousInAccessQueue(ReferenceEntry<K, V> previous);
+
+ /*
+ * Implemented by entries that use write order. Write entries are maintained in a
+ * doubly-linked list. New entries are added at the tail of the list at write time and stale
+ * entries are expired from the head of the list.
+ */
+
+ /**
+ * Returns the time that this entry was last written, in ns.
+ */
+ long getWriteTime();
+
+ /**
+ * Sets the entry write time in ns.
+ */
+ void setWriteTime(long time);
+
+ /**
+ * Returns the next entry in the write queue.
+ */
+ ReferenceEntry<K, V> getNextInWriteQueue();
+
+ /**
+ * Sets the next entry in the write queue.
+ */
+ void setNextInWriteQueue(ReferenceEntry<K, V> next);
+
+ /**
+ * Returns the previous entry in the write queue.
+ */
+ ReferenceEntry<K, V> getPreviousInWriteQueue();
+
+ /**
+ * Sets the previous entry in the write queue.
+ */
+ void setPreviousInWriteQueue(ReferenceEntry<K, V> previous);
+ }
+
+ private enum NullEntry implements ReferenceEntry<Object, Object> {
+ INSTANCE;
+
+ @Override
+ public ValueReference<Object, Object> getValueReference() {
+ return null;
+ }
+
+ @Override
+ public void setValueReference(ValueReference<Object, Object> valueReference) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getNext() {
+ return null;
+ }
+
+ @Override
+ public int getHash() {
+ return 0;
+ }
+
+ @Override
+ public Object getKey() {
+ return null;
+ }
+
+ @Override
+ public long getAccessTime() {
+ return 0;
+ }
+
+ @Override
+ public void setAccessTime(long time) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getNextInAccessQueue() {
+ return this;
+ }
+
+ @Override
+ public void setNextInAccessQueue(ReferenceEntry<Object, Object> next) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getPreviousInAccessQueue() {
+ return this;
+ }
+
+ @Override
+ public void setPreviousInAccessQueue(ReferenceEntry<Object, Object> previous) {}
+
+ @Override
+ public long getWriteTime() {
+ return 0;
+ }
+
+ @Override
+ public void setWriteTime(long time) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getNextInWriteQueue() {
+ return this;
+ }
+
+ @Override
+ public void setNextInWriteQueue(ReferenceEntry<Object, Object> next) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getPreviousInWriteQueue() {
+ return this;
+ }
+
+ @Override
+ public void setPreviousInWriteQueue(ReferenceEntry<Object, Object> previous) {}
+ }
+
+ static abstract class AbstractReferenceEntry<K, V> implements ReferenceEntry<K, V> {
+ @Override
+ public ValueReference<K, V> getValueReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setValueReference(ValueReference<K, V> valueReference) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getHash() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public K getKey() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getAccessTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAccessTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextInAccessQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextInAccessQueue(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInAccessQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getWriteTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setWriteTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextInWriteQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextInWriteQueue(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInWriteQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value
+ static <K, V> ReferenceEntry<K, V> nullEntry() {
+ return (ReferenceEntry<K, V>) NullEntry.INSTANCE;
+ }
+
+ static final Queue<? extends Object> DISCARDING_QUEUE = new AbstractQueue<Object>() {
+ @Override
+ public boolean offer(Object o) {
+ return true;
+ }
+
+ @Override
+ public Object peek() {
+ return null;
+ }
+
+ @Override
+ public Object poll() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public Iterator<Object> iterator() {
+ return Iterators.emptyIterator();
+ }
+ };
+
+ /**
+ * Queue that discards all elements.
+ */
+ @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value
+ static <E> Queue<E> discardingQueue() {
+ return (Queue) DISCARDING_QUEUE;
+ }
+
+ /*
+ * Note: All of this duplicate code sucks, but it saves a lot of memory. If only Java had mixins!
+ * To maintain this code, make a change for the strong reference type. Then, cut and paste, and
+ * replace "Strong" with "Soft" or "Weak" within the pasted text. The primary difference is that
+ * strong entries store the key reference directly while soft and weak entries delegate to their
+ * respective superclasses.
+ */
+
+ /**
+ * Used for strongly-referenced keys.
+ */
+ static class StrongEntry<K, V> implements ReferenceEntry<K, V> {
+ final K key;
+
+ StrongEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ this.key = key;
+ this.hash = hash;
+ this.next = next;
+ }
+
+ @Override
+ public K getKey() {
+ return this.key;
+ }
+
+ // null access
+
+ @Override
+ public long getAccessTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAccessTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextInAccessQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextInAccessQueue(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInAccessQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // null write
+
+ @Override
+ public long getWriteTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setWriteTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextInWriteQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextInWriteQueue(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInWriteQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // The code below is exactly the same for each entry type.
+
+ final int hash;
+ final ReferenceEntry<K, V> next;
+ volatile ValueReference<K, V> valueReference = unset();
+
+ @Override
+ public ValueReference<K, V> getValueReference() {
+ return valueReference;
+ }
+
+ @Override
+ public void setValueReference(ValueReference<K, V> valueReference) {
+ this.valueReference = valueReference;
+ }
+
+ @Override
+ public int getHash() {
+ return hash;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNext() {
+ return next;
+ }
+ }
+
+ static final class StrongAccessEntry<K, V> extends StrongEntry<K, V>
+ implements ReferenceEntry<K, V> {
+ StrongAccessEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(key, hash, next);
+ }
+
+ // The code below is exactly the same for each access entry type.
+
+ volatile long accessTime = Long.MAX_VALUE;
+
+ @Override
+ public long getAccessTime() {
+ return accessTime;
+ }
+
+ @Override
+ public void setAccessTime(long time) {
+ this.accessTime = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextAccess = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextInAccessQueue() {
+ return nextAccess;
+ }
+
+ @Override
+ public void setNextInAccessQueue(ReferenceEntry<K, V> next) {
+ this.nextAccess = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousAccess = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInAccessQueue() {
+ return previousAccess;
+ }
+
+ @Override
+ public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) {
+ this.previousAccess = previous;
+ }
+ }
+
+ static final class StrongWriteEntry<K, V>
+ extends StrongEntry<K, V> implements ReferenceEntry<K, V> {
+ StrongWriteEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(key, hash, next);
+ }
+
+ // The code below is exactly the same for each write entry type.
+
+ volatile long writeTime = Long.MAX_VALUE;
+
+ @Override
+ public long getWriteTime() {
+ return writeTime;
+ }
+
+ @Override
+ public void setWriteTime(long time) {
+ this.writeTime = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextWrite = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextInWriteQueue() {
+ return nextWrite;
+ }
+
+ @Override
+ public void setNextInWriteQueue(ReferenceEntry<K, V> next) {
+ this.nextWrite = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousWrite = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInWriteQueue() {
+ return previousWrite;
+ }
+
+ @Override
+ public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) {
+ this.previousWrite = previous;
+ }
+ }
+
+ static final class StrongAccessWriteEntry<K, V>
+ extends StrongEntry<K, V> implements ReferenceEntry<K, V> {
+ StrongAccessWriteEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(key, hash, next);
+ }
+
+ // The code below is exactly the same for each access entry type.
+
+ volatile long accessTime = Long.MAX_VALUE;
+
+ @Override
+ public long getAccessTime() {
+ return accessTime;
+ }
+
+ @Override
+ public void setAccessTime(long time) {
+ this.accessTime = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextAccess = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextInAccessQueue() {
+ return nextAccess;
+ }
+
+ @Override
+ public void setNextInAccessQueue(ReferenceEntry<K, V> next) {
+ this.nextAccess = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousAccess = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInAccessQueue() {
+ return previousAccess;
+ }
+
+ @Override
+ public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) {
+ this.previousAccess = previous;
+ }
+
+ // The code below is exactly the same for each write entry type.
+
+ volatile long writeTime = Long.MAX_VALUE;
+
+ @Override
+ public long getWriteTime() {
+ return writeTime;
+ }
+
+ @Override
+ public void setWriteTime(long time) {
+ this.writeTime = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextWrite = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextInWriteQueue() {
+ return nextWrite;
+ }
+
+ @Override
+ public void setNextInWriteQueue(ReferenceEntry<K, V> next) {
+ this.nextWrite = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousWrite = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInWriteQueue() {
+ return previousWrite;
+ }
+
+ @Override
+ public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) {
+ this.previousWrite = previous;
+ }
+ }
+
+ /**
+ * Used for weakly-referenced keys.
+ */
+ static class WeakEntry<K, V> extends WeakReference<K> implements ReferenceEntry<K, V> {
+ WeakEntry(ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(key, queue);
+ this.hash = hash;
+ this.next = next;
+ }
+
+ @Override
+ public K getKey() {
+ return get();
+ }
+
+ // null access
+
+ @Override
+ public long getAccessTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setAccessTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextInAccessQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextInAccessQueue(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInAccessQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // null write
+
+ @Override
+ public long getWriteTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setWriteTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextInWriteQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextInWriteQueue(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInWriteQueue() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // The code below is exactly the same for each entry type.
+
+ final int hash;
+ final ReferenceEntry<K, V> next;
+ volatile ValueReference<K, V> valueReference = unset();
+
+ @Override
+ public ValueReference<K, V> getValueReference() {
+ return valueReference;
+ }
+
+ @Override
+ public void setValueReference(ValueReference<K, V> valueReference) {
+ this.valueReference = valueReference;
+ }
+
+ @Override
+ public int getHash() {
+ return hash;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNext() {
+ return next;
+ }
+ }
+
+ static final class WeakAccessEntry<K, V>
+ extends WeakEntry<K, V> implements ReferenceEntry<K, V> {
+ WeakAccessEntry(
+ ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(queue, key, hash, next);
+ }
+
+ // The code below is exactly the same for each access entry type.
+
+ volatile long accessTime = Long.MAX_VALUE;
+
+ @Override
+ public long getAccessTime() {
+ return accessTime;
+ }
+
+ @Override
+ public void setAccessTime(long time) {
+ this.accessTime = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextAccess = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextInAccessQueue() {
+ return nextAccess;
+ }
+
+ @Override
+ public void setNextInAccessQueue(ReferenceEntry<K, V> next) {
+ this.nextAccess = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousAccess = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInAccessQueue() {
+ return previousAccess;
+ }
+
+ @Override
+ public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) {
+ this.previousAccess = previous;
+ }
+ }
+
+ static final class WeakWriteEntry<K, V>
+ extends WeakEntry<K, V> implements ReferenceEntry<K, V> {
+ WeakWriteEntry(
+ ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(queue, key, hash, next);
+ }
+
+ // The code below is exactly the same for each write entry type.
+
+ volatile long writeTime = Long.MAX_VALUE;
+
+ @Override
+ public long getWriteTime() {
+ return writeTime;
+ }
+
+ @Override
+ public void setWriteTime(long time) {
+ this.writeTime = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextWrite = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextInWriteQueue() {
+ return nextWrite;
+ }
+
+ @Override
+ public void setNextInWriteQueue(ReferenceEntry<K, V> next) {
+ this.nextWrite = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousWrite = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInWriteQueue() {
+ return previousWrite;
+ }
+
+ @Override
+ public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) {
+ this.previousWrite = previous;
+ }
+ }
+
+ static final class WeakAccessWriteEntry<K, V>
+ extends WeakEntry<K, V> implements ReferenceEntry<K, V> {
+ WeakAccessWriteEntry(
+ ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(queue, key, hash, next);
+ }
+
+ // The code below is exactly the same for each access entry type.
+
+ volatile long accessTime = Long.MAX_VALUE;
+
+ @Override
+ public long getAccessTime() {
+ return accessTime;
+ }
+
+ @Override
+ public void setAccessTime(long time) {
+ this.accessTime = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextAccess = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextInAccessQueue() {
+ return nextAccess;
+ }
+
+ @Override
+ public void setNextInAccessQueue(ReferenceEntry<K, V> next) {
+ this.nextAccess = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousAccess = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInAccessQueue() {
+ return previousAccess;
+ }
+
+ @Override
+ public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) {
+ this.previousAccess = previous;
+ }
+
+ // The code below is exactly the same for each write entry type.
+
+ volatile long writeTime = Long.MAX_VALUE;
+
+ @Override
+ public long getWriteTime() {
+ return writeTime;
+ }
+
+ @Override
+ public void setWriteTime(long time) {
+ this.writeTime = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextWrite = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextInWriteQueue() {
+ return nextWrite;
+ }
+
+ @Override
+ public void setNextInWriteQueue(ReferenceEntry<K, V> next) {
+ this.nextWrite = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousWrite = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInWriteQueue() {
+ return previousWrite;
+ }
+
+ @Override
+ public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) {
+ this.previousWrite = previous;
+ }
+ }
+
+ /**
+ * References a weak value.
+ */
+ static class WeakValueReference<K, V>
+ extends WeakReference<V> implements ValueReference<K, V> {
+ final ReferenceEntry<K, V> entry;
+
+ WeakValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry) {
+ super(referent, queue);
+ this.entry = entry;
+ }
+
+ @Override
+ public int getWeight() {
+ return 1;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return entry;
+ }
+
+ @Override
+ public void notifyNewValue(V newValue) {}
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ return new WeakValueReference<K, V>(queue, value, entry);
+ }
+
+ @Override
+ public boolean isLoading() {
+ return false;
+ }
+
+ @Override
+ public boolean isActive() {
+ return true;
+ }
+
+ @Override
+ public V waitForValue() {
+ return get();
+ }
+ }
+
+ /**
+ * References a soft value.
+ */
+ static class SoftValueReference<K, V>
+ extends SoftReference<V> implements ValueReference<K, V> {
+ final ReferenceEntry<K, V> entry;
+
+ SoftValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry) {
+ super(referent, queue);
+ this.entry = entry;
+ }
+
+ @Override
+ public int getWeight() {
+ return 1;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return entry;
+ }
+
+ @Override
+ 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);
+ }
+
+ @Override
+ public boolean isLoading() {
+ return false;
+ }
+
+ @Override
+ public boolean isActive() {
+ return true;
+ }
+
+ @Override
+ public V waitForValue() {
+ return get();
+ }
+ }
+
+ /**
+ * References a strong value.
+ */
+ static class StrongValueReference<K, V> implements ValueReference<K, V> {
+ final V referent;
+
+ StrongValueReference(V referent) {
+ this.referent = referent;
+ }
+
+ @Override
+ public V get() {
+ return referent;
+ }
+
+ @Override
+ public int getWeight() {
+ return 1;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return null;
+ }
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ return this;
+ }
+
+ @Override
+ public boolean isLoading() {
+ return false;
+ }
+
+ @Override
+ public boolean isActive() {
+ return true;
+ }
+
+ @Override
+ public V waitForValue() {
+ return get();
+ }
+
+ @Override
+ public void notifyNewValue(V newValue) {}
+ }
+
+ /**
+ * References a weak value.
+ */
+ static final class WeightedWeakValueReference<K, V> extends WeakValueReference<K, V> {
+ final int weight;
+
+ WeightedWeakValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry,
+ int weight) {
+ super(queue, referent, entry);
+ this.weight = weight;
+ }
+
+ @Override
+ public int getWeight() {
+ return weight;
+ }
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ return new WeightedWeakValueReference<K, V>(queue, value, entry, weight);
+ }
+ }
+
+ /**
+ * References a soft value.
+ */
+ static final class WeightedSoftValueReference<K, V> extends SoftValueReference<K, V> {
+ final int weight;
+
+ WeightedSoftValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry,
+ int weight) {
+ super(queue, referent, entry);
+ this.weight = weight;
+ }
+
+ @Override
+ public int getWeight() {
+ 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);
+ }
+
+ }
+
+ /**
+ * References a strong value.
+ */
+ static final class WeightedStrongValueReference<K, V> extends StrongValueReference<K, V> {
+ final int weight;
+
+ WeightedStrongValueReference(V referent, int weight) {
+ super(referent);
+ this.weight = weight;
+ }
+
+ @Override
+ public int getWeight() {
+ return weight;
+ }
+ }
+
+ /**
+ * Applies a supplemental hash function to a given hash code, which defends against poor quality
+ * hash functions. This is critical when the concurrent hash map uses power-of-two length hash
+ * tables, that otherwise encounter collisions for hash codes that do not differ in lower or
+ * upper bits.
+ *
+ * @param h hash code
+ */
+ static int rehash(int h) {
+ // Spread bits to regularize both segment and index locations,
+ // using variant of single-word Wang/Jenkins hash.
+ // TODO(kevinb): use Hashing/move this to Hashing?
+ h += (h << 15) ^ 0xffffcd7d;
+ h ^= (h >>> 10);
+ h += (h << 3);
+ h ^= (h >>> 6);
+ h += (h << 2) + (h << 14);
+ return h ^ (h >>> 16);
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link Segment#newEntry} directly.
+ */
+ @GuardedBy("Segment.this")
+ @VisibleForTesting
+ ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return segmentFor(hash).newEntry(key, hash, next);
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link Segment#copyEntry} directly.
+ */
+ @GuardedBy("Segment.this")
+ @VisibleForTesting
+ ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
+ int hash = original.getHash();
+ return segmentFor(hash).copyEntry(original, newNext);
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link Segment#setValue} instead.
+ */
+ @GuardedBy("Segment.this")
+ @VisibleForTesting
+ ValueReference<K, V> newValueReference(ReferenceEntry<K, V> entry, V value, int weight) {
+ int hash = entry.getHash();
+ return valueStrength.referenceValue(segmentFor(hash), entry, value, weight);
+ }
+
+ int hash(Object key) {
+ int h = keyEquivalence.hash(key);
+ return rehash(h);
+ }
+
+ void reclaimValue(ValueReference<K, V> valueReference) {
+ ReferenceEntry<K, V> entry = valueReference.getEntry();
+ int hash = entry.getHash();
+ segmentFor(hash).reclaimValue(entry.getKey(), hash, valueReference);
+ }
+
+ void reclaimKey(ReferenceEntry<K, V> entry) {
+ int hash = entry.getHash();
+ segmentFor(hash).reclaimKey(entry, hash);
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link Segment#getLiveValue}
+ * instead.
+ */
+ @VisibleForTesting
+ boolean isLive(ReferenceEntry<K, V> entry, long now) {
+ return segmentFor(entry.getHash()).getLiveValue(entry, now) != null;
+ }
+
+ /**
+ * Returns the segment that should be used for a key with the given hash.
+ *
+ * @param hash the hash code for the key
+ * @return the segment
+ */
+ Segment<K, V> segmentFor(int hash) {
+ // TODO(fry): Lazily create segments?
+ return segments[(hash >>> segmentShift) & segmentMask];
+ }
+
+ Segment<K, V> createSegment(
+ int initialCapacity, long maxSegmentWeight, StatsCounter statsCounter) {
+ return new Segment<K, V>(this, initialCapacity, maxSegmentWeight, statsCounter);
+ }
+
+ /**
+ * Gets the value from an entry. Returns null if the entry is invalid, partially-collected,
+ * loading, or expired. Unlike {@link Segment#getLiveValue} this method does not attempt to
+ * cleanup stale entries. As such it should only be called outside of a segment context, such as
+ * during iteration.
+ */
+ @Nullable
+ V getLiveValue(ReferenceEntry<K, V> entry, long now) {
+ if (entry.getKey() == null) {
+ return null;
+ }
+ V value = entry.getValueReference().get();
+ if (value == null) {
+ return null;
+ }
+
+ if (isExpired(entry, now)) {
+ return null;
+ }
+ return value;
+ }
+
+ // expiration
+
+ /**
+ * Returns true if the entry has expired.
+ */
+ boolean isExpired(ReferenceEntry<K, V> entry, long now) {
+ if (expiresAfterAccess()
+ && (now - entry.getAccessTime() > expireAfterAccessNanos)) {
+ return true;
+ }
+ if (expiresAfterWrite()
+ && (now - entry.getWriteTime() > expireAfterWriteNanos)) {
+ return true;
+ }
+ return false;
+ }
+
+ // queues
+
+ @GuardedBy("Segment.this")
+ static <K, V> void connectAccessOrder(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
+ previous.setNextInAccessQueue(next);
+ next.setPreviousInAccessQueue(previous);
+ }
+
+ @GuardedBy("Segment.this")
+ static <K, V> void nullifyAccessOrder(ReferenceEntry<K, V> nulled) {
+ ReferenceEntry<K, V> nullEntry = nullEntry();
+ nulled.setNextInAccessQueue(nullEntry);
+ nulled.setPreviousInAccessQueue(nullEntry);
+ }
+
+ @GuardedBy("Segment.this")
+ static <K, V> void connectWriteOrder(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
+ previous.setNextInWriteQueue(next);
+ next.setPreviousInWriteQueue(previous);
+ }
+
+ @GuardedBy("Segment.this")
+ static <K, V> void nullifyWriteOrder(ReferenceEntry<K, V> nulled) {
+ ReferenceEntry<K, V> nullEntry = nullEntry();
+ nulled.setNextInWriteQueue(nullEntry);
+ nulled.setPreviousInWriteQueue(nullEntry);
+ }
+
+ /**
+ * Notifies listeners that an entry has been automatically removed due to expiration, eviction,
+ * or eligibility for garbage collection. This should be called every time expireEntries or
+ * evictEntry is called (once the lock is released).
+ */
+ void processPendingNotifications() {
+ RemovalNotification<K, V> notification;
+ while ((notification = removalNotificationQueue.poll()) != null) {
+ try {
+ removalListener.onRemoval(notification);
+ } catch (Throwable e) {
+ logger.log(Level.WARNING, "Exception thrown by removal listener", e);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ final Segment<K, V>[] newSegmentArray(int ssize) {
+ return new Segment[ssize];
+ }
+
+ // Inner Classes
+
+ /**
+ * Segments are specialized versions of hash tables. This subclass inherits from ReentrantLock
+ * opportunistically, just to simplify some locking and avoid separate construction.
+ */
+ @SuppressWarnings("serial") // This class is never serialized.
+ static class Segment<K, V> extends ReentrantLock {
+
+ /*
+ * TODO(fry): Consider copying variables (like evictsBySize) from outer class into this class.
+ * It will require more memory but will reduce indirection.
+ */
+
+ /*
+ * Segments maintain a table of entry lists that are ALWAYS kept in a consistent state, so can
+ * be read without locking. Next fields of nodes are immutable (final). All list additions are
+ * performed at the front of each bin. This makes it easy to check changes, and also fast to
+ * traverse. When nodes would otherwise be changed, new nodes are created to replace them. This
+ * works well for hash tables since the bin lists tend to be short. (The average length is less
+ * than two.)
+ *
+ * Read operations can thus proceed without locking, but rely on selected uses of volatiles to
+ * ensure that completed write operations performed by other threads are noticed. For most
+ * purposes, the "count" field, tracking the number of elements, serves as that volatile
+ * variable ensuring visibility. This is convenient because this field needs to be read in many
+ * read operations anyway:
+ *
+ * - All (unsynchronized) read operations must first read the "count" field, and should not
+ * look at table entries if it is 0.
+ *
+ * - All (synchronized) write operations should write to the "count" field after structurally
+ * changing any bin. The operations must not take any action that could even momentarily
+ * cause a concurrent read operation to see inconsistent data. This is made easier by the
+ * nature of the read operations in Map. For example, no operation can reveal that the table
+ * has grown but the threshold has not yet been updated, so there are no atomicity requirements
+ * for this with respect to reads.
+ *
+ * As a guide, all critical volatile reads and writes to the count field are marked in code
+ * comments.
+ */
+
+ final LocalCache<K, V> map;
+
+ /**
+ * The number of live elements in this segment's region.
+ */
+ volatile int count;
+
+ /**
+ * The weight of the live elements in this segment's region.
+ */
+ @GuardedBy("Segment.this")
+ int totalWeight;
+
+ /**
+ * Number of updates that alter the size of the table. This is used during bulk-read methods to
+ * make sure they see a consistent snapshot: If modCounts change during a traversal of segments
+ * loading size or checking containsValue, then we might have an inconsistent view of state
+ * so (usually) must retry.
+ */
+ int modCount;
+
+ /**
+ * The table is expanded when its size exceeds this threshold. (The value of this field is
+ * always {@code (int)(capacity * 0.75)}.)
+ */
+ int threshold;
+
+ /**
+ * The per-segment table.
+ */
+ volatile AtomicReferenceArray<ReferenceEntry<K, V>> table;
+
+ /**
+ * The maximum weight of this segment. UNSET_INT if there is no maximum.
+ */
+ final long maxSegmentWeight;
+
+ /**
+ * The key reference queue contains entries whose keys have been garbage collected, and which
+ * need to be cleaned up internally.
+ */
+ final ReferenceQueue<K> keyReferenceQueue;
+
+ /**
+ * The value reference queue contains value references whose values have been garbage collected,
+ * and which need to be cleaned up internally.
+ */
+ final ReferenceQueue<V> valueReferenceQueue;
+
+ /**
+ * The recency queue is used to record which entries were accessed for updating the access
+ * list's ordering. It is drained as a batch operation when either the DRAIN_THRESHOLD is
+ * crossed or a write occurs on the segment.
+ */
+ final Queue<ReferenceEntry<K, V>> recencyQueue;
+
+ /**
+ * A counter of the number of reads since the last write, used to drain queues on a small
+ * fraction of read operations.
+ */
+ final AtomicInteger readCount = new AtomicInteger();
+
+ /**
+ * A queue of elements currently in the map, ordered by write time. Elements are added to the
+ * tail of the queue on write.
+ */
+ @GuardedBy("Segment.this")
+ final Queue<ReferenceEntry<K, V>> writeQueue;
+
+ /**
+ * A queue of elements currently in the map, ordered by access time. Elements are added to the
+ * tail of the queue on access (note that writes count as accesses).
+ */
+ @GuardedBy("Segment.this")
+ final Queue<ReferenceEntry<K, V>> accessQueue;
+
+ /** Accumulates cache statistics. */
+ final StatsCounter statsCounter;
+
+ Segment(LocalCache<K, V> map, int initialCapacity, long maxSegmentWeight,
+ StatsCounter statsCounter) {
+ this.map = map;
+ this.maxSegmentWeight = maxSegmentWeight;
+ this.statsCounter = statsCounter;
+ initTable(newEntryArray(initialCapacity));
+
+ keyReferenceQueue = map.usesKeyReferences()
+ ? new ReferenceQueue<K>() : null;
+
+ valueReferenceQueue = map.usesValueReferences()
+ ? new ReferenceQueue<V>() : null;
+
+ recencyQueue = map.usesAccessQueue()
+ ? new ConcurrentLinkedQueue<ReferenceEntry<K, V>>()
+ : LocalCache.<ReferenceEntry<K, V>>discardingQueue();
+
+ writeQueue = map.usesWriteQueue()
+ ? new WriteQueue<K, V>()
+ : LocalCache.<ReferenceEntry<K, V>>discardingQueue();
+
+ accessQueue = map.usesAccessQueue()
+ ? new AccessQueue<K, V>()
+ : LocalCache.<ReferenceEntry<K, V>>discardingQueue();
+ }
+
+ AtomicReferenceArray<ReferenceEntry<K, V>> newEntryArray(int size) {
+ return new AtomicReferenceArray<ReferenceEntry<K, V>>(size);
+ }
+
+ void initTable(AtomicReferenceArray<ReferenceEntry<K, V>> newTable) {
+ this.threshold = newTable.length() * 3 / 4; // 0.75
+ if (!map.customWeigher() && this.threshold == maxSegmentWeight) {
+ // prevent spurious expansion before eviction
+ this.threshold++;
+ }
+ this.table = newTable;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> 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));
+ return newEntry;
+ }
+
+ /**
+ * Sets a new value of an entry. Adds newly created entries at the end of the access queue.
+ */
+ @GuardedBy("Segment.this")
+ void setValue(ReferenceEntry<K, V> entry, K key, V value, long now) {
+ ValueReference<K, V> previous = entry.getValueReference();
+ int weight = map.weigher.weigh(key, value);
+ checkState(weight >= 0, "Weights must be non-negative");
+
+ ValueReference<K, V> valueReference =
+ map.valueStrength.referenceValue(this, entry, value, weight);
+ entry.setValueReference(valueReference);
+ recordWrite(entry, weight, now);
+ previous.notifyNewValue(value);
+ }
+
+ // loading
+
+ V get(K key, int hash, CacheLoader<? super K, V> loader) throws ExecutionException {
+ try {
+ if (count != 0) { // read-volatile
+ // don't call getLiveEntry, which would ignore loading values
+ ReferenceEntry<K, V> e = getEntry(key, hash);
+ if (e != null) {
+ long now = map.ticker.read();
+ V value = getLiveValue(e, now);
+ if (value != null) {
+ recordRead(e, now);
+ statsCounter.recordHits(1);
+ return scheduleRefresh(e, key, hash, value, now, loader);
+ }
+ ValueReference<K, V> valueReference = e.getValueReference();
+ if (valueReference.isLoading()) {
+ return waitForLoadingValue(e, key, valueReference);
+ }
+ }
+ }
+
+ // at this point e is either null or expired;
+ return lockedGetOrLoad(key, hash, loader);
+ } catch (ExecutionException ee) {
+ Throwable cause = ee.getCause();
+ if (cause instanceof Error) {
+ throw new ExecutionError((Error) cause);
+ } else if (cause instanceof RuntimeException) {
+ throw new UncheckedExecutionException(cause);
+ }
+ throw ee;
+ } finally {
+ postReadCleanup();
+ }
+ }
+
+ V lockedGetOrLoad(K key, int hash, CacheLoader<? super K, V> loader)
+ throws ExecutionException {
+ ReferenceEntry<K, V> e;
+ ValueReference<K, V> valueReference = null;
+ LoadingValueReference<K, V> loadingValueReference = null;
+ boolean createNewEntry = true;
+
+ lock();
+ try {
+ // re-read ticker once inside the lock
+ long now = map.ticker.read();
+ preWriteCleanup(now);
+
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ valueReference = e.getValueReference();
+ if (valueReference.isLoading()) {
+ createNewEntry = false;
+ } else {
+ V value = valueReference.get();
+ if (value == null) {
+ enqueueNotification(entryKey, hash, valueReference, RemovalCause.COLLECTED);
+ } else if (map.isExpired(e, now)) {
+ // This is a duplicate check, as preWriteCleanup already purged expired
+ // entries, but let's accomodate an incorrect expiration queue.
+ enqueueNotification(entryKey, hash, valueReference, RemovalCause.EXPIRED);
+ } else {
+ recordLockedRead(e, now);
+ statsCounter.recordHits(1);
+ // we were concurrent with loading; don't consider refresh
+ return value;
+ }
+
+ // immediately reuse invalid entries
+ writeQueue.remove(e);
+ accessQueue.remove(e);
+ this.count = newCount; // write-volatile
+ }
+ break;
+ }
+ }
+
+ if (createNewEntry) {
+ loadingValueReference = new LoadingValueReference<K, V>();
+
+ if (e == null) {
+ e = newEntry(key, hash, first);
+ e.setValueReference(loadingValueReference);
+ table.set(index, e);
+ } else {
+ e.setValueReference(loadingValueReference);
+ }
+ }
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+
+ if (createNewEntry) {
+ try {
+ // Synchronizes on the entry to allow failing fast when a recursive load is
+ // detected. This may be circumvented when an entry is copied, but will fail fast most
+ // of the time.
+ synchronized (e) {
+ return loadSync(key, hash, loadingValueReference, loader);
+ }
+ } finally {
+ statsCounter.recordMisses(1);
+ }
+ } else {
+ // The entry already exists. Wait for loading.
+ return waitForLoadingValue(e, key, valueReference);
+ }
+ }
+
+ V waitForLoadingValue(ReferenceEntry<K, V> e, K key, ValueReference<K, V> valueReference)
+ throws ExecutionException {
+ if (!valueReference.isLoading()) {
+ throw new AssertionError();
+ }
+
+ checkState(!Thread.holdsLock(e), "Recursive load");
+ // don't consider expiration as we're concurrent with loading
+ try {
+ V value = valueReference.waitForValue();
+ if (value == null) {
+ throw new InvalidCacheLoadException("CacheLoader returned null for key " + key + ".");
+ }
+ // re-read ticker now that loading has completed
+ long now = map.ticker.read();
+ recordRead(e, now);
+ return value;
+ } finally {
+ statsCounter.recordMisses(1);
+ }
+ }
+
+ // at most one of loadSync/loadAsync may be called for any given LoadingValueReference
+
+ V loadSync(K key, int hash, LoadingValueReference<K, V> loadingValueReference,
+ CacheLoader<? super K, V> loader) throws ExecutionException {
+ ListenableFuture<V> loadingFuture = loadingValueReference.loadFuture(key, loader);
+ return getAndRecordStats(key, hash, loadingValueReference, loadingFuture);
+ }
+
+ ListenableFuture<V> loadAsync(final K key, final int hash,
+ final LoadingValueReference<K, V> loadingValueReference, CacheLoader<? super K, V> loader) {
+ final ListenableFuture<V> loadingFuture = loadingValueReference.loadFuture(key, loader);
+ loadingFuture.addListener(
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ V newValue = getAndRecordStats(key, hash, loadingValueReference, loadingFuture);
+ // update loadingFuture for the sake of other pending requests
+ loadingValueReference.set(newValue);
+ } catch (Throwable t) {
+ logger.log(Level.WARNING, "Exception thrown during refresh", t);
+ loadingValueReference.setException(t);
+ }
+ }
+ }, sameThreadExecutor);
+ return loadingFuture;
+ }
+
+ /**
+ * Waits uninterruptibly for {@code newValue} to be loaded, and then records loading stats.
+ */
+ V getAndRecordStats(K key, int hash, LoadingValueReference<K, V> loadingValueReference,
+ ListenableFuture<V> newValue) throws ExecutionException {
+ V value = null;
+ try {
+ value = getUninterruptibly(newValue);
+ if (value == null) {
+ throw new InvalidCacheLoadException("CacheLoader returned null for key " + key + ".");
+ }
+ statsCounter.recordLoadSuccess(loadingValueReference.elapsedNanos());
+ storeLoadedValue(key, hash, loadingValueReference, value);
+ return value;
+ } finally {
+ if (value == null) {
+ statsCounter.recordLoadException(loadingValueReference.elapsedNanos());
+ removeLoadingValue(key, hash, loadingValueReference);
+ }
+ }
+ }
+
+ 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)) {
+ V newValue = refresh(key, hash, loader);
+ if (newValue != null) {
+ return newValue;
+ }
+ }
+ return oldValue;
+ }
+
+ /**
+ * Refreshes the value associated with {@code key}, unless another thread is already doing so.
+ * Returns the newly refreshed value associated with {@code key} if it was refreshed inline, or
+ * {@code null} if another thread is performing the refresh or if an error occurs during
+ * refresh.
+ */
+ @Nullable
+ V refresh(K key, int hash, CacheLoader<? super K, V> loader) {
+ final LoadingValueReference<K, V> loadingValueReference =
+ insertLoadingValueReference(key, hash);
+ if (loadingValueReference == null) {
+ return null;
+ }
+
+ ListenableFuture<V> result = loadAsync(key, hash, loadingValueReference, loader);
+ if (result.isDone()) {
+ try {
+ return Uninterruptibles.getUninterruptibly(result);
+ } catch (Throwable t) {
+ // don't let refresh exceptions propagate; error was already logged
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a newly inserted {@code LoadingValueReference}, or null if the live value reference
+ * is already loading.
+ */
+ @Nullable
+ LoadingValueReference<K, V> insertLoadingValueReference(final K key, final int hash) {
+ ReferenceEntry<K, V> e = null;
+ lock();
+ try {
+ long now = map.ticker.read();
+ preWriteCleanup(now);
+
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ // Look for an existing entry.
+ for (e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ // We found an existing entry.
+
+ ValueReference<K, V> valueReference = e.getValueReference();
+ if (valueReference.isLoading()) {
+ // refresh is a no-op if loading is pending
+ return null;
+ }
+
+ // continue returning old value while loading
+ ++modCount;
+ LoadingValueReference<K, V> loadingValueReference =
+ new LoadingValueReference<K, V>(valueReference);
+ e.setValueReference(loadingValueReference);
+ return loadingValueReference;
+ }
+ }
+
+ ++modCount;
+ LoadingValueReference<K, V> loadingValueReference = new LoadingValueReference<K, V>();
+ e = newEntry(key, hash, first);
+ e.setValueReference(loadingValueReference);
+ table.set(index, e);
+ return loadingValueReference;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ // reference queues, for garbage collection cleanup
+
+ /**
+ * Cleanup collected entries when the lock is available.
+ */
+ void tryDrainReferenceQueues() {
+ if (tryLock()) {
+ try {
+ drainReferenceQueues();
+ } finally {
+ unlock();
+ }
+ }
+ }
+
+ /**
+ * Drain the key and value reference queues, cleaning up internal entries containing garbage
+ * collected keys or values.
+ */
+ @GuardedBy("Segment.this")
+ void drainReferenceQueues() {
+ if (map.usesKeyReferences()) {
+ drainKeyReferenceQueue();
+ }
+ if (map.usesValueReferences()) {
+ drainValueReferenceQueue();
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ void drainKeyReferenceQueue() {
+ Reference<? extends K> ref;
+ int i = 0;
+ while ((ref = keyReferenceQueue.poll()) != null) {
+ @SuppressWarnings("unchecked")
+ ReferenceEntry<K, V> entry = (ReferenceEntry<K, V>) ref;
+ map.reclaimKey(entry);
+ if (++i == DRAIN_MAX) {
+ break;
+ }
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ void drainValueReferenceQueue() {
+ Reference<? extends V> ref;
+ int i = 0;
+ while ((ref = valueReferenceQueue.poll()) != null) {
+ @SuppressWarnings("unchecked")
+ ValueReference<K, V> valueReference = (ValueReference<K, V>) ref;
+ map.reclaimValue(valueReference);
+ if (++i == DRAIN_MAX) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Clears all entries from the key and value reference queues.
+ */
+ void clearReferenceQueues() {
+ if (map.usesKeyReferences()) {
+ clearKeyReferenceQueue();
+ }
+ if (map.usesValueReferences()) {
+ clearValueReferenceQueue();
+ }
+ }
+
+ void clearKeyReferenceQueue() {
+ while (keyReferenceQueue.poll() != null) {}
+ }
+
+ void clearValueReferenceQueue() {
+ while (valueReferenceQueue.poll() != null) {}
+ }
+
+ // recency queue, shared by expiration and eviction
+
+ /**
+ * Records the relative order in which this read was performed by adding {@code entry} to the
+ * recency queue. At write-time, or when the queue is full past the threshold, the queue will
+ * be drained and the entries therein processed.
+ *
+ * <p>Note: locked reads should use {@link #recordLockedRead}.
+ */
+ void recordRead(ReferenceEntry<K, V> entry, long now) {
+ if (map.recordsAccess()) {
+ entry.setAccessTime(now);
+ }
+ recencyQueue.add(entry);
+ }
+
+ /**
+ * Updates the eviction metadata that {@code entry} was just read. This currently amounts to
+ * adding {@code entry} to relevant eviction lists.
+ *
+ * <p>Note: this method should only be called under lock, as it directly manipulates the
+ * eviction queues. Unlocked reads should use {@link #recordRead}.
+ */
+ @GuardedBy("Segment.this")
+ void recordLockedRead(ReferenceEntry<K, V> entry, long now) {
+ if (map.recordsAccess()) {
+ entry.setAccessTime(now);
+ }
+ accessQueue.add(entry);
+ }
+
+ /**
+ * Updates eviction metadata that {@code entry} was just written. This currently amounts to
+ * adding {@code entry} to relevant eviction lists.
+ */
+ @GuardedBy("Segment.this")
+ void recordWrite(ReferenceEntry<K, V> entry, int weight, long now) {
+ // we are already under lock, so drain the recency queue immediately
+ drainRecencyQueue();
+ totalWeight += weight;
+
+ if (map.recordsAccess()) {
+ entry.setAccessTime(now);
+ }
+ if (map.recordsWrite()) {
+ entry.setWriteTime(now);
+ }
+ accessQueue.add(entry);
+ writeQueue.add(entry);
+ }
+
+ /**
+ * Drains the recency queue, updating eviction metadata that the entries therein were read in
+ * the specified relative order. This currently amounts to adding them to relevant eviction
+ * lists (accounting for the fact that they could have been removed from the map since being
+ * added to the recency queue).
+ */
+ @GuardedBy("Segment.this")
+ void drainRecencyQueue() {
+ ReferenceEntry<K, V> e;
+ while ((e = recencyQueue.poll()) != null) {
+ // An entry may be in the recency queue despite it being removed from
+ // the map . This can occur when the entry was concurrently read while a
+ // writer is removing it from the segment or after a clear has removed
+ // all of the segment's entries.
+ if (accessQueue.contains(e)) {
+ accessQueue.add(e);
+ }
+ }
+ }
+
+ // expiration
+
+ /**
+ * Cleanup expired entries when the lock is available.
+ */
+ void tryExpireEntries(long now) {
+ if (tryLock()) {
+ try {
+ expireEntries(now);
+ } finally {
+ unlock();
+ // don't call postWriteCleanup as we're in a read
+ }
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ void expireEntries(long now) {
+ drainRecencyQueue();
+
+ ReferenceEntry<K, V> e;
+ while ((e = writeQueue.peek()) != null && map.isExpired(e, now)) {
+ if (!removeEntry(e, e.getHash(), RemovalCause.EXPIRED)) {
+ throw new AssertionError();
+ }
+ }
+ while ((e = accessQueue.peek()) != null && map.isExpired(e, now)) {
+ if (!removeEntry(e, e.getHash(), RemovalCause.EXPIRED)) {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ // eviction
+
+ @GuardedBy("Segment.this")
+ void enqueueNotification(ReferenceEntry<K, V> entry, RemovalCause cause) {
+ enqueueNotification(entry.getKey(), entry.getHash(), entry.getValueReference(), cause);
+ }
+
+ @GuardedBy("Segment.this")
+ void enqueueNotification(@Nullable K key, int hash, ValueReference<K, V> valueReference,
+ RemovalCause cause) {
+ totalWeight -= valueReference.getWeight();
+ if (cause.wasEvicted()) {
+ statsCounter.recordEviction();
+ }
+ if (map.removalNotificationQueue != DISCARDING_QUEUE) {
+ V value = valueReference.get();
+ RemovalNotification<K, V> notification = new RemovalNotification<K, V>(key, value, cause);
+ map.removalNotificationQueue.offer(notification);
+ }
+ }
+
+ /**
+ * Performs eviction if the segment is full. This should only be called prior to adding a new
+ * entry and increasing {@code count}.
+ */
+ @GuardedBy("Segment.this")
+ void evictEntries() {
+ if (!map.evictsBySize()) {
+ return;
+ }
+
+ drainRecencyQueue();
+ while (totalWeight > maxSegmentWeight) {
+ ReferenceEntry<K, V> e = getNextEvictable();
+ if (!removeEntry(e, e.getHash(), RemovalCause.SIZE)) {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ // TODO(fry): instead implement this with an eviction head
+ ReferenceEntry<K, V> getNextEvictable() {
+ for (ReferenceEntry<K, V> e : accessQueue) {
+ int weight = e.getValueReference().getWeight();
+ if (weight > 0) {
+ return e;
+ }
+ }
+ throw new AssertionError();
+ }
+
+ /**
+ * Returns first entry of bin for given hash.
+ */
+ ReferenceEntry<K, V> getFirst(int hash) {
+ // read this volatile field only once
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ return table.get(hash & (table.length() - 1));
+ }
+
+ // Specialized implementations of map methods
+
+ @Nullable
+ ReferenceEntry<K, V> getEntry(Object key, int hash) {
+ for (ReferenceEntry<K, V> e = getFirst(hash); e != null; e = e.getNext()) {
+ if (e.getHash() != hash) {
+ continue;
+ }
+
+ K entryKey = e.getKey();
+ if (entryKey == null) {
+ tryDrainReferenceQueues();
+ continue;
+ }
+
+ if (map.keyEquivalence.equivalent(key, entryKey)) {
+ return e;
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ ReferenceEntry<K, V> getLiveEntry(Object key, int hash, long now) {
+ ReferenceEntry<K, V> e = getEntry(key, hash);
+ if (e == null) {
+ return null;
+ } else if (map.isExpired(e, now)) {
+ tryExpireEntries(now);
+ return null;
+ }
+ return e;
+ }
+
+ /**
+ * Gets the value from an entry. Returns null if the entry is invalid, partially-collected,
+ * loading, or expired.
+ */
+ V getLiveValue(ReferenceEntry<K, V> entry, long now) {
+ if (entry.getKey() == null) {
+ tryDrainReferenceQueues();
+ return null;
+ }
+ V value = entry.getValueReference().get();
+ if (value == null) {
+ tryDrainReferenceQueues();
+ return null;
+ }
+
+ if (map.isExpired(entry, now)) {
+ tryExpireEntries(now);
+ return null;
+ }
+ return value;
+ }
+
+ @Nullable
+ V get(Object key, int hash) {
+ try {
+ if (count != 0) { // read-volatile
+ long now = map.ticker.read();
+ ReferenceEntry<K, V> e = getLiveEntry(key, hash, now);
+ if (e == null) {
+ return null;
+ }
+
+ V value = e.getValueReference().get();
+ if (value != null) {
+ recordRead(e, now);
+ return scheduleRefresh(e, e.getKey(), hash, value, now, map.defaultLoader);
+ }
+ tryDrainReferenceQueues();
+ }
+ return null;
+ } finally {
+ postReadCleanup();
+ }
+ }
+
+ boolean containsKey(Object key, int hash) {
+ try {
+ if (count != 0) { // read-volatile
+ long now = map.ticker.read();
+ ReferenceEntry<K, V> e = getLiveEntry(key, hash, now);
+ if (e == null) {
+ return false;
+ }
+ return e.getValueReference().get() != null;
+ }
+
+ return false;
+ } finally {
+ postReadCleanup();
+ }
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link
+ * LocalCache#containsValue} directly.
+ */
+ @VisibleForTesting
+ boolean containsValue(Object value) {
+ try {
+ if (count != 0) { // read-volatile
+ long now = map.ticker.read();
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int length = table.length();
+ for (int i = 0; i < length; ++i) {
+ for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) {
+ V entryValue = getLiveValue(e, now);
+ if (entryValue == null) {
+ continue;
+ }
+ if (map.valueEquivalence.equivalent(value, entryValue)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ } finally {
+ postReadCleanup();
+ }
+ }
+
+ @Nullable
+ V put(K key, int hash, V value, boolean onlyIfAbsent) {
+ lock();
+ try {
+ long now = map.ticker.read();
+ 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);
+
+ // Look for an existing entry.
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ // We found an existing entry.
+
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+
+ if (entryValue == null) {
+ ++modCount;
+ if (valueReference.isActive()) {
+ enqueueNotification(key, hash, valueReference, RemovalCause.COLLECTED);
+ setValue(e, key, value, now);
+ newCount = this.count; // count remains unchanged
+ } else {
+ setValue(e, key, value, now);
+ newCount = this.count + 1;
+ }
+ this.count = newCount; // write-volatile
+ evictEntries();
+ return null;
+ } else if (onlyIfAbsent) {
+ // Mimic
+ // "if (!map.containsKey(key)) ...
+ // else return map.get(key);
+ recordLockedRead(e, now);
+ return entryValue;
+ } else {
+ // clobber existing entry, count remains unchanged
+ ++modCount;
+ enqueueNotification(key, hash, valueReference, RemovalCause.REPLACED);
+ setValue(e, key, value, now);
+ evictEntries();
+ return entryValue;
+ }
+ }
+ }
+
+ // Create a new entry.
+ ++modCount;
+ ReferenceEntry<K, V> newEntry = newEntry(key, hash, first);
+ setValue(newEntry, key, value, now);
+ table.set(index, newEntry);
+ newCount = this.count + 1;
+ this.count = newCount; // write-volatile
+ evictEntries();
+ return null;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ /**
+ * Expands the table if possible.
+ */
+ @GuardedBy("Segment.this")
+ void expand() {
+ AtomicReferenceArray<ReferenceEntry<K, V>> oldTable = table;
+ int oldCapacity = oldTable.length();
+ if (oldCapacity >= MAXIMUM_CAPACITY) {
+ return;
+ }
+
+ /*
+ * Reclassify nodes in each list to new Map. Because we are using power-of-two expansion, the
+ * elements from each bin must either stay at same index, or move with a power of two offset.
+ * We eliminate unnecessary node creation by catching cases where old nodes can be reused
+ * because their next fields won't change. Statistically, at the default threshold, only
+ * about one-sixth of them need cloning when a table doubles. The nodes they replace will be
+ * garbage collectable as soon as they are no longer referenced by any reader thread that may
+ * be in the midst of traversing table right now.
+ */
+
+ int newCount = count;
+ AtomicReferenceArray<ReferenceEntry<K, V>> newTable = newEntryArray(oldCapacity << 1);
+ threshold = newTable.length() * 3 / 4;
+ int newMask = newTable.length() - 1;
+ for (int oldIndex = 0; oldIndex < oldCapacity; ++oldIndex) {
+ // We need to guarantee that any existing reads of old Map can
+ // proceed. So we cannot yet null out each bin.
+ ReferenceEntry<K, V> head = oldTable.get(oldIndex);
+
+ if (head != null) {
+ ReferenceEntry<K, V> next = head.getNext();
+ int headIndex = head.getHash() & newMask;
+
+ // Single node on list
+ if (next == null) {
+ newTable.set(headIndex, head);
+ } else {
+ // Reuse the consecutive sequence of nodes with the same target
+ // index from the end of the list. tail points to the first
+ // entry in the reusable list.
+ ReferenceEntry<K, V> tail = head;
+ int tailIndex = headIndex;
+ for (ReferenceEntry<K, V> e = next; e != null; e = e.getNext()) {
+ int newIndex = e.getHash() & newMask;
+ if (newIndex != tailIndex) {
+ // The index changed. We'll need to copy the previous entry.
+ tailIndex = newIndex;
+ tail = e;
+ }
+ }
+ newTable.set(tailIndex, tail);
+
+ // 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 {
+ removeCollectedEntry(e);
+ newCount--;
+ }
+ }
+ }
+ }
+ }
+ table = newTable;
+ this.count = newCount;
+ }
+
+ boolean replace(K key, int hash, V oldValue, V newValue) {
+ lock();
+ try {
+ long now = map.ticker.read();
+ preWriteCleanup(now);
+
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+ if (entryValue == null) {
+ if (valueReference.isActive()) {
+ // If the value disappeared, this entry is partially collected.
+ int newCount = this.count - 1;
+ ++modCount;
+ ReferenceEntry<K, V> newFirst = removeValueFromChain(
+ first, e, entryKey, hash, valueReference, RemovalCause.COLLECTED);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ }
+ return false;
+ }
+
+ if (map.valueEquivalence.equivalent(oldValue, entryValue)) {
+ ++modCount;
+ enqueueNotification(key, hash, valueReference, RemovalCause.REPLACED);
+ setValue(e, key, newValue, now);
+ evictEntries();
+ return true;
+ } else {
+ // Mimic
+ // "if (map.containsKey(key) && map.get(key).equals(oldValue))..."
+ recordLockedRead(e, now);
+ return false;
+ }
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ @Nullable
+ V replace(K key, int hash, V newValue) {
+ lock();
+ try {
+ long now = map.ticker.read();
+ preWriteCleanup(now);
+
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+ if (entryValue == null) {
+ if (valueReference.isActive()) {
+ // If the value disappeared, this entry is partially collected.
+ int newCount = this.count - 1;
+ ++modCount;
+ ReferenceEntry<K, V> newFirst = removeValueFromChain(
+ first, e, entryKey, hash, valueReference, RemovalCause.COLLECTED);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ }
+ return null;
+ }
+
+ ++modCount;
+ enqueueNotification(key, hash, valueReference, RemovalCause.REPLACED);
+ setValue(e, key, newValue, now);
+ evictEntries();
+ return entryValue;
+ }
+ }
+
+ return null;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ @Nullable
+ V remove(Object key, int hash) {
+ lock();
+ try {
+ long now = map.ticker.read();
+ preWriteCleanup(now);
+
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+
+ RemovalCause cause;
+ if (entryValue != null) {
+ cause = RemovalCause.EXPLICIT;
+ } else if (valueReference.isActive()) {
+ cause = RemovalCause.COLLECTED;
+ } else {
+ // currently loading
+ return null;
+ }
+
+ ++modCount;
+ ReferenceEntry<K, V> newFirst = removeValueFromChain(
+ first, e, entryKey, hash, valueReference, cause);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return entryValue;
+ }
+ }
+
+ return null;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ boolean storeLoadedValue(K key, int hash, LoadingValueReference<K, V> oldValueReference,
+ V newValue) {
+ lock();
+ try {
+ long now = map.ticker.read();
+ 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);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && 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)) {
+ ++modCount;
+ if (oldValueReference.isActive()) {
+ RemovalCause cause =
+ (entryValue == null) ? RemovalCause.COLLECTED : RemovalCause.REPLACED;
+ enqueueNotification(key, hash, oldValueReference, cause);
+ newCount--;
+ }
+ setValue(e, key, newValue, now);
+ this.count = newCount; // write-volatile
+ evictEntries();
+ return true;
+ }
+
+ // the loaded value was already clobbered
+ valueReference = new WeightedStrongValueReference<K, V>(newValue, 0);
+ enqueueNotification(key, hash, valueReference, RemovalCause.REPLACED);
+ return false;
+ }
+ }
+
+ ++modCount;
+ ReferenceEntry<K, V> newEntry = newEntry(key, hash, first);
+ setValue(newEntry, key, newValue, now);
+ table.set(index, newEntry);
+ this.count = newCount; // write-volatile
+ evictEntries();
+ return true;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ boolean remove(Object key, int hash, Object value) {
+ lock();
+ try {
+ long now = map.ticker.read();
+ preWriteCleanup(now);
+
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+
+ RemovalCause cause;
+ if (map.valueEquivalence.equivalent(value, entryValue)) {
+ cause = RemovalCause.EXPLICIT;
+ } else if (entryValue == null && valueReference.isActive()) {
+ cause = RemovalCause.COLLECTED;
+ } else {
+ // currently loading
+ return false;
+ }
+
+ ++modCount;
+ ReferenceEntry<K, V> newFirst = removeValueFromChain(
+ first, e, entryKey, hash, valueReference, cause);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return (cause == RemovalCause.EXPLICIT);
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ void clear() {
+ if (count != 0) { // read-volatile
+ lock();
+ try {
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ for (int i = 0; i < table.length(); ++i) {
+ for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) {
+ // Loading references aren't actually in the map yet.
+ if (e.getValueReference().isActive()) {
+ enqueueNotification(e, RemovalCause.EXPLICIT);
+ }
+ }
+ }
+ for (int i = 0; i < table.length(); ++i) {
+ table.set(i, null);
+ }
+ clearReferenceQueues();
+ writeQueue.clear();
+ accessQueue.clear();
+ readCount.set(0);
+
+ ++modCount;
+ count = 0; // write-volatile
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ @Nullable
+ ReferenceEntry<K, V> removeValueFromChain(ReferenceEntry<K, V> first,
+ ReferenceEntry<K, V> entry, @Nullable K key, int hash, ValueReference<K, V> valueReference,
+ RemovalCause cause) {
+ enqueueNotification(key, hash, valueReference, cause);
+ writeQueue.remove(entry);
+ accessQueue.remove(entry);
+
+ if (valueReference.isLoading()) {
+ valueReference.notifyNewValue(null);
+ return first;
+ } else {
+ return removeEntryFromChain(first, entry);
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ @Nullable
+ ReferenceEntry<K, V> removeEntryFromChain(ReferenceEntry<K, V> first,
+ ReferenceEntry<K, V> entry) {
+ 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 {
+ removeCollectedEntry(e);
+ newCount--;
+ }
+ }
+ this.count = newCount;
+ return newFirst;
+ }
+
+ @GuardedBy("Segment.this")
+ void removeCollectedEntry(ReferenceEntry<K, V> entry) {
+ enqueueNotification(entry, RemovalCause.COLLECTED);
+ writeQueue.remove(entry);
+ accessQueue.remove(entry);
+ }
+
+ /**
+ * Removes an entry whose key has been garbage collected.
+ */
+ boolean reclaimKey(ReferenceEntry<K, V> entry, int hash) {
+ lock();
+ try {
+ int newCount = count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ if (e == entry) {
+ ++modCount;
+ ReferenceEntry<K, V> newFirst = removeValueFromChain(
+ first, e, e.getKey(), hash, e.getValueReference(), RemovalCause.COLLECTED);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return true;
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ /**
+ * Removes an entry whose value has been garbage collected.
+ */
+ boolean reclaimValue(K key, int hash, ValueReference<K, V> valueReference) {
+ lock();
+ try {
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> v = e.getValueReference();
+ if (v == valueReference) {
+ ++modCount;
+ ReferenceEntry<K, V> newFirst = removeValueFromChain(
+ first, e, entryKey, hash, valueReference, RemovalCause.COLLECTED);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return true;
+ }
+ return false;
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ if (!isHeldByCurrentThread()) { // don't cleanup inside of put
+ postWriteCleanup();
+ }
+ }
+ }
+
+ boolean removeLoadingValue(K key, int hash, LoadingValueReference<K, V> valueReference) {
+ lock();
+ try {
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> v = e.getValueReference();
+ if (v == valueReference) {
+ if (valueReference.isActive()) {
+ e.setValueReference(valueReference.getOldValue());
+ } else {
+ ReferenceEntry<K, V> newFirst = removeEntryFromChain(first, e);
+ table.set(index, newFirst);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ boolean removeEntry(ReferenceEntry<K, V> entry, int hash, RemovalCause cause) {
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ if (e == entry) {
+ ++modCount;
+ ReferenceEntry<K, V> newFirst = removeValueFromChain(
+ first, e, e.getKey(), hash, e.getValueReference(), cause);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * 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.
+ */
+ void postReadCleanup() {
+ if ((readCount.incrementAndGet() & DRAIN_THRESHOLD) == 0) {
+ cleanUp();
+ }
+ }
+
+ /**
+ * Performs routine cleanup prior to executing a write. This should be called every time a
+ * write thread acquires the segment lock, immediately after acquiring the lock.
+ *
+ * <p>Post-condition: expireEntries has been run.
+ */
+ @GuardedBy("Segment.this")
+ void preWriteCleanup(long now) {
+ runLockedCleanup(now);
+ }
+
+ /**
+ * Performs routine cleanup following a write.
+ */
+ void postWriteCleanup() {
+ runUnlockedCleanup();
+ }
+
+ void cleanUp() {
+ long now = map.ticker.read();
+ runLockedCleanup(now);
+ runUnlockedCleanup();
+ }
+
+ void runLockedCleanup(long now) {
+ if (tryLock()) {
+ try {
+ drainReferenceQueues();
+ expireEntries(now); // calls drainRecencyQueue
+ readCount.set(0);
+ } finally {
+ unlock();
+ }
+ }
+ }
+
+ void runUnlockedCleanup() {
+ // locked cleanup may generate notifications we can send unlocked
+ if (!isHeldByCurrentThread()) {
+ map.processPendingNotifications();
+ }
+ }
+
+ }
+
+ static class LoadingValueReference<K, V> implements ValueReference<K, V> {
+ volatile ValueReference<K, V> oldValue;
+
+ // TODO(fry): rename get, then extend AbstractFuture instead of containing SettableFuture
+ final SettableFuture<V> futureValue = SettableFuture.create();
+ final Stopwatch stopwatch = new Stopwatch();
+
+ public LoadingValueReference() {
+ this(LocalCache.<K, V>unset());
+ }
+
+ public LoadingValueReference(ValueReference<K, V> oldValue) {
+ this.oldValue = oldValue;
+ }
+
+ @Override
+ public boolean isLoading() {
+ return true;
+ }
+
+ @Override
+ public boolean isActive() {
+ return oldValue.isActive();
+ }
+
+ @Override
+ public int getWeight() {
+ return oldValue.getWeight();
+ }
+
+ public boolean set(@Nullable V newValue) {
+ return futureValue.set(newValue);
+ }
+
+ public boolean setException(Throwable t) {
+ return setException(futureValue, t);
+ }
+
+ private static boolean setException(SettableFuture<?> future, Throwable t) {
+ try {
+ return future.setException(t);
+ } catch (Error e) {
+ // the error will already be propagated by the loading thread
+ return false;
+ }
+ }
+
+ private ListenableFuture<V> fullyFailedFuture(Throwable t) {
+ SettableFuture<V> future = SettableFuture.create();
+ setException(future, t);
+ return future;
+ }
+
+ @Override
+ public void notifyNewValue(@Nullable V newValue) {
+ if (newValue != null) {
+ // The pending load was clobbered by a manual write.
+ // Unblock all pending gets, and have them return the new value.
+ set(newValue);
+ } else {
+ // The pending load was removed. Delay notifications until loading completes.
+ oldValue = unset();
+ }
+
+ // TODO(fry): could also cancel loading if we had a handle on its future
+ }
+
+ public ListenableFuture<V> loadFuture(K key, CacheLoader<? super K, V> loader) {
+ stopwatch.start();
+ V previousValue = oldValue.get();
+ try {
+ if (previousValue == null) {
+ V newValue = loader.load(key);
+ return set(newValue) ? futureValue : Futures.immediateFuture(newValue);
+ } else {
+ ListenableFuture<V> newValue = loader.reload(key, previousValue);
+ // rely on loadAsync to call set in order to avoid adding a second listener here
+ 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.elapsedTime(NANOSECONDS);
+ }
+
+ @Override
+ public V waitForValue() throws ExecutionException {
+ return getUninterruptibly(futureValue);
+ }
+
+ @Override
+ public V get() {
+ return oldValue.get();
+ }
+
+ public ValueReference<K, V> getOldValue() {
+ return oldValue;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return null;
+ }
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry) {
+ return this;
+ }
+ }
+
+ // Queues
+
+ /**
+ * A custom queue for managing eviction order. Note that this is tightly integrated with {@code
+ * ReferenceEntry}, upon which it relies to perform its linking.
+ *
+ * <p>Note that this entire implementation makes the assumption that all elements which are in
+ * the map are also in this queue, and that all elements not in the queue are not in the map.
+ *
+ * <p>The benefits of creating our own queue are that (1) we can replace elements in the middle
+ * of the queue as part of copyWriteEntry, and (2) the contains method is highly optimized
+ * for the current model.
+ */
+ static final class WriteQueue<K, V> extends AbstractQueue<ReferenceEntry<K, V>> {
+ final ReferenceEntry<K, V> head = new AbstractReferenceEntry<K, V>() {
+
+ @Override
+ public long getWriteTime() {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public void setWriteTime(long time) {}
+
+ ReferenceEntry<K, V> nextWrite = this;
+
+ @Override
+ public ReferenceEntry<K, V> getNextInWriteQueue() {
+ return nextWrite;
+ }
+
+ @Override
+ public void setNextInWriteQueue(ReferenceEntry<K, V> next) {
+ this.nextWrite = next;
+ }
+
+ ReferenceEntry<K, V> previousWrite = this;
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInWriteQueue() {
+ return previousWrite;
+ }
+
+ @Override
+ public void setPreviousInWriteQueue(ReferenceEntry<K, V> previous) {
+ this.previousWrite = previous;
+ }
+ };
+
+ // implements Queue
+
+ @Override
+ public boolean offer(ReferenceEntry<K, V> entry) {
+ // unlink
+ connectWriteOrder(entry.getPreviousInWriteQueue(), entry.getNextInWriteQueue());
+
+ // add to tail
+ connectWriteOrder(head.getPreviousInWriteQueue(), entry);
+ connectWriteOrder(entry, head);
+
+ return true;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> peek() {
+ ReferenceEntry<K, V> next = head.getNextInWriteQueue();
+ return (next == head) ? null : next;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> poll() {
+ ReferenceEntry<K, V> next = head.getNextInWriteQueue();
+ if (next == head) {
+ return null;
+ }
+
+ remove(next);
+ return next;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean remove(Object o) {
+ ReferenceEntry<K, V> e = (ReferenceEntry) o;
+ ReferenceEntry<K, V> previous = e.getPreviousInWriteQueue();
+ ReferenceEntry<K, V> next = e.getNextInWriteQueue();
+ connectWriteOrder(previous, next);
+ nullifyWriteOrder(e);
+
+ return next != NullEntry.INSTANCE;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean contains(Object o) {
+ ReferenceEntry<K, V> e = (ReferenceEntry) o;
+ return e.getNextInWriteQueue() != NullEntry.INSTANCE;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return head.getNextInWriteQueue() == head;
+ }
+
+ @Override
+ public int size() {
+ int size = 0;
+ for (ReferenceEntry<K, V> e = head.getNextInWriteQueue(); e != head;
+ e = e.getNextInWriteQueue()) {
+ size++;
+ }
+ return size;
+ }
+
+ @Override
+ public void clear() {
+ ReferenceEntry<K, V> e = head.getNextInWriteQueue();
+ while (e != head) {
+ ReferenceEntry<K, V> next = e.getNextInWriteQueue();
+ nullifyWriteOrder(e);
+ e = next;
+ }
+
+ head.setNextInWriteQueue(head);
+ head.setPreviousInWriteQueue(head);
+ }
+
+ @Override
+ public Iterator<ReferenceEntry<K, V>> iterator() {
+ return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) {
+ @Override
+ protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) {
+ ReferenceEntry<K, V> next = previous.getNextInWriteQueue();
+ return (next == head) ? null : next;
+ }
+ };
+ }
+ }
+
+ /**
+ * A custom queue for managing access order. Note that this is tightly integrated with
+ * {@code ReferenceEntry}, upon which it reliese to perform its linking.
+ *
+ * <p>Note that this entire implementation makes the assumption that all elements which are in
+ * the map are also in this queue, and that all elements not in the queue are not in the map.
+ *
+ * <p>The benefits of creating our own queue are that (1) we can replace elements in the middle
+ * of the queue as part of copyWriteEntry, and (2) the contains method is highly optimized
+ * for the current model.
+ */
+ static final class AccessQueue<K, V> extends AbstractQueue<ReferenceEntry<K, V>> {
+ final ReferenceEntry<K, V> head = new AbstractReferenceEntry<K, V>() {
+
+ @Override
+ public long getAccessTime() {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public void setAccessTime(long time) {}
+
+ ReferenceEntry<K, V> nextAccess = this;
+
+ @Override
+ public ReferenceEntry<K, V> getNextInAccessQueue() {
+ return nextAccess;
+ }
+
+ @Override
+ public void setNextInAccessQueue(ReferenceEntry<K, V> next) {
+ this.nextAccess = next;
+ }
+
+ ReferenceEntry<K, V> previousAccess = this;
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousInAccessQueue() {
+ return previousAccess;
+ }
+
+ @Override
+ public void setPreviousInAccessQueue(ReferenceEntry<K, V> previous) {
+ this.previousAccess = previous;
+ }
+ };
+
+ // implements Queue
+
+ @Override
+ public boolean offer(ReferenceEntry<K, V> entry) {
+ // unlink
+ connectAccessOrder(entry.getPreviousInAccessQueue(), entry.getNextInAccessQueue());
+
+ // add to tail
+ connectAccessOrder(head.getPreviousInAccessQueue(), entry);
+ connectAccessOrder(entry, head);
+
+ return true;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> peek() {
+ ReferenceEntry<K, V> next = head.getNextInAccessQueue();
+ return (next == head) ? null : next;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> poll() {
+ ReferenceEntry<K, V> next = head.getNextInAccessQueue();
+ if (next == head) {
+ return null;
+ }
+
+ remove(next);
+ return next;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean remove(Object o) {
+ ReferenceEntry<K, V> e = (ReferenceEntry) o;
+ ReferenceEntry<K, V> previous = e.getPreviousInAccessQueue();
+ ReferenceEntry<K, V> next = e.getNextInAccessQueue();
+ connectAccessOrder(previous, next);
+ nullifyAccessOrder(e);
+
+ return next != NullEntry.INSTANCE;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean contains(Object o) {
+ ReferenceEntry<K, V> e = (ReferenceEntry) o;
+ return e.getNextInAccessQueue() != NullEntry.INSTANCE;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return head.getNextInAccessQueue() == head;
+ }
+
+ @Override
+ public int size() {
+ int size = 0;
+ for (ReferenceEntry<K, V> e = head.getNextInAccessQueue(); e != head;
+ e = e.getNextInAccessQueue()) {
+ size++;
+ }
+ return size;
+ }
+
+ @Override
+ public void clear() {
+ ReferenceEntry<K, V> e = head.getNextInAccessQueue();
+ while (e != head) {
+ ReferenceEntry<K, V> next = e.getNextInAccessQueue();
+ nullifyAccessOrder(e);
+ e = next;
+ }
+
+ head.setNextInAccessQueue(head);
+ head.setPreviousInAccessQueue(head);
+ }
+
+ @Override
+ public Iterator<ReferenceEntry<K, V>> iterator() {
+ return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) {
+ @Override
+ protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) {
+ ReferenceEntry<K, V> next = previous.getNextInAccessQueue();
+ return (next == head) ? null : next;
+ }
+ };
+ }
+ }
+
+ // Cache support
+
+ public void cleanUp() {
+ for (Segment<?, ?> segment : segments) {
+ segment.cleanUp();
+ }
+ }
+
+ // ConcurrentMap methods
+
+ @Override
+ public boolean isEmpty() {
+ /*
+ * Sum per-segment modCounts to avoid mis-reporting when elements are concurrently added and
+ * removed in one segment while checking another, in which case the table was never actually
+ * empty at any point. (The sum ensures accuracy up through at least 1<<31 per-segment
+ * modifications before recheck.) Method containsValue() uses similar constructions for
+ * stability checks.
+ */
+ long sum = 0L;
+ Segment<K, V>[] segments = this.segments;
+ for (int i = 0; i < segments.length; ++i) {
+ if (segments[i].count != 0) {
+ return false;
+ }
+ sum += segments[i].modCount;
+ }
+
+ if (sum != 0L) { // recheck unless no modifications
+ for (int i = 0; i < segments.length; ++i) {
+ if (segments[i].count != 0) {
+ return false;
+ }
+ sum -= segments[i].modCount;
+ }
+ if (sum != 0L) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ long longSize() {
+ Segment<K, V>[] segments = this.segments;
+ long sum = 0;
+ for (int i = 0; i < segments.length; ++i) {
+ sum += segments[i].count;
+ }
+ return sum;
+ }
+
+ @Override
+ public int size() {
+ return Ints.saturatedCast(longSize());
+ }
+
+ @Override
+ @Nullable
+ public V get(@Nullable Object key) {
+ if (key == null) {
+ return null;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).get(key, hash);
+ }
+
+ @Nullable
+ public V getIfPresent(Object key) {
+ int hash = hash(checkNotNull(key));
+ V value = segmentFor(hash).get(key, hash);
+ if (value == null) {
+ globalStatsCounter.recordMisses(1);
+ } else {
+ globalStatsCounter.recordHits(1);
+ }
+ return value;
+ }
+
+ V get(K key, CacheLoader<? super K, V> loader) throws ExecutionException {
+ int hash = hash(checkNotNull(key));
+ return segmentFor(hash).get(key, hash, loader);
+ }
+
+ V getOrLoad(K key) throws ExecutionException {
+ return get(key, defaultLoader);
+ }
+
+ ImmutableMap<K, V> getAllPresent(Iterable<?> keys) {
+ int hits = 0;
+ int misses = 0;
+
+ Map<K, V> result = Maps.newLinkedHashMap();
+ for (Object 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);
+ hits++;
+ }
+ }
+ globalStatsCounter.recordHits(hits);
+ globalStatsCounter.recordMisses(misses);
+ return ImmutableMap.copyOf(result);
+ }
+
+ ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
+ int hits = 0;
+ int misses = 0;
+
+ Map<K, V> result = Maps.newLinkedHashMap();
+ Set<K> keysToLoad = Sets.newLinkedHashSet();
+ for (K key : keys) {
+ V value = get(key);
+ if (!result.containsKey(key)) {
+ result.put(key, value);
+ if (value == null) {
+ misses++;
+ keysToLoad.add(key);
+ } else {
+ hits++;
+ }
+ }
+ }
+
+ try {
+ if (!keysToLoad.isEmpty()) {
+ try {
+ Map<K, V> newEntries = loadAll(keysToLoad, defaultLoader);
+ for (K key : keysToLoad) {
+ V value = newEntries.get(key);
+ if (value == null) {
+ throw new InvalidCacheLoadException("loadAll failed to return a value for " + key);
+ }
+ result.put(key, value);
+ }
+ } catch (UnsupportedLoadingOperationException e) {
+ // loadAll not implemented, fallback to load
+ for (K key : keysToLoad) {
+ misses--; // get will count this miss
+ result.put(key, get(key, defaultLoader));
+ }
+ }
+ }
+ return ImmutableMap.copyOf(result);
+ } finally {
+ globalStatsCounter.recordHits(hits);
+ globalStatsCounter.recordMisses(misses);
+ }
+ }
+
+ /**
+ * Returns the result of calling {@link CacheLoader#loadAll}, or null if {@code loader} doesn't
+ * implement {@code loadAll}.
+ */
+ @Nullable
+ Map<K, V> loadAll(Set<? extends K> keys, CacheLoader<? super K, V> loader)
+ throws ExecutionException {
+ Stopwatch stopwatch = new Stopwatch().start();
+ Map<K, V> result;
+ boolean success = false;
+ try {
+ @SuppressWarnings("unchecked") // safe since all keys extend K
+ Map<K, V> map = (Map<K, V>) loader.loadAll(keys);
+ result = map;
+ success = true;
+ } 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) {
+ throw new ExecutionException(e);
+ } catch (Error e) {
+ throw new ExecutionError(e);
+ } finally {
+ if (!success) {
+ globalStatsCounter.recordLoadException(stopwatch.elapsedTime(NANOSECONDS));
+ }
+ }
+
+ if (result == null) {
+ globalStatsCounter.recordLoadException(stopwatch.elapsedTime(NANOSECONDS));
+ throw new InvalidCacheLoadException(loader + " returned null map from loadAll");
+ }
+
+ stopwatch.stop();
+ // TODO(fry): batch by segment
+ boolean nullsPresent = false;
+ for (Map.Entry<K, V> entry : result.entrySet()) {
+ K key = entry.getKey();
+ V value = entry.getValue();
+ if (key == null || value == null) {
+ // delay failure until non-null entries are stored
+ nullsPresent = true;
+ } else {
+ put(key, value);
+ }
+ }
+
+ if (nullsPresent) {
+ 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.elapsedTime(NANOSECONDS));
+ return result;
+ }
+
+ /**
+ * Returns the internal entry for the specified key. The entry may be loading, expired, or
+ * partially collected.
+ */
+ ReferenceEntry<K, V> getEntry(@Nullable Object key) {
+ // does not impact recency ordering
+ if (key == null) {
+ return null;
+ }
+ int hash = hash(key);
+ 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);
+ }
+
+ @Override
+ public boolean containsKey(@Nullable Object key) {
+ // does not impact recency ordering
+ if (key == null) {
+ return false;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).containsKey(key, hash);
+ }
+
+ @Override
+ public boolean containsValue(@Nullable Object value) {
+ // does not impact recency ordering
+ if (value == null) {
+ return false;
+ }
+
+ // This implementation is patterned after ConcurrentHashMap, but without the locking. The only
+ // way for it to return a false negative would be for the target value to jump around in the map
+ // 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.
+ long now = ticker.read();
+ final Segment<K,V>[] segments = this.segments;
+ long last = -1L;
+ for (int i = 0; i < CONTAINS_VALUE_RETRIES; i++) {
+ long sum = 0L;
+ for (Segment<K, V> segment : segments) {
+ // ensure visibility of most recent completed write
+ @SuppressWarnings({"UnusedDeclaration", "unused"})
+ int c = segment.count; // read-volatile
+
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = segment.table;
+ 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, now);
+ if (v != null && valueEquivalence.equivalent(value, v)) {
+ return true;
+ }
+ }
+ }
+ sum += segment.modCount;
+ }
+ if (sum == last) {
+ break;
+ }
+ last = sum;
+ }
+ return false;
+ }
+
+ @Override
+ public V put(K key, V value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ int hash = hash(key);
+ return segmentFor(hash).put(key, hash, value, false);
+ }
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ int hash = hash(key);
+ return segmentFor(hash).put(key, hash, value, true);
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ for (Entry<? extends K, ? extends V> e : m.entrySet()) {
+ put(e.getKey(), e.getValue());
+ }
+ }
+
+ @Override
+ public V remove(@Nullable Object key) {
+ if (key == null) {
+ return null;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).remove(key, hash);
+ }
+
+ @Override
+ public boolean remove(@Nullable Object key, @Nullable Object value) {
+ if (key == null || value == null) {
+ return false;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).remove(key, hash, value);
+ }
+
+ @Override
+ public boolean replace(K key, @Nullable V oldValue, V newValue) {
+ checkNotNull(key);
+ checkNotNull(newValue);
+ if (oldValue == null) {
+ return false;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).replace(key, hash, oldValue, newValue);
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ int hash = hash(key);
+ return segmentFor(hash).replace(key, hash, value);
+ }
+
+ @Override
+ public void clear() {
+ for (Segment<K, V> segment : segments) {
+ segment.clear();
+ }
+ }
+
+ void invalidateAll(Iterable<?> keys) {
+ // TODO(fry): batch by segment
+ for (Object key : keys) {
+ remove(key);
+ }
+ }
+
+ Set<K> keySet;
+
+ @Override
+ public Set<K> keySet() {
+ // does not impact recency ordering
+ Set<K> ks = keySet;
+ return (ks != null) ? ks : (keySet = new KeySet());
+ }
+
+ Collection<V> values;
+
+ @Override
+ public Collection<V> values() {
+ // does not impact recency ordering
+ Collection<V> vs = values;
+ return (vs != null) ? vs : (values = new Values());
+ }
+
+ Set<Entry<K, V>> entrySet;
+
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ // does not impact recency ordering
+ Set<Entry<K, V>> es = entrySet;
+ return (es != null) ? es : (entrySet = new EntrySet());
+ }
+
+ // Iterator Support
+
+ abstract class HashIterator {
+
+ int nextSegmentIndex;
+ int nextTableIndex;
+ Segment<K, V> currentSegment;
+ AtomicReferenceArray<ReferenceEntry<K, V>> currentTable;
+ ReferenceEntry<K, V> nextEntry;
+ WriteThroughEntry nextExternal;
+ WriteThroughEntry lastReturned;
+
+ HashIterator() {
+ nextSegmentIndex = segments.length - 1;
+ nextTableIndex = -1;
+ advance();
+ }
+
+ final void advance() {
+ nextExternal = null;
+
+ if (nextInChain()) {
+ return;
+ }
+
+ if (nextInTable()) {
+ return;
+ }
+
+ while (nextSegmentIndex >= 0) {
+ currentSegment = segments[nextSegmentIndex--];
+ if (currentSegment.count != 0) {
+ currentTable = currentSegment.table;
+ nextTableIndex = currentTable.length() - 1;
+ if (nextInTable()) {
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Finds the next entry in the current chain. Returns true if an entry was found.
+ */
+ boolean nextInChain() {
+ if (nextEntry != null) {
+ for (nextEntry = nextEntry.getNext(); nextEntry != null; nextEntry = nextEntry.getNext()) {
+ if (advanceTo(nextEntry)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Finds the next entry in the current table. Returns true if an entry was found.
+ */
+ boolean nextInTable() {
+ while (nextTableIndex >= 0) {
+ if ((nextEntry = currentTable.get(nextTableIndex--)) != null) {
+ if (advanceTo(nextEntry) || nextInChain()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Advances to the given entry. Returns true if the entry was valid, false if it should be
+ * skipped.
+ */
+ boolean advanceTo(ReferenceEntry<K, V> entry) {
+ try {
+ long now = ticker.read();
+ K key = entry.getKey();
+ V value = getLiveValue(entry, now);
+ if (value != null) {
+ nextExternal = new WriteThroughEntry(key, value);
+ return true;
+ } else {
+ // Skip stale entry.
+ return false;
+ }
+ } finally {
+ currentSegment.postReadCleanup();
+ }
+ }
+
+ public boolean hasNext() {
+ return nextExternal != null;
+ }
+
+ WriteThroughEntry nextEntry() {
+ if (nextExternal == null) {
+ throw new NoSuchElementException();
+ }
+ lastReturned = nextExternal;
+ advance();
+ return lastReturned;
+ }
+
+ public void remove() {
+ checkState(lastReturned != null);
+ LocalCache.this.remove(lastReturned.getKey());
+ lastReturned = null;
+ }
+ }
+
+ final class KeyIterator extends HashIterator implements Iterator<K> {
+
+ @Override
+ public K next() {
+ return nextEntry().getKey();
+ }
+ }
+
+ final class ValueIterator extends HashIterator implements Iterator<V> {
+
+ @Override
+ public V next() {
+ return nextEntry().getValue();
+ }
+ }
+
+ /**
+ * Custom Entry class used by EntryIterator.next(), that relays setValue changes to the
+ * underlying map.
+ */
+ final class WriteThroughEntry implements Entry<K, V> {
+ final K key; // non-null
+ V value; // non-null
+
+ WriteThroughEntry(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public K getKey() {
+ return key;
+ }
+
+ @Override
+ public V getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ // Cannot use key and value equivalence
+ if (object instanceof Entry) {
+ Entry<?, ?> that = (Entry<?, ?>) object;
+ return key.equals(that.getKey()) && value.equals(that.getValue());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ // Cannot use key and value equivalence
+ return key.hashCode() ^ value.hashCode();
+ }
+
+ @Override
+ public V setValue(V newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns a string representation of the form <code>{key}={value}</code>.
+ */
+ @Override public String toString() {
+ return getKey() + "=" + getValue();
+ }
+ }
+
+ final class EntryIterator extends HashIterator implements Iterator<Entry<K, V>> {
+
+ @Override
+ public Entry<K, V> next() {
+ return nextEntry();
+ }
+ }
+
+ final class KeySet extends AbstractSet<K> {
+
+ @Override
+ public Iterator<K> iterator() {
+ return new KeyIterator();
+ }
+
+ @Override
+ public int size() {
+ return LocalCache.this.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return LocalCache.this.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return LocalCache.this.containsKey(o);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return LocalCache.this.remove(o) != null;
+ }
+
+ @Override
+ public void clear() {
+ LocalCache.this.clear();
+ }
+ }
+
+ final class Values extends AbstractCollection<V> {
+
+ @Override
+ public Iterator<V> iterator() {
+ return new ValueIterator();
+ }
+
+ @Override
+ public int size() {
+ return LocalCache.this.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return LocalCache.this.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return LocalCache.this.containsValue(o);
+ }
+
+ @Override
+ public void clear() {
+ LocalCache.this.clear();
+ }
+ }
+
+ final class EntrySet extends AbstractSet<Entry<K, V>> {
+
+ @Override
+ public Iterator<Entry<K, V>> iterator() {
+ return new EntryIterator();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ Entry<?, ?> e = (Entry<?, ?>) o;
+ Object key = e.getKey();
+ if (key == null) {
+ return false;
+ }
+ V v = LocalCache.this.get(key);
+
+ return v != null && valueEquivalence.equivalent(e.getValue(), v);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ Entry<?, ?> e = (Entry<?, ?>) o;
+ 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
+
+ /**
+ * Serializes the configuration of a LocalCache, reconsitituting it as a Cache using
+ * CacheBuilder upon deserialization. An instance of this class is fit for use by the writeReplace
+ * of LocalManualCache.
+ *
+ * Unfortunately, readResolve() doesn't get called when a circular dependency is present, so the
+ * proxy must be able to behave as the cache itself.
+ */
+ static class ManualSerializationProxy<K, V>
+ extends ForwardingCache<K, V> implements Serializable {
+ private static final long serialVersionUID = 1;
+
+ final Strength keyStrength;
+ final Strength valueStrength;
+ final Equivalence<Object> keyEquivalence;
+ final Equivalence<Object> valueEquivalence;
+ final long expireAfterWriteNanos;
+ final long expireAfterAccessNanos;
+ final long maxWeight;
+ final Weigher<K, V> weigher;
+ final int concurrencyLevel;
+ final RemovalListener<? super K, ? super V> removalListener;
+ final Ticker ticker;
+ final CacheLoader<? super K, V> loader;
+
+ transient Cache<K, V> delegate;
+
+ ManualSerializationProxy(LocalCache<K, V> cache) {
+ this(
+ cache.keyStrength,
+ cache.valueStrength,
+ cache.keyEquivalence,
+ cache.valueEquivalence,
+ cache.expireAfterWriteNanos,
+ cache.expireAfterAccessNanos,
+ cache.maxWeight,
+ cache.weigher,
+ cache.concurrencyLevel,
+ cache.removalListener,
+ cache.ticker,
+ cache.defaultLoader);
+ }
+
+ private ManualSerializationProxy(
+ Strength keyStrength, Strength valueStrength,
+ Equivalence<Object> keyEquivalence, Equivalence<Object> valueEquivalence,
+ long expireAfterWriteNanos, long expireAfterAccessNanos, long maxWeight,
+ Weigher<K, V> weigher, int concurrencyLevel,
+ RemovalListener<? super K, ? super V> removalListener,
+ Ticker ticker, CacheLoader<? super K, V> loader) {
+ this.keyStrength = keyStrength;
+ this.valueStrength = valueStrength;
+ this.keyEquivalence = keyEquivalence;
+ this.valueEquivalence = valueEquivalence;
+ this.expireAfterWriteNanos = expireAfterWriteNanos;
+ this.expireAfterAccessNanos = expireAfterAccessNanos;
+ this.maxWeight = maxWeight;
+ this.weigher = weigher;
+ this.concurrencyLevel = concurrencyLevel;
+ this.removalListener = removalListener;
+ this.ticker = (ticker == Ticker.systemTicker() || ticker == NULL_TICKER)
+ ? null : ticker;
+ this.loader = loader;
+ }
+
+ CacheBuilder<Object, Object> recreateCacheBuilder() {
+ CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder()
+ .setKeyStrength(keyStrength)
+ .setValueStrength(valueStrength)
+ .keyEquivalence(keyEquivalence)
+ .valueEquivalence(valueEquivalence)
+ .concurrencyLevel(concurrencyLevel);
+ builder.strictParsing = false;
+ builder.removalListener(removalListener);
+ if (expireAfterWriteNanos > 0) {
+ builder.expireAfterWrite(expireAfterWriteNanos, TimeUnit.NANOSECONDS);
+ }
+ if (expireAfterAccessNanos > 0) {
+ builder.expireAfterAccess(expireAfterAccessNanos, TimeUnit.NANOSECONDS);
+ }
+ if (weigher != OneWeigher.INSTANCE) {
+ builder.weigher(weigher);
+ if (maxWeight != UNSET_INT) {
+ builder.maximumWeight(maxWeight);
+ }
+ } else {
+ if (maxWeight != UNSET_INT) {
+ builder.maximumSize(maxWeight);
+ }
+ }
+ if (ticker != null) {
+ builder.ticker(ticker);
+ }
+ return builder;
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ CacheBuilder<Object, Object> builder = recreateCacheBuilder();
+ this.delegate = builder.build();
+ }
+
+ private Object readResolve() {
+ return delegate;
+ }
+
+ @Override
+ protected Cache<K, V> delegate() {
+ return delegate;
+ }
+ }
+
+ /**
+ * Serializes the configuration of a LocalCache, reconsitituting it as an LoadingCache using
+ * CacheBuilder upon deserialization. An instance of this class is fit for use by the writeReplace
+ * of LocalLoadingCache.
+ *
+ * Unfortunately, readResolve() doesn't get called when a circular dependency is present, so the
+ * proxy must be able to behave as the cache itself.
+ */
+ static final class LoadingSerializationProxy<K, V>
+ extends ManualSerializationProxy<K, V> implements LoadingCache<K, V>, Serializable {
+ private static final long serialVersionUID = 1;
+
+ transient LoadingCache<K, V> autoDelegate;
+
+ LoadingSerializationProxy(LocalCache<K, V> cache) {
+ super(cache);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ CacheBuilder<Object, Object> builder = recreateCacheBuilder();
+ this.autoDelegate = builder.build(loader);
+ }
+
+ @Override
+ public V get(K key) throws ExecutionException {
+ return autoDelegate.get(key);
+ }
+
+ @Override
+ public V getUnchecked(K key) {
+ return autoDelegate.getUnchecked(key);
+ }
+
+ @Override
+ public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
+ return autoDelegate.getAll(keys);
+ }
+
+ @Override
+ public final V apply(K key) {
+ return autoDelegate.apply(key);
+ }
+
+ @Override
+ public void refresh(K key) {
+ autoDelegate.refresh(key);
+ }
+
+ private Object readResolve() {
+ return autoDelegate;
+ }
+ }
+
+ static class LocalManualCache<K, V> implements Cache<K, V>, Serializable {
+ final LocalCache<K, V> localCache;
+
+ LocalManualCache(CacheBuilder<? super K, ? super V> builder) {
+ this(new LocalCache<K, V>(builder, null));
+ }
+
+ private LocalManualCache(LocalCache<K, V> localCache) {
+ this.localCache = localCache;
+ }
+
+ // Cache methods
+
+ @Override
+ @Nullable
+ public V getIfPresent(Object key) {
+ return localCache.getIfPresent(key);
+ }
+
+ @Override
+ public V get(K key, final Callable<? extends V> valueLoader) throws ExecutionException {
+ checkNotNull(valueLoader);
+ return localCache.get(key, new CacheLoader<Object, V>() {
+ @Override
+ public V load(Object key) throws Exception {
+ return valueLoader.call();
+ }
+ });
+ }
+
+ @Override
+ public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) {
+ return localCache.getAllPresent(keys);
+ }
+
+ @Override
+ public void put(K key, V value) {
+ localCache.put(key, value);
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ localCache.putAll(m);
+ }
+
+ @Override
+ public void invalidate(Object key) {
+ checkNotNull(key);
+ localCache.remove(key);
+ }
+
+ @Override
+ public void invalidateAll(Iterable<?> keys) {
+ localCache.invalidateAll(keys);
+ }
+
+ @Override
+ public void invalidateAll() {
+ localCache.clear();
+ }
+
+ @Override
+ public long size() {
+ return localCache.longSize();
+ }
+
+ @Override
+ public ConcurrentMap<K, V> asMap() {
+ return localCache;
+ }
+
+ @Override
+ public CacheStats stats() {
+ SimpleStatsCounter aggregator = new SimpleStatsCounter();
+ aggregator.incrementBy(localCache.globalStatsCounter);
+ for (Segment<K, V> segment : localCache.segments) {
+ aggregator.incrementBy(segment.statsCounter);
+ }
+ return aggregator.snapshot();
+ }
+
+ @Override
+ public void cleanUp() {
+ localCache.cleanUp();
+ }
+
+ // Serialization Support
+
+ private static final long serialVersionUID = 1;
+
+ Object writeReplace() {
+ return new ManualSerializationProxy<K, V>(localCache);
+ }
+ }
+
+ static class LocalLoadingCache<K, V>
+ extends LocalManualCache<K, V> implements LoadingCache<K, V> {
+
+ LocalLoadingCache(CacheBuilder<? super K, ? super V> builder,
+ CacheLoader<? super K, V> loader) {
+ super(new LocalCache<K, V>(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());
+ }
+ }
+
+ @Override
+ public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
+ return localCache.getAll(keys);
+ }
+
+ @Override
+ public void refresh(K key) {
+ localCache.refresh(key);
+ }
+
+ @Override
+ public final V apply(K key) {
+ return getUnchecked(key);
+ }
+
+ // Serialization Support
+
+ private static final long serialVersionUID = 1;
+
+ Object writeReplace() {
+ return new LoadingSerializationProxy<K, V>(localCache);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/cache/LongAdder.java b/guava/src/com/google/common/cache/LongAdder.java
new file mode 100644
index 0000000..7838191
--- /dev/null
+++ b/guava/src/com/google/common/cache/LongAdder.java
@@ -0,0 +1,207 @@
+/*
+ * 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 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
+ */
+final class LongAdder extends Striped64 implements Serializable {
+ 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(java.io.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
new file mode 100644
index 0000000..6574b0e
--- /dev/null
+++ b/guava/src/com/google/common/cache/RemovalCause.java
@@ -0,0 +1,97 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * The reason why a cached entry was removed.
+ *
+ * @author Charles Fry
+ * @since 10.0
+ */
+@Beta
+public enum RemovalCause {
+ /**
+ * The entry was manually removed by the user. This can result from the user invoking
+ * {@link Cache#invalidate}, {@link Cache#invalidateAll(Iterable)}, {@link Cache#invalidateAll()},
+ * {@link Map#remove}, {@link ConcurrentMap#remove}, or {@link Iterator#remove}.
+ */
+ EXPLICIT {
+ @Override
+ boolean wasEvicted() {
+ return false;
+ }
+ },
+
+ /**
+ * The entry itself was not actually removed, but its value was replaced by the user. This can
+ * result from the user invoking {@link Cache#put}, {@link LoadingCache#refresh}, {@link Map#put},
+ * {@link Map#putAll}, {@link ConcurrentMap#replace(Object, Object)}, or
+ * {@link ConcurrentMap#replace(Object, Object, Object)}.
+ */
+ REPLACED {
+ @Override
+ boolean wasEvicted() {
+ return false;
+ }
+ },
+
+ /**
+ * The entry was removed automatically because its key or value was garbage-collected. This
+ * can occur when using {@link CacheBuilder#weakKeys}, {@link CacheBuilder#weakValues}, or
+ * {@link CacheBuilder#softValues}.
+ */
+ COLLECTED {
+ @Override
+ boolean wasEvicted() {
+ return true;
+ }
+ },
+
+ /**
+ * The entry's expiration timestamp has passed. This can occur when using
+ * {@link CacheBuilder#expireAfterWrite} or {@link CacheBuilder#expireAfterAccess}.
+ */
+ EXPIRED {
+ @Override
+ boolean wasEvicted() {
+ return true;
+ }
+ },
+
+ /**
+ * The entry was evicted due to size constraints. This can occur when using
+ * {@link CacheBuilder#maximumSize} or {@link CacheBuilder#maximumWeight}.
+ */
+ SIZE {
+ @Override
+ boolean wasEvicted() {
+ return true;
+ }
+ };
+
+ /**
+ * Returns {@code true} if there was an automatic removal due to eviction (the cause is neither
+ * {@link #EXPLICIT} nor {@link #REPLACED}).
+ */
+ abstract boolean wasEvicted();
+}
diff --git a/guava/src/com/google/common/cache/RemovalListener.java b/guava/src/com/google/common/cache/RemovalListener.java
new file mode 100644
index 0000000..e9b6c2c
--- /dev/null
+++ b/guava/src/com/google/common/cache/RemovalListener.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.cache;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * An object that can receive a notification when an entry is removed from a cache. The removal
+ * resulting in notification could have occured to an entry being manually removed or replaced, or
+ * due to eviction resulting from timed expiration, exceeding a maximum size, or garbage
+ * collection.
+ *
+ * <p>An instance may be called concurrently by multiple threads to process different entries.
+ * Implementations of this interface should avoid performing blocking calls or synchronizing on
+ * shared resources.
+ *
+ * @param <K> the most general type of keys this listener can listen for; for
+ * example {@code Object} if any key is acceptable
+ * @param <V> the most general type of values this listener can listen for; for
+ * example {@code Object} if any key is acceptable
+ * @author Charles Fry
+ * @since 10.0
+ */
+@Beta
+public interface RemovalListener<K, V> {
+ /**
+ * Notifies the listener that a removal occurred at some point in the past.
+ */
+ // Technically should accept RemovalNotification<? extends K, ? extends V>, but because
+ // RemovalNotification is guaranteed covariant, let's make users' lives simpler.
+ void onRemoval(RemovalNotification<K, V> notification);
+}
diff --git a/guava/src/com/google/common/cache/RemovalListeners.java b/guava/src/com/google/common/cache/RemovalListeners.java
new file mode 100644
index 0000000..18292fd
--- /dev/null
+++ b/guava/src/com/google/common/cache/RemovalListeners.java
@@ -0,0 +1,57 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A collection of common removal listeners.
+ *
+ * @author Charles Fry
+ * @since 10.0
+ */
+@Beta
+public final class RemovalListeners {
+
+ private RemovalListeners() {}
+
+ /**
+ * Returns a {@code RemovalListener} which processes all eviction
+ * notifications using {@code executor}.
+ *
+ * @param listener the backing listener
+ * @param executor the executor with which removal notifications are
+ * asynchronously executed
+ */
+ public static <K, V> RemovalListener<K, V> asynchronous(
+ final RemovalListener<K, V> listener, final Executor executor) {
+ return new RemovalListener<K, V>() {
+ @Override
+ public void onRemoval(final RemovalNotification<K, V> notification) {
+ executor.execute(new Runnable() {
+ @Override
+ public void run() {
+ listener.onRemoval(notification);
+ }
+ });
+ }
+ };
+ }
+
+}
diff --git a/guava/src/com/google/common/cache/RemovalNotification.java b/guava/src/com/google/common/cache/RemovalNotification.java
new file mode 100644
index 0000000..8e0066e
--- /dev/null
+++ b/guava/src/com/google/common/cache/RemovalNotification.java
@@ -0,0 +1,100 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+
+import java.util.Map.Entry;
+
+import javax.annotation.Nullable;
+
+/**
+ * A notification of the removal of a single entry. The key and/or value may be null if they were
+ * already garbage collected.
+ *
+ * <p>Like other {@code Map.Entry} instances associated with {@code CacheBuilder}, this class holds
+ * strong references to the key and value, regardless of the type of references the cache may be
+ * using.
+ *
+ * @author Charles Fry
+ * @since 10.0
+ */
+@Beta
+public final class RemovalNotification<K, V> implements Entry<K, V> {
+ @Nullable private final K key;
+ @Nullable private final V value;
+ private final RemovalCause cause;
+
+ RemovalNotification(@Nullable K key, @Nullable V value, RemovalCause cause) {
+ this.key = key;
+ this.value = value;
+ this.cause = checkNotNull(cause);
+ }
+
+ /**
+ * Returns the cause for which the entry was removed.
+ */
+ public RemovalCause getCause() {
+ return cause;
+ }
+
+ /**
+ * Returns {@code true} if there was an automatic removal due to eviction (the cause is neither
+ * {@link RemovalCause#EXPLICIT} nor {@link RemovalCause#REPLACED}).
+ */
+ public boolean wasEvicted() {
+ return cause.wasEvicted();
+ }
+
+ @Nullable @Override public K getKey() {
+ return key;
+ }
+
+ @Nullable @Override public V getValue() {
+ return value;
+ }
+
+ @Override public final V setValue(V value){
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Entry) {
+ Entry<?, ?> that = (Entry<?, ?>) object;
+ return Objects.equal(this.getKey(), that.getKey())
+ && Objects.equal(this.getValue(), that.getValue());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ K k = getKey();
+ V v = getValue();
+ return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
+ }
+
+ /**
+ * Returns a string representation of the form <code>{key}={value}</code>.
+ */
+ @Override public String toString() {
+ return getKey() + "=" + getValue();
+ }
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/cache/Striped64.java b/guava/src/com/google/common/cache/Striped64.java
new file mode 100644
index 0000000..c1ba850
--- /dev/null
+++ b/guava/src/com/google/common/cache/Striped64.java
@@ -0,0 +1,344 @@
+/*
+ * 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/SequenceLock.java?revision=1.17
+ */
+
+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 se) {
+ try {
+ return java.security.AccessController.doPrivileged
+ (new java.security
+ .PrivilegedExceptionAction<sun.misc.Unsafe>() {
+ public sun.misc.Unsafe run() throws Exception {
+ java.lang.reflect.Field f = sun.misc
+ .Unsafe.class.getDeclaredField("theUnsafe");
+ f.setAccessible(true);
+ return (sun.misc.Unsafe) f.get(null);
+ }});
+ } 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
new file mode 100644
index 0000000..4506f9e
--- /dev/null
+++ b/guava/src/com/google/common/cache/Weigher.java
@@ -0,0 +1,35 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+/**
+ * Calculates the weights of cache entries.
+ *
+ * @author Charles Fry
+ * @since 11.0
+ */
+@Beta
+public interface Weigher<K, V> {
+
+ /**
+ * Returns the weight of a cache entry. There is no unit for entry weights; rather they are simply
+ * relative to each other.
+ *
+ * @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
new file mode 100644
index 0000000..ea0297b
--- /dev/null
+++ b/guava/src/com/google/common/cache/package-info.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.
+ */
+
+/**
+ * This package contains caching utilities.
+ *
+ * <p>The core interface used to represent caches is {@link com.google.common.cache.Cache}.
+ * In-memory caches can be configured and created using
+ * {@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>.
+ *
+ * @author Charles Fry
+ */
+@ParametersAreNonnullByDefault
+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
new file mode 100644
index 0000000..dcf2db4
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractBiMap.java
@@ -0,0 +1,404 @@
+/*
+ * 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.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.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A general-purpose bimap implementation using any two backing {@code Map}
+ * instances.
+ *
+ * <p>Note that this class contains {@code equals()} calls that keep it from
+ * supporting {@code IdentityHashMap} backing maps.
+ *
+ * @author Kevin Bourrillion
+ * @author Mike Bostock
+ */
+@GwtCompatible(emulated = true)
+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;
+
+ /** Package-private constructor for creating a map-backed bimap. */
+ AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
+ setDelegates(forward, backward);
+ }
+
+ /** Private constructor for inverse bimap. */
+ private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) {
+ delegate = backward;
+ inverse = forward;
+ }
+
+ @Override protected Map<K, V> delegate() {
+ return delegate;
+ }
+
+ /**
+ * 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.
+ */
+ void setDelegates(Map<K, V> forward, Map<V, K> backward) {
+ checkState(delegate == null);
+ checkState(inverse == null);
+ checkArgument(forward.isEmpty());
+ checkArgument(backward.isEmpty());
+ checkArgument(forward != backward);
+ delegate = forward;
+ inverse = new Inverse<V, K>(backward, this);
+ }
+
+ void setInverse(AbstractBiMap<V, K> inverse) {
+ this.inverse = inverse;
+ }
+
+ // Query Operations (optimizations)
+
+ @Override public boolean containsValue(Object value) {
+ return inverse.containsKey(value);
+ }
+
+ // Modification Operations
+
+ @Override public V put(K key, V value) {
+ return putInBothMaps(key, value, false);
+ }
+
+ @Override
+ 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;
+ }
+ if (force) {
+ inverse().remove(value);
+ } else {
+ checkArgument(!containsValue(value), "value already present: %s", value);
+ }
+ V oldValue = delegate.put(key, value);
+ updateInverseMap(key, containedKey, oldValue, value);
+ return oldValue;
+ }
+
+ private void updateInverseMap(
+ K key, boolean containedKey, V oldValue, V newValue) {
+ if (containedKey) {
+ removeFromInverseMap(oldValue);
+ }
+ inverse.delegate.put(newValue, key);
+ }
+
+ @Override public V remove(Object key) {
+ return containsKey(key) ? removeFromBothMaps(key) : null;
+ }
+
+ private V removeFromBothMaps(Object key) {
+ V oldValue = delegate.remove(key);
+ removeFromInverseMap(oldValue);
+ return oldValue;
+ }
+
+ private void removeFromInverseMap(V oldValue) {
+ inverse.delegate.remove(oldValue);
+ }
+
+ // Bulk Operations
+
+ @Override public void putAll(Map<? extends K, ? extends V> map) {
+ for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ @Override public void clear() {
+ delegate.clear();
+ inverse.delegate.clear();
+ }
+
+ // Views
+
+ @Override
+ public BiMap<V, K> inverse() {
+ return inverse;
+ }
+
+ private transient Set<K> keySet;
+
+ @Override public Set<K> keySet() {
+ Set<K> result = keySet;
+ return (result == null) ? keySet = new KeySet() : result;
+ }
+
+ private class KeySet extends ForwardingSet<K> {
+ @Override protected Set<K> delegate() {
+ return delegate.keySet();
+ }
+
+ @Override public void clear() {
+ AbstractBiMap.this.clear();
+ }
+
+ @Override public boolean remove(Object key) {
+ if (!contains(key)) {
+ return false;
+ }
+ removeFromBothMaps(key);
+ return true;
+ }
+
+ @Override public boolean removeAll(Collection<?> keysToRemove) {
+ return standardRemoveAll(keysToRemove);
+ }
+
+ @Override public boolean retainAll(Collection<?> keysToRetain) {
+ return standardRetainAll(keysToRetain);
+ }
+
+ @Override public Iterator<K> iterator() {
+ return Maps.keyIterator(entrySet().iterator());
+ }
+ }
+
+ private transient Set<V> valueSet;
+
+ @Override public Set<V> values() {
+ /*
+ * We can almost reuse the inverse's keySet, except we have to fix the
+ * iteration order so that it is consistent with the forward map.
+ */
+ Set<V> result = valueSet;
+ return (result == null) ? valueSet = new ValueSet() : result;
+ }
+
+ private class ValueSet extends ForwardingSet<V> {
+ final Set<V> valuesDelegate = inverse.keySet();
+
+ @Override protected Set<V> delegate() {
+ return valuesDelegate;
+ }
+
+ @Override public Iterator<V> iterator() {
+ return Maps.valueIterator(entrySet().iterator());
+ }
+
+ @Override public Object[] toArray() {
+ return standardToArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return standardToArray(array);
+ }
+
+ @Override public String toString() {
+ return standardToString();
+ }
+ }
+
+ private transient Set<Entry<K, V>> entrySet;
+
+ @Override public Set<Entry<K, V>> entrySet() {
+ Set<Entry<K, V>> result = entrySet;
+ return (result == null) ? entrySet = new EntrySet() : result;
+ }
+
+ private class EntrySet extends ForwardingSet<Entry<K, V>> {
+ final Set<Entry<K, V>> esDelegate = delegate.entrySet();
+
+ @Override protected Set<Entry<K, V>> delegate() {
+ return esDelegate;
+ }
+
+ @Override public void clear() {
+ AbstractBiMap.this.clear();
+ }
+
+ @Override public boolean remove(Object object) {
+ if (!esDelegate.contains(object)) {
+ return false;
+ }
+
+ // safe because esDelgate.contains(object).
+ Entry<?, ?> entry = (Entry<?, ?>) object;
+ inverse.delegate.remove(entry.getValue());
+ /*
+ * Remove the mapping in inverse before removing from esDelegate because
+ * if entry is part of esDelegate, entry might be invalidated after the
+ * mapping is removed from esDelegate.
+ */
+ esDelegate.remove(entry);
+ return true;
+ }
+
+ @Override public Iterator<Entry<K, V>> iterator() {
+ final Iterator<Entry<K, V>> iterator = esDelegate.iterator();
+ return new Iterator<Entry<K, V>>() {
+ Entry<K, V> entry;
+
+ @Override public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override public Entry<K, V> next() {
+ entry = iterator.next();
+ final Entry<K, V> finalEntry = entry;
+
+ return new ForwardingMapEntry<K, V>() {
+ @Override protected Entry<K, V> delegate() {
+ return finalEntry;
+ }
+
+ @Override public V setValue(V value) {
+ // Preconditions keep the map and inverse consistent.
+ checkState(contains(this), "entry no longer in map");
+ // similar to putInBothMaps, but set via entry
+ if (Objects.equal(value, getValue())) {
+ return value;
+ }
+ checkArgument(!containsValue(value),
+ "value already present: %s", value);
+ V oldValue = finalEntry.setValue(value);
+ checkState(Objects.equal(value, get(getKey())),
+ "entry no longer in map");
+ updateInverseMap(getKey(), true, oldValue, value);
+ return oldValue;
+ }
+ };
+ }
+
+ @Override public void remove() {
+ checkState(entry != null);
+ V value = entry.getValue();
+ iterator.remove();
+ removeFromInverseMap(value);
+ }
+ };
+ }
+
+ // See java.util.Collections.CheckedEntrySet for details on attacks.
+
+ @Override public Object[] toArray() {
+ return standardToArray();
+ }
+ @Override public <T> T[] toArray(T[] array) {
+ return standardToArray(array);
+ }
+ @Override public boolean contains(Object o) {
+ return Maps.containsEntryImpl(delegate(), o);
+ }
+ @Override public boolean containsAll(Collection<?> c) {
+ return standardContainsAll(c);
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return standardRemoveAll(c);
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ return standardRetainAll(c);
+ }
+ }
+
+ /** The inverse of any other {@code AbstractBiMap} subclass. */
+ private static class Inverse<K, V> extends AbstractBiMap<K, V> {
+ private Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) {
+ super(backward, forward);
+ }
+
+ /*
+ * Serialization stores the forward bimap, the inverse of this inverse.
+ * Deserialization calls inverse() on the forward bimap and returns that
+ * inverse.
+ *
+ * If a bimap and its inverse are serialized together, the deserialized
+ * 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
+ */
+ @GwtIncompatible("java.io.ObjectOuputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(inverse());
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ setInverse((AbstractBiMap<V, K>) stream.readObject());
+ }
+
+ @GwtIncompatible("Not needed in the emulated source.")
+ Object readResolve() {
+ return inverse().inverse();
+ }
+
+ @GwtIncompatible("Not needed in emulated source.")
+ private static final long serialVersionUID = 0;
+ }
+
+ @GwtIncompatible("Not needed in emulated source.")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/AbstractIndexedListIterator.java b/guava/src/com/google/common/collect/AbstractIndexedListIterator.java
new file mode 100644
index 0000000..a58a2a0
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractIndexedListIterator.java
@@ -0,0 +1,109 @@
+/*
+ * 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;
+
+import static com.google.common.base.Preconditions.checkPositionIndex;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * This class provides a skeletal implementation of the {@link ListIterator}
+ * interface across a fixed number of elements that may be retrieved by
+ * position. It does not support {@link #remove}, {@link #set}, or {@link #add}.
+ *
+ * @author Jared Levy
+ */
+@GwtCompatible
+abstract class AbstractIndexedListIterator<E>
+ extends UnmodifiableListIterator<E> {
+ private final int size;
+ private int position;
+
+ /**
+ * Returns the element with the specified index. This method is called by
+ * {@link #next()}.
+ */
+ protected abstract E get(int index);
+
+ /**
+ * Constructs an iterator across a sequence of the given size whose initial
+ * position is 0. That is, the first call to {@link #next()} will return the
+ * first element (or throw {@link NoSuchElementException} if {@code size} is
+ * zero).
+ *
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ protected AbstractIndexedListIterator(int size) {
+ this(size, 0);
+ }
+
+ /**
+ * Constructs an iterator across a sequence of the given size with the given
+ * initial position. That is, the first call to {@link #nextIndex()} will
+ * return {@code position}, and the first call to {@link #next()} will return
+ * the element at that index, if available. Calls to {@link #previous()} can
+ * retrieve the preceding {@code position} elements.
+ *
+ * @throws IndexOutOfBoundsException if {@code position} is negative or is
+ * greater than {@code size}
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ protected AbstractIndexedListIterator(int size, int position) {
+ checkPositionIndex(position, size);
+ this.size = size;
+ this.position = position;
+ }
+
+ @Override
+ public final boolean hasNext() {
+ return position < size;
+ }
+
+ @Override
+ public final E next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return get(position++);
+ }
+
+ @Override
+ public final int nextIndex() {
+ return position;
+ }
+
+ @Override
+ public final boolean hasPrevious() {
+ return position > 0;
+ }
+
+ @Override
+ public final E previous() {
+ if (!hasPrevious()) {
+ throw new NoSuchElementException();
+ }
+ return get(--position);
+ }
+
+ @Override
+ public final int previousIndex() {
+ return position - 1;
+ }
+}
diff --git a/guava/src/com/google/common/collect/AbstractIterator.java b/guava/src/com/google/common/collect/AbstractIterator.java
new file mode 100644
index 0000000..b81a69c
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractIterator.java
@@ -0,0 +1,173 @@
+/*
+ * 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.checkState;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.NoSuchElementException;
+
+/**
+ * This class provides a skeletal implementation of the {@code Iterator}
+ * interface, to make this interface easier to implement for certain types of
+ * data sources.
+ *
+ * <p>{@code Iterator} requires its implementations to support querying the
+ * end-of-data status without changing the iterator's state, using the {@link
+ * #hasNext} method. But many data sources, such as {@link
+ * java.io.Reader#read()}, do not expose this information; the only way to
+ * discover whether there is any data left is by trying to retrieve it. These
+ * types of data sources are ordinarily difficult to write iterators for. But
+ * using this class, one must implement only the {@link #computeNext} method,
+ * and invoke the {@link #endOfData} method when appropriate.
+ *
+ * <p>Another example is an iterator that skips over null elements in a backing
+ * iterator. This could be implemented as: <pre> {@code
+ *
+ * public static Iterator<String> skipNulls(final Iterator<String> in) {
+ * return new AbstractIterator<String>() {
+ * protected String computeNext() {
+ * while (in.hasNext()) {
+ * String s = in.next();
+ * if (s != null) {
+ * return s;
+ * }
+ * }
+ * return endOfData();
+ * }
+ * };
+ * }}</pre>
+ *
+ * This class supports iterators that include null elements.
+ *
+ * @author Kevin Bourrillion
+ * @since 2.0 (imported from Google Collections Library)
+ */
+// When making changes to this class, please also update the copy at
+// com.google.common.base.AbstractIterator
+@GwtCompatible
+public abstract class AbstractIterator<T> extends UnmodifiableIterator<T> {
+ private State state = State.NOT_READY;
+
+ /** Constructor for use by subclasses. */
+ protected AbstractIterator() {}
+
+ private enum State {
+ /** We have computed the next element and haven't returned it yet. */
+ READY,
+
+ /** We haven't yet computed or have already returned the element. */
+ NOT_READY,
+
+ /** We have reached the end of the data and are finished. */
+ DONE,
+
+ /** We've suffered an exception and are kaput. */
+ FAILED,
+ }
+
+ private T next;
+
+ /**
+ * Returns the next element. <b>Note:</b> the implementation must call {@link
+ * #endOfData()} when there are no elements left in the iteration. Failure to
+ * do so could result in an infinite loop.
+ *
+ * <p>The initial invocation of {@link #hasNext()} or {@link #next()} calls
+ * this method, as does the first invocation of {@code hasNext} or {@code
+ * next} following each successful call to {@code next}. Once the
+ * implementation either invokes {@code endOfData} or throws an exception,
+ * {@code computeNext} is guaranteed to never be called again.
+ *
+ * <p>If this method throws an exception, it will propagate outward to the
+ * {@code hasNext} or {@code next} invocation that invoked this method. Any
+ * further attempts to use the iterator will result in an {@link
+ * IllegalStateException}.
+ *
+ * <p>The implementation of this method may not invoke the {@code hasNext},
+ * {@code next}, or {@link #peek()} methods on this instance; if it does, an
+ * {@code IllegalStateException} will result.
+ *
+ * @return the next element if there was one. If {@code endOfData} was called
+ * during execution, the return value will be ignored.
+ * @throws RuntimeException if any unrecoverable error happens. This exception
+ * will propagate outward to the {@code hasNext()}, {@code next()}, or
+ * {@code peek()} invocation that invoked this method. Any further
+ * attempts to use the iterator will result in an
+ * {@link IllegalStateException}.
+ */
+ protected abstract T computeNext();
+
+ /**
+ * Implementations of {@link #computeNext} <b>must</b> invoke this method when
+ * there are no elements left in the iteration.
+ *
+ * @return {@code null}; a convenience so your {@code computeNext}
+ * implementation can use the simple statement {@code return endOfData();}
+ */
+ protected final T endOfData() {
+ state = State.DONE;
+ return null;
+ }
+
+ @Override
+ public final boolean hasNext() {
+ checkState(state != State.FAILED);
+ switch (state) {
+ case DONE:
+ return false;
+ case READY:
+ return true;
+ default:
+ }
+ return tryToComputeNext();
+ }
+
+ private boolean tryToComputeNext() {
+ state = State.FAILED; // temporary pessimism
+ next = computeNext();
+ if (state != State.DONE) {
+ state = State.READY;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public final T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ state = State.NOT_READY;
+ return next;
+ }
+
+ /**
+ * Returns the next element in the iteration without advancing the iteration,
+ * according to the contract of {@link PeekingIterator#peek()}.
+ *
+ * <p>Implementations of {@code AbstractIterator} that wish to expose this
+ * functionality should implement {@code PeekingIterator}.
+ */
+ public final T peek() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return next;
+ }
+}
diff --git a/guava/src/com/google/common/collect/AbstractLinkedIterator.java b/guava/src/com/google/common/collect/AbstractLinkedIterator.java
new file mode 100644
index 0000000..8e722dd
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractLinkedIterator.java
@@ -0,0 +1,84 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.NoSuchElementException;
+
+import javax.annotation.Nullable;
+
+/**
+ * This class provides a skeletal implementation of the {@code Iterator}
+ * interface for sequences whose next element can always be derived from the
+ * previous element. Null elements are not supported, nor is the
+ * {@link #remove()} method.
+ *
+ * <p>Example: <pre> {@code
+ *
+ * Iterator<Integer> powersOfTwo = new AbstractLinkedIterator<Integer>(1) {
+ * protected Integer computeNext(Integer previous) {
+ * return (previous == 1 << 30) ? null : previous * 2;
+ * }
+ * };}</pre>
+ *
+ * @author Chris Povirk
+ * @since 8.0
+ * @deprecated This class has been renamed {@link AbstractSequentialIterator}.
+ * This class is scheduled to be removed in Guava release 13.0.
+ */
+@Beta
+@Deprecated
+@GwtCompatible
+public abstract class AbstractLinkedIterator<T>
+ extends UnmodifiableIterator<T> {
+ private T nextOrNull;
+
+ /**
+ * Creates a new iterator with the given first element, or, if {@code
+ * firstOrNull} is null, creates a new empty iterator.
+ */
+ protected AbstractLinkedIterator(@Nullable T firstOrNull) {
+ this.nextOrNull = firstOrNull;
+ }
+
+ /**
+ * Returns the element that follows {@code previous}, or returns {@code null}
+ * if no elements remain. This method is invoked during each call to
+ * {@link #next()} in order to compute the result of a <i>future</i> call to
+ * {@code next()}.
+ */
+ protected abstract T computeNext(T previous);
+
+ @Override
+ public final boolean hasNext() {
+ return nextOrNull != null;
+ }
+
+ @Override
+ public final T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ try {
+ return nextOrNull;
+ } finally {
+ nextOrNull = computeNext(nextOrNull);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/AbstractListMultimap.java b/guava/src/com/google/common/collect/AbstractListMultimap.java
new file mode 100644
index 0000000..ad24011
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractListMultimap.java
@@ -0,0 +1,120 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * Basic implementation of the {@link ListMultimap} interface. It's a wrapper
+ * around {@link AbstractMultimap} that converts the returned collections into
+ * {@code Lists}. The {@link #createCollection} method must return a {@code
+ * List}.
+ *
+ * @author Jared Levy
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+abstract class AbstractListMultimap<K, V>
+ extends AbstractMultimap<K, V> implements ListMultimap<K, V> {
+ /**
+ * Creates a new multimap that uses the provided map.
+ *
+ * @param map place to store the mapping from each key to its corresponding
+ * values
+ */
+ protected AbstractListMultimap(Map<K, Collection<V>> map) {
+ super(map);
+ }
+
+ @Override abstract List<V> createCollection();
+
+ // Following Javadoc copied from ListMultimap.
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because the values for a given key may have duplicates and follow the
+ * insertion ordering, this method returns a {@link List}, instead of the
+ * {@link Collection} specified in the {@link Multimap} interface.
+ */
+ @Override public List<V> get(@Nullable K key) {
+ return (List<V>) super.get(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because the values for a given key may have duplicates and follow the
+ * insertion ordering, this method returns a {@link List}, instead of the
+ * {@link Collection} specified in the {@link Multimap} interface.
+ */
+ @Override public List<V> removeAll(@Nullable Object key) {
+ return (List<V>) super.removeAll(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because the values for a given key may have duplicates and follow the
+ * insertion ordering, this method returns a {@link List}, instead of the
+ * {@link Collection} specified in the {@link Multimap} interface.
+ */
+ @Override public List<V> replaceValues(
+ @Nullable K key, Iterable<? extends V> values) {
+ return (List<V>) super.replaceValues(key, values);
+ }
+
+ /**
+ * Stores a key-value pair in the multimap.
+ *
+ * @param key key to store in the multimap
+ * @param value value to store in the multimap
+ * @return {@code true} always
+ */
+ @Override public boolean put(@Nullable K key, @Nullable V value) {
+ return super.put(key, value);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Though the method signature doesn't say so explicitly, the returned map
+ * has {@link List} values.
+ */
+ @Override public Map<K, Collection<V>> asMap() {
+ return super.asMap();
+ }
+
+ /**
+ * Compares the specified object to this multimap for equality.
+ *
+ * <p>Two {@code ListMultimap} instances are equal if, for each key, they
+ * contain the same values in the same order. If the value orderings disagree,
+ * the multimaps will not be considered equal.
+ */
+ @Override public boolean equals(@Nullable Object object) {
+ return super.equals(object);
+ }
+
+ private static final long serialVersionUID = 6588350623831699109L;
+}
diff --git a/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java b/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java
new file mode 100644
index 0000000..83d1953
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractMapBasedMultiset.java
@@ -0,0 +1,325 @@
+/*
+ * 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 static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Multisets.checkNonnegative;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.primitives.Ints;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * Basic implementation of {@code Multiset<E>} backed by an instance of {@code
+ * Map<E, Count>}.
+ *
+ * <p>For serialization to work, the subclass must specify explicit {@code
+ * readObject} and {@code writeObject} methods.
+ *
+ * @author Kevin Bourrillion
+ */
+@GwtCompatible(emulated = true)
+abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
+ implements Serializable {
+
+ private transient Map<E, Count> backingMap;
+
+ /*
+ * Cache the size for efficiency. Using a long lets us avoid the need for
+ * overflow checking and ensures that size() will function correctly even if
+ * the multiset had once been larger than Integer.MAX_VALUE.
+ */
+ private transient long size;
+
+ /** Standard constructor. */
+ protected AbstractMapBasedMultiset(Map<E, Count> backingMap) {
+ this.backingMap = checkNotNull(backingMap);
+ 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;
+ }
+
+ // Required Implementations
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Invoking {@link Multiset.Entry#getCount} on an entry in the returned
+ * set always returns the current count of that element in the multiset, as
+ * opposed to the count at the time the entry was retrieved.
+ */
+ @Override
+ public Set<Multiset.Entry<E>> entrySet() {
+ return super.entrySet();
+ }
+
+ @Override
+ Iterator<Entry<E>> entryIterator() {
+ final Iterator<Map.Entry<E, Count>> backingEntries =
+ backingMap.entrySet().iterator();
+ return new Iterator<Multiset.Entry<E>>() {
+ Map.Entry<E, Count> toRemove;
+
+ @Override
+ public boolean hasNext() {
+ return backingEntries.hasNext();
+ }
+
+ @Override
+ public Multiset.Entry<E> next() {
+ final Map.Entry<E, Count> mapEntry = backingEntries.next();
+ toRemove = mapEntry;
+ return new Multisets.AbstractEntry<E>() {
+ @Override
+ public E getElement() {
+ return mapEntry.getKey();
+ }
+ @Override
+ public int getCount() {
+ int count = mapEntry.getValue().get();
+ if (count == 0) {
+ Count frequency = backingMap.get(getElement());
+ if (frequency != null) {
+ count = frequency.get();
+ }
+ }
+ return count;
+ }
+ };
+ }
+
+ @Override
+ public void remove() {
+ Iterators.checkRemove(toRemove != null);
+ size -= toRemove.getValue().getAndSet(0);
+ backingEntries.remove();
+ toRemove = null;
+ }
+ };
+ }
+
+ @Override
+ public void clear() {
+ for (Count frequency : backingMap.values()) {
+ frequency.set(0);
+ }
+ backingMap.clear();
+ size = 0L;
+ }
+
+ @Override
+ int distinctElements() {
+ return backingMap.size();
+ }
+
+ // Optimizations - Query Operations
+
+ @Override public int size() {
+ return Ints.saturatedCast(size);
+ }
+
+ @Override public Iterator<E> iterator() {
+ return new MapBasedMultisetIterator();
+ }
+
+ /*
+ * Not subclassing AbstractMultiset$MultisetIterator because next() needs to
+ * retrieve the Map.Entry<E, AtomicInteger> entry, which can then be used for
+ * a more efficient remove() call.
+ */
+ private class MapBasedMultisetIterator implements Iterator<E> {
+ final Iterator<Map.Entry<E, Count>> entryIterator;
+ Map.Entry<E, Count> currentEntry;
+ int occurrencesLeft;
+ boolean canRemove;
+
+ MapBasedMultisetIterator() {
+ this.entryIterator = backingMap.entrySet().iterator();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return occurrencesLeft > 0 || entryIterator.hasNext();
+ }
+
+ @Override
+ public E next() {
+ if (occurrencesLeft == 0) {
+ currentEntry = entryIterator.next();
+ occurrencesLeft = currentEntry.getValue().get();
+ }
+ occurrencesLeft--;
+ canRemove = true;
+ return currentEntry.getKey();
+ }
+
+ @Override
+ public void remove() {
+ checkState(canRemove,
+ "no calls to next() since the last call to remove()");
+ int frequency = currentEntry.getValue().get();
+ if (frequency <= 0) {
+ throw new ConcurrentModificationException();
+ }
+ if (currentEntry.getValue().addAndGet(-1) == 0) {
+ entryIterator.remove();
+ }
+ size--;
+ canRemove = false;
+ }
+ }
+
+ @Override public int count(@Nullable Object element) {
+ 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
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if the call would result in more than
+ * {@link Integer#MAX_VALUE} occurrences of {@code element} in this
+ * multiset.
+ */
+ @Override public int add(@Nullable E element, int occurrences) {
+ if (occurrences == 0) {
+ return count(element);
+ }
+ checkArgument(
+ occurrences > 0, "occurrences cannot be negative: %s", occurrences);
+ Count frequency = backingMap.get(element);
+ int oldCount;
+ if (frequency == null) {
+ oldCount = 0;
+ backingMap.put(element, new Count(occurrences));
+ } else {
+ oldCount = frequency.get();
+ long newCount = (long) oldCount + (long) occurrences;
+ checkArgument(newCount <= Integer.MAX_VALUE,
+ "too many occurrences: %s", newCount);
+ frequency.getAndAdd(occurrences);
+ }
+ size += occurrences;
+ return oldCount;
+ }
+
+ @Override public int remove(@Nullable Object element, int occurrences) {
+ if (occurrences == 0) {
+ return count(element);
+ }
+ checkArgument(
+ occurrences > 0, "occurrences cannot be negative: %s", occurrences);
+ Count frequency = backingMap.get(element);
+ if (frequency == null) {
+ return 0;
+ }
+
+ int oldCount = frequency.get();
+
+ int numberRemoved;
+ if (oldCount > occurrences) {
+ numberRemoved = occurrences;
+ } else {
+ numberRemoved = oldCount;
+ backingMap.remove(element);
+ }
+
+ frequency.addAndGet(-numberRemoved);
+ size -= numberRemoved;
+ return oldCount;
+ }
+
+ // Roughly a 33% performance improvement over AbstractMultiset.setCount().
+ @Override public int setCount(@Nullable E element, int count) {
+ checkNonnegative(count, "count");
+
+ Count existingCounter;
+ int oldCount;
+ if (count == 0) {
+ existingCounter = backingMap.remove(element);
+ oldCount = getAndSet(existingCounter, count);
+ } else {
+ existingCounter = backingMap.get(element);
+ oldCount = getAndSet(existingCounter, count);
+
+ if (existingCounter == null) {
+ backingMap.put(element, new Count(count));
+ }
+ }
+
+ size += (count - oldCount);
+ return oldCount;
+ }
+
+ private static int getAndSet(Count i, int count) {
+ if (i == null) {
+ return 0;
+ }
+
+ return i.getAndSet(count);
+ }
+
+ // Views
+
+ @Override Set<E> createElementSet() {
+ return new MapBasedElementSet();
+ }
+
+ class MapBasedElementSet extends Multisets.ElementSet<E> {
+ @Override
+ Multiset<E> multiset() {
+ return AbstractMapBasedMultiset.this;
+ }
+ }
+
+ // Don't allow default serialization.
+ @GwtIncompatible("java.io.ObjectStreamException")
+ @SuppressWarnings("unused") // actually used during deserialization
+ private void readObjectNoData() throws ObjectStreamException {
+ throw new InvalidObjectException("Stream data required");
+ }
+
+ @GwtIncompatible("not needed in emulated source.")
+ private static final long serialVersionUID = -2250766705698539974L;
+}
diff --git a/guava/src/com/google/common/collect/AbstractMapEntry.java b/guava/src/com/google/common/collect/AbstractMapEntry.java
new file mode 100644
index 0000000..d790748
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractMapEntry.java
@@ -0,0 +1,67 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Objects;
+
+import java.util.Map.Entry;
+
+import javax.annotation.Nullable;
+
+/**
+ * Implementation of the {@code equals}, {@code hashCode}, and {@code toString}
+ * methods of {@code Entry}.
+ *
+ * @author Jared Levy
+ */
+@GwtCompatible
+abstract class AbstractMapEntry<K, V> implements Entry<K, V> {
+
+ @Override
+ public abstract K getKey();
+
+ @Override
+ public abstract V getValue();
+
+ @Override
+ public V setValue(V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Entry) {
+ Entry<?, ?> that = (Entry<?, ?>) object;
+ return Objects.equal(this.getKey(), that.getKey())
+ && Objects.equal(this.getValue(), that.getValue());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ K k = getKey();
+ V v = getValue();
+ return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
+ }
+
+ /**
+ * Returns a string representation of the form {@code {key}={value}}.
+ */
+ @Override public String toString() {
+ return getKey() + "=" + getValue();
+ }
+}
diff --git a/guava/src/com/google/common/collect/AbstractMultimap.java b/guava/src/com/google/common/collect/AbstractMultimap.java
new file mode 100644
index 0000000..e3b07a1
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractMultimap.java
@@ -0,0 +1,1414 @@
+/*
+ * 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 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;
+
+/**
+ * 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>, 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 totalSize == 0;
+ }
+
+ @Override
+ public boolean containsKey(@Nullable Object key) {
+ return map.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(@Nullable Object value) {
+ for (Collection<V> collection : map.values()) {
+ if (collection.contains(value)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
+ Collection<V> collection = map.get(key);
+ return collection != null && collection.contains(value);
+ }
+
+ // 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;
+ }
+
+ @Override
+ 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) {
+ if (!values.iterator().hasNext()) {
+ return false;
+ }
+ // TODO(user): investigate atomic failure?
+ 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
+ public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ boolean changed = false;
+ for (Map.Entry<? extends K, ? extends V> entry : multimap.entries()) {
+ changed |= put(entry.getKey(), entry.getValue());
+ }
+ return changed;
+ }
+
+ /**
+ * {@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);
+ Collection<V> output = createCollection();
+
+ if (collection != null) {
+ output.addAll(collection);
+ totalSize -= collection.size();
+ collection.clear();
+ }
+
+ return unmodifiableCollectionSubclass(output);
+ }
+
+ 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;
+ }
+ }
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ @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());
+ }
+ }
+
+ /** 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);
+ }
+ }
+
+ private transient Set<K> keySet;
+
+ @Override
+ public Set<K> keySet() {
+ Set<K> result = keySet;
+ return (result == null) ? keySet = createKeySet() : result;
+ }
+
+ 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() {
+ 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));
+ }
+ }
+
+ private transient Multiset<K> multiset;
+
+ @Override
+ public Multiset<K> keys() {
+ Multiset<K> result = multiset;
+ if (result == null) {
+ return multiset = new Multimaps.Keys<K, V>() {
+ @Override Multimap<K, V> multimap() {
+ return AbstractMultimap.this;
+ }
+ };
+ }
+ return result;
+ }
+
+ /**
+ * 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> 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<Map.Entry<K, V>> entries() {
+ Collection<Map.Entry<K, V>> result = entries;
+ return (result == null) ? entries = createEntries() : result;
+ }
+
+ 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;
+ }
+
+ 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
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Multimap) {
+ Multimap<?, ?> that = (Multimap<?, ?>) object;
+ return this.map.equals(that.asMap());
+ }
+ return false;
+ }
+
+ /**
+ * Returns the hash code for this multimap.
+ *
+ * <p>The hash code of a multimap is defined as the hash code of the map view,
+ * as returned by {@link Multimap#asMap}.
+ *
+ * @see Map#hashCode
+ */
+ @Override public int hashCode() {
+ return map.hashCode();
+ }
+
+ /**
+ * Returns a string representation of the multimap, generated by calling
+ * {@code toString} on the map returned by {@link Multimap#asMap}.
+ *
+ * @return a string representation of the multimap
+ */
+ @Override
+ public String 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
new file mode 100644
index 0000000..20ea93f
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractMultiset.java
@@ -0,0 +1,221 @@
+/*
+ * 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.collect.Multisets.setCountImpl;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Objects;
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * This class provides a skeletal implementation of the {@link Multiset}
+ * interface. A new multiset implementation can be created easily by extending
+ * this class and implementing the {@link Multiset#entrySet()} method, plus
+ * optionally overriding {@link #add(Object, int)} and
+ * {@link #remove(Object, int)} to enable modifications to the multiset.
+ *
+ * <p>The {@link #count} and {@link #size} implementations all iterate across
+ * the set returned by {@link Multiset#entrySet()}, as do many methods acting on
+ * the set returned by {@link #elementSet()}. Override those methods for better
+ * performance.
+ *
+ * @author Kevin Bourrillion
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+abstract class AbstractMultiset<E> extends AbstractCollection<E>
+ implements Multiset<E> {
+ // Query Operations
+
+ @Override public int size() {
+ return Multisets.sizeImpl(this);
+ }
+
+ @Override public boolean isEmpty() {
+ return entrySet().isEmpty();
+ }
+
+ @Override public boolean contains(@Nullable Object element) {
+ return count(element) > 0;
+ }
+
+ @Override public Iterator<E> iterator() {
+ return Multisets.iteratorImpl(this);
+ }
+
+ @Override
+ public int count(@Nullable Object element) {
+ for (Entry<E> entry : entrySet()) {
+ if (Objects.equal(entry.getElement(), element)) {
+ return entry.getCount();
+ }
+ }
+ return 0;
+ }
+
+ // Modification Operations
+
+ @Override public boolean add(@Nullable E element) {
+ add(element, 1);
+ return true;
+ }
+
+ @Override
+ public int add(@Nullable E element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean remove(@Nullable Object element) {
+ return remove(element, 1) > 0;
+ }
+
+ @Override
+ public int remove(@Nullable Object element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int setCount(@Nullable E element, int count) {
+ return setCountImpl(this, element, count);
+ }
+
+ @Override
+ public boolean setCount(@Nullable E element, int oldCount, int newCount) {
+ return setCountImpl(this, element, oldCount, newCount);
+ }
+
+ // Bulk Operations
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation is highly efficient when {@code elementsToAdd}
+ * is itself a {@link Multiset}.
+ */
+ @Override public boolean addAll(Collection<? extends E> elementsToAdd) {
+ return Multisets.addAllImpl(this, elementsToAdd);
+ }
+
+ @Override public boolean removeAll(Collection<?> elementsToRemove) {
+ return Multisets.removeAllImpl(this, elementsToRemove);
+ }
+
+ @Override public boolean retainAll(Collection<?> elementsToRetain) {
+ return Multisets.retainAllImpl(this, elementsToRetain);
+ }
+
+ @Override public void clear() {
+ Iterators.clear(entryIterator());
+ }
+
+ // Views
+
+ private transient Set<E> elementSet;
+
+ @Override
+ public Set<E> elementSet() {
+ Set<E> result = elementSet;
+ if (result == null) {
+ elementSet = result = createElementSet();
+ }
+ return result;
+ }
+
+ /**
+ * Creates a new instance of this multiset's element set, which will be
+ * returned by {@link #elementSet()}.
+ */
+ Set<E> createElementSet() {
+ return new ElementSet();
+ }
+
+ class ElementSet extends Multisets.ElementSet<E> {
+ @Override
+ Multiset<E> multiset() {
+ return AbstractMultiset.this;
+ }
+ }
+
+ 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;
+ }
+
+ class EntrySet extends Multisets.EntrySet<E> {
+ @Override Multiset<E> multiset() {
+ return AbstractMultiset.this;
+ }
+
+ @Override public Iterator<Entry<E>> iterator() {
+ return entryIterator();
+ }
+
+ @Override public int size() {
+ return distinctElements();
+ }
+ }
+
+ Set<Entry<E>> createEntrySet() {
+ return new EntrySet();
+ }
+
+ // Object methods
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation returns {@code true} if {@code object} is a multiset
+ * of the same size and if, for each element, the two multisets have the same
+ * count.
+ */
+ @Override public boolean equals(@Nullable Object object) {
+ return Multisets.equalsImpl(this, object);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation returns the hash code of {@link
+ * Multiset#entrySet()}.
+ */
+ @Override public int hashCode() {
+ return entrySet().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation returns the result of invoking {@code toString} on
+ * {@link Multiset#entrySet()}.
+ */
+ @Override public String toString() {
+ return entrySet().toString();
+ }
+}
diff --git a/guava/src/com/google/common/collect/AbstractSequentialIterator.java b/guava/src/com/google/common/collect/AbstractSequentialIterator.java
new file mode 100644
index 0000000..c6567f5
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractSequentialIterator.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import java.util.NoSuchElementException;
+
+import javax.annotation.Nullable;
+
+/**
+ * This class provides a skeletal implementation of the {@code Iterator}
+ * interface for sequences whose next element can always be derived from the
+ * previous element. Null elements are not supported, nor is the
+ * {@link #remove()} method.
+ *
+ * <p>Example: <pre> {@code
+ *
+ * Iterator<Integer> powersOfTwo =
+ * new AbstractSequentialIterator<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)
+ */
+@GwtCompatible
+public abstract class AbstractSequentialIterator<T>
+ extends UnmodifiableIterator<T> {
+ private T nextOrNull;
+
+ /**
+ * 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) {
+ this.nextOrNull = firstOrNull;
+ }
+
+ /**
+ * Returns the element that follows {@code previous}, or returns {@code null}
+ * if no elements remain. This method is invoked during each call to
+ * {@link #next()} in order to compute the result of a <i>future</i> call to
+ * {@code next()}.
+ */
+ protected abstract T computeNext(T previous);
+
+ @Override
+ public final boolean hasNext() {
+ return nextOrNull != null;
+ }
+
+ @Override
+ public final T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ try {
+ return nextOrNull;
+ } finally {
+ nextOrNull = computeNext(nextOrNull);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/AbstractSetMultimap.java b/guava/src/com/google/common/collect/AbstractSetMultimap.java
new file mode 100644
index 0000000..fe68470
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractSetMultimap.java
@@ -0,0 +1,132 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * Basic implementation of the {@link SetMultimap} interface. It's a wrapper
+ * 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 AbstractMultimap<K, V> implements SetMultimap<K, V> {
+ /**
+ * Creates a new multimap that uses the provided map.
+ *
+ * @param map place to store the mapping from each key to its corresponding
+ * values
+ */
+ protected AbstractSetMultimap(Map<K, Collection<V>> map) {
+ super(map);
+ }
+
+ @Override abstract Set<V> createCollection();
+
+ // Following Javadoc copied from SetMultimap.
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code SetMultimap} has unique values for a given key, this
+ * method returns a {@link Set}, instead of the {@link Collection} specified
+ * in the {@link Multimap} interface.
+ */
+ @Override public Set<V> get(@Nullable K key) {
+ return (Set<V>) super.get(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code SetMultimap} has unique values for a given key, this
+ * method returns a {@link Set}, instead of the {@link Collection} specified
+ * in the {@link Multimap} interface.
+ */
+ @Override public Set<Map.Entry<K, V>> entries() {
+ return (Set<Map.Entry<K, V>>) super.entries();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code SetMultimap} has unique values for a given key, this
+ * method returns a {@link Set}, instead of the {@link Collection} specified
+ * in the {@link Multimap} interface.
+ */
+ @Override public Set<V> removeAll(@Nullable Object key) {
+ return (Set<V>) super.removeAll(key);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code SetMultimap} has unique values for a given key, this
+ * method returns a {@link Set}, instead of the {@link Collection} specified
+ * in the {@link Multimap} interface.
+ *
+ * <p>Any duplicates in {@code values} will be stored in the multimap once.
+ */
+ @Override public Set<V> replaceValues(
+ @Nullable K key, Iterable<? extends V> values) {
+ return (Set<V>) super.replaceValues(key, values);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Though the method signature doesn't say so explicitly, the returned map
+ * has {@link Set} values.
+ */
+ @Override public Map<K, Collection<V>> asMap() {
+ return super.asMap();
+ }
+
+ /**
+ * Stores a key-value pair in the multimap.
+ *
+ * @param key key to store in the multimap
+ * @param value value to store in the multimap
+ * @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(K key, V value) {
+ return super.put(key, value);
+ }
+
+ /**
+ * Compares the specified object to this multimap for equality.
+ *
+ * <p>Two {@code SetMultimap} instances are equal if, for each key, they
+ * contain the same values. Equality does not depend on the ordering of keys
+ * or values.
+ */
+ @Override public boolean equals(@Nullable Object object) {
+ return super.equals(object);
+ }
+
+ private static final long serialVersionUID = 7431625294878419160L;
+}
diff --git a/guava/src/com/google/common/collect/AbstractSortedMultiset.java b/guava/src/com/google/common/collect/AbstractSortedMultiset.java
new file mode 100644
index 0000000..d226d3d
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractSortedMultiset.java
@@ -0,0 +1,147 @@
+/*
+ * 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 java.util.Comparator;
+import java.util.Iterator;
+import java.util.SortedSet;
+
+import javax.annotation.Nullable;
+
+/**
+ * This class provides a skeletal implementation of the {@link SortedMultiset} interface.
+ *
+ * <p>The {@link #count} and {@link #size} implementations all iterate across the set returned by
+ * {@link Multiset#entrySet()}, as do many methods acting on the set returned by
+ * {@link #elementSet()}. Override those methods for better performance.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+abstract class AbstractSortedMultiset<E> extends AbstractMultiset<E> implements SortedMultiset<E> {
+ @GwtTransient 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 SortedSet<E> elementSet() {
+ return (SortedSet<E>) super.elementSet();
+ }
+
+ @Override
+ SortedSet<E> createElementSet() {
+ return new SortedMultisets.ElementSet<E>() {
+ @Override
+ SortedMultiset<E> multiset() {
+ return AbstractSortedMultiset.this;
+ }
+ };
+ }
+
+ @Override
+ public Comparator<? super E> comparator() {
+ return comparator;
+ }
+
+ @Override
+ public Entry<E> firstEntry() {
+ Iterator<Entry<E>> entryIterator = entryIterator();
+ return entryIterator.hasNext() ? entryIterator.next() : null;
+ }
+
+ @Override
+ public Entry<E> lastEntry() {
+ Iterator<Entry<E>> entryIterator = descendingEntryIterator();
+ return entryIterator.hasNext() ? entryIterator.next() : null;
+ }
+
+ @Override
+ public Entry<E> pollFirstEntry() {
+ Iterator<Entry<E>> entryIterator = entryIterator();
+ if (entryIterator.hasNext()) {
+ Entry<E> result = entryIterator.next();
+ result = Multisets.immutableEntry(result.getElement(), result.getCount());
+ entryIterator.remove();
+ return result;
+ }
+ return null;
+ }
+
+ @Override
+ public Entry<E> pollLastEntry() {
+ Iterator<Entry<E>> entryIterator = descendingEntryIterator();
+ if (entryIterator.hasNext()) {
+ Entry<E> result = entryIterator.next();
+ result = Multisets.immutableEntry(result.getElement(), result.getCount());
+ entryIterator.remove();
+ return result;
+ }
+ return null;
+ }
+
+ @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);
+ return tailMultiset(fromElement, fromBoundType).headMultiset(toElement, toBoundType);
+ }
+
+ abstract Iterator<Entry<E>> descendingEntryIterator();
+
+ Iterator<E> descendingIterator() {
+ return Multisets.iteratorImpl(descendingMultiset());
+ }
+
+ private transient SortedMultiset<E> descendingMultiset;
+
+ @Override
+ public SortedMultiset<E> descendingMultiset() {
+ SortedMultiset<E> result = descendingMultiset;
+ return (result == null) ? descendingMultiset = createDescendingMultiset() : result;
+ }
+
+ SortedMultiset<E> createDescendingMultiset() {
+ return new SortedMultisets.DescendingMultiset<E>() {
+ @Override
+ SortedMultiset<E> forwardMultiset() {
+ return AbstractSortedMultiset.this;
+ }
+
+ @Override
+ Iterator<Entry<E>> entryIterator() {
+ return descendingEntryIterator();
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return descendingIterator();
+ }
+ };
+ }
+}
diff --git a/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java b/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java
new file mode 100644
index 0000000..2be5f4b
--- /dev/null
+++ b/guava/src/com/google/common/collect/AbstractSortedSetMultimap.java
@@ -0,0 +1,124 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.SortedSet;
+
+import javax.annotation.Nullable;
+
+/**
+ * Basic implementation of the {@link SortedSetMultimap} interface. It's a
+ * wrapper around {@link AbstractMultimap} that converts the returned
+ * collections into sorted sets. The {@link #createCollection} method
+ * must return a {@code SortedSet}.
+ *
+ * @author Jared Levy
+ */
+@GwtCompatible
+abstract class AbstractSortedSetMultimap<K, V>
+ extends AbstractSetMultimap<K, V> implements SortedSetMultimap<K, V> {
+ /**
+ * Creates a new multimap that uses the provided map.
+ *
+ * @param map place to store the mapping from each key to its corresponding
+ * values
+ */
+ protected AbstractSortedSetMultimap(Map<K, Collection<V>> map) {
+ super(map);
+ }
+
+ @Override abstract SortedSet<V> createCollection();
+
+ // Following Javadoc copied from Multimap and SortedSetMultimap.
+
+ /**
+ * 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.
+ *
+ * <p>Because a {@code SortedSetMultimap} has unique sorted values for a given
+ * key, this method returns a {@link SortedSet}, instead of the
+ * {@link Collection} specified in the {@link Multimap} interface.
+ */
+ @Override public SortedSet<V> get(@Nullable K key) {
+ return (SortedSet<V>) super.get(key);
+ }
+
+ /**
+ * Removes all values associated with a given key. The returned collection is
+ * immutable.
+ *
+ * <p>Because a {@code SortedSetMultimap} has unique sorted values for a given
+ * key, this method returns a {@link SortedSet}, instead of the
+ * {@link Collection} specified in the {@link Multimap} interface.
+ */
+ @Override public SortedSet<V> removeAll(@Nullable Object key) {
+ return (SortedSet<V>) super.removeAll(key);
+ }
+
+ /**
+ * Stores a collection of values with the same key, replacing any existing
+ * values for that key. The returned collection is immutable.
+ *
+ * <p>Because a {@code SortedSetMultimap} has unique sorted values for a given
+ * key, this method returns a {@link SortedSet}, instead of the
+ * {@link Collection} specified in the {@link Multimap} interface.
+ *
+ * <p>Any duplicates in {@code values} will be stored in the multimap once.
+ */
+ @Override public SortedSet<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ return (SortedSet<V>) super.replaceValues(key, values);
+ }
+
+ /**
+ * Returns a map view that associates each key with the corresponding values
+ * in the multimap. Changes to the returned map, such as element removal, will
+ * update the underlying multimap. The map does not support {@code setValue}
+ * on its entries, {@code put}, or {@code putAll}.
+ *
+ * <p>When passed a key that is present in the map, {@code
+ * asMap().get(Object)} has the same behavior as {@link #get}, returning a
+ * live collection. When passed a key that is not present, however, {@code
+ * asMap().get(Object)} returns {@code null} instead of an empty collection.
+ *
+ * <p>Though the method signature doesn't say so explicitly, the returned map
+ * has {@link SortedSet} values.
+ */
+ @Override public Map<K, Collection<V>> asMap() {
+ return super.asMap();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Consequently, the values do not follow their natural ordering or the
+ * ordering of the value comparator.
+ */
+ @Override public Collection<V> values() {
+ return super.values();
+ }
+
+ private static final long serialVersionUID = 430848587173315748L;
+}
diff --git a/guava/src/com/google/common/collect/AllEqualOrdering.java b/guava/src/com/google/common/collect/AllEqualOrdering.java
new file mode 100644
index 0000000..c30164b
--- /dev/null
+++ b/guava/src/com/google/common/collect/AllEqualOrdering.java
@@ -0,0 +1,66 @@
+/*
+ * 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
new file mode 100644
index 0000000..759c073
--- /dev/null
+++ b/guava/src/com/google/common/collect/ArrayListMultimap.java
@@ -0,0 +1,168 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Implementation of {@code Multimap} that uses an {@code ArrayList} to store
+ * the values for a given key. A {@link HashMap} associates each key with an
+ * {@link ArrayList} of values.
+ *
+ * <p>When iterating through the collections supplied by this class, the
+ * ordering of values for a given key agrees with the order in which the values
+ * were added.
+ *
+ * <p>This multimap allows duplicate key-value pairs. After adding a new
+ * key-value pair equal to an existing key-value pair, the {@code
+ * ArrayListMultimap} will contain entries for both the new value and the old
+ * value.
+ *
+ * <p>Keys and values may be null. All optional multimap methods are supported,
+ * and all returned views are modifiable.
+ *
+ * <p>The lists returned by {@link #get}, {@link #removeAll}, and {@link
+ * #replaceValues} all implement {@link java.util.RandomAccess}.
+ *
+ * <p>This class is not threadsafe when any concurrent operations update the
+ * 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)
+ */
+@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;
+
+ @VisibleForTesting transient int expectedValuesPerKey;
+
+ /**
+ * Creates a new, empty {@code ArrayListMultimap} with the default initial
+ * capacities.
+ */
+ public static <K, V> ArrayListMultimap<K, V> create() {
+ return new ArrayListMultimap<K, V>();
+ }
+
+ /**
+ * Constructs an empty {@code ArrayListMultimap} with enough capacity to hold
+ * the specified numbers of keys and values without resizing.
+ *
+ * @param expectedKeys the expected number of distinct keys
+ * @param expectedValuesPerKey the expected average number of values per key
+ * @throws IllegalArgumentException if {@code expectedKeys} or {@code
+ * expectedValuesPerKey} is negative
+ */
+ public static <K, V> ArrayListMultimap<K, V> create(
+ int expectedKeys, int expectedValuesPerKey) {
+ return new ArrayListMultimap<K, V>(expectedKeys, expectedValuesPerKey);
+ }
+
+ /**
+ * Constructs an {@code ArrayListMultimap} with the same mappings as the
+ * specified multimap.
+ *
+ * @param multimap the multimap whose contents are copied to this multimap
+ */
+ public static <K, V> ArrayListMultimap<K, V> create(
+ Multimap<? extends K, ? extends V> multimap) {
+ return new ArrayListMultimap<K, V>(multimap);
+ }
+
+ private ArrayListMultimap() {
+ super(new HashMap<K, Collection<V>>());
+ expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
+ }
+
+ private ArrayListMultimap(int expectedKeys, int expectedValuesPerKey) {
+ super(Maps.<K, Collection<V>>newHashMapWithExpectedSize(expectedKeys));
+ checkArgument(expectedValuesPerKey >= 0);
+ this.expectedValuesPerKey = expectedValuesPerKey;
+ }
+
+ private ArrayListMultimap(Multimap<? extends K, ? extends V> multimap) {
+ this(multimap.keySet().size(),
+ (multimap instanceof ArrayListMultimap) ?
+ ((ArrayListMultimap<?, ?>) multimap).expectedValuesPerKey :
+ DEFAULT_VALUES_PER_KEY);
+ putAll(multimap);
+ }
+
+ /**
+ * Creates a new, empty {@code ArrayList} to hold the collection of values for
+ * an arbitrary key.
+ */
+ @Override List<V> createCollection() {
+ return new ArrayList<V>(expectedValuesPerKey);
+ }
+
+ /**
+ * Reduces the memory used by this {@code ArrayListMultimap}, if feasible.
+ */
+ public void trimToSize() {
+ for (Collection<V> collection : backingMap().values()) {
+ ArrayList<V> arrayList = (ArrayList<V>) collection;
+ arrayList.trimToSize();
+ }
+ }
+
+ /**
+ * @serialData expectedValuesPerKey, number of distinct keys, and then for
+ * each distinct key: the key, number of values for that key, and the
+ * key's values
+ */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeInt(expectedValuesPerKey);
+ Serialization.writeMultimap(this, stream);
+ }
+
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ expectedValuesPerKey = stream.readInt();
+ int distinctKeys = Serialization.readCount(stream);
+ Map<K, Collection<V>> map = Maps.newHashMapWithExpectedSize(distinctKeys);
+ setMap(map);
+ Serialization.populateMultimap(this, stream, distinctKeys);
+ }
+
+ @GwtIncompatible("Not needed in emulated source.")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ArrayTable.java b/guava/src/com/google/common/collect/ArrayTable.java
new file mode 100644
index 0000000..d13f00c
--- /dev/null
+++ b/guava/src/com/google/common/collect/ArrayTable.java
@@ -0,0 +1,825 @@
+/*
+ * 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;
+
+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.Objects;
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.AbstractCollection;
+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.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * Fixed-size {@link Table} implementation backed by a two-dimensional array.
+ *
+ * <p>The allowed row and column keys must be supplied when the table is
+ * created. The table always contains a mapping for every row key / column pair.
+ * The value corresponding to a given row and column is null unless another
+ * value is provided.
+ *
+ * <p>The table's size is constant: the product of the number of supplied row
+ * keys and the number of supplied column keys. The {@code remove} and {@code
+ * clear} methods are not supported by the table or its views. The {@link
+ * #erase} and {@link #eraseAll} methods may be used instead.
+ *
+ * <p>The ordering of the row and column keys provided when the table is
+ * constructed determines the iteration ordering across rows and columns in the
+ * table's views. None of the view iterators support {@link Iterator#remove}.
+ * If the table is modified after an iterator is created, the iterator remains
+ * valid.
+ *
+ * <p>This class requires less memory than the {@link HashBasedTable} and {@link
+ * TreeBasedTable} implementations, except when the table is sparse.
+ *
+ * <p>Null row keys or column keys are not permitted.
+ *
+ * <p>This class provides methods involving the underlying array structure,
+ * where the array indices correspond to the position of a row or column in the
+ * lists of allowed keys and values. See the {@link #at}, {@link #set}, {@link
+ * #toArray}, {@link #rowKeyList}, and {@link #columnKeyList} methods for more
+ * details.
+ *
+ * <p>Note that this implementation is not synchronized. If multiple threads
+ * access the same cell of an {@code ArrayTable} concurrently and one of the
+ * threads modifies its value, there is no guarantee that the new value will be
+ * fully visible to the other threads. To guarantee that modifications are
+ * visible, synchronize access to the table. Unlike other {@code Table}
+ * 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
+public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
+
+ /**
+ * Creates an empty {@code ArrayTable}.
+ *
+ * @param rowKeys row keys that may be stored in the generated table
+ * @param columnKeys column keys that may be stored in the generated table
+ * @throws NullPointerException if any of the provided keys is null
+ * @throws IllegalArgumentException if {@code rowKeys} or {@code columnKeys}
+ * contains duplicates or is empty
+ */
+ public static <R, C, V> ArrayTable<R, C, V> create(
+ Iterable<? extends R> rowKeys, Iterable<? extends C> columnKeys) {
+ return new ArrayTable<R, C, V>(rowKeys, columnKeys);
+ }
+
+ /*
+ * TODO(jlevy): Add factory methods taking an Enum class, instead of an
+ * iterable, to specify the allowed row keys and/or column keys. Note that
+ * custom serialization logic is needed to support different enum sizes during
+ * serialization and deserialization.
+ */
+
+ /**
+ * Creates an {@code ArrayTable} with the mappings in the provided table.
+ *
+ * <p>If {@code table} includes a mapping with row key {@code r} and a
+ * separate mapping with column key {@code c}, the returned table contains a
+ * mapping with row key {@code r} and column key {@code c}. If that row key /
+ * column key pair in not in {@code table}, the pair maps to {@code null} in
+ * the generated table.
+ *
+ * <p>The returned table allows subsequent {@code put} calls with the row keys
+ * in {@code table.rowKeySet()} and the column keys in {@code
+ * table.columnKeySet()}. Calling {@link #put} with other keys leads to an
+ * {@code IllegalArgumentException}.
+ *
+ * <p>The ordering of {@code table.rowKeySet()} and {@code
+ * table.columnKeySet()} determines the row and column iteration ordering of
+ * the returned table.
+ *
+ * @throws NullPointerException if {@code table} has a null key
+ * @throws IllegalArgumentException if the provided table is empty
+ */
+ public static <R, C, V> ArrayTable<R, C, V> create(Table<R, C, V> table) {
+ return new ArrayTable<R, C, V>(table);
+ }
+
+ /**
+ * Creates an {@code ArrayTable} with the same mappings, allowed keys, and
+ * iteration ordering as the provided {@code ArrayTable}.
+ */
+ public static <R, C, V> ArrayTable<R, C, V> create(
+ ArrayTable<R, C, V> table) {
+ return new ArrayTable<R, C, V>(table);
+ }
+
+ private final ImmutableList<R> rowList;
+ private final ImmutableList<C> columnList;
+
+ // TODO(jlevy): Add getters returning rowKeyToIndex and columnKeyToIndex?
+ private final ImmutableMap<R, Integer> rowKeyToIndex;
+ private final ImmutableMap<C, Integer> columnKeyToIndex;
+ private final V[][] array;
+
+ private ArrayTable(Iterable<? extends R> rowKeys,
+ Iterable<? extends C> columnKeys) {
+ this.rowList = ImmutableList.copyOf(rowKeys);
+ this.columnList = ImmutableList.copyOf(columnKeys);
+ checkArgument(!rowList.isEmpty());
+ checkArgument(!columnList.isEmpty());
+
+ /*
+ * TODO(jlevy): Support empty rowKeys or columnKeys? If we do, when
+ * 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);
+
+ @SuppressWarnings("unchecked")
+ V[][] tmpArray
+ = (V[][]) new Object[rowList.size()][columnList.size()];
+ array = tmpArray;
+ }
+
+ 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) {
+ this(table.rowKeySet(), table.columnKeySet());
+ putAll(table);
+ }
+
+ private ArrayTable(ArrayTable<R, C, V> table) {
+ rowList = table.rowList;
+ columnList = table.columnList;
+ rowKeyToIndex = table.rowKeyToIndex;
+ columnKeyToIndex = table.columnKeyToIndex;
+ @SuppressWarnings("unchecked")
+ V[][] copy = (V[][]) new Object[rowList.size()][columnList.size()];
+ array = copy;
+ 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.
+ */
+ public ImmutableList<R> rowKeyList() {
+ return rowList;
+ }
+
+ /**
+ * Returns, as an immutable list, the column keys provided when the table was
+ * constructed, including those that are mapped to null values only.
+ */
+ public ImmutableList<C> columnKeyList() {
+ return columnList;
+ }
+
+ /**
+ * Returns the value corresponding to the specified row and column indices.
+ * The same value is returned by {@code
+ * get(rowKeyList().get(rowIndex), columnKeyList().get(columnIndex))}, but
+ * this method runs more quickly.
+ *
+ * @param rowIndex position of the row key in {@link #rowKeyList()}
+ * @param columnIndex position of the row key in {@link #columnKeyList()}
+ * @return the value with the specified row and column
+ * @throws IndexOutOfBoundsException if either index is negative, {@code
+ * rowIndex} is greater then or equal to the number of allowed row keys,
+ * or {@code columnIndex} is greater then or equal to the number of
+ * allowed column keys
+ */
+ public V at(int rowIndex, int columnIndex) {
+ return array[rowIndex][columnIndex];
+ }
+
+ /**
+ * Associates {@code value} with the specified row and column indices. The
+ * logic {@code
+ * put(rowKeyList().get(rowIndex), columnKeyList().get(columnIndex), value)}
+ * has the same behavior, but this method runs more quickly.
+ *
+ * @param rowIndex position of the row key in {@link #rowKeyList()}
+ * @param columnIndex position of the row key in {@link #columnKeyList()}
+ * @param value value to store in the table
+ * @return the previous value with the specified row and column
+ * @throws IndexOutOfBoundsException if either index is negative, {@code
+ * rowIndex} is greater then or equal to the number of allowed row keys,
+ * or {@code columnIndex} is greater then or equal to the number of
+ * allowed column keys
+ */
+ public V set(int rowIndex, int columnIndex, @Nullable V value) {
+ V oldValue = array[rowIndex][columnIndex];
+ array[rowIndex][columnIndex] = value;
+ return oldValue;
+ }
+
+ /**
+ * Returns a two-dimensional array with the table contents. The row and column
+ * indices correspond to the positions of the row and column in the iterables
+ * provided during table construction. If the table lacks a mapping for a
+ * given row and column, the corresponding array element is null.
+ *
+ * <p>Subsequent table changes will not modify the array, and vice versa.
+ *
+ * @param valueClass class of values stored in the returned array
+ */
+ public V[][] toArray(Class<V> valueClass) {
+ // Can change to use varargs in JDK 1.6 if we want
+ @SuppressWarnings("unchecked") // TODO: safe?
+ V[][] copy = (V[][]) Array.newInstance(
+ valueClass, new int[] { rowList.size(), columnList.size() });
+ for (int i = 0; i < rowList.size(); i++) {
+ System.arraycopy(array[i], 0, copy[i], 0, array[i].length);
+ }
+ return copy;
+ }
+
+ /**
+ * Not supported. Use {@link #eraseAll} instead.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated Use {@link #eraseAll}
+ */
+ @Override
+ @Deprecated public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Associates the value {@code null} with every pair of allowed row and column
+ * keys.
+ */
+ public void eraseAll() {
+ for (V[] row : array) {
+ Arrays.fill(row, null);
+ }
+ }
+
+ /**
+ * Returns {@code true} if the provided keys are among the keys provided when
+ * the table was constructed.
+ */
+ @Override
+ public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) {
+ return containsRow(rowKey) && containsColumn(columnKey);
+ }
+
+ /**
+ * Returns {@code true} if the provided column key is among the column keys
+ * provided when the table was constructed.
+ */
+ @Override
+ public boolean containsColumn(@Nullable Object columnKey) {
+ return columnKeyToIndex.containsKey(columnKey);
+ }
+
+ /**
+ * Returns {@code true} if the provided row key is among the row keys
+ * provided when the table was constructed.
+ */
+ @Override
+ public boolean containsRow(@Nullable Object rowKey) {
+ return rowKeyToIndex.containsKey(rowKey);
+ }
+
+ @Override
+ public boolean containsValue(@Nullable Object value) {
+ for (V[] row : array) {
+ for (V element : row) {
+ if (Objects.equal(value, element)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ return (rowIndex == null || columnIndex == null)
+ ? null : array[rowIndex][columnIndex];
+ }
+
+ /**
+ * Always returns {@code false}.
+ */
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if {@code rowKey} is not in {@link
+ * #rowKeySet()} or {@code columnKey} is not in {@link #columnKeySet()}.
+ */
+ @Override
+ public V put(R rowKey, C columnKey, @Nullable V value) {
+ checkNotNull(rowKey);
+ checkNotNull(columnKey);
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ checkArgument(rowIndex != null, "Row %s not in %s", rowKey, rowList);
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ checkArgument(columnIndex != null,
+ "Column %s not in %s", columnKey, columnList);
+ return set(rowIndex, columnIndex, value);
+ }
+
+ /*
+ * TODO(jlevy): Consider creating a merge() method, similar to putAll() but
+ * copying non-null values only.
+ */
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>If {@code table} is an {@code ArrayTable}, its null values will be
+ * stored in this table, possibly replacing values that were previously
+ * non-null.
+ *
+ * @throws NullPointerException if {@code table} has a null key
+ * @throws IllegalArgumentException if any of the provided table's row keys or
+ * column keys is not in {@link #rowKeySet()} or {@link #columnKeySet()}
+ */
+ @Override
+ public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
+ for (Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) {
+ put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
+ }
+ }
+
+ /**
+ * Not supported. Use {@link #erase} instead.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated Use {@link #erase}
+ */
+ @Override
+ @Deprecated public V remove(Object rowKey, Object columnKey) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Associates the value {@code null} with the specified keys, assuming both
+ * keys are valid. If either key is null or isn't among the keys provided
+ * during construction, this method has no effect.
+ *
+ * <p>This method is equivalent to {@code put(rowKey, columnKey, null)} when
+ * both provided keys are valid.
+ *
+ * @param rowKey row key of mapping to be erased
+ * @param columnKey column key of mapping to be erased
+ * @return the value previously associated with the keys, or {@code null} if
+ * no mapping existed for the keys
+ */
+ public V erase(@Nullable Object rowKey, @Nullable Object columnKey) {
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ if (rowIndex == null || columnIndex == null) {
+ return null;
+ }
+ return set(rowIndex, columnIndex, null);
+ }
+
+ // TODO(jlevy): Add eraseRow and eraseColumn methods?
+
+ @Override
+ public int size() {
+ return rowList.size() * columnList.size();
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof Table) {
+ Table<?, ?, ?> other = (Table<?, ?, ?>) obj;
+ return cellSet().equals(other.cellSet());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return cellSet().hashCode();
+ }
+
+ /**
+ * Returns the string representation {@code rowMap().toString()}.
+ */
+ @Override public String toString() {
+ return rowMap().toString();
+ }
+
+ private transient CellSet cellSet;
+
+ /**
+ * Returns an unmodifiable set of all row key / column key / value
+ * triplets. Changes to the table will update the returned set.
+ *
+ * <p>The returned set's iterator traverses the mappings with the first row
+ * key, the mappings with the second row key, and so on.
+ *
+ * <p>The value in the returned cells may change if the table subsequently
+ * changes.
+ *
+ * @return set of table cells consisting of row key / column key / value
+ * triplets
+ */
+ @Override
+ public Set<Cell<R, C, V>> cellSet() {
+ CellSet set = cellSet;
+ return (set == null) ? cellSet = new CellSet() : set;
+ }
+
+ private class CellSet extends AbstractSet<Cell<R, C, V>> {
+
+ @Override public Iterator<Cell<R, C, V>> iterator() {
+ return new AbstractIndexedListIterator<Cell<R, C, V>>(size()) {
+ @Override protected Cell<R, C, V> get(final int index) {
+ return new Tables.AbstractCell<R, C, V>() {
+ final int rowIndex = index / columnList.size();
+ final int columnIndex = index % columnList.size();
+ @Override
+ public R getRowKey() {
+ return rowList.get(rowIndex);
+ }
+ @Override
+ public C getColumnKey() {
+ return columnList.get(columnIndex);
+ }
+ @Override
+ public V getValue() {
+ return array[rowIndex][columnIndex];
+ }
+ };
+ }
+ };
+ }
+
+ @Override public int size() {
+ return ArrayTable.this.size();
+ }
+
+ @Override public boolean contains(Object obj) {
+ if (obj instanceof Cell) {
+ Cell<?, ?, ?> cell = (Cell<?, ?, ?>) obj;
+ Integer rowIndex = rowKeyToIndex.get(cell.getRowKey());
+ Integer columnIndex = columnKeyToIndex.get(cell.getColumnKey());
+ return rowIndex != null
+ && columnIndex != null
+ && Objects.equal(array[rowIndex][columnIndex], cell.getValue());
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Returns a view of all mappings that have the given column key. If the
+ * column key isn't in {@link #columnKeySet()}, an empty immutable map is
+ * returned.
+ *
+ * <p>Otherwise, for each row key in {@link #rowKeySet()}, the returned map
+ * associates the row key with the corresponding value in the table. Changes
+ * to the returned map will update the underlying table, and vice versa.
+ *
+ * @param columnKey key of column to search for in the table
+ * @return the corresponding map from row keys to values
+ */
+ @Override
+ public Map<R, V> column(C columnKey) {
+ checkNotNull(columnKey);
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ return (columnIndex == null)
+ ? ImmutableMap.<R, V>of() : new Column(columnIndex);
+ }
+
+ private class Column extends ArrayMap<R, V> {
+ final int columnIndex;
+
+ Column(int columnIndex) {
+ super(rowKeyToIndex);
+ this.columnIndex = columnIndex;
+ }
+
+ @Override
+ String getKeyRole() {
+ return "Row";
+ }
+
+ @Override
+ V getValue(int index) {
+ return at(index, columnIndex);
+ }
+
+ @Override
+ V setValue(int index, V newValue) {
+ return set(index, columnIndex, newValue);
+ }
+ }
+
+ /**
+ * Returns an immutable set of the valid column keys, including those that
+ * are associated with null values only.
+ *
+ * @return immutable set of column keys
+ */
+ @Override
+ public ImmutableSet<C> columnKeySet() {
+ return columnKeyToIndex.keySet();
+ }
+
+ private transient ColumnMap columnMap;
+
+ @Override
+ public Map<C, Map<R, V>> columnMap() {
+ ColumnMap map = columnMap;
+ return (map == null) ? columnMap = new ColumnMap() : map;
+ }
+
+ private class ColumnMap extends ArrayMap<C, Map<R, V>> {
+ private ColumnMap() {
+ super(columnKeyToIndex);
+ }
+
+ @Override
+ String getKeyRole() {
+ return "Column";
+ }
+
+ @Override
+ Map<R, V> getValue(int index) {
+ return new Column(index);
+ }
+
+ @Override
+ Map<R, V> setValue(int index, Map<R, V> newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<R, V> put(C key, Map<R, V> value) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * 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
+ * returned.
+ *
+ * <p>Otherwise, for each column key in {@link #columnKeySet()}, the returned
+ * map associates the column key with the corresponding value in the
+ * table. Changes to the returned map will update the underlying table, and
+ * vice versa.
+ *
+ * @param rowKey key of row to search for in the table
+ * @return the corresponding map from column keys to values
+ */
+ @Override
+ public Map<C, V> row(R rowKey) {
+ checkNotNull(rowKey);
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ return (rowIndex == null) ? ImmutableMap.<C, V>of() : new Row(rowIndex);
+ }
+
+ private class Row extends ArrayMap<C, V> {
+ final int rowIndex;
+
+ Row(int rowIndex) {
+ super(columnKeyToIndex);
+ this.rowIndex = rowIndex;
+ }
+
+ @Override
+ String getKeyRole() {
+ return "Column";
+ }
+
+ @Override
+ V getValue(int index) {
+ return at(rowIndex, index);
+ }
+
+ @Override
+ V setValue(int index, V newValue) {
+ return set(rowIndex, index, newValue);
+ }
+ }
+
+ /**
+ * Returns an immutable set of the valid row keys, including those that are
+ * associated with null values only.
+ *
+ * @return immutable set of row keys
+ */
+ @Override
+ public ImmutableSet<R> rowKeySet() {
+ return rowKeyToIndex.keySet();
+ }
+
+ private transient RowMap rowMap;
+
+ @Override
+ public Map<R, Map<C, V>> rowMap() {
+ RowMap map = rowMap;
+ return (map == null) ? rowMap = new RowMap() : map;
+ }
+
+ private class RowMap extends ArrayMap<R, Map<C, V>> {
+ private RowMap() {
+ super(rowKeyToIndex);
+ }
+
+ @Override
+ String getKeyRole() {
+ return "Row";
+ }
+
+ @Override
+ Map<C, V> getValue(int index) {
+ return new Row(index);
+ }
+
+ @Override
+ Map<C, V> setValue(int index, Map<C, V> newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<C, V> put(R key, Map<C, V> value) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private transient Collection<V> values;
+
+ /**
+ * Returns an unmodifiable collection of all values, which may contain
+ * duplicates. Changes to the table will update the returned collection.
+ *
+ * <p>The returned collection's iterator traverses the values of the first row
+ * key, the values of the second row key, and so on.
+ *
+ * @return collection of values
+ */
+ @Override
+ public Collection<V> values() {
+ Collection<V> v = values;
+ return (v == null) ? values = new Values() : v;
+ }
+
+ 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();
+ }
+ };
+ }
+
+ @Override public int size() {
+ return ArrayTable.this.size();
+ }
+ }
+
+ 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
new file mode 100644
index 0000000..a6203e0
--- /dev/null
+++ b/guava/src/com/google/common/collect/BiMap.java
@@ -0,0 +1,110 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A bimap (or "bidirectional map") is a map that preserves the uniqueness of
+ * 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)
+ */
+@GwtCompatible
+public interface BiMap<K, V> extends Map<K, V> {
+ // Modification Operations
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalArgumentException if the given value is already bound to a
+ * different key in this bimap. The bimap will remain unmodified in this
+ * event. To avoid this exception, call {@link #forcePut} instead.
+ */
+ @Override
+ V put(@Nullable K key, @Nullable V value);
+
+ /**
+ * An alternate form of {@code put} that silently removes any existing entry
+ * with the value {@code value} before proceeding with the {@link #put}
+ * operation. If the bimap previously contained the provided key-value
+ * mapping, this method has no effect.
+ *
+ * <p>Note that a successful call to this method could cause the size of the
+ * bimap to increase by one, stay the same, or even decrease by one.
+ *
+ * <p><b>Warning:</b> If an existing entry with this value is removed, the key
+ * for that entry is discarded and not returned.
+ *
+ * @param key the key with which the specified value is to be associated
+ * @param value the value to be associated with the specified key
+ * @return the value which was previously associated with the key, which may
+ * be {@code null}, or {@code null} if there was no previous entry
+ */
+ V forcePut(@Nullable K key, @Nullable V value);
+
+ // Bulk Operations
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p><b>Warning:</b> the results of calling this method may vary depending on
+ * the iteration order of {@code map}.
+ *
+ * @throws IllegalArgumentException if an attempt to {@code put} any
+ * entry fails. Note that some map entries may have been added to the
+ * bimap before the exception was thrown.
+ */
+ @Override
+ void putAll(Map<? extends K, ? extends V> map);
+
+ // Views
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a bimap has unique values, this method returns a {@link Set},
+ * instead of the {@link java.util.Collection} specified in the {@link Map}
+ * interface.
+ */
+ @Override
+ Set<V> values();
+
+ /**
+ * Returns the inverse view of this bimap, which maps each of this bimap's
+ * values to its associated key. The two bimaps are backed by the same data;
+ * any changes to one will appear in the other.
+ *
+ * <p><b>Note:</b>There is no guaranteed correspondence between the iteration
+ * order of a bimap and that of its inverse.
+ *
+ * @return the inverse view of this bimap
+ */
+ BiMap<V, K> inverse();
+}
diff --git a/guava/src/com/google/common/collect/BoundType.java b/guava/src/com/google/common/collect/BoundType.java
new file mode 100644
index 0000000..2290048
--- /dev/null
+++ b/guava/src/com/google/common/collect/BoundType.java
@@ -0,0 +1,57 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+/**
+ * Indicates whether an endpoint of some range is contained in the range itself ("closed") or not
+ * ("open"). If a range is unbounded on a side, it is neither open nor closed on that side; the
+ * bound simply does not exist.
+ *
+ * @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;
+ }
+ },
+ /**
+ * The endpoint value <i>is</i> considered part of the set ("inclusive").
+ */
+ CLOSED {
+ @Override
+ BoundType flip() {
+ return OPEN;
+ }
+ };
+
+ /**
+ * Returns the bound type corresponding to a boolean value for inclusivity.
+ */
+ static BoundType forBoolean(boolean inclusive) {
+ return inclusive ? CLOSED : OPEN;
+ }
+
+ abstract BoundType flip();
+}
diff --git a/guava/src/com/google/common/collect/ByFunctionOrdering.java b/guava/src/com/google/common/collect/ByFunctionOrdering.java
new file mode 100644
index 0000000..c148ba9
--- /dev/null
+++ b/guava/src/com/google/common/collect/ByFunctionOrdering.java
@@ -0,0 +1,70 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+
+import java.io.Serializable;
+
+import javax.annotation.Nullable;
+
+/**
+ * An ordering that orders elements by applying an order to the result of a
+ * function on those elements.
+ */
+@GwtCompatible(serializable = true)
+final class ByFunctionOrdering<F, T>
+ extends Ordering<F> implements Serializable {
+ final Function<F, ? extends T> function;
+ final Ordering<T> ordering;
+
+ ByFunctionOrdering(
+ Function<F, ? extends T> function, Ordering<T> ordering) {
+ this.function = checkNotNull(function);
+ this.ordering = checkNotNull(ordering);
+ }
+
+ @Override public int compare(F left, F right) {
+ return ordering.compare(function.apply(left), function.apply(right));
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof ByFunctionOrdering) {
+ ByFunctionOrdering<?, ?> that = (ByFunctionOrdering<?, ?>) object;
+ return this.function.equals(that.function)
+ && this.ordering.equals(that.ordering);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(function, ordering);
+ }
+
+ @Override public String toString() {
+ return ordering + ".onResultOf(" + function + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ClassToInstanceMap.java b/guava/src/com/google/common/collect/ClassToInstanceMap.java
new file mode 100644
index 0000000..b3f535c
--- /dev/null
+++ b/guava/src/com/google/common/collect/ClassToInstanceMap.java
@@ -0,0 +1,66 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * A map, each entry of which maps a Java
+ * <a href="http://tinyurl.com/2cmwkz">raw type</a> 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>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}
+ *
+ * @author Kevin Bourrillion
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public interface ClassToInstanceMap<B> extends Map<Class<? 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.
+ */
+ <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.
+ *
+ * @return the value previously associated with this class (possibly {@code
+ * null}), or {@code null} if there was no previous entry.
+ */
+ <T extends B> T putInstance(Class<T> type, @Nullable T value);
+}
diff --git a/guava/src/com/google/common/collect/Collections2.java b/guava/src/com/google/common/collect/Collections2.java
new file mode 100644
index 0000000..e3ae14a
--- /dev/null
+++ b/guava/src/com/google/common/collect/Collections2.java
@@ -0,0 +1,703 @@
+/*
+ * 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.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.
+ *
+ * @author Chris Povirk
+ * @author Mike Bostock
+ * @author Jared Levy
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public final class Collections2 {
+ private Collections2() {}
+
+ /**
+ * Returns the elements of {@code unfiltered} that satisfy a predicate. The
+ * returned collection is a live view of {@code unfiltered}; changes to one
+ * affect the other.
+ *
+ * <p>The resulting collection's iterator does not support {@code remove()},
+ * but all other collection methods are supported. When given an element that
+ * doesn't satisfy the predicate, the collection'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
+ * collection, only elements that satisfy the filter will be removed from the
+ * underlying collection.
+ *
+ * <p>The returned collection isn't threadsafe or serializable, even if
+ * {@code unfiltered} is.
+ *
+ * <p>Many of the filtered collection's methods, such as {@code size()},
+ * iterate across every element in the underlying collection 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.)
+ */
+ // TODO(kevinb): how can we omit that Iterables link when building gwt
+ // javadoc?
+ public static <E> Collection<E> filter(
+ Collection<E> unfiltered, Predicate<? super E> predicate) {
+ if (unfiltered instanceof FilteredCollection) {
+ // Support clear(), removeAll(), and retainAll() when filtering a filtered
+ // collection.
+ return ((FilteredCollection<E>) unfiltered).createCombined(predicate);
+ }
+
+ return new FilteredCollection<E>(
+ checkNotNull(unfiltered), checkNotNull(predicate));
+ }
+
+ /**
+ * Delegates to {@link Collection#contains}. Returns {@code false} if the
+ * {@code contains} method throws a {@code ClassCastException}.
+ */
+ static boolean safeContains(Collection<?> collection, Object object) {
+ try {
+ return collection.contains(object);
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ static class FilteredCollection<E> implements Collection<E> {
+ final Collection<E> unfiltered;
+ final Predicate<? super E> predicate;
+
+ FilteredCollection(Collection<E> unfiltered,
+ Predicate<? super E> predicate) {
+ this.unfiltered = unfiltered;
+ this.predicate = predicate;
+ }
+
+ FilteredCollection<E> createCombined(Predicate<? super E> newPredicate) {
+ return new FilteredCollection<E>(unfiltered,
+ Predicates.<E>and(predicate, newPredicate));
+ // .<E> above needed to compile in JDK 5
+ }
+
+ @Override
+ public boolean add(E element) {
+ checkArgument(predicate.apply(element));
+ return unfiltered.add(element);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends E> collection) {
+ for (E element : collection) {
+ checkArgument(predicate.apply(element));
+ }
+ return unfiltered.addAll(collection);
+ }
+
+ @Override
+ public void clear() {
+ Iterables.removeIf(unfiltered, predicate);
+ }
+
+ @Override
+ public boolean contains(Object element) {
+ try {
+ // unsafe cast can result in a CCE from predicate.apply(), which we
+ // will catch
+ @SuppressWarnings("unchecked")
+ E e = (E) element;
+
+ /*
+ * We check whether e satisfies the predicate, when we really mean to
+ * check whether the element contained in the set does. This is ok as
+ * long as the predicate is consistent with equals, as required.
+ */
+ return predicate.apply(e) && unfiltered.contains(element);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> collection) {
+ for (Object element : collection) {
+ if (!contains(element)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return !Iterators.any(unfiltered.iterator(), predicate);
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return Iterators.filter(unfiltered.iterator(), predicate);
+ }
+
+ @Override
+ public boolean remove(Object element) {
+ try {
+ // unsafe cast can result in a CCE from predicate.apply(), which we
+ // will catch
+ @SuppressWarnings("unchecked")
+ E e = (E) element;
+
+ // See comment in contains() concerning predicate.apply(e)
+ return predicate.apply(e) && unfiltered.remove(element);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean removeAll(final Collection<?> collection) {
+ checkNotNull(collection);
+ Predicate<E> combinedPredicate = new Predicate<E>() {
+ @Override
+ public boolean apply(E input) {
+ return predicate.apply(input) && collection.contains(input);
+ }
+ };
+ return Iterables.removeIf(unfiltered, combinedPredicate);
+ }
+
+ @Override
+ public boolean retainAll(final Collection<?> collection) {
+ checkNotNull(collection);
+ Predicate<E> combinedPredicate = new Predicate<E>() {
+ @Override
+ public boolean apply(E input) {
+ // See comment in contains() concerning predicate.apply(e)
+ return predicate.apply(input) && !collection.contains(input);
+ }
+ };
+ return Iterables.removeIf(unfiltered, combinedPredicate);
+ }
+
+ @Override
+ public int size() {
+ return Iterators.size(iterator());
+ }
+
+ @Override
+ public Object[] toArray() {
+ // creating an ArrayList so filtering happens once
+ return Lists.newArrayList(iterator()).toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] array) {
+ return Lists.newArrayList(iterator()).toArray(array);
+ }
+
+ @Override public String toString() {
+ return Iterators.toString(iterator());
+ }
+ }
+
+ /**
+ * Returns a collection that applies {@code function} to each element of
+ * {@code fromCollection}. The returned collection is a live view of {@code
+ * fromCollection}; changes to one affect the other.
+ *
+ * <p>The returned collection's {@code add()} and {@code addAll()} methods
+ * throw an {@link UnsupportedOperationException}. All other collection
+ * methods are supported, as long as {@code fromCollection} supports them.
+ *
+ * <p>The returned collection isn't threadsafe or serializable, even if
+ * {@code fromCollection} is.
+ *
+ * <p>When a live view is <i>not</i> needed, it may be faster to copy the
+ * transformed collection and use the copy.
+ *
+ * <p>If the input {@code Collection} is known to be a {@code List}, consider
+ * {@link Lists#transform}. If only an {@code Iterable} is available, use
+ * {@link Iterables#transform}.
+ */
+ public static <F, T> Collection<T> transform(Collection<F> fromCollection,
+ Function<? super F, T> function) {
+ return new TransformedCollection<F, T>(fromCollection, function);
+ }
+
+ static class TransformedCollection<F, T> extends AbstractCollection<T> {
+ final Collection<F> fromCollection;
+ final Function<? super F, ? extends T> function;
+
+ TransformedCollection(Collection<F> fromCollection,
+ Function<? super F, ? extends T> function) {
+ this.fromCollection = checkNotNull(fromCollection);
+ this.function = checkNotNull(function);
+ }
+
+ @Override public void clear() {
+ fromCollection.clear();
+ }
+
+ @Override public boolean isEmpty() {
+ return fromCollection.isEmpty();
+ }
+
+ @Override public Iterator<T> iterator() {
+ return Iterators.transform(fromCollection.iterator(), function);
+ }
+
+ @Override public int size() {
+ return fromCollection.size();
+ }
+ }
+
+ /**
+ * Returns {@code true} if the collection {@code self} contains all of the
+ * elements in the collection {@code c}.
+ *
+ * <p>This method iterates over the specified collection {@code c}, checking
+ * each element returned by the iterator in turn to see if it is contained in
+ * the specified collection {@code self}. If all elements are so contained,
+ * {@code true} is returned, otherwise {@code false}.
+ *
+ * @param self a collection which might contain all elements in {@code c}
+ * @param c a collection whose elements might be contained by {@code self}
+ */
+ static boolean containsAllImpl(Collection<?> self, Collection<?> c) {
+ checkNotNull(self);
+ for (Object o : c) {
+ if (!self.contains(o)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * An implementation of {@link Collection#toString()}.
+ */
+ static String toStringImpl(final Collection<?> collection) {
+ StringBuilder sb
+ = newStringBuilderForCollection(collection.size()).append('[');
+ STANDARD_JOINER.appendTo(
+ sb, Iterables.transform(collection, new Function<Object, Object>() {
+ @Override public Object apply(Object input) {
+ return input == collection ? "(this Collection)" : input;
+ }
+ }));
+ return sb.append(']').toString();
+ }
+
+ /**
+ * Returns best-effort-sized StringBuilder based on the given collection size.
+ */
+ static StringBuilder newStringBuilderForCollection(int size) {
+ checkArgument(size >= 0, "size must be non-negative");
+ return new StringBuilder((int) Math.min(size * 8L, Ints.MAX_POWER_OF_TWO));
+ }
+
+ /**
+ * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
+ */
+ static <T> Collection<T> cast(Iterable<T> iterable) {
+ 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;
+ }
+
+ 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;
+ }
+}
diff --git a/guava/src/com/google/common/collect/ComparatorOrdering.java b/guava/src/com/google/common/collect/ComparatorOrdering.java
new file mode 100644
index 0000000..5eb7612
--- /dev/null
+++ b/guava/src/com/google/common/collect/ComparatorOrdering.java
@@ -0,0 +1,87 @@
+/*
+ * 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.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;
+
+import javax.annotation.Nullable;
+
+/** An ordering for a pre-existing comparator. */
+@GwtCompatible(serializable = true)
+final class ComparatorOrdering<T> extends Ordering<T> implements Serializable {
+ final Comparator<T> comparator;
+
+ ComparatorOrdering(Comparator<T> comparator) {
+ this.comparator = checkNotNull(comparator);
+ }
+
+ @Override public int compare(T a, T b) {
+ return comparator.compare(a, b);
+ }
+
+ // Override just to remove a level of indirection from inner loops
+ @Override public int binarySearch(List<? extends T> sortedList, T key) {
+ return Collections.binarySearch(sortedList, key, comparator);
+ }
+
+ // Override just to remove a level of indirection from inner loops
+ @Override public <E extends T> List<E> sortedCopy(Iterable<E> iterable) {
+ List<E> list = Lists.newArrayList(iterable);
+ Collections.sort(list, comparator);
+ 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;
+ }
+ if (object instanceof ComparatorOrdering) {
+ ComparatorOrdering<?> that = (ComparatorOrdering<?>) object;
+ return this.comparator.equals(that.comparator);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return comparator.hashCode();
+ }
+
+ @Override public String toString() {
+ return comparator.toString();
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ComparisonChain.java b/guava/src/com/google/common/collect/ComparisonChain.java
new file mode 100644
index 0000000..2ed8cc4
--- /dev/null
+++ b/guava/src/com/google/common/collect/ComparisonChain.java
@@ -0,0 +1,225 @@
+/*
+ * 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;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.primitives.Booleans;
+import com.google.common.primitives.Ints;
+import com.google.common.primitives.Longs;
+
+import java.util.Comparator;
+
+import javax.annotation.Nullable;
+
+/**
+ * A utility for performing a "lazy" chained comparison statement, which
+ * performs comparisons only until it finds a nonzero result. For example:
+ * <pre> {@code
+ *
+ * public int compareTo(Foo that) {
+ * return ComparisonChain.start()
+ * .compare(this.aString, that.aString)
+ * .compare(this.anInt, that.anInt)
+ * .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
+ * .result();
+ * }}</pre>
+ *
+ * The value of this expression will have the same sign as the <i>first
+ * nonzero</i> comparison result in the chain, or will be zero if every
+ * comparison result was zero.
+ *
+ * <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
+ * @since 2.0
+ */
+@GwtCompatible
+public abstract class ComparisonChain {
+ private ComparisonChain() {}
+
+ /**
+ * Begins a new chained comparison statement. See example in the class
+ * documentation.
+ */
+ public static ComparisonChain start() {
+ return ACTIVE;
+ }
+
+ private static final ComparisonChain ACTIVE = new ComparisonChain() {
+ @SuppressWarnings("unchecked")
+ @Override public ComparisonChain compare(
+ Comparable left, Comparable right) {
+ return classify(left.compareTo(right));
+ }
+ @Override public <T> ComparisonChain compare(
+ @Nullable T left, @Nullable T right, Comparator<T> comparator) {
+ return classify(comparator.compare(left, right));
+ }
+ @Override public ComparisonChain compare(int left, int right) {
+ return classify(Ints.compare(left, right));
+ }
+ @Override public ComparisonChain compare(long left, long right) {
+ return classify(Longs.compare(left, right));
+ }
+ @Override public ComparisonChain compare(float left, float right) {
+ return classify(Float.compare(left, right));
+ }
+ @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) {
+ return classify(Booleans.compare(left, right));
+ }
+ ComparisonChain classify(int result) {
+ return (result < 0) ? LESS : (result > 0) ? GREATER : ACTIVE;
+ }
+ @Override public int result() {
+ return 0;
+ }
+ };
+
+ private static final ComparisonChain LESS = new InactiveComparisonChain(-1);
+
+ private static final ComparisonChain GREATER = new InactiveComparisonChain(1);
+
+ private static final class InactiveComparisonChain extends ComparisonChain {
+ final int result;
+
+ InactiveComparisonChain(int result) {
+ this.result = result;
+ }
+ @Override public ComparisonChain compare(
+ @Nullable Comparable left, @Nullable Comparable right) {
+ return this;
+ }
+ @Override public <T> ComparisonChain compare(@Nullable T left,
+ @Nullable T right, @Nullable Comparator<T> comparator) {
+ return this;
+ }
+ @Override public ComparisonChain compare(int left, int right) {
+ return this;
+ }
+ @Override public ComparisonChain compare(long left, long right) {
+ return this;
+ }
+ @Override public ComparisonChain compare(float left, float right) {
+ return this;
+ }
+ @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) {
+ return this;
+ }
+ @Override public int result() {
+ return result;
+ }
+ }
+
+ /**
+ * Compares two comparable objects as specified by {@link
+ * Comparable#compareTo}, <i>if</i> the result of this comparison chain
+ * has not already been determined.
+ */
+ public abstract ComparisonChain compare(
+ Comparable<?> left, Comparable<?> right);
+
+ /**
+ * Compares two objects using a comparator, <i>if</i> the result of this
+ * comparison chain has not already been determined.
+ */
+ public abstract <T> ComparisonChain compare(
+ @Nullable T left, @Nullable T right, Comparator<T> comparator);
+
+ /**
+ * Compares two {@code int} values as specified by {@link Ints#compare},
+ * <i>if</i> the result of this comparison chain has not already been
+ * determined.
+ */
+ public abstract ComparisonChain compare(int left, int right);
+
+ /**
+ * Compares two {@code long} values as specified by {@link Longs#compare},
+ * <i>if</i> the result of this comparison chain has not already been
+ * determined.
+ */
+ public abstract ComparisonChain compare(long left, long right);
+
+ /**
+ * Compares two {@code float} values as specified by {@link
+ * Float#compare}, <i>if</i> the result of this comparison chain has not
+ * already been determined.
+ */
+ public abstract ComparisonChain compare(float left, float right);
+
+ /**
+ * Compares two {@code double} values as specified by {@link
+ * Double#compare}, <i>if</i> the result of this comparison chain has not
+ * already been determined.
+ */
+ 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
+ * 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);
+ }
+
+ /**
+ * Ends this comparison chain and returns its result: a value having the
+ * same sign as the first nonzero comparison result in the chain, or zero if
+ * every result was zero.
+ */
+ public abstract int result();
+}
diff --git a/guava/src/com/google/common/collect/CompoundOrdering.java b/guava/src/com/google/common/collect/CompoundOrdering.java
new file mode 100644
index 0000000..26ebf54
--- /dev/null
+++ b/guava/src/com/google/common/collect/CompoundOrdering.java
@@ -0,0 +1,71 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/** An ordering that tries several comparators in order. */
+@GwtCompatible(serializable = true)
+final class CompoundOrdering<T> extends Ordering<T> implements Serializable {
+ final ImmutableList<Comparator<? super T>> comparators;
+
+ CompoundOrdering(Comparator<? super T> primary,
+ Comparator<? super T> secondary) {
+ this.comparators
+ = ImmutableList.<Comparator<? super T>>of(primary, secondary);
+ }
+
+ CompoundOrdering(Iterable<? extends Comparator<? super T>> comparators) {
+ this.comparators = ImmutableList.copyOf(comparators);
+ }
+
+ @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);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return 0;
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof CompoundOrdering) {
+ CompoundOrdering<?> that = (CompoundOrdering<?>) object;
+ return this.comparators.equals(that.comparators);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return comparators.hashCode();
+ }
+
+ @Override public String toString() {
+ return "Ordering.compound(" + comparators + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ComputationException.java b/guava/src/com/google/common/collect/ComputationException.java
new file mode 100644
index 0000000..5401aff
--- /dev/null
+++ b/guava/src/com/google/common/collect/ComputationException.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * Wraps an exception that occurred during a computation.
+ *
+ * @author Bob Lee
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public class ComputationException extends RuntimeException {
+ /**
+ * Creates a new instance with the given 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
new file mode 100644
index 0000000..fce866d
--- /dev/null
+++ b/guava/src/com/google/common/collect/ComputingConcurrentHashMap.java
@@ -0,0 +1,454 @@
+/*
+ * 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 static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Equivalence;
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+import com.google.common.collect.MapMaker.RemovalCause;
+import com.google.common.collect.MapMaker.RemovalListener;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+
+/**
+ * Adds computing functionality to {@link MapMakerInternalMap}.
+ *
+ * @author Bob Lee
+ * @author Charles Fry
+ */
+class ComputingConcurrentHashMap<K, V> extends MapMakerInternalMap<K, V> {
+ final Function<? super K, ? extends V> computingFunction;
+
+ /**
+ * Creates a new, empty map with the specified strategy, initial capacity, load factor and
+ * concurrency level.
+ */
+ ComputingConcurrentHashMap(MapMaker builder,
+ Function<? super K, ? extends V> computingFunction) {
+ super(builder);
+ this.computingFunction = checkNotNull(computingFunction);
+ }
+
+ @Override
+ Segment<K, V> createSegment(int initialCapacity, int maxSegmentSize) {
+ return new ComputingSegment<K, V>(this, initialCapacity, maxSegmentSize);
+ }
+
+ @Override
+ ComputingSegment<K, V> segmentFor(int hash) {
+ return (ComputingSegment<K, V>) super.segmentFor(hash);
+ }
+
+ V getOrCompute(K key) throws ExecutionException {
+ int hash = hash(checkNotNull(key));
+ return segmentFor(hash).getOrCompute(key, hash, computingFunction);
+ }
+
+ @SuppressWarnings("serial") // This class is never serialized.
+ static final class ComputingSegment<K, V> extends Segment<K, V> {
+ ComputingSegment(MapMakerInternalMap<K, V> map, int initialCapacity, int maxSegmentSize) {
+ super(map, initialCapacity, maxSegmentSize);
+ }
+
+ V getOrCompute(K key, int hash, Function<? super K, ? extends V> computingFunction)
+ throws ExecutionException {
+ try {
+ outer: while (true) {
+ // don't call getLiveEntry, which would ignore computing values
+ ReferenceEntry<K, V> e = getEntry(key, hash);
+ if (e != null) {
+ V value = getLiveValue(e);
+ if (value != null) {
+ recordRead(e);
+ return value;
+ }
+ }
+
+ // at this point e is either null, computing, or expired;
+ // avoid locking if it's already computing
+ if (e == null || !e.getValueReference().isComputingReference()) {
+ boolean createNewEntry = true;
+ ComputingValueReference<K, V> computingValueReference = null;
+ lock();
+ try {
+ preWriteCleanup();
+
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> valueReference = e.getValueReference();
+ if (valueReference.isComputingReference()) {
+ createNewEntry = false;
+ } else {
+ V value = e.getValueReference().get();
+ if (value == null) {
+ enqueueNotification(entryKey, hash, value, RemovalCause.COLLECTED);
+ } else if (map.expires() && map.isExpired(e)) {
+ // This is a duplicate check, as preWriteCleanup already purged expired
+ // entries, but let's accomodate an incorrect expiration queue.
+ enqueueNotification(entryKey, hash, value, RemovalCause.EXPIRED);
+ } else {
+ recordLockedRead(e);
+ return value;
+ }
+
+ // immediately reuse invalid entries
+ evictionQueue.remove(e);
+ expirationQueue.remove(e);
+ this.count = newCount; // write-volatile
+ }
+ break;
+ }
+ }
+
+ if (createNewEntry) {
+ computingValueReference = new ComputingValueReference<K, V>(computingFunction);
+
+ if (e == null) {
+ e = newEntry(key, hash, first);
+ e.setValueReference(computingValueReference);
+ table.set(index, e);
+ } else {
+ e.setValueReference(computingValueReference);
+ }
+ }
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+
+ if (createNewEntry) {
+ // This thread solely created the entry.
+ return compute(key, hash, e, computingValueReference);
+ }
+ }
+
+ // The entry already exists. Wait for the computation.
+ checkState(!Thread.holdsLock(e), "Recursive computation");
+ // don't consider expiration as we're concurrent with computation
+ V value = e.getValueReference().waitForValue();
+ if (value != null) {
+ recordRead(e);
+ return value;
+ }
+ // else computing thread will clearValue
+ continue outer;
+ }
+ } finally {
+ postReadCleanup();
+ }
+ }
+
+ V compute(K key, int hash, ReferenceEntry<K, V> e,
+ ComputingValueReference<K, V> computingValueReference)
+ throws ExecutionException {
+ V value = null;
+ long start = System.nanoTime();
+ long end = 0;
+ try {
+ // Synchronizes on the entry to allow failing fast when a recursive computation is
+ // detected. This is not fool-proof since the entry may be copied when the segment
+ // is written to.
+ synchronized (e) {
+ value = computingValueReference.compute(key, hash);
+ end = System.nanoTime();
+ }
+ if (value != null) {
+ // putIfAbsent
+ V oldValue = put(key, hash, value, true);
+ if (oldValue != null) {
+ // the computed value was already clobbered
+ enqueueNotification(key, hash, value, RemovalCause.REPLACED);
+ }
+ }
+ return value;
+ } finally {
+ if (end == 0) {
+ end = System.nanoTime();
+ }
+ if (value == null) {
+ clearValue(key, hash, computingValueReference);
+ }
+ }
+ }
+ }
+
+ /**
+ * Used to provide computation exceptions to other threads.
+ */
+ private static final class ComputationExceptionReference<K, V> implements ValueReference<K, V> {
+ final Throwable t;
+
+ ComputationExceptionReference(Throwable t) {
+ this.t = t;
+ }
+
+ @Override
+ public V get() {
+ return null;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return null;
+ }
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ return this;
+ }
+
+ @Override
+ public boolean isComputingReference() {
+ return false;
+ }
+
+ @Override
+ public V waitForValue() throws ExecutionException {
+ throw new ExecutionException(t);
+ }
+
+ @Override
+ public void clear(ValueReference<K, V> newValue) {}
+ }
+
+ /**
+ * Used to provide computation result to other threads.
+ */
+ private static final class ComputedReference<K, V> implements ValueReference<K, V> {
+ final V value;
+
+ ComputedReference(@Nullable V value) {
+ this.value = value;
+ }
+
+ @Override
+ public V get() {
+ return value;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return null;
+ }
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ return this;
+ }
+
+ @Override
+ public boolean isComputingReference() {
+ return false;
+ }
+
+ @Override
+ public V waitForValue() {
+ return get();
+ }
+
+ @Override
+ public void clear(ValueReference<K, V> newValue) {}
+ }
+
+ private static final class ComputingValueReference<K, V> implements ValueReference<K, V> {
+ final Function<? super K, ? extends V> computingFunction;
+
+ @GuardedBy("ComputingValueReference.this") // writes
+ volatile ValueReference<K, V> computedReference = unset();
+
+ public ComputingValueReference(Function<? super K, ? extends V> computingFunction) {
+ this.computingFunction = computingFunction;
+ }
+
+ @Override
+ public V get() {
+ // All computation lookups go through waitForValue. This method thus is
+ // only used by put, to whom we always want to appear absent.
+ return null;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return null;
+ }
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, @Nullable V value, ReferenceEntry<K, V> entry) {
+ return this;
+ }
+
+ @Override
+ public boolean isComputingReference() {
+ return true;
+ }
+
+ /**
+ * Waits for a computation to complete. Returns the result of the computation.
+ */
+ @Override
+ public V waitForValue() throws ExecutionException {
+ if (computedReference == UNSET) {
+ boolean interrupted = false;
+ try {
+ synchronized (this) {
+ while (computedReference == UNSET) {
+ try {
+ wait();
+ } catch (InterruptedException ie) {
+ interrupted = true;
+ }
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ return computedReference.waitForValue();
+ }
+
+ @Override
+ public void clear(ValueReference<K, V> newValue) {
+ // The pending computation was clobbered by a manual write. Unblock all
+ // pending gets, and have them return the new value.
+ setValueReference(newValue);
+
+ // TODO(fry): could also cancel computation if we had a thread handle
+ }
+
+ V compute(K key, int hash) throws ExecutionException {
+ V value;
+ try {
+ value = computingFunction.apply(key);
+ } catch (Throwable t) {
+ setValueReference(new ComputationExceptionReference<K, V>(t));
+ throw new ExecutionException(t);
+ }
+
+ setValueReference(new ComputedReference<K, V>(value));
+ return value;
+ }
+
+ void setValueReference(ValueReference<K, V> valueReference) {
+ synchronized (this) {
+ if (computedReference == UNSET) {
+ computedReference = valueReference;
+ notifyAll();
+ }
+ }
+ }
+ }
+
+ /**
+ * Overrides get() to compute on demand. Also throws an exception when {@code null} is returned
+ * from a computation.
+ */
+ static final class ComputingMapAdapter<K, V>
+ extends ComputingConcurrentHashMap<K, V> implements Serializable {
+ private static final long serialVersionUID = 0;
+
+ ComputingMapAdapter(MapMaker mapMaker,
+ Function<? super K, ? extends V> computingFunction) {
+ super(mapMaker, computingFunction);
+ }
+
+ @SuppressWarnings("unchecked") // unsafe, which is one advantage of Cache over Map
+ @Override
+ public V get(Object key) {
+ V value;
+ try {
+ value = getOrCompute((K) key);
+ } catch (ExecutionException e) {
+ Throwable cause = e.getCause();
+ Throwables.propagateIfInstanceOf(cause, ComputationException.class);
+ throw new ComputationException(cause);
+ }
+
+ if (value == null) {
+ throw new NullPointerException(computingFunction + " returned null for key " + key + ".");
+ }
+ return value;
+ }
+ }
+
+ // Serialization Support
+
+ private static final long serialVersionUID = 4;
+
+ @Override
+ Object writeReplace() {
+ return new ComputingSerializationProxy<K, V>(keyStrength, valueStrength, keyEquivalence,
+ valueEquivalence, expireAfterWriteNanos, expireAfterAccessNanos, maximumSize,
+ concurrencyLevel, removalListener, this, computingFunction);
+ }
+
+ static final class ComputingSerializationProxy<K, V> extends AbstractSerializationProxy<K, V> {
+
+ final Function<? super K, ? extends V> computingFunction;
+
+ ComputingSerializationProxy(Strength keyStrength, Strength valueStrength,
+ Equivalence<Object> keyEquivalence, Equivalence<Object> valueEquivalence,
+ long expireAfterWriteNanos, long expireAfterAccessNanos, int maximumSize,
+ int concurrencyLevel, RemovalListener<? super K, ? super V> removalListener,
+ ConcurrentMap<K, V> delegate, Function<? super K, ? extends V> computingFunction) {
+ super(keyStrength, valueStrength, keyEquivalence, valueEquivalence, expireAfterWriteNanos,
+ expireAfterAccessNanos, maximumSize, concurrencyLevel, removalListener, delegate);
+ this.computingFunction = computingFunction;
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ writeMapTo(out);
+ }
+
+ @SuppressWarnings("deprecation") // self-use
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ MapMaker mapMaker = readMapMaker(in);
+ delegate = mapMaker.makeComputingMap(computingFunction);
+ readEntries(in);
+ }
+
+ Object readResolve() {
+ return delegate;
+ }
+
+ private static final long serialVersionUID = 4;
+ }
+}
diff --git a/guava/src/com/google/common/collect/ConcurrentHashMultiset.java b/guava/src/com/google/common/collect/ConcurrentHashMultiset.java
new file mode 100644
index 0000000..b96ed8f
--- /dev/null
+++ b/guava/src/com/google/common/collect/ConcurrentHashMultiset.java
@@ -0,0 +1,605 @@
+/*
+ * 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 static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Multisets.checkNonnegative;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Serialization.FieldSetter;
+import com.google.common.math.IntMath;
+import com.google.common.primitives.Ints;
+
+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;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+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)
+ */
+public final class ConcurrentHashMultiset<E> extends AbstractMultiset<E> implements Serializable {
+
+ /*
+ * The ConcurrentHashMultiset's atomic operations are implemented primarily in terms of
+ * AtomicInteger's atomic operations, with some help from ConcurrentMap's atomic operations on
+ * creation and removal (including automatic removal of zeroes). If the modification of an
+ * AtomicInteger results in zero, we compareAndSet the value to zero; if that succeeds, we remove
+ * the entry from the Map. If another operation sees a zero in the map, it knows that the entry is
+ * about to be removed, so this operation may remove it (often by replacing it with a new
+ * AtomicInteger).
+ */
+
+ /** The number of occurrences of each element. */
+ private final transient ConcurrentMap<E, AtomicInteger> countMap;
+
+ // This constant allows the deserialization code to set a final field. This holder class
+ // makes sure it is not initialized unless an instance is deserialized.
+ private static class FieldSettersHolder {
+ static final FieldSetter<ConcurrentHashMultiset> COUNT_MAP_FIELD_SETTER =
+ Serialization.getFieldSetter(ConcurrentHashMultiset.class, "countMap");
+ }
+
+ /**
+ * Creates a new, empty {@code ConcurrentHashMultiset} using the default
+ * initial capacity, load factor, and concurrency settings.
+ */
+ public static <E> ConcurrentHashMultiset<E> create() {
+ // TODO(schmoe): provide a way to use this class with other (possibly arbitrary)
+ // ConcurrentMap implementors. One possibility is to extract most of this class into
+ // an AbstractConcurrentMapMultiset.
+ return new ConcurrentHashMultiset<E>(new ConcurrentHashMap<E, AtomicInteger>());
+ }
+
+ /**
+ * Creates a new {@code ConcurrentHashMultiset} containing the specified elements, using
+ * the default initial capacity, load factor, and concurrency settings.
+ *
+ * <p>This implementation is highly efficient when {@code elements} is itself a {@link Multiset}.
+ *
+ * @param elements the elements that the multiset should contain
+ */
+ public static <E> ConcurrentHashMultiset<E> create(Iterable<? extends E> elements) {
+ ConcurrentHashMultiset<E> multiset = ConcurrentHashMultiset.create();
+ Iterables.addAll(multiset, elements);
+ return multiset;
+ }
+
+ /**
+ * Creates a new, empty {@code ConcurrentHashMultiset} using {@code mapMaker}
+ * to construct the internal backing map.
+ *
+ * <p>If this {@link MapMaker} is configured to use entry eviction of any kind, this eviction
+ * applies to all occurrences of a given element as a single unit. However, most updates to the
+ * multiset do not count as map updates at all, since we're usually just mutating the value
+ * stored in the map, so {@link MapMaker#expireAfterAccess} makes sense (evict the entry that
+ * was queried or updated longest ago), but {@link MapMaker#expireAfterWrite} doesn't, because
+ * the eviction time is measured from when we saw the first occurrence of the object.
+ *
+ * <p>The returned multiset is serializable but any serialization caveats
+ * given in {@code MapMaker} apply.
+ *
+ * <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
+ public static <E> ConcurrentHashMultiset<E> create(
+ GenericMapMaker<? super E, ? super Number> mapMaker) {
+ return new ConcurrentHashMultiset<E>(mapMaker.<E, AtomicInteger>makeMap());
+ }
+
+ /**
+ * Creates an instance using {@code countMap} to store elements and their counts.
+ *
+ * <p>This instance will assume ownership of {@code countMap}, and other code
+ * should not maintain references to the map or modify it in any way.
+ *
+ * @param countMap backing map for storing the elements in the multiset and
+ * their counts. It must be empty.
+ * @throws IllegalArgumentException if {@code countMap} is not empty
+ */
+ @VisibleForTesting ConcurrentHashMultiset(ConcurrentMap<E, AtomicInteger> countMap) {
+ checkArgument(countMap.isEmpty());
+ this.countMap = countMap;
+ }
+
+ // Query Operations
+
+ /**
+ * Returns the number of occurrences of {@code element} in this multiset.
+ *
+ * @param element the element to look for
+ * @return the nonnegative number of occurrences of the element
+ */
+ @Override public int count(@Nullable Object 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,
+ * it is undefined which (if any) of these modifications will be reflected in the result.
+ */
+ @Override public int size() {
+ long sum = 0L;
+ for (AtomicInteger value : countMap.values()) {
+ sum += value.get();
+ }
+ return Ints.saturatedCast(sum);
+ }
+
+ /*
+ * Note: the superclass toArray() methods assume that size() gives a correct
+ * answer, which ours does not.
+ */
+
+ @Override public Object[] toArray() {
+ return snapshot().toArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return snapshot().toArray(array);
+ }
+
+ /*
+ * We'd love to use 'new ArrayList(this)' or 'list.addAll(this)', but
+ * either of these would recurse back to us again!
+ */
+ private List<E> snapshot() {
+ List<E> list = Lists.newArrayListWithExpectedSize(size());
+ for (Multiset.Entry<E> entry : entrySet()) {
+ E element = entry.getElement();
+ for (int i = entry.getCount(); i > 0; i--) {
+ list.add(element);
+ }
+ }
+ return list;
+ }
+
+ // Modification Operations
+
+ /**
+ * Adds a number of occurrences of the specified element to this multiset.
+ *
+ * @param element the element to add
+ * @param occurrences the number of occurrences to add
+ * @return the previous count of the element before the operation; possibly zero
+ * @throws IllegalArgumentException if {@code occurrences} is negative, or if
+ * 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 = safeGet(element);
+ if (existingCounter == null) {
+ existingCounter = countMap.putIfAbsent(element, new AtomicInteger(occurrences));
+ if (existingCounter == null) {
+ return 0;
+ }
+ // existingCounter != null: fall through to operate against the existing AtomicInteger
+ }
+
+ while (true) {
+ int oldValue = existingCounter.get();
+ if (oldValue != 0) {
+ try {
+ int newValue = IntMath.checkedAdd(oldValue, occurrences);
+ if (existingCounter.compareAndSet(oldValue, newValue)) {
+ // newValue can't == 0, so no need to check & remove
+ return oldValue;
+ }
+ } catch (ArithmeticException overflow) {
+ throw new IllegalArgumentException("Overflow adding " + occurrences
+ + " occurrences to a count of " + oldValue);
+ }
+ } else {
+ // In the case of a concurrent remove, we might observe a zero value, which means another
+ // thread is about to remove (element, existingCounter) from the map. Rather than wait,
+ // we can just do that work here.
+ AtomicInteger newCounter = new AtomicInteger(occurrences);
+ if ((countMap.putIfAbsent(element, newCounter) == null)
+ || countMap.replace(element, existingCounter, newCounter)) {
+ return 0;
+ }
+ break;
+ }
+ }
+
+ // If we're still here, there was a race, so just try again.
+ }
+ }
+
+ /**
+ * Removes a number of occurrences of the specified element from this multiset. If the multiset
+ * contains fewer than this number of occurrences to begin with, all occurrences will be removed.
+ *
+ * @param element the element whose occurrences should be removed
+ * @param occurrences the number of occurrences of the element to remove
+ * @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 = safeGet(element);
+ if (existingCounter == null) {
+ return 0;
+ }
+ while (true) {
+ int oldValue = existingCounter.get();
+ if (oldValue != 0) {
+ int newValue = Math.max(0, oldValue - occurrences);
+ if (existingCounter.compareAndSet(oldValue, newValue)) {
+ if (newValue == 0) {
+ // Just CASed to 0; remove the entry to clean up the map. If the removal fails,
+ // another thread has already replaced it with a new counter, which is fine.
+ countMap.remove(element, existingCounter);
+ }
+ return oldValue;
+ }
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ /**
+ * Removes exactly the specified number of occurrences of {@code element}, or makes no
+ * change if this is not possible.
+ *
+ * <p>This method, in contrast to {@link #remove(Object, int)}, has no effect when the
+ * element count is smaller than {@code occurrences}.
+ *
+ * @param element the element to remove
+ * @param occurrences the number of occurrences of {@code element} to remove
+ * @return {@code true} if the removal was possible (including if {@code occurrences} is zero)
+ */
+ public boolean removeExactly(@Nullable Object element, int occurrences) {
+ if (occurrences == 0) {
+ return true;
+ }
+ checkArgument(occurrences > 0, "Invalid occurrences: %s", occurrences);
+
+ AtomicInteger existingCounter = safeGet(element);
+ if (existingCounter == null) {
+ return false;
+ }
+ while (true) {
+ int oldValue = existingCounter.get();
+ if (oldValue < occurrences) {
+ return false;
+ }
+ int newValue = oldValue - occurrences;
+ if (existingCounter.compareAndSet(oldValue, newValue)) {
+ if (newValue == 0) {
+ // Just CASed to 0; remove the entry to clean up the map. If the removal fails,
+ // another thread has already replaced it with a new counter, which is fine.
+ countMap.remove(element, existingCounter);
+ }
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Adds or removes occurrences of {@code element} such that the {@link #count} of the
+ * element becomes {@code count}.
+ *
+ * @return the count of {@code element} in the multiset before this call
+ * @throws IllegalArgumentException if {@code count} is negative
+ */
+ @Override public int setCount(E element, int count) {
+ checkNotNull(element);
+ checkNonnegative(count, "count");
+ while (true) {
+ AtomicInteger existingCounter = safeGet(element);
+ if (existingCounter == null) {
+ if (count == 0) {
+ return 0;
+ } else {
+ existingCounter = countMap.putIfAbsent(element, new AtomicInteger(count));
+ if (existingCounter == null) {
+ return 0;
+ }
+ // existingCounter != null: fall through
+ }
+ }
+
+ while (true) {
+ int oldValue = existingCounter.get();
+ if (oldValue == 0) {
+ if (count == 0) {
+ return 0;
+ } else {
+ AtomicInteger newCounter = new AtomicInteger(count);
+ if ((countMap.putIfAbsent(element, newCounter) == null)
+ || countMap.replace(element, existingCounter, newCounter)) {
+ return 0;
+ }
+ }
+ break;
+ } else {
+ if (existingCounter.compareAndSet(oldValue, count)) {
+ if (count == 0) {
+ // Just CASed to 0; remove the entry to clean up the map. If the removal fails,
+ // another thread has already replaced it with a new counter, which is fine.
+ countMap.remove(element, existingCounter);
+ }
+ return oldValue;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the number of occurrences of {@code element} to {@code newCount}, but only if
+ * the count is currently {@code expectedOldCount}. If {@code element} does not appear
+ * in the multiset exactly {@code expectedOldCount} times, no changes will be made.
+ *
+ * @return {@code true} if the change was successful. This usually indicates
+ * that the multiset has been modified, but not always: in the case that
+ * {@code expectedOldCount == newCount}, the method will return {@code true} if
+ * the condition was met.
+ * @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 = safeGet(element);
+ if (existingCounter == null) {
+ if (expectedOldCount != 0) {
+ return false;
+ } else if (newCount == 0) {
+ return true;
+ } else {
+ // if our write lost the race, it must have lost to a nonzero value, so we can stop
+ return countMap.putIfAbsent(element, new AtomicInteger(newCount)) == null;
+ }
+ }
+ int oldValue = existingCounter.get();
+ if (oldValue == expectedOldCount) {
+ if (oldValue == 0) {
+ if (newCount == 0) {
+ // Just observed a 0; try to remove the entry to clean up the map
+ countMap.remove(element, existingCounter);
+ return true;
+ } else {
+ AtomicInteger newCounter = new AtomicInteger(newCount);
+ return (countMap.putIfAbsent(element, newCounter) == null)
+ || countMap.replace(element, existingCounter, newCounter);
+ }
+ } else {
+ if (existingCounter.compareAndSet(oldValue, newCount)) {
+ if (newCount == 0) {
+ // Just CASed to 0; remove the entry to clean up the map. If the removal fails,
+ // another thread has already replaced it with a new counter, which is fine.
+ countMap.remove(element, existingCounter);
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // Views
+
+ @Override Set<E> createElementSet() {
+ final Set<E> delegate = countMap.keySet();
+ return new ForwardingSet<E>() {
+ @Override protected Set<E> delegate() {
+ return delegate;
+ }
+ @Override public boolean remove(Object object) {
+ try {
+ return delegate.remove(object);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return standardRemoveAll(c);
+ }
+ };
+ }
+
+ private transient EntrySet entrySet;
+
+ @Override public Set<Multiset.Entry<E>> entrySet() {
+ EntrySet result = entrySet;
+ if (result == null) {
+ entrySet = result = new EntrySet();
+ }
+ return result;
+ }
+
+ @Override int distinctElements() {
+ return countMap.size();
+ }
+
+ @Override public boolean isEmpty() {
+ return countMap.isEmpty();
+ }
+
+ @Override Iterator<Entry<E>> entryIterator() {
+ // AbstractIterator makes this fairly clean, but it doesn't support remove(). To support
+ // remove(), we create an AbstractIterator, and then use ForwardingIterator to delegate to it.
+ final Iterator<Entry<E>> readOnlyIterator =
+ new AbstractIterator<Entry<E>>() {
+ private Iterator<Map.Entry<E, AtomicInteger>> mapEntries = countMap.entrySet().iterator();
+
+ @Override protected Entry<E> computeNext() {
+ while (true) {
+ if (!mapEntries.hasNext()) {
+ return endOfData();
+ }
+ Map.Entry<E, AtomicInteger> mapEntry = mapEntries.next();
+ int count = mapEntry.getValue().get();
+ if (count != 0) {
+ return Multisets.immutableEntry(mapEntry.getKey(), count);
+ }
+ }
+ }
+ };
+
+ return new ForwardingIterator<Entry<E>>() {
+ private Entry<E> last;
+
+ @Override protected Iterator<Entry<E>> delegate() {
+ return readOnlyIterator;
+ }
+
+ @Override public Entry<E> next() {
+ last = super.next();
+ return last;
+ }
+
+ @Override public void remove() {
+ checkState(last != null);
+ ConcurrentHashMultiset.this.setCount(last.getElement(), 0);
+ last = null;
+ }
+ };
+ }
+
+ @Override public void clear() {
+ countMap.clear();
+ }
+
+ private class EntrySet extends AbstractMultiset<E>.EntrySet {
+ @Override ConcurrentHashMultiset<E> multiset() {
+ return ConcurrentHashMultiset.this;
+ }
+
+ /*
+ * Note: the superclass toArray() methods assume that size() gives a correct
+ * answer, which ours does not.
+ */
+
+ @Override public Object[] toArray() {
+ return snapshot().toArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return snapshot().toArray(array);
+ }
+
+ private List<Multiset.Entry<E>> snapshot() {
+ List<Multiset.Entry<E>> list = Lists.newArrayListWithExpectedSize(size());
+ // Not Iterables.addAll(list, this), because that'll forward right back here.
+ 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;
+ }
+ }
+
+ /**
+ * @serialData the ConcurrentMap of elements and their counts.
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(countMap);
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ ConcurrentMap<E, Integer> deserializedCountMap =
+ (ConcurrentMap<E, Integer>) stream.readObject();
+ FieldSettersHolder.COUNT_MAP_FIELD_SETTER.set(this, deserializedCountMap);
+ }
+
+ private static final long serialVersionUID = 1;
+}
diff --git a/guava/src/com/google/common/collect/Constraint.java b/guava/src/com/google/common/collect/Constraint.java
new file mode 100644
index 0000000..93b683b
--- /dev/null
+++ b/guava/src/com/google/common/collect/Constraint.java
@@ -0,0 +1,67 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * A constraint that an element must satisfy in order to be added to a
+ * collection. For example, {@link Constraints#notNull()}, which prevents a
+ * collection from including any null elements, could be implemented like this:
+ * <pre> {@code
+ *
+ * public Object checkElement(Object element) {
+ * if (element == null) {
+ * throw new NullPointerException();
+ * }
+ * return element;
+ * }}</pre>
+ *
+ * In order to be effective, constraints should be deterministic; that is,
+ * they should not depend on state that can change (such as external state,
+ * random variables, and time) and should only depend on the value of the
+ * passed-in element. A non-deterministic constraint cannot reliably enforce
+ * that all the collection's elements meet the constraint, since the constraint
+ * is only enforced when elements are added.
+ *
+ * @see Constraints
+ * @see MapConstraint
+ * @author Mike Bostock
+ * @since 3.0
+ */
+@Beta
+@GwtCompatible
+public interface Constraint<E> {
+ /**
+ * Throws a suitable {@code RuntimeException} if the specified element is
+ * illegal. Typically this is either a {@link NullPointerException}, an
+ * {@link IllegalArgumentException}, or a {@link ClassCastException}, though
+ * an application-specific exception class may be used if appropriate.
+ *
+ * @param element the element to check
+ * @return the provided element
+ */
+ E checkElement(E element);
+
+ /**
+ * Returns a brief human readable description of this constraint, such as
+ * "Not null" or "Positive number".
+ */
+ @Override
+ String toString();
+}
diff --git a/guava/src/com/google/common/collect/Constraints.java b/guava/src/com/google/common/collect/Constraints.java
new file mode 100644
index 0000000..3b7f8bb
--- /dev/null
+++ b/guava/src/com/google/common/collect/Constraints.java
@@ -0,0 +1,382 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.RandomAccess;
+import java.util.Set;
+import java.util.SortedSet;
+
+/**
+ * Factories and utilities pertaining to the {@link Constraint} interface.
+ *
+ * @see MapConstraints
+ * @author Mike Bostock
+ * @author Jared Levy
+ * @since 3.0
+ */
+@Beta
+@GwtCompatible
+public final class Constraints {
+ private Constraints() {}
+
+ // enum singleton pattern
+ private enum NotNullConstraint implements Constraint<Object> {
+ INSTANCE;
+
+ @Override
+ public Object checkElement(Object element) {
+ return checkNotNull(element);
+ }
+
+ @Override public String toString() {
+ return "Not null";
+ }
+ }
+
+ /**
+ * Returns a constraint that verifies that the element is not null. If the
+ * element is null, a {@link NullPointerException} is thrown.
+ */
+ // safe to narrow the type since checkElement returns its argument directly
+ @SuppressWarnings("unchecked")
+ public static <E> Constraint<E> notNull() {
+ return (Constraint<E>) NotNullConstraint.INSTANCE;
+ }
+
+ /**
+ * Returns a constrained view of the specified collection, using the specified
+ * constraint. Any operations that add new elements to the collection will
+ * call the provided constraint. However, this method does not verify that
+ * existing elements satisfy the constraint.
+ *
+ * <p>The returned collection is not serializable.
+ *
+ * @param collection the collection to constrain
+ * @param constraint the constraint that validates added elements
+ * @return a constrained view of the collection
+ */
+ public static <E> Collection<E> constrainedCollection(
+ Collection<E> collection, Constraint<? super E> constraint) {
+ return new ConstrainedCollection<E>(collection, constraint);
+ }
+
+ /** @see Constraints#constrainedCollection */
+ static class ConstrainedCollection<E> extends ForwardingCollection<E> {
+ private final Collection<E> delegate;
+ private final Constraint<? super E> constraint;
+
+ public ConstrainedCollection(
+ Collection<E> delegate, Constraint<? super E> constraint) {
+ this.delegate = checkNotNull(delegate);
+ this.constraint = checkNotNull(constraint);
+ }
+ @Override protected Collection<E> delegate() {
+ return delegate;
+ }
+ @Override public boolean add(E element) {
+ constraint.checkElement(element);
+ return delegate.add(element);
+ }
+ @Override public boolean addAll(Collection<? extends E> elements) {
+ return delegate.addAll(checkElements(elements, constraint));
+ }
+ }
+
+ /**
+ * Returns a constrained view of the specified set, using the specified
+ * constraint. Any operations that add new elements to the set will call the
+ * provided constraint. However, this method does not verify that existing
+ * elements satisfy the constraint.
+ *
+ * <p>The returned set is not serializable.
+ *
+ * @param set the set to constrain
+ * @param constraint the constraint that validates added elements
+ * @return a constrained view of the set
+ */
+ public static <E> Set<E> constrainedSet(
+ Set<E> set, Constraint<? super E> constraint) {
+ return new ConstrainedSet<E>(set, constraint);
+ }
+
+ /** @see Constraints#constrainedSet */
+ static class ConstrainedSet<E> extends ForwardingSet<E> {
+ private final Set<E> delegate;
+ private final Constraint<? super E> constraint;
+
+ public ConstrainedSet(Set<E> delegate, Constraint<? super E> constraint) {
+ this.delegate = checkNotNull(delegate);
+ this.constraint = checkNotNull(constraint);
+ }
+ @Override protected Set<E> delegate() {
+ return delegate;
+ }
+ @Override public boolean add(E element) {
+ constraint.checkElement(element);
+ return delegate.add(element);
+ }
+ @Override public boolean addAll(Collection<? extends E> elements) {
+ return delegate.addAll(checkElements(elements, constraint));
+ }
+ }
+
+ /**
+ * Returns a constrained view of the specified sorted set, using the specified
+ * constraint. Any operations that add new elements to the sorted set will
+ * call the provided constraint. However, this method does not verify that
+ * existing elements satisfy the constraint.
+ *
+ * <p>The returned set is not serializable.
+ *
+ * @param sortedSet the sorted set to constrain
+ * @param constraint the constraint that validates added elements
+ * @return a constrained view of the sorted set
+ */
+ public static <E> SortedSet<E> constrainedSortedSet(
+ SortedSet<E> sortedSet, Constraint<? super E> constraint) {
+ return new ConstrainedSortedSet<E>(sortedSet, constraint);
+ }
+
+ /** @see Constraints#constrainedSortedSet */
+ private static class ConstrainedSortedSet<E> extends ForwardingSortedSet<E> {
+ final SortedSet<E> delegate;
+ final Constraint<? super E> constraint;
+
+ ConstrainedSortedSet(
+ SortedSet<E> delegate, Constraint<? super E> constraint) {
+ this.delegate = checkNotNull(delegate);
+ this.constraint = checkNotNull(constraint);
+ }
+ @Override protected SortedSet<E> delegate() {
+ return delegate;
+ }
+ @Override public SortedSet<E> headSet(E toElement) {
+ return constrainedSortedSet(delegate.headSet(toElement), constraint);
+ }
+ @Override public SortedSet<E> subSet(E fromElement, E toElement) {
+ return constrainedSortedSet(
+ delegate.subSet(fromElement, toElement), constraint);
+ }
+ @Override public SortedSet<E> tailSet(E fromElement) {
+ return constrainedSortedSet(delegate.tailSet(fromElement), constraint);
+ }
+ @Override public boolean add(E element) {
+ constraint.checkElement(element);
+ return delegate.add(element);
+ }
+ @Override public boolean addAll(Collection<? extends E> elements) {
+ return delegate.addAll(checkElements(elements, constraint));
+ }
+ }
+
+ /**
+ * Returns a constrained view of the specified list, using the specified
+ * constraint. Any operations that add new elements to the list will call the
+ * provided constraint. However, this method does not verify that existing
+ * elements satisfy the constraint.
+ *
+ * <p>If {@code list} implements {@link RandomAccess}, so will the returned
+ * list. The returned list is not serializable.
+ *
+ * @param list the list to constrain
+ * @param constraint the constraint that validates added elements
+ * @return a constrained view of the list
+ */
+ public static <E> List<E> constrainedList(
+ List<E> list, Constraint<? super E> constraint) {
+ return (list instanceof RandomAccess)
+ ? new ConstrainedRandomAccessList<E>(list, constraint)
+ : new ConstrainedList<E>(list, constraint);
+ }
+
+ /** @see Constraints#constrainedList */
+ @GwtCompatible
+ private static class ConstrainedList<E> extends ForwardingList<E> {
+ final List<E> delegate;
+ final Constraint<? super E> constraint;
+
+ ConstrainedList(List<E> delegate, Constraint<? super E> constraint) {
+ this.delegate = checkNotNull(delegate);
+ this.constraint = checkNotNull(constraint);
+ }
+ @Override protected List<E> delegate() {
+ return delegate;
+ }
+
+ @Override public boolean add(E element) {
+ constraint.checkElement(element);
+ return delegate.add(element);
+ }
+ @Override public void add(int index, E element) {
+ constraint.checkElement(element);
+ delegate.add(index, element);
+ }
+ @Override public boolean addAll(Collection<? extends E> elements) {
+ return delegate.addAll(checkElements(elements, constraint));
+ }
+ @Override public boolean addAll(int index, Collection<? extends E> elements)
+ {
+ return delegate.addAll(index, checkElements(elements, constraint));
+ }
+ @Override public ListIterator<E> listIterator() {
+ return constrainedListIterator(delegate.listIterator(), constraint);
+ }
+ @Override public ListIterator<E> listIterator(int index) {
+ return constrainedListIterator(delegate.listIterator(index), constraint);
+ }
+ @Override public E set(int index, E element) {
+ constraint.checkElement(element);
+ return delegate.set(index, element);
+ }
+ @Override public List<E> subList(int fromIndex, int toIndex) {
+ return constrainedList(
+ delegate.subList(fromIndex, toIndex), constraint);
+ }
+ }
+
+ /** @see Constraints#constrainedList */
+ static class ConstrainedRandomAccessList<E> extends ConstrainedList<E>
+ implements RandomAccess {
+ ConstrainedRandomAccessList(
+ List<E> delegate, Constraint<? super E> constraint) {
+ super(delegate, constraint);
+ }
+ }
+
+ /**
+ * Returns a constrained view of the specified list iterator, using the
+ * specified constraint. Any operations that would add new elements to the
+ * underlying list will be verified by the constraint.
+ *
+ * @param listIterator the iterator for which to return a constrained view
+ * @param constraint the constraint for elements in the list
+ * @return a constrained view of the specified iterator
+ */
+ private static <E> ListIterator<E> constrainedListIterator(
+ ListIterator<E> listIterator, Constraint<? super E> constraint) {
+ return new ConstrainedListIterator<E>(listIterator, constraint);
+ }
+
+ /** @see Constraints#constrainedListIterator */
+ static class ConstrainedListIterator<E> extends ForwardingListIterator<E> {
+ private final ListIterator<E> delegate;
+ private final Constraint<? super E> constraint;
+
+ public ConstrainedListIterator(
+ ListIterator<E> delegate, Constraint<? super E> constraint) {
+ this.delegate = delegate;
+ this.constraint = constraint;
+ }
+ @Override protected ListIterator<E> delegate() {
+ return delegate;
+ }
+
+ @Override public void add(E element) {
+ constraint.checkElement(element);
+ delegate.add(element);
+ }
+ @Override public void set(E element) {
+ constraint.checkElement(element);
+ delegate.set(element);
+ }
+ }
+
+ static <E> Collection<E> constrainedTypePreservingCollection(
+ Collection<E> collection, Constraint<E> constraint) {
+ if (collection instanceof SortedSet) {
+ return constrainedSortedSet((SortedSet<E>) collection, constraint);
+ } else if (collection instanceof Set) {
+ return constrainedSet((Set<E>) collection, constraint);
+ } else if (collection instanceof List) {
+ return constrainedList((List<E>) collection, constraint);
+ } else {
+ return constrainedCollection(collection, constraint);
+ }
+ }
+
+ /**
+ * Returns a constrained view of the specified multiset, using the specified
+ * constraint. Any operations that add new elements to the multiset will call
+ * the provided constraint. However, this method does not verify that
+ * existing elements satisfy the constraint.
+ *
+ * <p>The returned multiset is not serializable.
+ *
+ * @param multiset the multiset to constrain
+ * @param constraint the constraint that validates added elements
+ * @return a constrained view of the multiset
+ */
+ public static <E> Multiset<E> constrainedMultiset(
+ Multiset<E> multiset, Constraint<? super E> constraint) {
+ return new ConstrainedMultiset<E>(multiset, constraint);
+ }
+
+ /** @see Constraints#constrainedMultiset */
+ static class ConstrainedMultiset<E> extends ForwardingMultiset<E> {
+ private Multiset<E> delegate;
+ private final Constraint<? super E> constraint;
+
+ public ConstrainedMultiset(
+ Multiset<E> delegate, Constraint<? super E> constraint) {
+ this.delegate = checkNotNull(delegate);
+ this.constraint = checkNotNull(constraint);
+ }
+ @Override protected Multiset<E> delegate() {
+ return delegate;
+ }
+ @Override public boolean add(E element) {
+ return standardAdd(element);
+ }
+ @Override public boolean addAll(Collection<? extends E> elements) {
+ return delegate.addAll(checkElements(elements, constraint));
+ }
+ @Override public int add(E element, int occurrences) {
+ constraint.checkElement(element);
+ return delegate.add(element, occurrences);
+ }
+ @Override public int setCount(E element, int count) {
+ constraint.checkElement(element);
+ return delegate.setCount(element, count);
+ }
+ @Override public boolean setCount(E element, int oldCount, int newCount) {
+ constraint.checkElement(element);
+ return delegate.setCount(element, oldCount, newCount);
+ }
+ }
+
+ /*
+ * TODO(kevinb): For better performance, avoid making a copy of the elements
+ * by having addAll() call add() repeatedly instead.
+ */
+
+ private static <E> Collection<E> checkElements(
+ Collection<E> elements, Constraint<? super E> constraint) {
+ Collection<E> copy = Lists.newArrayList(elements);
+ for (E element : copy) {
+ constraint.checkElement(element);
+ }
+ return copy;
+ }
+}
diff --git a/guava/src/com/google/common/collect/ContiguousSet.java b/guava/src/com/google/common/collect/ContiguousSet.java
new file mode 100644
index 0000000..11be93e
--- /dev/null
+++ b/guava/src/com/google/common/collect/ContiguousSet.java
@@ -0,0 +1,172 @@
+/*
+ * 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.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 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(Ranges.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
+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(Ranges.atLeast(domain.minValue()));
+ }
+ if (!range.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()
+ || 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) {
+ super(Ordering.natural());
+ this.domain = domain;
+ }
+
+ @Override public ContiguousSet<C> headSet(C toElement) {
+ return headSetImpl(checkNotNull(toElement), false);
+ }
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override public ContiguousSet<C> headSet(C toElement, boolean inclusive) {
+ return headSetImpl(checkNotNull(toElement), inclusive);
+ }
+
+ @Override public ContiguousSet<C> subSet(C fromElement, C toElement) {
+ checkNotNull(fromElement);
+ checkNotNull(toElement);
+ checkArgument(comparator().compare(fromElement, toElement) <= 0);
+ return subSetImpl(fromElement, true, toElement, false);
+ }
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override public ContiguousSet<C> subSet(C fromElement, boolean fromInclusive, C toElement,
+ boolean toInclusive) {
+ checkNotNull(fromElement);
+ checkNotNull(toElement);
+ checkArgument(comparator().compare(fromElement, toElement) <= 0);
+ return subSetImpl(fromElement, fromInclusive, toElement, toInclusive);
+ }
+
+ @Override public ContiguousSet<C> tailSet(C fromElement) {
+ return tailSetImpl(checkNotNull(fromElement), true);
+ }
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override public ContiguousSet<C> tailSet(C fromElement, boolean inclusive) {
+ return tailSetImpl(checkNotNull(fromElement), inclusive);
+ }
+
+ /*
+ * These methods perform most headSet, subSet, and tailSet logic, besides parameter validation.
+ */
+ /*@Override*/ abstract ContiguousSet<C> headSetImpl(C toElement, boolean inclusive);
+
+ /*@Override*/ abstract ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive,
+ C toElement, boolean toInclusive);
+
+ /*@Override*/ abstract ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive);
+
+ /**
+ * Returns the set of values that are contained in both this set and the other.
+ *
+ * <p>This method should always be used instead of
+ * {@link Sets#intersection} for {@link ContiguousSet} instances.
+ */
+ public abstract ContiguousSet<C> intersection(ContiguousSet<C> other);
+
+ /**
+ * Returns a range, closed on both ends, whose endpoints are the minimum and maximum values
+ * contained in this set. This is equivalent to {@code range(CLOSED, CLOSED)}.
+ *
+ * @throws NoSuchElementException if this set is empty
+ */
+ public abstract Range<C> range();
+
+ /**
+ * Returns the minimal range with the given boundary types for which all values in this set are
+ * {@linkplain Range#contains(Comparable) contained} within the range.
+ *
+ * <p>Note that this method will return ranges with unbounded endpoints if {@link BoundType#OPEN}
+ * is requested for a domain minimum or maximum. For example, if {@code set} was created from the
+ * range {@code [1..Integer.MAX_VALUE]} then {@code set.range(CLOSED, OPEN)} must return
+ * {@code [1..∞)}.
+ *
+ * @throws NoSuchElementException if this set is empty
+ */
+ public abstract Range<C> range(BoundType lowerBoundType, BoundType upperBoundType);
+
+ /** Returns a short-hand representation of the contents such as {@code "[1..100]"}. */
+ @Override public String toString() {
+ return range().toString();
+ }
+}
diff --git a/guava/src/com/google/common/collect/Count.java b/guava/src/com/google/common/collect/Count.java
new file mode 100644
index 0000000..768e298
--- /dev/null
+++ b/guava/src/com/google/common/collect/Count.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 com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+
+import javax.annotation.Nullable;
+
+/**
+ * A mutable value of type {@code int}, for multisets to use in tracking counts of values.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+final class Count implements Serializable {
+ private int value;
+
+ Count(int value) {
+ this.value = value;
+ }
+
+ public int get() {
+ return value;
+ }
+
+ public int getAndAdd(int delta) {
+ int result = value;
+ value = result + delta;
+ return result;
+ }
+
+ public int addAndGet(int delta) {
+ return value += delta;
+ }
+
+ public void set(int newValue) {
+ value = newValue;
+ }
+
+ public int getAndSet(int newValue) {
+ int result = value;
+ value = newValue;
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ return obj instanceof Count && ((Count) obj).value == value;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(value);
+ }
+}
diff --git a/guava/src/com/google/common/collect/Cut.java b/guava/src/com/google/common/collect/Cut.java
new file mode 100644
index 0000000..204ea0c
--- /dev/null
+++ b/guava/src/com/google/common/collect/Cut.java
@@ -0,0 +1,347 @@
+/*
+ * 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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.primitives.Booleans;
+
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+
+import javax.annotation.Nullable;
+
+/**
+ * Implementation detail for the internal structure of {@link Range} instances. Represents
+ * a unique way of "cutting" a "number line" (actually of instances of type {@code C}, not
+ * necessarily "numbers") into two sections; this can be done below a certain value, above
+ * a certain value, below all values or above all values. With this object defined in this
+ * way, an interval can always be represented by a pair of {@code Cut} instances.
+ *
+ * @author Kevin Bourrillion
+ */
+@GwtCompatible
+abstract class Cut<C extends Comparable> implements Comparable<Cut<C>>, Serializable {
+ final C endpoint;
+
+ Cut(@Nullable C endpoint) {
+ this.endpoint = endpoint;
+ }
+
+ abstract boolean isLessThan(C value);
+
+ abstract BoundType typeAsLowerBound();
+ abstract BoundType typeAsUpperBound();
+
+ abstract Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain);
+ abstract Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain);
+
+ abstract void describeAsLowerBound(StringBuilder sb);
+ abstract void describeAsUpperBound(StringBuilder sb);
+
+ abstract C leastValueAbove(DiscreteDomain<C> domain);
+ abstract C greatestValueBelow(DiscreteDomain<C> domain);
+
+ /*
+ * The canonical form is a BelowValue cut whenever possible, otherwise ABOVE_ALL, or
+ * (only in the case of types that are unbounded below) BELOW_ALL.
+ */
+ Cut<C> canonical(DiscreteDomain<C> domain) {
+ return this;
+ }
+
+ // note: overriden by {BELOW,ABOVE}_ALL
+ @Override
+ public int compareTo(Cut<C> that) {
+ if (that == belowAll()) {
+ return 1;
+ }
+ if (that == aboveAll()) {
+ return -1;
+ }
+ int result = Range.compareOrThrow(endpoint, that.endpoint);
+ if (result != 0) {
+ return result;
+ }
+ // same value. below comes before above
+ return Booleans.compare(
+ this instanceof AboveValue, that instanceof AboveValue);
+ }
+
+ C endpoint() {
+ return endpoint;
+ }
+
+ @SuppressWarnings("unchecked") // catching CCE
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof Cut) {
+ // It might not really be a Cut<C>, but we'll catch a CCE if it's not
+ Cut<C> that = (Cut<C>) obj;
+ try {
+ int compareResult = compareTo(that);
+ return compareResult == 0;
+ } catch (ClassCastException ignored) {
+ }
+ }
+ return false;
+ }
+
+ /*
+ * The implementation neither produces nor consumes any non-null instance of type C, so
+ * casting the type parameter is safe.
+ */
+ @SuppressWarnings("unchecked")
+ static <C extends Comparable> Cut<C> belowAll() {
+ return (Cut<C>) BelowAll.INSTANCE;
+ }
+
+ private static final long serialVersionUID = 0;
+
+ private static final class BelowAll extends Cut<Comparable<?>> {
+ private static final BelowAll INSTANCE = new BelowAll();
+
+ private BelowAll() {
+ super(null);
+ }
+ @Override Comparable<?> endpoint() {
+ throw new IllegalStateException("range unbounded on this side");
+ }
+ @Override boolean isLessThan(Comparable<?> value) {
+ return true;
+ }
+ @Override BoundType typeAsLowerBound() {
+ throw new IllegalStateException();
+ }
+ @Override BoundType typeAsUpperBound() {
+ throw new AssertionError("this statement should be unreachable");
+ }
+ @Override Cut<Comparable<?>> withLowerBoundType(BoundType boundType,
+ DiscreteDomain<Comparable<?>> domain) {
+ throw new IllegalStateException();
+ }
+ @Override Cut<Comparable<?>> withUpperBoundType(BoundType boundType,
+ DiscreteDomain<Comparable<?>> domain) {
+ throw new AssertionError("this statement should be unreachable");
+ }
+ @Override void describeAsLowerBound(StringBuilder sb) {
+ sb.append("(-\u221e");
+ }
+ @Override void describeAsUpperBound(StringBuilder sb) {
+ throw new AssertionError();
+ }
+ @Override Comparable<?> leastValueAbove(
+ DiscreteDomain<Comparable<?>> domain) {
+ return domain.minValue();
+ }
+ @Override Comparable<?> greatestValueBelow(
+ DiscreteDomain<Comparable<?>> domain) {
+ throw new AssertionError();
+ }
+ @Override Cut<Comparable<?>> canonical(
+ DiscreteDomain<Comparable<?>> domain) {
+ try {
+ return Cut.<Comparable<?>>belowValue(domain.minValue());
+ } catch (NoSuchElementException e) {
+ return this;
+ }
+ }
+ @Override public int compareTo(Cut<Comparable<?>> o) {
+ return (o == this) ? 0 : -1;
+ }
+ private Object readResolve() {
+ return INSTANCE;
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /*
+ * The implementation neither produces nor consumes any non-null instance of
+ * type C, so casting the type parameter is safe.
+ */
+ @SuppressWarnings("unchecked")
+ static <C extends Comparable> Cut<C> aboveAll() {
+ return (Cut<C>) AboveAll.INSTANCE;
+ }
+
+ private static final class AboveAll extends Cut<Comparable<?>> {
+ private static final AboveAll INSTANCE = new AboveAll();
+
+ private AboveAll() {
+ super(null);
+ }
+ @Override Comparable<?> endpoint() {
+ throw new IllegalStateException("range unbounded on this side");
+ }
+ @Override boolean isLessThan(Comparable<?> value) {
+ return false;
+ }
+ @Override BoundType typeAsLowerBound() {
+ throw new AssertionError("this statement should be unreachable");
+ }
+ @Override BoundType typeAsUpperBound() {
+ throw new IllegalStateException();
+ }
+ @Override Cut<Comparable<?>> withLowerBoundType(BoundType boundType,
+ DiscreteDomain<Comparable<?>> domain) {
+ throw new AssertionError("this statement should be unreachable");
+ }
+ @Override Cut<Comparable<?>> withUpperBoundType(BoundType boundType,
+ DiscreteDomain<Comparable<?>> domain) {
+ throw new IllegalStateException();
+ }
+ @Override void describeAsLowerBound(StringBuilder sb) {
+ throw new AssertionError();
+ }
+ @Override void describeAsUpperBound(StringBuilder sb) {
+ sb.append("+\u221e)");
+ }
+ @Override Comparable<?> leastValueAbove(
+ DiscreteDomain<Comparable<?>> domain) {
+ throw new AssertionError();
+ }
+ @Override Comparable<?> greatestValueBelow(
+ DiscreteDomain<Comparable<?>> domain) {
+ return domain.maxValue();
+ }
+ @Override public int compareTo(Cut<Comparable<?>> o) {
+ return (o == this) ? 0 : 1;
+ }
+ private Object readResolve() {
+ return INSTANCE;
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ static <C extends Comparable> Cut<C> belowValue(C endpoint) {
+ return new BelowValue<C>(endpoint);
+ }
+
+ private static final class BelowValue<C extends Comparable> extends Cut<C> {
+ BelowValue(C endpoint) {
+ super(checkNotNull(endpoint));
+ }
+
+ @Override boolean isLessThan(C value) {
+ return Range.compareOrThrow(endpoint, value) <= 0;
+ }
+ @Override BoundType typeAsLowerBound() {
+ return BoundType.CLOSED;
+ }
+ @Override BoundType typeAsUpperBound() {
+ return BoundType.OPEN;
+ }
+ @Override Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) {
+ switch (boundType) {
+ case CLOSED:
+ return this;
+ case OPEN:
+ @Nullable C previous = domain.previous(endpoint);
+ return (previous == null) ? Cut.<C>belowAll() : new AboveValue<C>(previous);
+ default:
+ throw new AssertionError();
+ }
+ }
+ @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) {
+ switch (boundType) {
+ case CLOSED:
+ @Nullable C previous = domain.previous(endpoint);
+ return (previous == null) ? Cut.<C>aboveAll() : new AboveValue<C>(previous);
+ case OPEN:
+ return this;
+ default:
+ throw new AssertionError();
+ }
+ }
+ @Override void describeAsLowerBound(StringBuilder sb) {
+ sb.append('[').append(endpoint);
+ }
+ @Override void describeAsUpperBound(StringBuilder sb) {
+ sb.append(endpoint).append(')');
+ }
+ @Override C leastValueAbove(DiscreteDomain<C> domain) {
+ return endpoint;
+ }
+ @Override C greatestValueBelow(DiscreteDomain<C> domain) {
+ return domain.previous(endpoint);
+ }
+ @Override public int hashCode() {
+ return endpoint.hashCode();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ static <C extends Comparable> Cut<C> aboveValue(C endpoint) {
+ return new AboveValue<C>(endpoint);
+ }
+
+ private static final class AboveValue<C extends Comparable> extends Cut<C> {
+ AboveValue(C endpoint) {
+ super(checkNotNull(endpoint));
+ }
+
+ @Override boolean isLessThan(C value) {
+ return Range.compareOrThrow(endpoint, value) < 0;
+ }
+ @Override BoundType typeAsLowerBound() {
+ return BoundType.OPEN;
+ }
+ @Override BoundType typeAsUpperBound() {
+ return BoundType.CLOSED;
+ }
+ @Override Cut<C> withLowerBoundType(BoundType boundType, DiscreteDomain<C> domain) {
+ switch (boundType) {
+ case OPEN:
+ return this;
+ case CLOSED:
+ @Nullable C next = domain.next(endpoint);
+ return (next == null) ? Cut.<C>belowAll() : belowValue(next);
+ default:
+ throw new AssertionError();
+ }
+ }
+ @Override Cut<C> withUpperBoundType(BoundType boundType, DiscreteDomain<C> domain) {
+ switch (boundType) {
+ case OPEN:
+ @Nullable C next = domain.next(endpoint);
+ return (next == null) ? Cut.<C>aboveAll() : belowValue(next);
+ case CLOSED:
+ return this;
+ default:
+ throw new AssertionError();
+ }
+ }
+ @Override void describeAsLowerBound(StringBuilder sb) {
+ sb.append('(').append(endpoint);
+ }
+ @Override void describeAsUpperBound(StringBuilder sb) {
+ sb.append(endpoint).append(']');
+ }
+ @Override C leastValueAbove(DiscreteDomain<C> domain) {
+ return domain.next(endpoint);
+ }
+ @Override C greatestValueBelow(DiscreteDomain<C> domain) {
+ return endpoint;
+ }
+ @Override Cut<C> canonical(DiscreteDomain<C> domain) {
+ C next = leastValueAbove(domain);
+ return (next != null) ? belowValue(next) : Cut.<C>aboveAll();
+ }
+ @Override public int hashCode() {
+ return ~endpoint.hashCode();
+ }
+ 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
new file mode 100644
index 0000000..d2d0088
--- /dev/null
+++ b/guava/src/com/google/common/collect/DescendingImmutableSortedMultiset.java
@@ -0,0 +1,97 @@
+/*
+ * 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 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) {
+ this.forward = forward;
+ }
+
+ @Override
+ public int count(@Nullable Object element) {
+ return forward.count(element);
+ }
+
+ @Override
+ public Entry<E> firstEntry() {
+ return forward.lastEntry();
+ }
+
+ @Override
+ public Entry<E> lastEntry() {
+ return forward.firstEntry();
+ }
+
+ @Override
+ public int size() {
+ return forward.size();
+ }
+
+ @Override
+ public ImmutableSortedSet<E> elementSet() {
+ return forward.elementSet().descendingSet();
+ }
+
+ @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();
+ }
+ };
+ }
+
+ @Override
+ public ImmutableSortedMultiset<E> descendingMultiset() {
+ return forward;
+ }
+
+ @Override
+ public ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
+ return forward.tailMultiset(upperBound, boundType).descendingMultiset();
+ }
+
+ @Override
+ public ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
+ return forward.headMultiset(lowerBound, boundType).descendingMultiset();
+ }
+
+ @Override
+ boolean isPartialView() {
+ return forward.isPartialView();
+ }
+}
diff --git a/guava/src/com/google/common/collect/DiscreteDomain.java b/guava/src/com/google/common/collect/DiscreteDomain.java
new file mode 100644
index 0000000..a3f97f3
--- /dev/null
+++ b/guava/src/com/google/common/collect/DiscreteDomain.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.NoSuchElementException;
+
+/**
+ * A descriptor for a <i>discrete</i> {@code Comparable} domain such as all
+ * {@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.
+ *
+ * <p>A discrete domain always represents the <i>entire</i> set of values of its
+ * 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> {
+ /** Constructor for use by subclasses. */
+ protected DiscreteDomain() {}
+
+ /**
+ * Returns the unique least value of type {@code C} that is greater than
+ * {@code value}, or {@code null} if none exists. Inverse operation to {@link
+ * #previous}.
+ *
+ * @param value any value of type {@code C}
+ * @return the least value greater than {@code value}, or {@code null} if
+ * {@code value} is {@code maxValue()}
+ */
+ public abstract C next(C value);
+
+ /**
+ * Returns the unique greatest value of type {@code C} that is less than
+ * {@code value}, or {@code null} if none exists. Inverse operation to {@link
+ * #next}.
+ *
+ * @param value any value of type {@code C}
+ * @return the greatest value less than {@code value}, or {@code null} if
+ * {@code value} is {@code minValue()}
+ */
+ public abstract C previous(C value);
+
+ /**
+ * Returns a signed value indicating how many nested invocations of {@link
+ * #next} (if positive) or {@link #previous} (if negative) are needed to reach
+ * {@code end} starting from {@code start}. For example, if {@code end =
+ * next(next(next(start)))}, then {@code distance(start, end) == 3} and {@code
+ * distance(end, start) == -3}. As well, {@code distance(a, a)} is always
+ * zero.
+ *
+ * <p>Note that this function is necessarily well-defined for any discrete
+ * 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,
+ * respectively.
+ */
+ public abstract long distance(C start, C end);
+
+ /**
+ * Returns the minimum value of type {@code C}, if it has one. The minimum
+ * value is the unique value for which {@link Comparable#compareTo(Object)}
+ * never returns a positive value for any input of type {@code C}.
+ *
+ * <p>The default implementation throws {@code NoSuchElementException}.
+ *
+ * @return the minimum value of type {@code C}; never null
+ * @throws NoSuchElementException if the type has no (practical) minimum
+ * value; for example, {@link java.math.BigInteger}
+ */
+ public C minValue() {
+ throw new NoSuchElementException();
+ }
+
+ /**
+ * Returns the maximum value of type {@code C}, if it has one. The maximum
+ * value is the unique value for which {@link Comparable#compareTo(Object)}
+ * never returns a negative value for any input of type {@code C}.
+ *
+ * <p>The default implementation throws {@code NoSuchElementException}.
+ *
+ * @return the maximum value of type {@code C}; never null
+ * @throws NoSuchElementException if the type has no (practical) maximum
+ * value; for example, {@link java.math.BigInteger}
+ */
+ 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
new file mode 100644
index 0000000..4cd5b48
--- /dev/null
+++ b/guava/src/com/google/common/collect/DiscreteDomains.java
@@ -0,0 +1,162 @@
+/*
+ * 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.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
+ */
+@GwtCompatible
+@Beta
+public final class DiscreteDomains {
+ private DiscreteDomains() {}
+
+ /**
+ * Returns the discrete domain for values of type {@code Integer}.
+ */
+ 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;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns the discrete domain for values of type {@code Long}.
+ */
+ 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;
+ }
+
+ 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
new file mode 100644
index 0000000..fbf1961
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyContiguousSet.java
@@ -0,0 +1,136 @@
+/*
+ * 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 com.google.common.annotations.GwtIncompatible;
+
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An empty contiguous set.
+ *
+ * @author Gregory Kick
+ */
+@GwtCompatible(emulated = true)
+@SuppressWarnings("unchecked") // allow ungenerified Comparable types
+final class EmptyContiguousSet<C extends Comparable> extends ContiguousSet<C> {
+ EmptyContiguousSet(DiscreteDomain<C> domain) {
+ super(domain);
+ }
+
+ @Override public C first() {
+ throw new NoSuchElementException();
+ }
+
+ @Override public C last() {
+ throw new NoSuchElementException();
+ }
+
+ @Override public int size() {
+ return 0;
+ }
+
+ @Override public ContiguousSet<C> intersection(ContiguousSet<C> other) {
+ return this;
+ }
+
+ @Override public Range<C> range() {
+ throw new NoSuchElementException();
+ }
+
+ @Override public Range<C> range(BoundType lowerBoundType, BoundType upperBoundType) {
+ throw new NoSuchElementException();
+ }
+
+ @Override ContiguousSet<C> headSetImpl(C toElement, boolean inclusive) {
+ return this;
+ }
+
+ @Override ContiguousSet<C> subSetImpl(
+ C fromElement, boolean fromInclusive, C toElement, boolean toInclusive) {
+ return this;
+ }
+
+ @Override ContiguousSet<C> tailSetImpl(C fromElement, boolean fromInclusive) {
+ return this;
+ }
+
+ @GwtIncompatible("not used by GWT emulation")
+ @Override int indexOf(Object target) {
+ return -1;
+ }
+
+ @Override public UnmodifiableIterator<C> iterator() {
+ return Iterators.emptyIterator();
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public ImmutableList<C> asList() {
+ return ImmutableList.of();
+ }
+
+ @Override public String toString() {
+ return "[]";
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Set) {
+ Set<?> that = (Set<?>) object;
+ return that.isEmpty();
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return 0;
+ }
+
+ @GwtIncompatible("serialization")
+ private static final class SerializedForm<C extends Comparable> implements Serializable {
+ private final DiscreteDomain<C> domain;
+
+ private SerializedForm(DiscreteDomain<C> domain) {
+ this.domain = domain;
+ }
+
+ private Object readResolve() {
+ return new EmptyContiguousSet<C>(domain);
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ @GwtIncompatible("serialization")
+ @Override
+ 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
new file mode 100644
index 0000000..8839a07
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableBiMap.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+/**
+ * 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 ImmutableMap<Object, Object> delegate() {
+ return ImmutableMap.of();
+ }
+ @Override public ImmutableBiMap<Object, Object> inverse() {
+ return this;
+ }
+ @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
new file mode 100644
index 0000000..b854d2b
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableList.java
@@ -0,0 +1,131 @@
+/*
+ * 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.checkElementIndex;
+import static com.google.common.base.Preconditions.checkPositionIndex;
+import static com.google.common.base.Preconditions.checkPositionIndexes;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.List;
+
+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();
+
+ private EmptyImmutableList() {}
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public boolean contains(@Nullable Object target) {
+ return false;
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ return targets.isEmpty();
+ }
+
+ @Override public UnmodifiableIterator<Object> iterator() {
+ return listIterator();
+ }
+
+ @Override public Object[] toArray() {
+ return ObjectArrays.EMPTY_ARRAY;
+ }
+
+ @Override public <T> T[] toArray(T[] a) {
+ if (a.length > 0) {
+ a[0] = null;
+ }
+ return a;
+ }
+
+ @Override
+ public Object get(int index) {
+ // guaranteed to fail, but at least we get a consistent message
+ checkElementIndex(index, 0);
+ throw new AssertionError("unreachable");
+ }
+
+ @Override public int indexOf(@Nullable Object target) {
+ return -1;
+ }
+
+ @Override public int lastIndexOf(@Nullable Object target) {
+ return -1;
+ }
+
+ @Override public ImmutableList<Object> subList(int fromIndex, int toIndex) {
+ checkPositionIndexes(fromIndex, toIndex, 0);
+ return this;
+ }
+
+ @Override public ImmutableList<Object> reverse() {
+ return this;
+ }
+
+ @Override public UnmodifiableListIterator<Object> listIterator() {
+ return Iterators.EMPTY_LIST_ITERATOR;
+ }
+
+ @Override public UnmodifiableListIterator<Object> listIterator(int start) {
+ checkPositionIndex(start, 0);
+ return Iterators.EMPTY_LIST_ITERATOR;
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof List) {
+ List<?> that = (List<?>) object;
+ return that.isEmpty();
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return 1;
+ }
+
+ @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/EmptyImmutableListMultimap.java b/guava/src/com/google/common/collect/EmptyImmutableListMultimap.java
new file mode 100644
index 0000000..2a6836d
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableListMultimap.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+/**
+ * Implementation of {@link ImmutableListMultimap} with no entries.
+ *
+ * @author Jared Levy
+ */
+@GwtCompatible(serializable = true)
+class EmptyImmutableListMultimap extends ImmutableListMultimap<Object, Object> {
+ static final EmptyImmutableListMultimap INSTANCE
+ = new EmptyImmutableListMultimap();
+
+ private EmptyImmutableListMultimap() {
+ super(ImmutableMap.<Object, ImmutableList<Object>>of(), 0);
+ }
+
+ private Object readResolve() {
+ return INSTANCE; // preserve singleton property
+ }
+
+ private static final long serialVersionUID = 0;
+}
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..1aaf1c9
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableMap.java
@@ -0,0 +1,99 @@
+/*
+ * 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 ImmutableSet<Entry<Object, Object>> createEntrySet() {
+ throw new AssertionError("should never be called");
+ }
+
+ @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
new file mode 100644
index 0000000..1931342
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableMultiset.java
@@ -0,0 +1,114 @@
+/*
+ * 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.Collection;
+
+import javax.annotation.Nullable;
+
+/**
+ * An empty immutable multiset.
+ *
+ * @author Jared Levy
+ * @author Louis Wasserman
+ */
+@GwtCompatible(serializable = true)
+final class EmptyImmutableMultiset extends ImmutableMultiset<Object> {
+ static final EmptyImmutableMultiset INSTANCE = new EmptyImmutableMultiset();
+
+ @Override
+ public int count(@Nullable Object element) {
+ return 0;
+ }
+
+ @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();
+ }
+
+ @Override
+ ImmutableSet<Entry<Object>> createEntrySet() {
+ throw new AssertionError("should never be called");
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @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<Object> asList() {
+ return ImmutableList.of();
+ }
+
+ Object readResolve() {
+ return INSTANCE; // preserve singleton property
+ }
+
+ 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
new file mode 100644
index 0000000..e70b051
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableSet.java
@@ -0,0 +1,100 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An empty immutable set.
+ *
+ * @author Kevin Bourrillion
+ */
+@GwtCompatible(serializable = true, emulated = true)
+final class EmptyImmutableSet extends ImmutableSet<Object> {
+ static final EmptyImmutableSet INSTANCE = new EmptyImmutableSet();
+
+ private EmptyImmutableSet() {}
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public boolean contains(@Nullable Object target) {
+ return false;
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ return targets.isEmpty();
+ }
+
+ @Override public UnmodifiableIterator<Object> iterator() {
+ return Iterators.emptyIterator();
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public Object[] toArray() {
+ return ObjectArrays.EMPTY_ARRAY;
+ }
+
+ @Override public <T> T[] toArray(T[] a) {
+ return asList().toArray(a);
+ }
+
+ @Override
+ public ImmutableList<Object> asList() {
+ return ImmutableList.of();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Set) {
+ Set<?> that = (Set<?>) object;
+ return that.isEmpty();
+ }
+ return false;
+ }
+
+ @Override public final int hashCode() {
+ return 0;
+ }
+
+ @Override boolean isHashCodeFast() {
+ return true;
+ }
+
+ @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/EmptyImmutableSetMultimap.java b/guava/src/com/google/common/collect/EmptyImmutableSetMultimap.java
new file mode 100644
index 0000000..810de3c
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableSetMultimap.java
@@ -0,0 +1,40 @@
+/*
+ * 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;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * Implementation of {@link ImmutableListMultimap} with no entries.
+ *
+ * @author Mike Ward
+ */
+@GwtCompatible(serializable = true)
+class EmptyImmutableSetMultimap extends ImmutableSetMultimap<Object, Object> {
+ static final EmptyImmutableSetMultimap INSTANCE
+ = new EmptyImmutableSetMultimap();
+
+ private EmptyImmutableSetMultimap() {
+ super(ImmutableMap.<Object, ImmutableSet<Object>>of(), 0, null);
+ }
+
+ private Object readResolve() {
+ return INSTANCE; // preserve singleton property
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/EmptyImmutableSortedMap.java b/guava/src/com/google/common/collect/EmptyImmutableSortedMap.java
new file mode 100644
index 0000000..eafc126
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableSortedMap.java
@@ -0,0 +1,119 @@
+/*
+ * 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 java.util.Comparator;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * An empty immutable sorted map.
+ *
+ * @author Louis Wasserman
+ */
+@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 int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object instanceof Map) {
+ Map<?, ?> map = (Map<?, ?>) object;
+ return map.isEmpty();
+ }
+ return false;
+ }
+
+ @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
new file mode 100644
index 0000000..a7ddf28
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableSortedMultiset.java
@@ -0,0 +1,139 @@
+/*
+ * 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 java.util.Collection;
+import java.util.Comparator;
+
+import javax.annotation.Nullable;
+
+/**
+ * An empty immutable sorted multiset.
+ *
+ * @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);
+ }
+
+ @Override
+ public Entry<E> firstEntry() {
+ return null;
+ }
+
+ @Override
+ public Entry<E> lastEntry() {
+ return null;
+ }
+
+ @Override
+ public int count(@Nullable Object element) {
+ return 0;
+ }
+
+ @Override
+ public boolean contains(@Nullable Object object) {
+ return false;
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> targets) {
+ return targets.isEmpty();
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public ImmutableSortedSet<E> elementSet() {
+ return elementSet;
+ }
+
+ @Override
+ public ImmutableSet<Entry<E>> entrySet() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ ImmutableSet<Entry<E>> createEntrySet() {
+ throw new AssertionError("should never be called");
+ }
+
+ @Override
+ public ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
+ checkNotNull(upperBound);
+ checkNotNull(boundType);
+ return this;
+ }
+
+ @Override
+ public ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
+ checkNotNull(lowerBound);
+ checkNotNull(boundType);
+ return this;
+ }
+
+ @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() {
+ 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
new file mode 100644
index 0000000..06508e0
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableSortedSet.java
@@ -0,0 +1,127 @@
+/*
+ * 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.Collection;
+import java.util.Comparator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An empty immutable sorted set.
+ *
+ * @author Jared Levy
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // uses writeReplace(), not default serialization
+class EmptyImmutableSortedSet<E> extends ImmutableSortedSet<E> {
+ EmptyImmutableSortedSet(Comparator<? super E> comparator) {
+ super(comparator);
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @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();
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public ImmutableList<E> asList() {
+ return ImmutableList.of();
+ }
+
+ @Override public Object[] toArray() {
+ return ObjectArrays.EMPTY_ARRAY;
+ }
+
+ @Override public <T> T[] toArray(T[] a) {
+ return asList().toArray(a);
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Set) {
+ Set<?> that = (Set<?>) object;
+ return that.isEmpty();
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return 0;
+ }
+
+ @Override public String toString() {
+ return "[]";
+ }
+
+ @Override
+ public E first() {
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public E last() {
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ ImmutableSortedSet<E> headSetImpl(E toElement, boolean inclusive) {
+ return this;
+ }
+
+ @Override
+ ImmutableSortedSet<E> subSetImpl(
+ E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ return this;
+ }
+
+ @Override
+ ImmutableSortedSet<E> tailSetImpl(E fromElement, boolean inclusive) {
+ return this;
+ }
+
+ @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
new file mode 100644
index 0000000..65b8042
--- /dev/null
+++ b/guava/src/com/google/common/collect/EmptyImmutableTable.java
@@ -0,0 +1,128 @@
+/*
+ * 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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * An empty implementation of {@link ImmutableTable}.
+ *
+ * @author Gregory Kick
+ */
+@GwtCompatible
+@Immutable
+final class EmptyImmutableTable extends ImmutableTable<Object, Object, Object> {
+ static final EmptyImmutableTable INSTANCE = new EmptyImmutableTable();
+
+ private EmptyImmutableTable() {}
+
+ @Override public int size() {
+ return 0;
+ }
+
+ @Override public Object get(@Nullable Object rowKey,
+ @Nullable Object columnKey) {
+ return null;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof Table) {
+ Table<?, ?, ?> that = (Table<?, ?, ?>) obj;
+ return that.isEmpty();
+ } else {
+ return false;
+ }
+ }
+
+ @Override public int hashCode() {
+ return 0;
+ }
+
+ @Override public ImmutableSet<Cell<Object, Object, Object>> cellSet() {
+ return ImmutableSet.of();
+ }
+
+ @Override public ImmutableMap<Object, Object> column(Object columnKey) {
+ checkNotNull(columnKey);
+ return ImmutableMap.of();
+ }
+
+ @Override public ImmutableSet<Object> columnKeySet() {
+ return ImmutableSet.of();
+ }
+
+ @Override public ImmutableMap<Object, Map<Object, Object>> columnMap() {
+ return ImmutableMap.of();
+ }
+
+ @Override public boolean contains(@Nullable Object rowKey,
+ @Nullable Object columnKey) {
+ return false;
+ }
+
+ @Override public boolean containsColumn(@Nullable Object columnKey) {
+ return false;
+ }
+
+ @Override public boolean containsRow(@Nullable Object rowKey) {
+ return false;
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ return false;
+ }
+
+ @Override public ImmutableMap<Object, Object> row(Object rowKey) {
+ checkNotNull(rowKey);
+ return ImmutableMap.of();
+ }
+
+ @Override public ImmutableSet<Object> rowKeySet() {
+ return ImmutableSet.of();
+ }
+
+ @Override public ImmutableMap<Object, Map<Object, Object>> rowMap() {
+ return ImmutableMap.of();
+ }
+
+ @Override public String toString() {
+ return "{}";
+ }
+
+ @Override public ImmutableCollection<Object> values() {
+ return ImmutableSet.of();
+ }
+
+ Object readResolve() {
+ return INSTANCE; // preserve singleton property
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/EnumBiMap.java b/guava/src/com/google/common/collect/EnumBiMap.java
new file mode 100644
index 0000000..05d84ed
--- /dev/null
+++ b/guava/src/com/google/common/collect/EnumBiMap.java
@@ -0,0 +1,151 @@
+/*
+ * 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.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.EnumMap;
+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)
+ */
+@GwtCompatible(emulated = true)
+public final class EnumBiMap<K extends Enum<K>, V extends Enum<V>>
+ extends AbstractBiMap<K, V> {
+ private transient Class<K> keyType;
+ private transient Class<V> valueType;
+
+ /**
+ * Returns a new, empty {@code EnumBiMap} using the specified key and value
+ * types.
+ *
+ * @param keyType the key type
+ * @param valueType the value type
+ */
+ public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V>
+ create(Class<K> keyType, Class<V> valueType) {
+ return new EnumBiMap<K, V>(keyType, valueType);
+ }
+
+ /**
+ * Returns a new bimap with the same mappings as the specified map. If the
+ * specified map is an {@code EnumBiMap}, the new bimap has the same types as
+ * the provided map. Otherwise, the specified map must contain at least one
+ * mapping, in order to determine the key and value types.
+ *
+ * @param map the map whose mappings are to be placed in this map
+ * @throws IllegalArgumentException if map is not an {@code EnumBiMap}
+ * instance and contains no mappings
+ */
+ public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V>
+ create(Map<K, V> map) {
+ EnumBiMap<K, V> bimap = create(inferKeyType(map), inferValueType(map));
+ bimap.putAll(map);
+ return bimap;
+ }
+
+ private EnumBiMap(Class<K> keyType, Class<V> valueType) {
+ super(WellBehavedMap.wrap(new EnumMap<K, V>(keyType)),
+ WellBehavedMap.wrap(new EnumMap<V, K>(valueType)));
+ this.keyType = keyType;
+ this.valueType = valueType;
+ }
+
+ static <K extends Enum<K>> Class<K> inferKeyType(Map<K, ?> map) {
+ if (map instanceof EnumBiMap) {
+ return ((EnumBiMap<K, ?>) map).keyType();
+ }
+ if (map instanceof EnumHashBiMap) {
+ return ((EnumHashBiMap<K, ?>) map).keyType();
+ }
+ checkArgument(!map.isEmpty());
+ return map.keySet().iterator().next().getDeclaringClass();
+ }
+
+ private static <V extends Enum<V>> Class<V> inferValueType(Map<?, V> map) {
+ if (map instanceof EnumBiMap) {
+ return ((EnumBiMap<?, V>) map).valueType;
+ }
+ checkArgument(!map.isEmpty());
+ return map.values().iterator().next().getDeclaringClass();
+ }
+
+ /** Returns the associated key type. */
+ public Class<K> keyType() {
+ return keyType;
+ }
+
+ /** Returns the associated value type. */
+ public Class<V> valueType() {
+ 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.
+ */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(keyType);
+ stream.writeObject(valueType);
+ Serialization.writeMap(this, stream);
+ }
+
+ @SuppressWarnings("unchecked") // reading fields populated by writeObject
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ keyType = (Class<K>) stream.readObject();
+ valueType = (Class<V>) stream.readObject();
+ setDelegates(
+ WellBehavedMap.wrap(new EnumMap<K, V>(keyType)),
+ WellBehavedMap.wrap(new EnumMap<V, K>(valueType)));
+ Serialization.populateMap(this, stream);
+ }
+
+ @GwtIncompatible("not needed in emulated source.")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/EnumHashBiMap.java b/guava/src/com/google/common/collect/EnumHashBiMap.java
new file mode 100644
index 0000000..c43daf0
--- /dev/null
+++ b/guava/src/com/google/common/collect/EnumHashBiMap.java
@@ -0,0 +1,130 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * A {@code BiMap} backed by an {@code EnumMap} instance for keys-to-values, and
+ * 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)
+ */
+@GwtCompatible(emulated = true)
+public final class EnumHashBiMap<K extends Enum<K>, V>
+ extends AbstractBiMap<K, V> {
+ private transient Class<K> keyType;
+
+ /**
+ * Returns a new, empty {@code EnumHashBiMap} using the specified key type.
+ *
+ * @param keyType the key type
+ */
+ public static <K extends Enum<K>, V> EnumHashBiMap<K, V>
+ create(Class<K> keyType) {
+ return new EnumHashBiMap<K, V>(keyType);
+ }
+
+ /**
+ * Constructs a new bimap with the same mappings as the specified map. If the
+ * specified map is an {@code EnumHashBiMap} or an {@link EnumBiMap}, the new
+ * bimap has the same key type as the input bimap. Otherwise, the specified
+ * map must contain at least one mapping, in order to determine the key type.
+ *
+ * @param map the map whose mappings are to be placed in this map
+ * @throws IllegalArgumentException if map is not an {@code EnumBiMap} or an
+ * {@code EnumHashBiMap} instance and contains no mappings
+ */
+ public static <K extends Enum<K>, V> EnumHashBiMap<K, V>
+ create(Map<K, ? extends V> map) {
+ EnumHashBiMap<K, V> bimap = create(EnumBiMap.inferKeyType(map));
+ bimap.putAll(map);
+ return bimap;
+ }
+
+ private EnumHashBiMap(Class<K> keyType) {
+ super(WellBehavedMap.wrap(
+ new EnumMap<K, V>(keyType)),
+ Maps.<V, K>newHashMapWithExpectedSize(
+ keyType.getEnumConstants().length));
+ 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);
+ }
+
+ @Override public V put(K key, @Nullable V value) {
+ return super.put(key, value);
+ }
+
+ @Override public V forcePut(K key, @Nullable V value) {
+ return super.forcePut(key, value);
+ }
+
+ /** Returns the associated key type. */
+ public Class<K> keyType() {
+ return keyType;
+ }
+
+ /**
+ * @serialData the key class, 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 {
+ stream.defaultWriteObject();
+ stream.writeObject(keyType);
+ Serialization.writeMap(this, stream);
+ }
+
+ @SuppressWarnings("unchecked") // reading field populated by writeObject
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ keyType = (Class<K>) stream.readObject();
+ setDelegates(WellBehavedMap.wrap(new EnumMap<K, V>(keyType)),
+ new HashMap<V, K>(keyType.getEnumConstants().length * 3 / 2));
+ Serialization.populateMap(this, stream);
+ }
+
+ @GwtIncompatible("only needed in emulated source.")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/EnumMultiset.java b/guava/src/com/google/common/collect/EnumMultiset.java
new file mode 100644
index 0000000..756f01e
--- /dev/null
+++ b/guava/src/com/google/common/collect/EnumMultiset.java
@@ -0,0 +1,94 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.EnumMap;
+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)
+ */
+@GwtCompatible(emulated = true)
+public final class EnumMultiset<E extends Enum<E>> extends AbstractMapBasedMultiset<E> {
+ /** Creates an empty {@code EnumMultiset}. */
+ public static <E extends Enum<E>> EnumMultiset<E> create(Class<E> type) {
+ return new EnumMultiset<E>(type);
+ }
+
+ /**
+ * Creates a new {@code EnumMultiset} containing the specified elements.
+ *
+ * <p>This implementation is highly efficient when {@code elements} is itself a {@link
+ * Multiset}.
+ *
+ * @param elements the elements that the multiset should contain
+ * @throws IllegalArgumentException if {@code elements} is empty
+ */
+ public static <E extends Enum<E>> EnumMultiset<E> create(Iterable<E> elements) {
+ Iterator<E> iterator = elements.iterator();
+ checkArgument(iterator.hasNext(), "EnumMultiset constructor passed empty Iterable");
+ EnumMultiset<E> multiset = new EnumMultiset<E>(iterator.next().getDeclaringClass());
+ Iterables.addAll(multiset, elements);
+ return multiset;
+ }
+
+ private transient Class<E> type;
+
+ /** Creates an empty {@code EnumMultiset}. */
+ private EnumMultiset(Class<E> type) {
+ super(WellBehavedMap.wrap(new EnumMap<E, Count>(type)));
+ this.type = type;
+ }
+
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(type);
+ Serialization.writeMultiset(this, stream);
+ }
+
+ /**
+ * @serialData the {@code Class<E>} for the enum type, the number of distinct
+ * elements, the first element, its count, the second element, its
+ * count, and so on
+ */
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ Class<E> localType = (Class<E>) stream.readObject();
+ type = localType;
+ setBackingMap(WellBehavedMap.wrap(new EnumMap<E, Count>(type)));
+ Serialization.populateMultiset(this, stream);
+ }
+
+ @GwtIncompatible("Not needed in emulated source")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ExplicitOrdering.java b/guava/src/com/google/common/collect/ExplicitOrdering.java
new file mode 100644
index 0000000..0a2e181
--- /dev/null
+++ b/guava/src/com/google/common/collect/ExplicitOrdering.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/** An ordering that compares objects according to a given order. */
+@GwtCompatible(serializable = true)
+final class ExplicitOrdering<T> extends Ordering<T> implements Serializable {
+ final ImmutableMap<T, Integer> rankMap;
+
+ ExplicitOrdering(List<T> valuesInOrder) {
+ this(buildRankMap(valuesInOrder));
+ }
+
+ ExplicitOrdering(ImmutableMap<T, Integer> rankMap) {
+ this.rankMap = rankMap;
+ }
+
+ @Override public int compare(T left, T right) {
+ return rank(left) - rank(right); // safe because both are nonnegative
+ }
+
+ private int rank(T value) {
+ Integer rank = rankMap.get(value);
+ if (rank == null) {
+ throw new IncomparableValueException(value);
+ }
+ return rank;
+ }
+
+ private static <T> ImmutableMap<T, Integer> buildRankMap(
+ List<T> valuesInOrder) {
+ ImmutableMap.Builder<T, Integer> builder = ImmutableMap.builder();
+ int rank = 0;
+ for (T value : valuesInOrder) {
+ builder.put(value, rank++);
+ }
+ return builder.build();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof ExplicitOrdering) {
+ ExplicitOrdering<?> that = (ExplicitOrdering<?>) object;
+ return this.rankMap.equals(that.rankMap);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return rankMap.hashCode();
+ }
+
+ @Override public String toString() {
+ return "Ordering.explicit(" + rankMap.keySet() + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/FluentIterable.java b/guava/src/com/google/common/collect/FluentIterable.java
new file mode 100644
index 0000000..5482536
--- /dev/null
+++ b/guava/src/com/google/common/collect/FluentIterable.java
@@ -0,0 +1,399 @@
+/*
+ * 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.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}s 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 #toImmutableList})
+ * <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)
+ * .toImmutableList();}</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
+ */
+@Beta
+@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
+ */
+ public <T> FluentIterable<T> transformAndConcat(
+ Function<? super E, ? extends Iterable<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.
+ */
+ public final ImmutableList<E> toImmutableList() {
+ 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 toSortedImmutableList(Ordering.natural())}.
+ *
+ * @param comparator the function by which to sort list elements
+ * @throws NullPointerException if any element is null
+ * @since 13.0
+ */
+ public final ImmutableList<E> toSortedImmutableList(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.
+ */
+ public final ImmutableSet<E> toImmutableSet() {
+ 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 comaprator.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
+ */
+ public final ImmutableSortedSet<E> toImmutableSortedSet(Comparator<? super E> comparator) {
+ return ImmutableSortedSet.copyOf(comparator, iterable);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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/ForwardingCollection.java b/guava/src/com/google/common/collect/ForwardingCollection.java
new file mode 100644
index 0000000..a6a46f0
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingCollection.java
@@ -0,0 +1,265 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Objects;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.annotation.Nullable;
+
+/**
+ * A collection which forwards all its method calls to another collection.
+ * Subclasses should override one or more methods to modify the behavior of the
+ * backing collection as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p><b>Warning:</b> The methods of {@code ForwardingCollection} 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
+ * #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>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 Kevin Bourrillion
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingCollection<E> extends ForwardingObject
+ implements Collection<E> {
+ // TODO(user): identify places where thread safety is actually lost
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingCollection() {}
+
+ @Override protected abstract Collection<E> delegate();
+
+ @Override
+ public Iterator<E> iterator() {
+ return delegate().iterator();
+ }
+
+ @Override
+ public int size() {
+ return delegate().size();
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> collection) {
+ return delegate().removeAll(collection);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return delegate().isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object object) {
+ return delegate().contains(object);
+ }
+
+ @Override
+ public boolean add(E element) {
+ return delegate().add(element);
+ }
+
+ @Override
+ public boolean remove(Object object) {
+ return delegate().remove(object);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> collection) {
+ return delegate().containsAll(collection);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends E> collection) {
+ return delegate().addAll(collection);
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> collection) {
+ return delegate().retainAll(collection);
+ }
+
+ @Override
+ public void clear() {
+ delegate().clear();
+ }
+
+ @Override
+ public Object[] toArray() {
+ return delegate().toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] array) {
+ return delegate().toArray(array);
+ }
+
+ /**
+ * A sensible definition of {@link #contains} in terms of {@link #iterator}.
+ * If you override {@link #iterator}, you may wish to override {@link
+ * #contains} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardContains(@Nullable Object object) {
+ return Iterators.contains(iterator(), object);
+ }
+
+ /**
+ * A sensible definition of {@link #containsAll} in terms of {@link #contains}
+ * . If you override {@link #contains}, you may wish to override {@link
+ * #containsAll} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardContainsAll(Collection<?> collection) {
+ for (Object o : collection) {
+ if (!contains(o)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A sensible definition of {@link #addAll} in terms of {@link #add}. If you
+ * override {@link #add}, you may wish to override {@link #addAll} to forward
+ * to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardAddAll(Collection<? extends E> collection) {
+ return Iterators.addAll(this, collection.iterator());
+ }
+
+ /**
+ * A sensible definition of {@link #remove} in terms of {@link #iterator},
+ * using the iterator's {@code remove} method. If you override {@link
+ * #iterator}, you may wish to override {@link #remove} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardRemove(@Nullable Object object) {
+ Iterator<E> iterator = iterator();
+ while (iterator.hasNext()) {
+ if (Objects.equal(iterator.next(), object)) {
+ iterator.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A sensible definition of {@link #removeAll} in terms of {@link #iterator},
+ * using the iterator's {@code remove} method. If you override {@link
+ * #iterator}, you may wish to override {@link #removeAll} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardRemoveAll(Collection<?> collection) {
+ return Iterators.removeAll(iterator(), collection);
+ }
+
+ /**
+ * A sensible definition of {@link #retainAll} in terms of {@link #iterator},
+ * using the iterator's {@code remove} method. If you override {@link
+ * #iterator}, you may wish to override {@link #retainAll} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardRetainAll(Collection<?> collection) {
+ return Iterators.retainAll(iterator(), collection);
+ }
+
+ /**
+ * A sensible definition of {@link #clear} in terms of {@link #iterator},
+ * using the iterator's {@code remove} method. If you override {@link
+ * #iterator}, you may wish to override {@link #clear} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected void standardClear() {
+ Iterator<E> iterator = iterator();
+ while (iterator.hasNext()) {
+ iterator.next();
+ iterator.remove();
+ }
+ }
+
+ /**
+ * A sensible definition of {@link #isEmpty} as {@code !iterator().hasNext}.
+ * If you override {@link #isEmpty}, you may wish to override {@link #isEmpty}
+ * to forward to this implementation. Alternately, it may be more efficient to
+ * implement {@code isEmpty} as {@code size() == 0}.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardIsEmpty() {
+ return !iterator().hasNext();
+ }
+
+ /**
+ * A sensible definition of {@link #toString} in terms of {@link #iterator}.
+ * If you override {@link #iterator}, you may wish to override {@link
+ * #toString} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected String standardToString() {
+ return Collections2.toStringImpl(this);
+ }
+
+ /**
+ * A sensible definition of {@link #toArray()} in terms of {@link
+ * #toArray(Object[])}. If you override {@link #toArray(Object[])}, you may
+ * wish to override {@link #toArray} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected Object[] standardToArray() {
+ Object[] newArray = new Object[size()];
+ return toArray(newArray);
+ }
+
+ /**
+ * A sensible definition of {@link #toArray(Object[])} in terms of {@link
+ * #size} and {@link #iterator}. If you override either of these methods, you
+ * may wish to override {@link #toArray} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected <T> T[] standardToArray(T[] array) {
+ return ObjectArrays.toArrayImpl(this, array);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingConcurrentMap.java b/guava/src/com/google/common/collect/ForwardingConcurrentMap.java
new file mode 100644
index 0000000..0336dd1
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingConcurrentMap.java
@@ -0,0 +1,61 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * A concurrent map which forwards all its method calls to another concurrent
+ * 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>.
+ *
+ * @author Charles Fry
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingConcurrentMap<K, V> extends ForwardingMap<K, V>
+ implements ConcurrentMap<K, V> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingConcurrentMap() {}
+
+ @Override protected abstract ConcurrentMap<K, V> delegate();
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ return delegate().putIfAbsent(key, value);
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ return delegate().remove(key, value);
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ return delegate().replace(key, value);
+ }
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ return delegate().replace(key, oldValue, newValue);
+ }
+
+}
diff --git a/guava/src/com/google/common/collect/ForwardingDeque.java b/guava/src/com/google/common/collect/ForwardingDeque.java
new file mode 100644
index 0000000..27d63f3
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingDeque.java
@@ -0,0 +1,136 @@
+/*
+ * 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.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, 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 Kurt Alfred Kluever
+ * @since 12.0
+ */
+@Beta
+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/ForwardingImmutableList.java b/guava/src/com/google/common/collect/ForwardingImmutableList.java
new file mode 100644
index 0000000..2b9092e
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingImmutableList.java
@@ -0,0 +1,29 @@
+/*
+ * 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
new file mode 100644
index 0000000..a367157
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingImmutableMap.java
@@ -0,0 +1,29 @@
+/*
+ * 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
new file mode 100644
index 0000000..c7d7bf6
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingImmutableSet.java
@@ -0,0 +1,29 @@
+/*
+ * 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/ForwardingIterator.java b/guava/src/com/google/common/collect/ForwardingIterator.java
new file mode 100644
index 0000000..b8927d4
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingIterator.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Iterator;
+
+/**
+ * An iterator which forwards all its method calls to another iterator.
+ * Subclasses should override one or more methods to modify the behavior of the
+ * backing iterator as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Kevin Bourrillion
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingIterator<T>
+ extends ForwardingObject implements Iterator<T> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingIterator() {}
+
+ @Override protected abstract Iterator<T> delegate();
+
+ @Override
+ public boolean hasNext() {
+ return delegate().hasNext();
+ }
+
+ @Override
+ public T next() {
+ return delegate().next();
+ }
+
+ @Override
+ public void remove() {
+ delegate().remove();
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingList.java b/guava/src/com/google/common/collect/ForwardingList.java
new file mode 100644
index 0000000..49d5c5a
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingList.java
@@ -0,0 +1,239 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.annotation.Nullable;
+
+/**
+ * A list which forwards all its method calls to another list. Subclasses should
+ * override one or more methods to modify the behavior of the backing list as
+ * desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p>This class does not implement {@link java.util.RandomAccess}. If the
+ * delegate supports random access, the {@code ForwardingList} subclass should
+ * implement the {@code RandomAccess} interface.
+ *
+ * <p><b>Warning:</b> The methods of {@code ForwardingList} 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
+ * #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>The {@code standard} methods and any 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 Mike Bostock
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingList<E> extends ForwardingCollection<E>
+ implements List<E> {
+ // TODO(user): identify places where thread safety is actually lost
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingList() {}
+
+ @Override protected abstract List<E> delegate();
+
+ @Override
+ public void add(int index, E element) {
+ delegate().add(index, element);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends E> elements) {
+ return delegate().addAll(index, elements);
+ }
+
+ @Override
+ public E get(int index) {
+ return delegate().get(index);
+ }
+
+ @Override
+ public int indexOf(Object element) {
+ return delegate().indexOf(element);
+ }
+
+ @Override
+ public int lastIndexOf(Object element) {
+ return delegate().lastIndexOf(element);
+ }
+
+ @Override
+ public ListIterator<E> listIterator() {
+ return delegate().listIterator();
+ }
+
+ @Override
+ public ListIterator<E> listIterator(int index) {
+ return delegate().listIterator(index);
+ }
+
+ @Override
+ public E remove(int index) {
+ return delegate().remove(index);
+ }
+
+ @Override
+ public E set(int index, E element) {
+ return delegate().set(index, element);
+ }
+
+ @Override
+ public List<E> subList(int fromIndex, int toIndex) {
+ return delegate().subList(fromIndex, toIndex);
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return object == this || delegate().equals(object);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+
+ /**
+ * A sensible default implementation of {@link #add(Object)}, in terms of
+ * {@link #add(int, Object)}. If you override {@link #add(int, Object)}, you
+ * may wish to override {@link #add(Object)} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardAdd(E element){
+ add(size(), element);
+ return true;
+ }
+
+ /**
+ * A sensible default implementation of {@link #addAll(int, Collection)}, in
+ * terms of the {@code add} method of {@link #listIterator(int)}. If you
+ * override {@link #listIterator(int)}, you may wish to override {@link
+ * #addAll(int, Collection)} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardAddAll(
+ int index, Iterable<? extends E> elements) {
+ return Lists.addAllImpl(this, index, elements);
+ }
+
+ /**
+ * A sensible default implementation of {@link #indexOf}, in terms of {@link
+ * #listIterator()}. If you override {@link #listIterator()}, you may wish to
+ * override {@link #indexOf} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardIndexOf(@Nullable Object element) {
+ return Lists.indexOfImpl(this, element);
+ }
+
+ /**
+ * A sensible default implementation of {@link #lastIndexOf}, in terms of
+ * {@link #listIterator(int)}. If you override {@link #listIterator(int)}, you
+ * may wish to override {@link #lastIndexOf} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardLastIndexOf(@Nullable Object element) {
+ return Lists.lastIndexOfImpl(this, element);
+ }
+
+ /**
+ * A sensible default implementation of {@link #iterator}, in terms of
+ * {@link #listIterator()}. If you override {@link #listIterator()}, you may
+ * wish to override {@link #iterator} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected Iterator<E> standardIterator() {
+ return listIterator();
+ }
+
+ /**
+ * A sensible default implementation of {@link #listIterator()}, in terms of
+ * {@link #listIterator(int)}. If you override {@link #listIterator(int)}, you
+ * may wish to override {@link #listIterator()} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @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
+ * this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected ListIterator<E> standardListIterator(int start) {
+ return Lists.listIteratorImpl(this, start);
+ }
+
+ /**
+ * A sensible default implementation of {@link #subList(int, int)}. If you
+ * override any other methods, you may wish to override {@link #subList(int,
+ * int)} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected List<E> standardSubList(int fromIndex, int toIndex) {
+ return Lists.subListImpl(this, fromIndex, toIndex);
+ }
+
+ /**
+ * A sensible definition of {@link #equals(Object)} in terms of {@link #size}
+ * and {@link #iterator}. If you override either of those methods, you may
+ * wish to override {@link #equals(Object)} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardEquals(@Nullable Object object) {
+ return Lists.equalsImpl(this, object);
+ }
+
+ /**
+ * A sensible definition of {@link #hashCode} in terms of {@link #iterator}.
+ * If you override {@link #iterator}, you may wish to override {@link
+ * #hashCode} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardHashCode() {
+ return Lists.hashCodeImpl(this);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingListIterator.java b/guava/src/com/google/common/collect/ForwardingListIterator.java
new file mode 100644
index 0000000..e2ebe55
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingListIterator.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.ListIterator;
+
+/**
+ * A list iterator which forwards all its method calls to another list
+ * iterator. Subclasses should override one or more methods to modify the
+ * behavior of the backing iterator as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Mike Bostock
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingListIterator<E> extends ForwardingIterator<E>
+ implements ListIterator<E> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingListIterator() {}
+
+ @Override protected abstract ListIterator<E> delegate();
+
+ @Override
+ public void add(E element) {
+ delegate().add(element);
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return delegate().hasPrevious();
+ }
+
+ @Override
+ public int nextIndex() {
+ return delegate().nextIndex();
+ }
+
+ @Override
+ public E previous() {
+ return delegate().previous();
+ }
+
+ @Override
+ public int previousIndex() {
+ return delegate().previousIndex();
+ }
+
+ @Override
+ public void set(E element) {
+ delegate().set(element);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingListMultimap.java b/guava/src/com/google/common/collect/ForwardingListMultimap.java
new file mode 100644
index 0000000..3b1d55e
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingListMultimap.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * A list multimap which forwards all its method calls to another list multimap.
+ * Subclasses should override one or more methods to modify the behavior of
+ * the backing multimap as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Kurt Alfred Kluever
+ * @since 3.0
+ */
+@GwtCompatible
+public abstract class ForwardingListMultimap<K, V>
+ extends ForwardingMultimap<K, V> implements ListMultimap<K, V> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingListMultimap() {}
+
+ @Override protected abstract ListMultimap<K, V> delegate();
+
+ @Override public List<V> get(@Nullable K key) {
+ return delegate().get(key);
+ }
+
+ @Override public List<V> removeAll(@Nullable Object key) {
+ return delegate().removeAll(key);
+ }
+
+ @Override public List<V> replaceValues(K key, Iterable<? extends V> values) {
+ return delegate().replaceValues(key, values);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingMap.java b/guava/src/com/google/common/collect/ForwardingMap.java
new file mode 100644
index 0000000..a332b22
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingMap.java
@@ -0,0 +1,319 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Objects;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A map which forwards all its method calls to another 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 ForwardingMap} 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, where appropriate, use {@link
+ * Objects#equal} to test equality for both keys and values. This may not be
+ * the desired behavior for map implementations that use non-standard notions of
+ * key equality, such as a {@code SortedMap} whose comparator is not consistent
+ * with {@code equals}.
+ *
+ * <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 Kevin Bourrillion
+ * @author Jared Levy
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingMap<K, V> extends ForwardingObject
+ implements Map<K, V> {
+ // TODO(user): identify places where thread safety is actually lost
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingMap() {}
+
+ @Override protected abstract Map<K, V> delegate();
+
+ @Override
+ public int size() {
+ return delegate().size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return delegate().isEmpty();
+ }
+
+ @Override
+ public V remove(Object object) {
+ return delegate().remove(object);
+ }
+
+ @Override
+ public void clear() {
+ delegate().clear();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return delegate().containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return delegate().containsValue(value);
+ }
+
+ @Override
+ public V get(Object key) {
+ return delegate().get(key);
+ }
+
+ @Override
+ public V put(K key, V value) {
+ return delegate().put(key, value);
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> map) {
+ delegate().putAll(map);
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return delegate().keySet();
+ }
+
+ @Override
+ public Collection<V> values() {
+ return delegate().values();
+ }
+
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ return delegate().entrySet();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return object == this || delegate().equals(object);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+
+ /**
+ * A sensible definition of {@link #putAll(Map)} in terms of {@link
+ * #put(Object, Object)}. If you override {@link #put(Object, Object)}, you
+ * may wish to override {@link #putAll(Map)} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected void standardPutAll(Map<? extends K, ? extends V> map) {
+ Maps.putAllImpl(this, map);
+ }
+
+ /**
+ * A sensible, albeit inefficient, definition of {@link #remove} in terms of
+ * the {@code iterator} method of {@link #entrySet}. If you override {@link
+ * #entrySet}, you may wish to override {@link #remove} to forward to this
+ * implementation.
+ *
+ * <p>Alternately, you may wish to override {@link #remove} with {@code
+ * keySet().remove}, assuming that approach would not lead to an infinite
+ * loop.
+ *
+ * @since 7.0
+ */
+ @Beta protected V standardRemove(@Nullable Object key) {
+ Iterator<Entry<K, V>> entryIterator = entrySet().iterator();
+ while (entryIterator.hasNext()) {
+ Entry<K, V> entry = entryIterator.next();
+ if (Objects.equal(entry.getKey(), key)) {
+ V value = entry.getValue();
+ entryIterator.remove();
+ return value;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * A sensible definition of {@link #clear} in terms of the {@code iterator}
+ * method of {@link #entrySet}. In many cases, you may wish to override
+ * {@link #clear} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected void standardClear() {
+ Iterator<Entry<K, V>> entryIterator = entrySet().iterator();
+ while (entryIterator.hasNext()) {
+ entryIterator.next();
+ entryIterator.remove();
+ }
+ }
+
+ /**
+ * A sensible implementation of {@link Map#keySet} in terms of the following
+ * methods: {@link ForwardingMap#clear}, {@link ForwardingMap#containsKey},
+ * {@link ForwardingMap#isEmpty}, {@link ForwardingMap#remove}, {@link
+ * ForwardingMap#size}, and the {@link Set#iterator} method of {@link
+ * ForwardingMap#entrySet}. In many cases, you may wish to override {@link
+ * ForwardingMap#keySet} to forward to this implementation or a subclass
+ * thereof.
+ *
+ * @since 10.0
+ */
+ @Beta
+ protected class StandardKeySet extends Maps.KeySet<K, V> {
+ /** Constructor for use by subclasses. */
+ public StandardKeySet() {}
+
+ @Override
+ Map<K, V> map() {
+ return ForwardingMap.this;
+ }
+ }
+
+ /**
+ * A sensible, albeit inefficient, definition of {@link #containsKey} in terms
+ * of the {@code iterator} method of {@link #entrySet}. If you override {@link
+ * #entrySet}, you may wish to override {@link #containsKey} to forward to
+ * this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardContainsKey(@Nullable Object key) {
+ return Maps.containsKeyImpl(this, key);
+ }
+
+ /**
+ * A sensible implementation of {@link Map#values} in terms of the following
+ * methods: {@link ForwardingMap#clear}, {@link ForwardingMap#containsValue},
+ * {@link ForwardingMap#isEmpty}, {@link ForwardingMap#size}, and the {@link
+ * Set#iterator} method of {@link ForwardingMap#entrySet}. In many cases, you
+ * may wish to override {@link ForwardingMap#values} to forward to this
+ * implementation or a subclass thereof.
+ *
+ * @since 10.0
+ */
+ @Beta
+ protected class StandardValues extends Maps.Values<K, V> {
+ /** Constructor for use by subclasses. */
+ public StandardValues() {}
+
+ @Override
+ Map<K, V> map() {
+ return ForwardingMap.this;
+ }
+ }
+
+ /**
+ * A sensible definition of {@link #containsValue} in terms of the {@code
+ * iterator} method of {@link #entrySet}. If you override {@link #entrySet},
+ * you may wish to override {@link #containsValue} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardContainsValue(@Nullable Object value) {
+ return Maps.containsValueImpl(this, value);
+ }
+
+ /**
+ * A sensible implementation of {@link Map#entrySet} in terms of the following
+ * methods: {@link ForwardingMap#clear}, {@link ForwardingMap#containsKey},
+ * {@link ForwardingMap#get}, {@link ForwardingMap#isEmpty}, {@link
+ * ForwardingMap#remove}, and {@link ForwardingMap#size}. In many cases, you
+ * may wish to override {@link #entrySet} to forward to this implementation
+ * or a subclass thereof.
+ *
+ * @since 10.0
+ */
+ @Beta
+ protected abstract class StandardEntrySet extends Maps.EntrySet<K, V> {
+ /** Constructor for use by subclasses. */
+ public StandardEntrySet() {}
+
+ @Override
+ Map<K, V> map() {
+ return ForwardingMap.this;
+ }
+ }
+
+ /**
+ * A sensible definition of {@link #isEmpty} in terms of the {@code iterator}
+ * method of {@link #entrySet}. If you override {@link #entrySet}, you may
+ * wish to override {@link #isEmpty} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardIsEmpty() {
+ return !entrySet().iterator().hasNext();
+ }
+
+ /**
+ * A sensible definition of {@link #equals} in terms of the {@code equals}
+ * method of {@link #entrySet}. If you override {@link #entrySet}, you may
+ * wish to override {@link #equals} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardEquals(@Nullable Object object) {
+ return Maps.equalsImpl(this, object);
+ }
+
+ /**
+ * A sensible definition of {@link #hashCode} in terms of the {@code iterator}
+ * method of {@link #entrySet}. If you override {@link #entrySet}, you may
+ * wish to override {@link #hashCode} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardHashCode() {
+ return Sets.hashCodeImpl(entrySet());
+ }
+
+ /**
+ * A sensible definition of {@link #toString} in terms of the {@code iterator}
+ * method of {@link #entrySet}. If you override {@link #entrySet}, you may
+ * wish to override {@link #toString} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @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
new file mode 100644
index 0000000..ff201a5
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingMapEntry.java
@@ -0,0 +1,128 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Objects;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Nullable;
+
+/**
+ * A map entry which forwards all its method calls to another map entry.
+ * Subclasses should override one or more methods to modify the behavior of the
+ * backing map entry as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p><i>Warning:</i> The methods of {@code ForwardingMapEntry} forward
+ * <i>indiscriminately</i> to the methods of the delegate. For example,
+ * overriding {@link #getValue} alone <i>will not</i> change the behavior of
+ * {@link #equals}, which can lead to unexpected behavior. In this case, you
+ * should override {@code equals} as well, either providing your own
+ * implementation, or delegating to the provided {@code standardEquals} method.
+ *
+ * <p>Each of the {@code standard} methods, where appropriate, use {@link
+ * Objects#equal} to test equality for both keys and values. This may not be
+ * the desired behavior for map implementations that use non-standard notions of
+ * key equality, such as the entry of a {@code SortedMap} whose comparator is
+ * not consistent with {@code equals}.
+ *
+ * <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 Mike Bostock
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingMapEntry<K, V>
+ extends ForwardingObject implements Map.Entry<K, V> {
+ // TODO(user): identify places where thread safety is actually lost
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingMapEntry() {}
+
+ @Override protected abstract Map.Entry<K, V> delegate();
+
+ @Override
+ public K getKey() {
+ return delegate().getKey();
+ }
+
+ @Override
+ public V getValue() {
+ return delegate().getValue();
+ }
+
+ @Override
+ public V setValue(V value) {
+ return delegate().setValue(value);
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return delegate().equals(object);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+
+ /**
+ * A sensible definition of {@link #equals(Object)} in terms of {@link
+ * #getKey()} and {@link #getValue()}. If you override either of these
+ * methods, you may wish to override {@link #equals(Object)} to forward to
+ * this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardEquals(@Nullable Object object) {
+ if (object instanceof Entry) {
+ Entry<?, ?> that = (Entry<?, ?>) object;
+ return Objects.equal(this.getKey(), that.getKey())
+ && Objects.equal(this.getValue(), that.getValue());
+ }
+ return false;
+ }
+
+ /**
+ * A sensible definition of {@link #hashCode()} in terms of {@link #getKey()}
+ * and {@link #getValue()}. If you override either of these methods, you may
+ * wish to override {@link #hashCode()} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardHashCode() {
+ K k = getKey();
+ V v = getValue();
+ return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
+ }
+
+ /**
+ * A sensible definition of {@link #toString} in terms of {@link
+ * #getKey} and {@link #getValue}. If you override either of these
+ * methods, you may wish to override {@link #equals} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected String standardToString() {
+ return getKey() + "=" + getValue();
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingMultimap.java b/guava/src/com/google/common/collect/ForwardingMultimap.java
new file mode 100644
index 0000000..c860820
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingMultimap.java
@@ -0,0 +1,143 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A multimap which forwards all its method calls to another multimap.
+ * Subclasses should override one or more methods to modify the behavior of
+ * the backing multimap as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Robert Konigsberg
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingMultimap<K, V> extends ForwardingObject
+ implements Multimap<K, V> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingMultimap() {}
+
+ @Override protected abstract Multimap<K, V> delegate();
+
+ @Override
+ public Map<K, Collection<V>> asMap() {
+ return delegate().asMap();
+ }
+
+ @Override
+ public void clear() {
+ delegate().clear();
+ }
+
+ @Override
+ public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
+ return delegate().containsEntry(key, value);
+ }
+
+ @Override
+ public boolean containsKey(@Nullable Object key) {
+ return delegate().containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(@Nullable Object value) {
+ return delegate().containsValue(value);
+ }
+
+ @Override
+ public Collection<Entry<K, V>> entries() {
+ return delegate().entries();
+ }
+
+ @Override
+ public Collection<V> get(@Nullable K key) {
+ return delegate().get(key);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return delegate().isEmpty();
+ }
+
+ @Override
+ public Multiset<K> keys() {
+ return delegate().keys();
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return delegate().keySet();
+ }
+
+ @Override
+ public boolean put(K key, V value) {
+ return delegate().put(key, value);
+ }
+
+ @Override
+ public boolean putAll(K key, Iterable<? extends V> values) {
+ return delegate().putAll(key, values);
+ }
+
+ @Override
+ public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ return delegate().putAll(multimap);
+ }
+
+ @Override
+ public boolean remove(@Nullable Object key, @Nullable Object value) {
+ return delegate().remove(key, value);
+ }
+
+ @Override
+ public Collection<V> removeAll(@Nullable Object key) {
+ return delegate().removeAll(key);
+ }
+
+ @Override
+ public Collection<V> replaceValues(K key, Iterable<? extends V> values) {
+ return delegate().replaceValues(key, values);
+ }
+
+ @Override
+ public int size() {
+ return delegate().size();
+ }
+
+ @Override
+ public Collection<V> values() {
+ return delegate().values();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return object == this || delegate().equals(object);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingMultiset.java b/guava/src/com/google/common/collect/ForwardingMultiset.java
new file mode 100644
index 0000000..a1aa9c0
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingMultiset.java
@@ -0,0 +1,313 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Objects;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A multiset which forwards all its method calls to another multiset.
+ * Subclasses should override one or more methods to modify the behavior of the
+ * backing multiset as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p><b>Warning:</b> The methods of {@code ForwardingMultiset} forward
+ * <b>indiscriminately</b> to the methods of the delegate. For example,
+ * overriding {@link #add(Object, int)} alone <b>will not</b> change the
+ * behavior of {@link #add(Object)}, which can lead to unexpected behavior. In
+ * this case, you should override {@code add(Object)} as well, either providing
+ * your own implementation, or delegating to the provided {@code standardAdd}
+ * method.
+ *
+ * <p>The {@code standard} methods and any 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 Kevin Bourrillion
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
+ implements Multiset<E> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingMultiset() {}
+
+ @Override protected abstract Multiset<E> delegate();
+
+ @Override
+ public int count(Object element) {
+ return delegate().count(element);
+ }
+
+ @Override
+ public int add(E element, int occurrences) {
+ return delegate().add(element, occurrences);
+ }
+
+ @Override
+ public int remove(Object element, int occurrences) {
+ return delegate().remove(element, occurrences);
+ }
+
+ @Override
+ public Set<E> elementSet() {
+ return delegate().elementSet();
+ }
+
+ @Override
+ public Set<Entry<E>> entrySet() {
+ return delegate().entrySet();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return object == this || delegate().equals(object);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+
+ @Override
+ public int setCount(E element, int count) {
+ return delegate().setCount(element, count);
+ }
+
+ @Override
+ public boolean setCount(E element, int oldCount, int newCount) {
+ return delegate().setCount(element, oldCount, newCount);
+ }
+
+ /**
+ * A sensible definition of {@link #contains} in terms of {@link #count}. If
+ * you override {@link #count}, you may wish to override {@link #contains} to
+ * forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Override @Beta protected boolean standardContains(@Nullable Object object) {
+ return count(object) > 0;
+ }
+
+ /**
+ * A sensible definition of {@link #clear} in terms of the {@code iterator}
+ * method of {@link #entrySet}. If you override {@link #entrySet}, you may
+ * wish to override {@link #clear} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Override @Beta protected void standardClear() {
+ Iterator<Entry<E>> entryIterator = entrySet().iterator();
+ while (entryIterator.hasNext()) {
+ entryIterator.next();
+ entryIterator.remove();
+ }
+ }
+
+ /**
+ * A sensible, albeit inefficient, definition of {@link #count} in terms of
+ * {@link #entrySet}. If you override {@link #entrySet}, you may wish to
+ * override {@link #count} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardCount(@Nullable Object object) {
+ for (Entry<?> entry : this.entrySet()) {
+ if (Objects.equal(entry.getElement(), object)) {
+ return entry.getCount();
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * A sensible definition of {@link #add(Object)} in terms of {@link
+ * #add(Object, int)}. If you override {@link #add(Object, int)}, you may
+ * wish to override {@link #add(Object)} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardAdd(E element) {
+ add(element, 1);
+ return true;
+ }
+
+ /**
+ * A sensible definition of {@link #addAll(Collection)} in terms of {@link
+ * #add(Object)} and {@link #add(Object, int)}. If you override either of
+ * these methods, you may wish to override {@link #addAll(Collection)} to
+ * forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta @Override protected boolean standardAddAll(
+ Collection<? extends E> elementsToAdd) {
+ return Multisets.addAllImpl(this, elementsToAdd);
+ }
+
+ /**
+ * A sensible definition of {@link #remove(Object)} in terms of {@link
+ * #remove(Object, int)}. If you override {@link #remove(Object, int)}, you
+ * may wish to override {@link #remove(Object)} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta @Override protected boolean standardRemove(Object element) {
+ return remove(element, 1) > 0;
+ }
+
+ /**
+ * A sensible definition of {@link #removeAll} in terms of the {@code
+ * removeAll} method of {@link #elementSet}. If you override {@link
+ * #elementSet}, you may wish to override {@link #removeAll} to forward to
+ * this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta @Override protected boolean standardRemoveAll(
+ Collection<?> elementsToRemove) {
+ return Multisets.removeAllImpl(this, elementsToRemove);
+ }
+
+ /**
+ * A sensible definition of {@link #retainAll} in terms of the {@code
+ * retainAll} method of {@link #elementSet}. If you override {@link
+ * #elementSet}, you may wish to override {@link #retainAll} to forward to
+ * this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta @Override protected boolean standardRetainAll(
+ Collection<?> elementsToRetain) {
+ return Multisets.retainAllImpl(this, elementsToRetain);
+ }
+
+ /**
+ * A sensible definition of {@link #setCount(Object, int)} in terms of {@link
+ * #count(Object)}, {@link #add(Object, int)}, and {@link #remove(Object,
+ * int)}. {@link #entrySet()}. If you override any of these methods, you may
+ * wish to override {@link #setCount(Object, int)} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardSetCount(E element, int count) {
+ return Multisets.setCountImpl(this, element, count);
+ }
+
+ /**
+ * A sensible definition of {@link #setCount(Object, int, int)} in terms of
+ * {@link #count(Object)} and {@link #setCount(Object, int)}. If you override
+ * either of these methods, you may wish to override {@link #setCount(Object,
+ * int, int)} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardSetCount(
+ E element, int oldCount, int newCount) {
+ return Multisets.setCountImpl(this, element, oldCount, newCount);
+ }
+
+ /**
+ * A sensible implementation of {@link Multiset#elementSet} in terms of the
+ * following methods: {@link ForwardingMultiset#clear}, {@link
+ * ForwardingMultiset#contains}, {@link ForwardingMultiset#containsAll},
+ * {@link ForwardingMultiset#count}, {@link ForwardingMultiset#isEmpty}, the
+ * {@link Set#size} and {@link Set#iterator} methods of {@link
+ * ForwardingMultiset#entrySet}, and {@link ForwardingMultiset#remove(Object,
+ * int)}. In many situations, you may wish to override {@link
+ * ForwardingMultiset#elementSet} to forward to this implementation or a
+ * subclass thereof.
+ *
+ * @since 10.0
+ */
+ @Beta
+ protected class StandardElementSet extends Multisets.ElementSet<E> {
+ /** Constructor for use by subclasses. */
+ public StandardElementSet() {}
+
+ @Override
+ Multiset<E> multiset() {
+ return ForwardingMultiset.this;
+ }
+ }
+
+ /**
+ * A sensible definition of {@link #iterator} in terms of {@link #entrySet}
+ * and {@link #remove(Object)}. If you override either of these methods, you
+ * may wish to override {@link #iterator} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected Iterator<E> standardIterator() {
+ return Multisets.iteratorImpl(this);
+ }
+
+ /**
+ * A sensible, albeit inefficient, definition of {@link #size} in terms of
+ * {@link #entrySet}. If you override {@link #entrySet}, you may wish to
+ * override {@link #size} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardSize() {
+ return Multisets.sizeImpl(this);
+ }
+
+ /**
+ * A sensible, albeit inefficient, definition of {@link #size} in terms of
+ * {@code entrySet().size()} and {@link #count}. If you override either of
+ * these methods, you may wish to override {@link #size} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardEquals(@Nullable Object object) {
+ return Multisets.equalsImpl(this, object);
+ }
+
+ /**
+ * A sensible definition of {@link #hashCode} as {@code entrySet().hashCode()}
+ * . If you override {@link #entrySet}, you may wish to override {@link
+ * #hashCode} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardHashCode() {
+ return entrySet().hashCode();
+ }
+
+ /**
+ * A sensible definition of {@link #toString} as {@code entrySet().toString()}
+ * . If you override {@link #entrySet}, you may wish to override {@link
+ * #toString} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @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
new file mode 100644
index 0000000..bf9388b
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingNavigableMap.java
@@ -0,0 +1,412 @@
+/*
+ * 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;
+
+import javax.annotation.Nullable;
+
+/**
+ * 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
+ */
+@Beta
+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 poll(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 poll(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() {}
+
+ @Override
+ NavigableMap<K, V> map() {
+ return 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.
+ */
+ 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);
+ }
+
+ @Nullable
+ private static <T> T poll(Iterator<T> iterator) {
+ if (iterator.hasNext()) {
+ T result = iterator.next();
+ iterator.remove();
+ return result;
+ }
+ return null;
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingNavigableSet.java b/guava/src/com/google/common/collect/ForwardingNavigableSet.java
new file mode 100644
index 0000000..f89b1fb
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingNavigableSet.java
@@ -0,0 +1,250 @@
+/*
+ * 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;
+
+import javax.annotation.Nullable;
+
+/**
+ * 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
+ */
+@Beta
+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 poll(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 poll(delegate().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.
+ */
+ 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);
+ }
+
+ @Nullable
+ private E poll(Iterator<E> iterator) {
+ if (iterator.hasNext()) {
+ E result = iterator.next();
+ iterator.remove();
+ return result;
+ }
+ return null;
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingObject.java b/guava/src/com/google/common/collect/ForwardingObject.java
new file mode 100644
index 0000000..7fecdee
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingObject.java
@@ -0,0 +1,76 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+
+/**
+ * An abstract base class for implementing the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ * The {@link #delegate()} method must be overridden to return the instance
+ * being decorated.
+ *
+ * <p>This class does <i>not</i> forward the {@code hashCode} and {@code equals}
+ * methods through to the backing object, but relies on {@code Object}'s
+ * implementation. This is necessary to preserve the symmetry of {@code equals}.
+ * Custom definitions of equality are usually based on an interface, such as
+ * {@code Set} or {@code List}, so that the implementation of {@code equals} can
+ * cast the object being tested for equality to the custom interface. {@code
+ * ForwardingObject} implements no such custom interfaces directly; they
+ * are implemented only in subclasses. Therefore, forwarding {@code equals}
+ * would break symmetry, as the forwarding object might consider itself equal to
+ * the object being tested, but the reverse could not be true. This behavior is
+ * consistent with the JDK's collection wrappers, such as
+ * {@link java.util.Collections#unmodifiableCollection}. Use an
+ * interface-specific subclass of {@code ForwardingObject}, such as {@link
+ * ForwardingList}, to preserve equality behavior, or override {@code equals}
+ * directly.
+ *
+ * <p>The {@code toString} method is forwarded to the delegate. Although this
+ * class does not implement {@link Serializable}, a serializable subclass may be
+ * created since this class has a parameter-less constructor.
+ *
+ * @author Mike Bostock
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingObject {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingObject() {}
+
+ /**
+ * Returns the backing delegate instance that methods are forwarded to.
+ * Abstract subclasses generally override this method with an abstract method
+ * that has a more specific return type, such as {@link
+ * ForwardingSet#delegate}. Concrete subclasses override this method to supply
+ * the instance being decorated.
+ */
+ protected abstract Object delegate();
+
+ /**
+ * Returns the string representation generated by the delegate's
+ * {@code toString} method.
+ */
+ @Override public String toString() {
+ return delegate().toString();
+ }
+
+ /* No equals or hashCode. See class comments for details. */
+}
diff --git a/guava/src/com/google/common/collect/ForwardingQueue.java b/guava/src/com/google/common/collect/ForwardingQueue.java
new file mode 100644
index 0000000..3d30aaf
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingQueue.java
@@ -0,0 +1,123 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.NoSuchElementException;
+import java.util.Queue;
+
+/**
+ * A queue which forwards all its method calls to another queue. Subclasses
+ * should override one or more methods to modify the behavior of the backing
+ * queue as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p><b>Warning:</b> The methods of {@code ForwardingQueue} 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, 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 Mike Bostock
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingQueue<E> extends ForwardingCollection<E>
+ implements Queue<E> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingQueue() {}
+
+ @Override protected abstract Queue<E> delegate();
+
+ @Override
+ public boolean offer(E o) {
+ return delegate().offer(o);
+ }
+
+ @Override
+ public E poll() {
+ return delegate().poll();
+ }
+
+ @Override
+ public E remove() {
+ return delegate().remove();
+ }
+
+ @Override
+ public E peek() {
+ return delegate().peek();
+ }
+
+ @Override
+ public E element() {
+ return delegate().element();
+ }
+
+ /**
+ * A sensible definition of {@link #offer} in terms of {@link #add}. If you
+ * override {@link #add}, you may wish to override {@link #offer} to forward
+ * to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected boolean standardOffer(E e) {
+ try {
+ return add(e);
+ } catch (IllegalStateException caught) {
+ return false;
+ }
+ }
+
+ /**
+ * A sensible definition of {@link #peek} in terms of {@link #element}. If you
+ * override {@link #element}, you may wish to override {@link #peek} to
+ * forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected E standardPeek() {
+ try {
+ return element();
+ } catch (NoSuchElementException caught) {
+ return null;
+ }
+ }
+
+ /**
+ * A sensible definition of {@link #poll} in terms of {@link #remove}. If you
+ * override {@link #remove}, you may wish to override {@link #poll} to forward
+ * to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected E standardPoll() {
+ try {
+ return remove();
+ } catch (NoSuchElementException caught) {
+ return null;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingSet.java b/guava/src/com/google/common/collect/ForwardingSet.java
new file mode 100644
index 0000000..ef4b343
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingSet.java
@@ -0,0 +1,101 @@
+/*
+ * 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.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;
+
+/**
+ * A set which forwards all its method calls to another 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><b>Warning:</b> The methods of {@code ForwardingSet} 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
+ * #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>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 Kevin Bourrillion
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingSet<E> extends ForwardingCollection<E>
+ implements Set<E> {
+ // TODO(user): identify places where thread safety is actually lost
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingSet() {}
+
+ @Override protected abstract Set<E> delegate();
+
+ @Override public boolean equals(@Nullable Object object) {
+ return object == this || delegate().equals(object);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+
+ /**
+ * 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
+ */
+ @Beta protected boolean standardEquals(@Nullable Object object) {
+ return Sets.equalsImpl(this, object);
+ }
+
+ /**
+ * A sensible definition of {@link #hashCode} in terms of {@link #iterator}.
+ * If you override {@link #iterator}, you may wish to override {@link #equals}
+ * to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected int standardHashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingSetMultimap.java b/guava/src/com/google/common/collect/ForwardingSetMultimap.java
new file mode 100644
index 0000000..a923946
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingSetMultimap.java
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A set multimap which forwards all its method calls to another set multimap.
+ * Subclasses should override one or more methods to modify the behavior of
+ * the backing multimap as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Kurt Alfred Kluever
+ * @since 3.0
+ */
+@GwtCompatible
+public abstract class ForwardingSetMultimap<K, V>
+ extends ForwardingMultimap<K, V> implements SetMultimap<K, V> {
+
+ @Override protected abstract SetMultimap<K, V> delegate();
+
+ @Override public Set<Entry<K, V>> entries() {
+ return delegate().entries();
+ }
+
+ @Override public Set<V> get(@Nullable K key) {
+ return delegate().get(key);
+ }
+
+ @Override public Set<V> removeAll(@Nullable Object key) {
+ return delegate().removeAll(key);
+ }
+
+ @Override public Set<V> replaceValues(K key, Iterable<? extends V> values) {
+ return delegate().replaceValues(key, values);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingSortedMap.java b/guava/src/com/google/common/collect/ForwardingSortedMap.java
new file mode 100644
index 0000000..0808039
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingSortedMap.java
@@ -0,0 +1,171 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.SortedMap;
+
+import javax.annotation.Nullable;
+
+/**
+ * A sorted map which forwards all its method calls to another sorted map.
+ * Subclasses should override one or more methods to modify the behavior of
+ * the backing sorted 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 ForwardingSortedMap} 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, where appropriate, use the
+ * comparator of the map to test equality for both keys and values, unlike
+ * {@code ForwardingMap}.
+ *
+ * <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 Mike Bostock
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingSortedMap<K, V> extends ForwardingMap<K, V>
+ implements SortedMap<K, V> {
+ // TODO(user): identify places where thread safety is actually lost
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingSortedMap() {}
+
+ @Override protected abstract SortedMap<K, V> delegate();
+
+ @Override
+ public Comparator<? super K> comparator() {
+ return delegate().comparator();
+ }
+
+ @Override
+ public K firstKey() {
+ return delegate().firstKey();
+ }
+
+ @Override
+ public SortedMap<K, V> headMap(K toKey) {
+ return delegate().headMap(toKey);
+ }
+
+ @Override
+ public K lastKey() {
+ return delegate().lastKey();
+ }
+
+ @Override
+ public SortedMap<K, V> subMap(K fromKey, K toKey) {
+ return delegate().subMap(fromKey, toKey);
+ }
+
+ @Override
+ public SortedMap<K, V> tailMap(K fromKey) {
+ return delegate().tailMap(fromKey);
+ }
+
+ // unsafe, but worst case is a CCE is thrown, which callers will be expecting
+ @SuppressWarnings("unchecked")
+ private int unsafeCompare(Object k1, Object k2) {
+ Comparator<? super K> comparator = comparator();
+ if (comparator == null) {
+ return ((Comparable<Object>) k1).compareTo(k2);
+ } else {
+ return ((Comparator<Object>) comparator).compare(k1, k2);
+ }
+ }
+
+ /**
+ * A sensible definition of {@link #containsKey} in terms of the {@code
+ * firstKey()} method of {@link #tailMap}. If you override {@link #tailMap},
+ * you may wish to override {@link #containsKey} to forward to this
+ * implementation.
+ *
+ * @since 7.0
+ */
+ @Override @Beta protected boolean standardContainsKey(@Nullable Object key) {
+ try {
+ // any CCE will be caught
+ @SuppressWarnings("unchecked")
+ SortedMap<Object, V> self = (SortedMap<Object, V>) this;
+ Object ceilingKey = self.tailMap(key).firstKey();
+ return unsafeCompare(ceilingKey, key) == 0;
+ } catch (ClassCastException e) {
+ return false;
+ } catch (NoSuchElementException e) {
+ return false;
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+
+ /**
+ * A sensible definition of {@link #remove} in terms of the {@code
+ * iterator()} of the {@code entrySet()} of {@link #tailMap}. If you override
+ * {@link #tailMap}, you may wish to override {@link #remove} to forward
+ * to this implementation.
+ *
+ * @since 7.0
+ */
+ @Override @Beta protected V standardRemove(@Nullable Object key) {
+ try {
+ // any CCE will be caught
+ @SuppressWarnings("unchecked")
+ SortedMap<Object, V> self = (SortedMap<Object, V>) this;
+ Iterator<Entry<Object, V>> entryIterator =
+ self.tailMap(key).entrySet().iterator();
+ if (entryIterator.hasNext()) {
+ Entry<Object, V> ceilingEntry = entryIterator.next();
+ if (unsafeCompare(ceilingEntry.getKey(), key) == 0) {
+ V value = ceilingEntry.getValue();
+ entryIterator.remove();
+ return value;
+ }
+ }
+ } catch (ClassCastException e) {
+ return null;
+ } catch (NullPointerException e) {
+ return null;
+ }
+ return null;
+ }
+
+ /**
+ * A sensible default implementation of {@link #subMap(Object, Object)} in
+ * terms of {@link #headMap(Object)} and {@link #tailMap(Object)}. In some
+ * situations, you may wish to override {@link #subMap(Object, Object)} to
+ * forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected SortedMap<K, V> standardSubMap(K fromKey, K toKey) {
+ return tailMap(fromKey).headMap(toKey);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingSortedSet.java b/guava/src/com/google/common/collect/ForwardingSortedSet.java
new file mode 100644
index 0000000..756d9af
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingSortedSet.java
@@ -0,0 +1,166 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.SortedSet;
+
+import javax.annotation.Nullable;
+
+/**
+ * A sorted set which forwards all its method calls to another sorted set.
+ * Subclasses should override one or more methods to modify the behavior of the
+ * backing sorted 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 ForwardingSortedSet} 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, where appropriate, 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 Mike Bostock
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public abstract class ForwardingSortedSet<E> extends ForwardingSet<E>
+ implements SortedSet<E> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingSortedSet() {}
+
+ @Override protected abstract SortedSet<E> delegate();
+
+ @Override
+ public Comparator<? super E> comparator() {
+ return delegate().comparator();
+ }
+
+ @Override
+ public E first() {
+ return delegate().first();
+ }
+
+ @Override
+ public SortedSet<E> headSet(E toElement) {
+ return delegate().headSet(toElement);
+ }
+
+ @Override
+ public E last() {
+ return delegate().last();
+ }
+
+ @Override
+ public SortedSet<E> subSet(E fromElement, E toElement) {
+ return delegate().subSet(fromElement, toElement);
+ }
+
+ @Override
+ public SortedSet<E> tailSet(E fromElement) {
+ return delegate().tailSet(fromElement);
+ }
+
+ // unsafe, but worst case is a CCE is thrown, which callers will be expecting
+ @SuppressWarnings("unchecked")
+ private int unsafeCompare(Object o1, Object o2) {
+ Comparator<? super E> comparator = comparator();
+ return (comparator == null)
+ ? ((Comparable<Object>) o1).compareTo(o2)
+ : ((Comparator<Object>) comparator).compare(o1, o2);
+ }
+
+ /**
+ * A sensible definition of {@link #contains} in terms of the {@code first()}
+ * method of {@link #tailSet}. If you override {@link #tailSet}, you may wish
+ * to override {@link #contains} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Override @Beta protected boolean standardContains(@Nullable Object object) {
+ try {
+ // any ClassCastExceptions are caught
+ @SuppressWarnings("unchecked")
+ SortedSet<Object> self = (SortedSet<Object>) this;
+ Object ceiling = self.tailSet(object).first();
+ return unsafeCompare(ceiling, object) == 0;
+ } catch (ClassCastException e) {
+ return false;
+ } catch (NoSuchElementException e) {
+ return false;
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+
+ /**
+ * A sensible definition of {@link #remove} in terms of the {@code iterator()}
+ * method of {@link #tailSet}. If you override {@link #tailSet}, you may wish
+ * to override {@link #remove} to forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Override @Beta protected boolean standardRemove(@Nullable Object object) {
+ try {
+ // any ClassCastExceptions are caught
+ @SuppressWarnings("unchecked")
+ SortedSet<Object> self = (SortedSet<Object>) this;
+ Iterator<Object> iterator = self.tailSet(object).iterator();
+ if (iterator.hasNext()) {
+ Object ceiling = iterator.next();
+ if (unsafeCompare(ceiling, object) == 0) {
+ iterator.remove();
+ return true;
+ }
+ }
+ } catch (ClassCastException e) {
+ return false;
+ } catch (NullPointerException e) {
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * A sensible default implementation of {@link #subSet(Object, Object)} in
+ * terms of {@link #headSet(Object)} and {@link #tailSet(Object)}. In some
+ * situations, you may wish to override {@link #subSet(Object, Object)} to
+ * forward to this implementation.
+ *
+ * @since 7.0
+ */
+ @Beta protected SortedSet<E> standardSubSet(E fromElement, E toElement) {
+ return tailSet(fromElement).headSet(toElement);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingSortedSetMultimap.java b/guava/src/com/google/common/collect/ForwardingSortedSetMultimap.java
new file mode 100644
index 0000000..d90c305
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingSortedSetMultimap.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import java.util.Comparator;
+import java.util.SortedSet;
+
+import javax.annotation.Nullable;
+
+/**
+ * A sorted set multimap which forwards all its method calls to another sorted
+ * set multimap. Subclasses should override one or more methods to modify the
+ * behavior of the backing multimap as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Kurt Alfred Kluever
+ * @since 3.0
+ */
+@GwtCompatible
+public abstract class ForwardingSortedSetMultimap<K, V>
+ extends ForwardingSetMultimap<K, V> implements SortedSetMultimap<K, V> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingSortedSetMultimap() {}
+
+ @Override protected abstract SortedSetMultimap<K, V> delegate();
+
+ @Override public SortedSet<V> get(@Nullable K key) {
+ return delegate().get(key);
+ }
+
+ @Override public SortedSet<V> removeAll(@Nullable Object key) {
+ return delegate().removeAll(key);
+ }
+
+ @Override public SortedSet<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ return delegate().replaceValues(key, values);
+ }
+
+ @Override public Comparator<? super V> valueComparator() {
+ return delegate().valueComparator();
+ }
+}
diff --git a/guava/src/com/google/common/collect/ForwardingTable.java b/guava/src/com/google/common/collect/ForwardingTable.java
new file mode 100644
index 0000000..92cc876
--- /dev/null
+++ b/guava/src/com/google/common/collect/ForwardingTable.java
@@ -0,0 +1,144 @@
+/*
+ * 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;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A table which forwards all its method calls to another table. 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>.
+ *
+ * @author Gregory Kick
+ * @since 7.0
+ */
+@GwtCompatible
+public abstract class ForwardingTable<R, C, V> extends ForwardingObject
+ implements Table<R, C, V> {
+ /** Constructor for use by subclasses. */
+ protected ForwardingTable() {}
+
+ @Override protected abstract Table<R, C, V> delegate();
+
+ @Override
+ public Set<Cell<R, C, V>> cellSet() {
+ return delegate().cellSet();
+ }
+
+ @Override
+ public void clear() {
+ delegate().clear();
+ }
+
+ @Override
+ public Map<R, V> column(C columnKey) {
+ return delegate().column(columnKey);
+ }
+
+ @Override
+ public Set<C> columnKeySet() {
+ return delegate().columnKeySet();
+ }
+
+ @Override
+ public Map<C, Map<R, V>> columnMap() {
+ return delegate().columnMap();
+ }
+
+ @Override
+ public boolean contains(Object rowKey, Object columnKey) {
+ return delegate().contains(rowKey, columnKey);
+ }
+
+ @Override
+ public boolean containsColumn(Object columnKey) {
+ return delegate().containsColumn(columnKey);
+ }
+
+ @Override
+ public boolean containsRow(Object rowKey) {
+ return delegate().containsRow(rowKey);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return delegate().containsValue(value);
+ }
+
+ @Override
+ public V get(Object rowKey, Object columnKey) {
+ return delegate().get(rowKey, columnKey);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return delegate().isEmpty();
+ }
+
+ @Override
+ public V put(R rowKey, C columnKey, V value) {
+ return delegate().put(rowKey, columnKey, value);
+ }
+
+ @Override
+ public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
+ delegate().putAll(table);
+ }
+
+ @Override
+ public V remove(Object rowKey, Object columnKey) {
+ return delegate().remove(rowKey, columnKey);
+ }
+
+ @Override
+ public Map<C, V> row(R rowKey) {
+ return delegate().row(rowKey);
+ }
+
+ @Override
+ public Set<R> rowKeySet() {
+ return delegate().rowKeySet();
+ }
+
+ @Override
+ public Map<R, Map<C, V>> rowMap() {
+ return delegate().rowMap();
+ }
+
+ @Override
+ public int size() {
+ return delegate().size();
+ }
+
+ @Override
+ public Collection<V> values() {
+ return delegate().values();
+ }
+
+ @Override public boolean equals(Object obj) {
+ return (obj == this) || delegate().equals(obj);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+}
diff --git a/guava/src/com/google/common/collect/GeneralRange.java b/guava/src/com/google/common/collect/GeneralRange.java
new file mode 100644
index 0000000..c083d83
--- /dev/null
+++ b/guava/src/com/google/common/collect/GeneralRange.java
@@ -0,0 +1,304 @@
+/*
+ * 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 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;
+
+/**
+ * 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)
+final class GeneralRange<T> implements Serializable {
+ /**
+ * Converts a Range to a GeneralRange.
+ */
+ static <T extends Comparable> GeneralRange<T> from(Range<T> range) {
+ @Nullable
+ T lowerEndpoint = range.hasLowerBound() ? range.lowerEndpoint() : null;
+ BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : OPEN;
+
+ @Nullable
+ T upperEndpoint = range.hasUpperBound() ? range.upperEndpoint() : null;
+ BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : OPEN;
+ return new GeneralRange<T>(Ordering.natural(), range.hasLowerBound(), lowerEndpoint,
+ lowerBoundType, range.hasUpperBound(), upperEndpoint, upperBoundType);
+ }
+
+ /**
+ * Returns the whole range relative to the specified comparator.
+ */
+ static <T> GeneralRange<T> all(Comparator<? super T> comparator) {
+ return new GeneralRange<T>(comparator, false, null, OPEN, false, null, OPEN);
+ }
+
+ /**
+ * Returns everything above the endpoint relative to the specified comparator, with the specified
+ * endpoint behavior.
+ */
+ static <T> GeneralRange<T> downTo(Comparator<? super T> comparator, @Nullable T endpoint,
+ BoundType boundType) {
+ return new GeneralRange<T>(comparator, true, endpoint, boundType, false, null, OPEN);
+ }
+
+ /**
+ * Returns everything below the endpoint relative to the specified comparator, with the specified
+ * endpoint behavior.
+ */
+ static <T> GeneralRange<T> upTo(Comparator<? super T> comparator, @Nullable T endpoint,
+ BoundType boundType) {
+ return new GeneralRange<T>(comparator, false, null, OPEN, true, endpoint, boundType);
+ }
+
+ /**
+ * Returns everything between the endpoints relative to the specified comparator, with the
+ * specified endpoint behavior.
+ */
+ static <T> GeneralRange<T> range(Comparator<? super T> comparator, @Nullable T lower,
+ BoundType lowerType, @Nullable T upper, BoundType upperType) {
+ return new GeneralRange<T>(comparator, true, lower, lowerType, true, upper, upperType);
+ }
+
+ private final Comparator<? super T> comparator;
+ private final boolean hasLowerBound;
+ @Nullable
+ private final T lowerEndpoint;
+ private final BoundType lowerBoundType;
+ private final boolean hasUpperBound;
+ @Nullable
+ private final T upperEndpoint;
+ private final BoundType upperBoundType;
+
+ private GeneralRange(Comparator<? super T> comparator, boolean hasLowerBound,
+ @Nullable T lowerEndpoint, BoundType lowerBoundType, boolean hasUpperBound,
+ @Nullable T upperEndpoint, BoundType upperBoundType) {
+ this.comparator = checkNotNull(comparator);
+ this.hasLowerBound = hasLowerBound;
+ this.hasUpperBound = hasUpperBound;
+ this.lowerEndpoint = lowerEndpoint;
+ this.lowerBoundType = checkNotNull(lowerBoundType);
+ this.upperEndpoint = upperEndpoint;
+ this.upperBoundType = checkNotNull(upperBoundType);
+
+ if (hasLowerBound) {
+ comparator.compare(lowerEndpoint, lowerEndpoint);
+ }
+ if (hasUpperBound) {
+ comparator.compare(upperEndpoint, upperEndpoint);
+ }
+ if (hasLowerBound && hasUpperBound) {
+ int cmp = comparator.compare(lowerEndpoint, upperEndpoint);
+ // be consistent with Range
+ checkArgument(cmp <= 0, "lowerEndpoint (%s) > upperEndpoint (%s)", lowerEndpoint,
+ upperEndpoint);
+ if (cmp == 0) {
+ checkArgument(lowerBoundType != OPEN | upperBoundType != OPEN);
+ }
+ }
+ }
+
+ Comparator<? super T> comparator() {
+ return comparator;
+ }
+
+ boolean hasLowerBound() {
+ return hasLowerBound;
+ }
+
+ boolean hasUpperBound() {
+ return hasUpperBound;
+ }
+
+ boolean isEmpty() {
+ return (hasUpperBound() && tooLow(getUpperEndpoint()))
+ || (hasLowerBound() && tooHigh(getLowerEndpoint()));
+ }
+
+ boolean tooLow(@Nullable T t) {
+ if (!hasLowerBound()) {
+ return false;
+ }
+ T lbound = getLowerEndpoint();
+ int cmp = comparator.compare(t, lbound);
+ return cmp < 0 | (cmp == 0 & getLowerBoundType() == OPEN);
+ }
+
+ boolean tooHigh(@Nullable T t) {
+ if (!hasUpperBound()) {
+ return false;
+ }
+ T ubound = getUpperEndpoint();
+ int cmp = comparator.compare(t, ubound);
+ return cmp > 0 | (cmp == 0 & getUpperBoundType() == OPEN);
+ }
+
+ boolean contains(@Nullable T t) {
+ return !tooLow(t) && !tooHigh(t);
+ }
+
+ /**
+ * Returns the intersection of the two ranges, or an empty range if their intersection is empty.
+ */
+ GeneralRange<T> intersect(GeneralRange<T> other) {
+ checkNotNull(other);
+ checkArgument(comparator.equals(other.comparator));
+
+ boolean hasLowBound = this.hasLowerBound;
+ @Nullable
+ T lowEnd = getLowerEndpoint();
+ BoundType lowType = getLowerBoundType();
+ if (!hasLowerBound()) {
+ hasLowBound = other.hasLowerBound;
+ lowEnd = other.getLowerEndpoint();
+ lowType = other.getLowerBoundType();
+ } 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();
+ }
+ }
+
+ boolean hasUpBound = this.hasUpperBound;
+ @Nullable
+ T upEnd = getUpperEndpoint();
+ BoundType upType = getUpperBoundType();
+ if (!hasUpperBound()) {
+ hasUpBound = other.hasUpperBound;
+ upEnd = other.getUpperEndpoint();
+ upType = other.getUpperBoundType();
+ } 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();
+ }
+ }
+
+ if (hasLowBound && hasUpBound) {
+ int cmp = comparator.compare(lowEnd, upEnd);
+ if (cmp > 0 || (cmp == 0 && lowType == OPEN && upType == OPEN)) {
+ // force allowed empty range
+ lowEnd = upEnd;
+ lowType = OPEN;
+ upType = CLOSED;
+ }
+ }
+
+ return new GeneralRange<T>(comparator, hasLowBound, lowEnd, lowType, hasUpBound, upEnd, upType);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ 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());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(comparator, getLowerEndpoint(), getLowerBoundType(), getUpperEndpoint(),
+ getUpperBoundType());
+ }
+
+ private transient GeneralRange<T> reverse;
+
+ /**
+ * Returns the same range relative to the reversed comparator.
+ */
+ 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.reverse = this;
+ return this.reverse = result;
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(comparator).append(":");
+ switch (getLowerBoundType()) {
+ case CLOSED:
+ builder.append('[');
+ break;
+ case OPEN:
+ builder.append('(');
+ break;
+ }
+ if (hasLowerBound()) {
+ builder.append(getLowerEndpoint());
+ } else {
+ builder.append("-\u221e");
+ }
+ builder.append(',');
+ if (hasUpperBound()) {
+ builder.append(getUpperEndpoint());
+ } else {
+ builder.append("\u221e");
+ }
+ switch (getUpperBoundType()) {
+ case CLOSED:
+ builder.append(']');
+ break;
+ case OPEN:
+ builder.append(')');
+ break;
+ }
+ return builder.toString();
+ }
+
+ T getLowerEndpoint() {
+ return lowerEndpoint;
+ }
+
+ BoundType getLowerBoundType() {
+ return lowerBoundType;
+ }
+
+ T getUpperEndpoint() {
+ return upperEndpoint;
+ }
+
+ BoundType getUpperBoundType() {
+ return upperBoundType;
+ }
+}
diff --git a/guava/src/com/google/common/collect/GenericMapMaker.java b/guava/src/com/google/common/collect/GenericMapMaker.java
new file mode 100644
index 0000000..65bfa15
--- /dev/null
+++ b/guava/src/com/google/common/collect/GenericMapMaker.java
@@ -0,0 +1,143 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.collect.MapMaker.RemovalListener;
+import com.google.common.collect.MapMaker.RemovalNotification;
+
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A class exactly like {@link MapMaker}, except restricted in the types of maps it can build.
+ * For the most part, you should probably just ignore the existence of this class.
+ *
+ * @param <K0> the base type for all key types of maps built by this map maker
+ * @param <V0> the base type for all value types of maps built by this map maker
+ * @author Kevin Bourrillion
+ * @since 7.0
+ */
+@Beta
+@GwtCompatible(emulated = true)
+public abstract class GenericMapMaker<K0, V0> {
+ @GwtIncompatible("To be supported")
+ enum NullListener implements RemovalListener<Object, Object> {
+ INSTANCE;
+
+ @Override
+ public void onRemoval(RemovalNotification<Object, Object> notification) {}
+ }
+
+ // Set by MapMaker, but sits in this class to preserve the type relationship
+ @GwtIncompatible("To be supported")
+ RemovalListener<K0, V0> removalListener;
+
+ // No subclasses but our own
+ GenericMapMaker() {}
+
+ /**
+ * See {@link MapMaker#keyEquivalence}.
+ */
+ @GwtIncompatible("To be supported")
+ abstract GenericMapMaker<K0, V0> keyEquivalence(Equivalence<Object> equivalence);
+
+ /**
+ * See {@link MapMaker#initialCapacity}.
+ */
+ public abstract GenericMapMaker<K0, V0> initialCapacity(int initialCapacity);
+
+ /**
+ * See {@link MapMaker#maximumSize}.
+ */
+ abstract GenericMapMaker<K0, V0> maximumSize(int maximumSize);
+
+ /**
+ * See {@link MapMaker#concurrencyLevel}.
+ */
+ public abstract GenericMapMaker<K0, V0> concurrencyLevel(int concurrencyLevel);
+
+ /**
+ * See {@link MapMaker#weakKeys}.
+ */
+ @GwtIncompatible("java.lang.ref.WeakReference")
+ public abstract GenericMapMaker<K0, V0> weakKeys();
+
+ /**
+ * 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")
+ public abstract GenericMapMaker<K0, V0> weakValues();
+
+ /**
+ * See {@link MapMaker#softValues}.
+ */
+ @GwtIncompatible("java.lang.ref.SoftReference")
+ public abstract GenericMapMaker<K0, V0> softValues();
+
+ /**
+ * See {@link MapMaker#expireAfterWrite}.
+ */
+ abstract GenericMapMaker<K0, V0> expireAfterWrite(long duration, TimeUnit unit);
+
+ /**
+ * See {@link MapMaker#expireAfterAccess}.
+ */
+ @GwtIncompatible("To be supported")
+ abstract GenericMapMaker<K0, V0> expireAfterAccess(long duration, TimeUnit unit);
+
+ /*
+ * Note that MapMaker's removalListener() is not here, because once you're interacting with a
+ * GenericMapMaker you've already called that, and shouldn't be calling it again.
+ */
+
+ @SuppressWarnings("unchecked") // safe covariant cast
+ @GwtIncompatible("To be supported")
+ <K extends K0, V extends V0> RemovalListener<K, V> getRemovalListener() {
+ return (RemovalListener<K, V>) Objects.firstNonNull(removalListener, NullListener.INSTANCE);
+ }
+
+ /**
+ * See {@link MapMaker#makeMap}.
+ */
+ public abstract <K extends K0, V extends V0> ConcurrentMap<K, V> makeMap();
+
+ /**
+ * See {@link MapMaker#makeCustomMap}.
+ */
+ @GwtIncompatible("MapMakerInternalMap")
+ abstract <K, V> MapMakerInternalMap<K, V> makeCustomMap();
+
+ /**
+ * See {@link MapMaker#makeComputingMap}.
+ */
+ @Deprecated
+ public abstract <K extends K0, V extends V0> ConcurrentMap<K, V> makeComputingMap(
+ Function<? super K, ? extends V> computingFunction);
+}
diff --git a/guava/src/com/google/common/collect/GwtTransient.java b/guava/src/com/google/common/collect/GwtTransient.java
new file mode 100644
index 0000000..a9a15e9
--- /dev/null
+++ b/guava/src/com/google/common/collect/GwtTransient.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 static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Private replacement for {@link com.google.gwt.user.client.rpc.GwtTransient}
+ * to work around build-system quirks. This annotation should be used
+ * <b>only</b> in {@code com.google.common.collect}.
+ */
+@Documented
+@GwtCompatible
+@Retention(RUNTIME)
+@Target(FIELD)
+@interface GwtTransient {
+}
diff --git a/guava/src/com/google/common/collect/HashBasedTable.java b/guava/src/com/google/common/collect/HashBasedTable.java
new file mode 100644
index 0000000..4944174
--- /dev/null
+++ b/guava/src/com/google/common/collect/HashBasedTable.java
@@ -0,0 +1,148 @@
+/*
+ * 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.checkArgument;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Supplier;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * Implementation of {@link Table} using hash tables.
+ *
+ * <p>The views returned by {@link #column}, {@link #columnKeySet()}, and {@link
+ * #columnMap()} have iterators that don't support {@code remove()}. Otherwise,
+ * all optional operations are supported. Null row keys, columns keys, and
+ * values are not supported.
+ *
+ * <p>Lookups by row key are often faster than lookups by column key, because
+ * the data is stored in a {@code Map<R, Map<C, V>>}. A method call like {@code
+ * column(columnKey).get(rowKey)} still runs quickly, since the row key is
+ * provided. However, {@code column(columnKey).size()} takes longer, since an
+ * iteration across all row keys occurs.
+ *
+ * <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)
+public class HashBasedTable<R, C, V> extends StandardTable<R, C, V> {
+ private static class Factory<C, V>
+ implements Supplier<Map<C, V>>, Serializable {
+ final int expectedSize;
+ Factory(int expectedSize) {
+ this.expectedSize = expectedSize;
+ }
+ @Override
+ public Map<C, V> get() {
+ return Maps.newHashMapWithExpectedSize(expectedSize);
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Creates an empty {@code HashBasedTable}.
+ */
+ public static <R, C, V> HashBasedTable<R, C, V> create() {
+ return new HashBasedTable<R, C, V>(
+ new HashMap<R, Map<C, V>>(), new Factory<C, V>(0));
+ }
+
+ /**
+ * Creates an empty {@code HashBasedTable} with the specified map sizes.
+ *
+ * @param expectedRows the expected number of distinct row keys
+ * @param expectedCellsPerRow the expected number of column key / value
+ * mappings in each row
+ * @throws IllegalArgumentException if {@code expectedRows} or {@code
+ * expectedCellsPerRow} is negative
+ */
+ public static <R, C, V> HashBasedTable<R, C, V> create(
+ int expectedRows, int expectedCellsPerRow) {
+ checkArgument(expectedCellsPerRow >= 0);
+ Map<R, Map<C, V>> backingMap =
+ Maps.newHashMapWithExpectedSize(expectedRows);
+ return new HashBasedTable<R, C, V>(
+ backingMap, new Factory<C, V>(expectedCellsPerRow));
+ }
+
+ /**
+ * Creates a {@code HashBasedTable} with the same mappings as the specified
+ * table.
+ *
+ * @param table the table to copy
+ * @throws NullPointerException if any of the row keys, column keys, or values
+ * in {@code table} is null
+ */
+ public static <R, C, V> HashBasedTable<R, C, V> create(
+ Table<? extends R, ? extends C, ? extends V> table) {
+ HashBasedTable<R, C, V> result = create();
+ result.putAll(table);
+ return result;
+ }
+
+ HashBasedTable(Map<R, Map<C, V>> backingMap, Factory<C, V> factory) {
+ super(backingMap, factory);
+ }
+
+ // Overriding so NullPointerTester test passes.
+
+ @Override public boolean contains(
+ @Nullable Object rowKey, @Nullable Object columnKey) {
+ return super.contains(rowKey, columnKey);
+ }
+
+ @Override public boolean containsColumn(@Nullable Object columnKey) {
+ return super.containsColumn(columnKey);
+ }
+
+ @Override public boolean containsRow(@Nullable Object rowKey) {
+ return super.containsRow(rowKey);
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ return super.containsValue(value);
+ }
+
+ @Override public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
+ return super.get(rowKey, columnKey);
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ return super.equals(obj);
+ }
+
+ @Override public V remove(
+ @Nullable Object rowKey, @Nullable Object columnKey) {
+ return super.remove(rowKey, columnKey);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/HashBiMap.java b/guava/src/com/google/common/collect/HashBiMap.java
new file mode 100644
index 0000000..3b7a3ca
--- /dev/null
+++ b/guava/src/com/google/common/collect/HashBiMap.java
@@ -0,0 +1,118 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * 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.
+ *
+ * <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)
+ */
+@GwtCompatible(emulated = true)
+public final class HashBiMap<K, V> extends AbstractBiMap<K, V> {
+
+ /**
+ * Returns a new, empty {@code HashBiMap} with the default initial capacity
+ * (16).
+ */
+ public static <K, V> HashBiMap<K, V> create() {
+ 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
+ */
+ 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.
+ */
+ 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 HashBiMap() {
+ super(new HashMap<K, V>(), new HashMap<V, K>());
+ }
+
+ private HashBiMap(int expectedSize) {
+ super(
+ Maps.<K, V>newHashMapWithExpectedSize(expectedSize),
+ Maps.<V, K>newHashMapWithExpectedSize(expectedSize));
+ }
+
+ // Override these two methods to show that keys and values may be null
+
+ @Override public V put(@Nullable K key, @Nullable V value) {
+ return super.put(key, value);
+ }
+
+ @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.
+ */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMap(this, stream);
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ int size = Serialization.readCount(stream);
+ setDelegates(Maps.<K, V>newHashMapWithExpectedSize(size),
+ Maps.<V, K>newHashMapWithExpectedSize(size));
+ Serialization.populateMap(this, stream, size);
+ }
+
+ @GwtIncompatible("Not needed in emulated source")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/HashMultimap.java b/guava/src/com/google/common/collect/HashMultimap.java
new file mode 100644
index 0000000..bab2a05
--- /dev/null
+++ b/guava/src/com/google/common/collect/HashMultimap.java
@@ -0,0 +1,142 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Implementation of {@link Multimap} using hash tables.
+ *
+ * <p>The multimap does not store duplicate key-value pairs. Adding a new
+ * key-value pair equal to an existing key-value pair has no effect.
+ *
+ * <p>Keys and values may be null. All optional multimap methods are supported,
+ * and all returned views are modifiable.
+ *
+ * <p>This class is not threadsafe when any concurrent operations update the
+ * multimap. Concurrent read operations will work correctly. To allow concurrent
+ * update operations, wrap your multimap with a call to {@link
+ * Multimaps#synchronizedSetMultimap}.
+ *
+ * @author Jared Levy
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+public final class HashMultimap<K, V> extends AbstractSetMultimap<K, V> {
+ private static final int DEFAULT_VALUES_PER_KEY = 2;
+
+ @VisibleForTesting
+ transient int expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
+
+ /**
+ * Creates a new, empty {@code HashMultimap} with the default initial
+ * capacities.
+ */
+ public static <K, V> HashMultimap<K, V> create() {
+ return new HashMultimap<K, V>();
+ }
+
+ /**
+ * Constructs an empty {@code HashMultimap} with enough capacity to hold the
+ * specified numbers of keys and values without rehashing.
+ *
+ * @param expectedKeys the expected number of distinct keys
+ * @param expectedValuesPerKey the expected average number of values per key
+ * @throws IllegalArgumentException if {@code expectedKeys} or {@code
+ * expectedValuesPerKey} is negative
+ */
+ public static <K, V> HashMultimap<K, V> create(
+ int expectedKeys, int expectedValuesPerKey) {
+ return new HashMultimap<K, V>(expectedKeys, expectedValuesPerKey);
+ }
+
+ /**
+ * Constructs a {@code HashMultimap} with the same mappings as the specified
+ * multimap. If a key-value mapping appears multiple times in the input
+ * multimap, it only appears once in the constructed multimap.
+ *
+ * @param multimap the multimap whose contents are copied to this multimap
+ */
+ public static <K, V> HashMultimap<K, V> create(
+ Multimap<? extends K, ? extends V> multimap) {
+ return new HashMultimap<K, V>(multimap);
+ }
+
+ private HashMultimap() {
+ super(new HashMap<K, Collection<V>>());
+ }
+
+ private HashMultimap(int expectedKeys, int expectedValuesPerKey) {
+ super(Maps.<K, Collection<V>>newHashMapWithExpectedSize(expectedKeys));
+ Preconditions.checkArgument(expectedValuesPerKey >= 0);
+ this.expectedValuesPerKey = expectedValuesPerKey;
+ }
+
+ private HashMultimap(Multimap<? extends K, ? extends V> multimap) {
+ super(Maps.<K, Collection<V>>newHashMapWithExpectedSize(
+ multimap.keySet().size()));
+ putAll(multimap);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Creates an empty {@code HashSet} for a collection of values for one key.
+ *
+ * @return a new {@code HashSet} containing a collection of values for one key
+ */
+ @Override Set<V> createCollection() {
+ return Sets.<V>newHashSetWithExpectedSize(expectedValuesPerKey);
+ }
+
+ /**
+ * @serialData expectedValuesPerKey, number of distinct keys, and then for
+ * each distinct key: the key, number of values for that key, and the
+ * key's values
+ */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeInt(expectedValuesPerKey);
+ Serialization.writeMultimap(this, stream);
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ expectedValuesPerKey = stream.readInt();
+ int distinctKeys = Serialization.readCount(stream);
+ Map<K, Collection<V>> map = Maps.newHashMapWithExpectedSize(distinctKeys);
+ setMap(map);
+ Serialization.populateMultimap(this, stream, distinctKeys);
+ }
+
+ @GwtIncompatible("Not needed in emulated source")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/HashMultiset.java b/guava/src/com/google/common/collect/HashMultiset.java
new file mode 100644
index 0000000..51cf7fb
--- /dev/null
+++ b/guava/src/com/google/common/collect/HashMultiset.java
@@ -0,0 +1,101 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+
+/**
+ * Multiset implementation backed by a {@link HashMap}.
+ *
+ * @author Kevin Bourrillion
+ * @author Jared Levy
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+public final class HashMultiset<E> extends AbstractMapBasedMultiset<E> {
+
+ /**
+ * Creates a new, empty {@code HashMultiset} using the default initial
+ * capacity.
+ */
+ public static <E> HashMultiset<E> create() {
+ return new HashMultiset<E>();
+ }
+
+ /**
+ * Creates a new, empty {@code HashMultiset} with the specified expected
+ * number of distinct elements.
+ *
+ * @param distinctElements the expected number of distinct elements
+ * @throws IllegalArgumentException if {@code distinctElements} is negative
+ */
+ public static <E> HashMultiset<E> create(int distinctElements) {
+ return new HashMultiset<E>(distinctElements);
+ }
+
+ /**
+ * Creates a new {@code HashMultiset} containing the specified elements.
+ *
+ * <p>This implementation is highly efficient when {@code elements} is itself
+ * a {@link Multiset}.
+ *
+ * @param elements the elements that the multiset should contain
+ */
+ public static <E> HashMultiset<E> create(Iterable<? extends E> elements) {
+ HashMultiset<E> multiset =
+ create(Multisets.inferDistinctElements(elements));
+ Iterables.addAll(multiset, elements);
+ return multiset;
+ }
+
+ private HashMultiset() {
+ super(new HashMap<E, Count>());
+ }
+
+ private HashMultiset(int distinctElements) {
+ super(Maps.<E, Count>newHashMapWithExpectedSize(distinctElements));
+ }
+
+ /**
+ * @serialData 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 {
+ stream.defaultWriteObject();
+ Serialization.writeMultiset(this, stream);
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ int distinctElements = Serialization.readCount(stream);
+ setBackingMap(
+ Maps.<E, Count>newHashMapWithExpectedSize(distinctElements));
+ Serialization.populateMultiset(this, stream, distinctElements);
+ }
+
+ @GwtIncompatible("Not needed in emulated source.")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/Hashing.java b/guava/src/com/google/common/collect/Hashing.java
new file mode 100644
index 0000000..9c5f6bc
--- /dev/null
+++ b/guava/src/com/google/common/collect/Hashing.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * Static methods for implementing hash-based collections.
+ *
+ * @author Kevin Bourrillion
+ * @author Jesse Wilson
+ */
+@GwtCompatible
+final class Hashing {
+ private Hashing() {}
+
+ /*
+ * 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) {
+ 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
new file mode 100644
index 0000000..249abee
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableAsList.java
@@ -0,0 +1,84 @@
+/*
+ * 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;
+
+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.
+ *
+ * @author Jared Levy
+ * @author Louis Wasserman
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial")
+abstract class ImmutableAsList<E> extends ImmutableList<E> {
+ abstract ImmutableCollection<E> delegateCollection();
+
+ @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();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return delegateCollection().isEmpty();
+ }
+
+ @Override
+ boolean isPartialView() {
+ return delegateCollection().isPartialView();
+ }
+
+ /**
+ * 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) {
+ this.collection = collection;
+ }
+ Object readResolve() {
+ return collection.asList();
+ }
+ 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());
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableBiMap.java b/guava/src/com/google/common/collect/ImmutableBiMap.java
new file mode 100644
index 0000000..27ba968
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableBiMap.java
@@ -0,0 +1,305 @@
+/*
+ * 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 immutable {@link BiMap} with reliable user-specified iteration order. Does
+ * not permit null keys or values. An {@code ImmutableBiMap} and its inverse
+ * have the same iteration ordering.
+ *
+ * <p>An instance of {@code ImmutableBiMap} contains its own data and will
+ * <i>never</i> change. {@code ImmutableBiMap} is convenient for
+ * {@code public static final} maps ("constant maps") and also lets you easily
+ * make a "defensive copy" of a bimap provided to your class by a caller.
+ *
+ * <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 class are
+ * guaranteed to be immutable.
+ *
+ * @author Jared Levy
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
+ implements BiMap<K, V> {
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Returns an immutable bimap containing a single entry.
+ */
+ public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {
+ return new RegularImmutableBiMap<K, V>(ImmutableMap.of(k1, v1));
+ }
+
+ /**
+ * Returns an immutable map containing the given entries, in order.
+ *
+ * @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 RegularImmutableBiMap<K, V>(ImmutableMap.of(k1, v1, k2, v2));
+ }
+
+ /**
+ * Returns an immutable map containing the given entries, in order.
+ *
+ * @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, K k3, V v3) {
+ return new RegularImmutableBiMap<K, V>(ImmutableMap.of(
+ k1, v1, k2, v2, k3, v3));
+ }
+
+ /**
+ * Returns an immutable map containing the given entries, in order.
+ *
+ * @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, K k3, V v3, K k4, V v4) {
+ return new RegularImmutableBiMap<K, V>(ImmutableMap.of(
+ k1, v1, k2, v2, k3, v3, k4, v4));
+ }
+
+ /**
+ * Returns an immutable map containing the given entries, in order.
+ *
+ * @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, K k3, V v3, K k4, V v4, K k5, V v5) {
+ 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.
+
+ /**
+ * Returns a new builder. The generated builder is equivalent to the builder
+ * created by the {@link Builder} constructor.
+ */
+ public static <K, V> Builder<K, V> builder() {
+ return new Builder<K, V>();
+ }
+
+ /**
+ * A builder for creating immutable bimap instances, especially {@code public
+ * static final} bimaps ("constant bimaps"). Example: <pre> {@code
+ *
+ * static final ImmutableBiMap<String, Integer> WORD_TO_INT =
+ * new ImmutableBiMap.Builder<String, Integer>()
+ * .put("one", 1)
+ * .put("two", 2)
+ * .put("three", 3)
+ * .build();}</pre>
+ *
+ * For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods
+ * are even more convenient.
+ *
+ * <p>Builder instances can be reused - it is safe to call {@link #build}
+ * multiple times to build multiple bimaps in series. Each bimap is a superset
+ * of the bimaps created before it.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> {
+
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder
+ * generated by {@link ImmutableBiMap#builder}.
+ */
+ public Builder() {}
+
+ /**
+ * Associates {@code key} with {@code value} in the built bimap. Duplicate
+ * keys or values are not allowed, and will cause {@link #build} to fail.
+ */
+ @Override public Builder<K, V> put(K key, V value) {
+ super.put(key, value);
+ return this;
+ }
+
+ /**
+ * Associates all of the given map's keys and values in the built bimap.
+ * Duplicate keys or values are not allowed, and will cause {@link #build}
+ * to fail.
+ *
+ * @throws NullPointerException if any key or value in {@code map} is null
+ */
+ @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
+ super.putAll(map);
+ return this;
+ }
+
+ /**
+ * Returns a newly-created immutable bimap.
+ *
+ * @throws IllegalArgumentException if duplicate keys or values were added
+ */
+ @Override public ImmutableBiMap<K, V> build() {
+ ImmutableMap<K, V> map = super.build();
+ if (map.isEmpty()) {
+ return of();
+ }
+ return new RegularImmutableBiMap<K, V>(map);
+ }
+ }
+
+ /**
+ * Returns an immutable bimap containing the same entries as {@code map}. If
+ * {@code map} somehow contains entries with duplicate keys (for example, if
+ * it is a {@code SortedMap} whose comparator is not <i>consistent with
+ * equals</i>), the results of this method are undefined.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * @throws IllegalArgumentException if two keys have the same value
+ * @throws NullPointerException if any key or value in {@code map} is null
+ */
+ public static <K, V> ImmutableBiMap<K, V> copyOf(
+ Map<? extends K, ? extends V> map) {
+ if (map instanceof ImmutableBiMap) {
+ @SuppressWarnings("unchecked") // safe since map is not writable
+ ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map;
+ // TODO(user): if we need to make a copy of a BiMap because the
+ // forward map is a view, don't make a copy of the non-view delegate map
+ if (!bimap.isPartialView()) {
+ return bimap;
+ }
+ }
+
+ 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}
+ *
+ * <p>The inverse of an {@code ImmutableBiMap} is another
+ * {@code ImmutableBiMap}.
+ */
+ @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 ImmutableSet<Entry<K, V>> createEntrySet() {
+ 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.
+ */
+ @Override public ImmutableSet<V> values() {
+ return inverse().keySet();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the bimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @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();
+ }
+
+ /**
+ * Serialized type for all ImmutableBiMap instances. It captures the logical
+ * contents and they are reconstructed using public factory methods. This
+ * ensures that the implementation types remain as implementation details.
+ *
+ * Since the bimap is immutable, ImmutableBiMap doesn't require special logic
+ * for keeping the bimap and its inverse in sync during serialization, the way
+ * AbstractBiMap does.
+ */
+ private static class SerializedForm extends ImmutableMap.SerializedForm {
+ SerializedForm(ImmutableBiMap<?, ?> bimap) {
+ super(bimap);
+ }
+ @Override Object readResolve() {
+ Builder<Object, Object> builder = new Builder<Object, Object>();
+ return createMap(builder);
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ @Override Object writeReplace() {
+ return new SerializedForm(this);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java b/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java
new file mode 100644
index 0000000..1c596e2
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableClassToInstanceMap.java
@@ -0,0 +1,154 @@
+/*
+ * 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;
+
+import com.google.common.primitives.Primitives;
+
+import java.util.Map;
+
+/**
+ * A class-to-instance map backed by an {@link ImmutableMap}. See also {@link
+ * MutableClassToInstanceMap}.
+ *
+ * @author Kevin Bourrillion
+ * @since 2.0 (imported from Google Collections Library)
+ */
+public final class ImmutableClassToInstanceMap<B> extends
+ ForwardingMap<Class<? extends B>, B> implements ClassToInstanceMap<B> {
+ /**
+ * Returns a new builder. The generated builder is equivalent to the builder
+ * created by the {@link Builder} constructor.
+ */
+ public static <B> Builder<B> builder() {
+ return new Builder<B>();
+ }
+
+ /**
+ * A builder for creating immutable class-to-instance maps. Example:
+ * <pre> {@code
+ *
+ * static final ImmutableClassToInstanceMap<Handler> HANDLERS =
+ * new ImmutableClassToInstanceMap.Builder<Handler>()
+ * .put(FooHandler.class, new FooHandler())
+ * .put(BarHandler.class, new SubBarHandler())
+ * .put(Handler.class, new QuuxHandler())
+ * .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 2.0 (imported from Google Collections Library)
+ */
+ public static final class Builder<B> {
+ private final ImmutableMap.Builder<Class<? extends B>, B> mapBuilder
+ = ImmutableMap.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(key, value);
+ return this;
+ }
+
+ /**
+ * Associates all of {@code map's} keys and values in the built map.
+ * Duplicate keys are not allowed, and will cause {@link #build} to fail.
+ *
+ * @throws NullPointerException if any key or value in {@code map} is null
+ * @throws ClassCastException if any value is not an instance of the type
+ * specified by its key
+ */
+ public <T extends B> Builder<B> putAll(
+ Map<? extends Class<? extends T>, ? extends T> map) {
+ for (Entry<? extends Class<? extends T>, ? extends T> entry
+ : map.entrySet()) {
+ Class<? extends T> type = entry.getKey();
+ T value = entry.getValue();
+ mapBuilder.put(type, cast(type, value));
+ }
+ return this;
+ }
+
+ private static <B, T extends B> T cast(Class<T> type, B value) {
+ return Primitives.wrap(type).cast(value);
+ }
+
+ /**
+ * Returns a new immutable class-to-instance map containing the entries
+ * provided to this builder.
+ *
+ * @throws IllegalArgumentException if duplicate keys were added
+ */
+ public ImmutableClassToInstanceMap<B> build() {
+ return new ImmutableClassToInstanceMap<B>(mapBuilder.build());
+ }
+ }
+
+ /**
+ * Returns an immutable map containing the same entries as {@code map}. If
+ * {@code map} somehow contains entries with duplicate keys (for example, if
+ * it is a {@code SortedMap} whose comparator is not <i>consistent with
+ * equals</i>), the results of this method are undefined.
+ *
+ * <p><b>Note:</b> Despite what the method name suggests, if {@code map} is
+ * an {@code ImmutableClassToInstanceMap}, no copy will actually be performed.
+ *
+ * @throws NullPointerException if any key or value in {@code map} is null
+ * @throws ClassCastException if any value is not an instance of the type
+ * specified by its key
+ */
+ public static <B, S extends B> ImmutableClassToInstanceMap<B> copyOf(
+ Map<? extends Class<? extends S>, ? extends S> map) {
+ if (map instanceof ImmutableClassToInstanceMap) {
+ @SuppressWarnings("unchecked") // covariant casts safe (unmodifiable)
+ // Eclipse won't compile if we cast to the parameterized type.
+ ImmutableClassToInstanceMap<B> cast = (ImmutableClassToInstanceMap) map;
+ return cast;
+ }
+ return new Builder<B>().putAll(map).build();
+ }
+
+ private final ImmutableMap<Class<? extends B>, B> delegate;
+
+ private ImmutableClassToInstanceMap(
+ ImmutableMap<Class<? extends B>, B> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override protected Map<Class<? extends B>, B> delegate() {
+ return delegate;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked") // value could not get in if not a T
+ public <T extends B> T getInstance(Class<T> type) {
+ return (T) delegate.get(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();
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableCollection.java b/guava/src/com/google/common/collect/ImmutableCollection.java
new file mode 100644
index 0000000..d7e37ee
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableCollection.java
@@ -0,0 +1,376 @@
+/*
+ * 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.VisibleForTesting;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable collection. Does not permit null elements.
+ *
+ * <p>In addition to the {@link Collection} methods, this class has an {@link
+ * #asList()} method, which returns a list view of the collection's elements.
+ *
+ * <p><b>Note:</b> Although this class is not final, it cannot be subclassed
+ * outside of this package as it has no public or protected constructors. Thus,
+ * instances of this type are guaranteed to be immutable.
+ *
+ * @author Jesse Wilson
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(emulated = true)
+@SuppressWarnings("serial") // we're overriding default serialization
+public abstract class ImmutableCollection<E>
+ implements Collection<E>, Serializable {
+ static final ImmutableCollection<Object> EMPTY_IMMUTABLE_COLLECTION
+ = new EmptyImmutableCollection();
+
+ ImmutableCollection() {}
+
+ /**
+ * Returns an unmodifiable iterator across the elements in this collection.
+ */
+ @Override
+ public abstract UnmodifiableIterator<E> iterator();
+
+ @Override
+ public Object[] toArray() {
+ return ObjectArrays.toArrayImpl(this);
+ }
+
+ @Override
+ public <T> T[] toArray(T[] other) {
+ return ObjectArrays.toArrayImpl(this, other);
+ }
+
+ @Override
+ public boolean contains(@Nullable Object object) {
+ return object != null && Iterators.contains(iterator(), object);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> targets) {
+ return Collections2.containsAllImpl(this, targets);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ @Override public String toString() {
+ return Collections2.toStringImpl(this);
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean add(E e) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean remove(Object object) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean addAll(Collection<? extends E> newElements) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean removeAll(Collection<?> oldElements) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean retainAll(Collection<?> elementsToKeep) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ /*
+ * TODO(kevinb): Restructure code so ImmutableList doesn't contain this
+ * variable, which it doesn't use.
+ */
+ private transient ImmutableList<E> asList;
+
+ /**
+ * Returns a list view of the collection.
+ *
+ * @since 2.0
+ */
+ public ImmutableList<E> asList() {
+ ImmutableList<E> list = asList;
+ return (list == null) ? (asList = createAsList()) : list;
+ }
+
+ ImmutableList<E> createAsList() {
+ switch (size()) {
+ case 0:
+ return ImmutableList.of();
+ case 1:
+ return ImmutableList.of(iterator().next());
+ default:
+ return new RegularImmutableAsList<E>(this, toArray());
+ }
+ }
+
+ abstract boolean isPartialView();
+
+ private static class EmptyImmutableCollection
+ extends ImmutableCollection<Object> {
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public boolean contains(@Nullable Object object) {
+ return false;
+ }
+
+ @Override public UnmodifiableIterator<Object> iterator() {
+ return Iterators.EMPTY_LIST_ITERATOR;
+ }
+
+ private static final Object[] EMPTY_ARRAY = new Object[0];
+
+ @Override public Object[] toArray() {
+ return EMPTY_ARRAY;
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ if (array.length > 0) {
+ array[0] = null;
+ }
+ return array;
+ }
+
+ @Override ImmutableList<Object> createAsList() {
+ return ImmutableList.of();
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+ }
+
+ /**
+ * Nonempty collection stored in an array.
+ */
+ private static class ArrayImmutableCollection<E>
+ extends ImmutableCollection<E> {
+ private final E[] elements;
+
+ ArrayImmutableCollection(E[] elements) {
+ this.elements = elements;
+ }
+
+ @Override
+ public int size() {
+ return elements.length;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ return Iterators.forArray(elements);
+ }
+
+ @Override ImmutableList<E> createAsList() {
+ return elements.length == 1 ? new SingletonImmutableList<E>(elements[0])
+ : new RegularImmutableList<E>(elements);
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+ }
+
+ /*
+ * Serializes ImmutableCollections as their logical contents. This ensures
+ * that implementation types do not leak into the serialized representation.
+ */
+ private static class SerializedForm implements Serializable {
+ final Object[] elements;
+ SerializedForm(Object[] elements) {
+ this.elements = elements;
+ }
+ Object readResolve() {
+ return elements.length == 0
+ ? EMPTY_IMMUTABLE_COLLECTION
+ : new ArrayImmutableCollection<Object>(Platform.clone(elements));
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ Object writeReplace() {
+ return new SerializedForm(toArray());
+ }
+
+ /**
+ * Abstract base class for builders of {@link ImmutableCollection} types.
+ *
+ * @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() {
+ }
+
+ /**
+ * Adds {@code element} to the {@code ImmutableCollection} being built.
+ *
+ * <p>Note that each builder class covariantly returns its own type from
+ * this method.
+ *
+ * @param element the element to add
+ * @return this {@code Builder} instance
+ * @throws NullPointerException if {@code element} is null
+ */
+ public abstract Builder<E> add(E element);
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableCollection}
+ * being built.
+ *
+ * <p>Note that each builder class overrides this method in order to
+ * covariantly return its own type.
+ *
+ * @param elements the elements to add
+ * @return this {@code Builder} instance
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ public Builder<E> add(E... elements) {
+ for (E element : elements) {
+ add(element);
+ }
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableCollection}
+ * being built.
+ *
+ * <p>Note that each builder class overrides this method in order to
+ * covariantly return its own type.
+ *
+ * @param elements the elements to add
+ * @return this {@code Builder} instance
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ public Builder<E> addAll(Iterable<? extends E> elements) {
+ for (E element : elements) {
+ add(element);
+ }
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableCollection}
+ * being built.
+ *
+ * <p>Note that each builder class overrides this method in order to
+ * covariantly return its own type.
+ *
+ * @param elements the elements to add
+ * @return this {@code Builder} instance
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ public Builder<E> addAll(Iterator<? extends E> elements) {
+ while (elements.hasNext()) {
+ add(elements.next());
+ }
+ return this;
+ }
+
+ /**
+ * Returns a newly-created {@code ImmutableCollection} of the appropriate
+ * type, containing the elements provided to this builder.
+ *
+ * <p>Note that each builder class covariantly returns the appropriate type
+ * of {@code ImmutableCollection} from this method.
+ */
+ public abstract ImmutableCollection<E> build();
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableEntry.java b/guava/src/com/google/common/collect/ImmutableEntry.java
new file mode 100644
index 0000000..3824d7a
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableEntry.java
@@ -0,0 +1,52 @@
+/*
+ * 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.io.Serializable;
+
+import javax.annotation.Nullable;
+
+/**
+ * @see com.google.common.collect.Maps#immutableEntry(Object, Object)
+ */
+@GwtCompatible(serializable = true)
+class ImmutableEntry<K, V> extends AbstractMapEntry<K, V>
+ implements Serializable {
+ private final K key;
+ private final V value;
+
+ ImmutableEntry(@Nullable K key, @Nullable V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Nullable @Override public K getKey() {
+ return key;
+ }
+
+ @Nullable @Override public V getValue() {
+ return value;
+ }
+
+ @Override public final V setValue(V value){
+ throw new UnsupportedOperationException();
+ }
+
+ 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
new file mode 100644
index 0000000..ac6dd0e
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableEnumSet.java
@@ -0,0 +1,116 @@
+/*
+ * 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;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.EnumSet;
+
+/**
+ * Implementation of {@link ImmutableSet} backed by a non-empty {@link
+ * java.util.EnumSet}.
+ *
+ * @author Jared Levy
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // we're overriding default serialization
+final class ImmutableEnumSet<E extends Enum<E>> extends ImmutableSet<E> {
+ /*
+ * Notes on EnumSet and <E extends Enum<E>>:
+ *
+ * This class isn't an arbitrary ForwardingImmutableSet because we need to
+ * know that calling {@code clone()} during deserialization will return an
+ * object that no one else has a reference to, allowing us to guarantee
+ * immutability. Hence, we support only {@link EnumSet}.
+ */
+ private final transient EnumSet<E> delegate;
+
+ ImmutableEnumSet(EnumSet<E> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ return Iterators.unmodifiableIterator(delegate.iterator());
+ }
+
+ @Override
+ public int size() {
+ return delegate.size();
+ }
+
+ @Override public boolean contains(Object object) {
+ return delegate.contains(object);
+ }
+
+ @Override public boolean containsAll(Collection<?> collection) {
+ return delegate.containsAll(collection);
+ }
+
+ @Override public boolean isEmpty() {
+ return delegate.isEmpty();
+ }
+
+ @Override public Object[] toArray() {
+ return delegate.toArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return delegate.toArray(array);
+ }
+
+ @Override public boolean equals(Object object) {
+ return object == this || delegate.equals(object);
+ }
+
+ private transient int hashCode;
+
+ @Override public int hashCode() {
+ int result = hashCode;
+ return (result == 0) ? hashCode = delegate.hashCode() : result;
+ }
+
+ @Override public String toString() {
+ return delegate.toString();
+ }
+
+ // All callers of the constructor are restricted to <E extends Enum<E>>.
+ @Override Object writeReplace() {
+ return new EnumSerializedForm<E>(delegate);
+ }
+
+ /*
+ * This class is used to serialize ImmutableEnumSet instances.
+ */
+ private static class EnumSerializedForm<E extends Enum<E>>
+ implements Serializable {
+ final EnumSet<E> delegate;
+ EnumSerializedForm(EnumSet<E> delegate) {
+ this.delegate = delegate;
+ }
+ Object readResolve() {
+ // EJ2 #76: Write readObject() methods defensively.
+ return new ImmutableEnumSet<E>(delegate.clone());
+ }
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableList.java b/guava/src/com/google/common/collect/ImmutableList.java
new file mode 100644
index 0000000..1791bef
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableList.java
@@ -0,0 +1,749 @@
+/*
+ * 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.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 java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.RandomAccess;
+
+import javax.annotation.Nullable;
+
+/**
+ * A high-performance, immutable, random-access {@code List} implementation.
+ * Does not permit null elements.
+ *
+ * <p>Unlike {@link Collections#unmodifiableList}, which is a <i>view</i> of a
+ * separate collection that can still change, an instance of {@code
+ * ImmutableList} contains its own private data and will <i>never</i> change.
+ * {@code ImmutableList} is convenient for {@code public static final} lists
+ * ("constant lists") and also lets you easily make a "defensive copy" of a list
+ * provided to your class by a caller.
+ *
+ * <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>.
+ *
+ * @see ImmutableMap
+ * @see ImmutableSet
+ * @author Kevin Bourrillion
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // we're overriding default serialization
+public abstract class ImmutableList<E> extends ImmutableCollection<E>
+ implements List<E>, RandomAccess {
+ /**
+ * Returns the empty immutable list. This set behaves and performs comparably
+ * to {@link Collections#emptyList}, and is preferable mainly for consistency
+ * and maintainability of your code.
+ */
+ // Casting to any type is safe because the list will never hold any elements.
+ @SuppressWarnings("unchecked")
+ public static <E> ImmutableList<E> of() {
+ return (ImmutableList<E>) EmptyImmutableList.INSTANCE;
+ }
+
+ /**
+ * Returns an immutable list containing a single element. This list behaves
+ * and performs comparably to {@link Collections#singleton}, but will not
+ * accept a null element. It is preferable mainly for consistency and
+ * maintainability of your code.
+ *
+ * @throws NullPointerException if {@code element} is null
+ */
+ public static <E> ImmutableList<E> of(E element) {
+ return new SingletonImmutableList<E>(element);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(E e1, E e2) {
+ return construct(e1, e2);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(E e1, E e2, E e3) {
+ return construct(e1, e2, e3);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4) {
+ return construct(e1, e2, e3, e4);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5) {
+ return construct(e1, e2, e3, e4, e5);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+ return construct(e1, e2, e3, e4, e5, e6);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(
+ E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+ return construct(e1, e2, e3, e4, e5, e6, e7);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(
+ E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+ return construct(e1, e2, e3, e4, e5, e6, e7, e8);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(
+ E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+ return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(
+ E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+ return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableList<E> of(
+ E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11) {
+ return construct(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11);
+ }
+
+ // These go up to eleven. After that, you just get the varargs form, and
+ // whatever warnings might come along with it. :(
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ * @since 3.0 (source-compatible since 2.0)
+ */
+ public static <E> ImmutableList<E> of(
+ E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10, E e11, E e12,
+ E... others) {
+ Object[] array = new Object[12 + others.length];
+ array[0] = e1;
+ array[1] = e2;
+ array[2] = e3;
+ array[3] = e4;
+ array[4] = e5;
+ array[5] = e6;
+ array[6] = e7;
+ array[7] = e8;
+ array[8] = e9;
+ array[9] = e10;
+ array[10] = e11;
+ array[11] = e12;
+ System.arraycopy(others, 0, array, 12, others.length);
+ return construct(array);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order. If
+ * {@code elements} is a {@link Collection}, this method behaves exactly as
+ * {@link #copyOf(Collection)}; otherwise, it behaves exactly as {@code
+ * copyOf(elements.iterator()}.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements) {
+ checkNotNull(elements); // TODO(kevinb): is this here only for GWT?
+ return (elements instanceof Collection)
+ ? copyOf(Collections2.cast(elements))
+ : copyOf(elements.iterator());
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * <p>Note that if {@code list} is a {@code List<String>}, then {@code
+ * ImmutableList.copyOf(list)} returns an {@code ImmutableList<String>}
+ * containing each of the strings in {@code list}, while
+ * ImmutableList.of(list)} returns an {@code ImmutableList<List<String>>}
+ * containing one element (the given list itself).
+ *
+ * <p>This method is safe to use even when {@code elements} is a synchronized
+ * or concurrent collection that is currently being modified by another
+ * thread.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {
+ if (elements instanceof ImmutableCollection) {
+ @SuppressWarnings("unchecked") // all supported methods are covariant
+ ImmutableList<E> list = ((ImmutableCollection<E>) elements).asList();
+ return list.isPartialView() ? copyFromCollection(list) : list;
+ }
+ return copyFromCollection(elements);
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @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();
+ }
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ * @since 3.0
+ */
+ public static <E> ImmutableList<E> copyOf(E[] elements) {
+ switch (elements.length) {
+ case 0:
+ return ImmutableList.of();
+ case 1:
+ return new SingletonImmutableList<E>(elements[0]);
+ default:
+ return construct(elements.clone());
+ }
+ }
+
+ /**
+ * 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) {
+ switch (elements.length) {
+ case 0:
+ return of();
+ case 1:
+ @SuppressWarnings("unchecked") // collection had only Es in it
+ ImmutableList<E> list = new SingletonImmutableList<E>((E) elements[0]);
+ return list;
+ default:
+ 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);
+ }
+ return new RegularImmutableList<E>(elements);
+ }
+
+ ImmutableList() {}
+
+ // This declaration is needed to make List.iterator() and
+ // ImmutableCollection.iterator() consistent.
+ @Override public UnmodifiableIterator<E> iterator() {
+ return listIterator();
+ }
+
+ @Override public UnmodifiableListIterator<E> listIterator() {
+ 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 int indexOf(@Nullable Object object) {
+ return (object == null) ? -1 : Lists.indexOfImpl(this, object);
+ }
+
+ @Override
+ public int lastIndexOf(@Nullable Object object) {
+ return (object == null) ? -1 : Lists.lastIndexOfImpl(this, object);
+ }
+
+ @Override
+ public boolean contains(@Nullable Object object) {
+ return indexOf(object) >= 0;
+ }
+
+ // constrain the return type to ImmutableList<E>
+
+ /**
+ * Returns an immutable list of the elements between the specified {@code
+ * fromIndex}, inclusive, and {@code toIndex}, exclusive. (If {@code
+ * fromIndex} and {@code toIndex} are equal, the empty immutable list is
+ * 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;
+ }
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the list unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean addAll(int index, Collection<? extends E> newElements) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the list unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final E set(int index, E element) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the list unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final void add(int index, E element) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the list unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final E remove(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns this list instance.
+ *
+ * @since 2.0
+ */
+ @Override public ImmutableList<E> asList() {
+ return this;
+ }
+
+ /**
+ * Returns a view of this immutable list in reverse order. For example, {@code
+ * ImmutableList.of(1, 2, 3).reverse()} is equivalent to {@code
+ * ImmutableList.of(3, 2, 1)}.
+ *
+ * @return a view of this immutable list in reverse order
+ * @since 7.0
+ */
+ public ImmutableList<E> reverse() {
+ return new ReverseImmutableList<E>(this);
+ }
+
+ private static class ReverseImmutableList<E> extends ImmutableList<E> {
+ private final transient ImmutableList<E> forwardList;
+ private final transient int size;
+
+ ReverseImmutableList(ImmutableList<E> backingList) {
+ this.forwardList = backingList;
+ this.size = backingList.size();
+ }
+
+ private int reverseIndex(int index) {
+ return (size - 1) - index;
+ }
+
+ private int reversePosition(int index) {
+ return size - index;
+ }
+
+ @Override public ImmutableList<E> reverse() {
+ return forwardList;
+ }
+
+ @Override public boolean contains(@Nullable Object object) {
+ return forwardList.contains(object);
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ return forwardList.containsAll(targets);
+ }
+
+ @Override public int indexOf(@Nullable Object object) {
+ int index = forwardList.lastIndexOf(object);
+ return (index >= 0) ? reverseIndex(index) : -1;
+ }
+
+ @Override public int lastIndexOf(@Nullable Object object) {
+ int index = forwardList.indexOf(object);
+ return (index >= 0) ? reverseIndex(index) : -1;
+ }
+
+ @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
+ checkPositionIndexes(fromIndex, toIndex, size);
+ return forwardList.subList(
+ reversePosition(toIndex), reversePosition(fromIndex)).reverse();
+ }
+
+ @Override public E get(int index) {
+ checkElementIndex(index, size);
+ return forwardList.get(reverseIndex(index));
+ }
+
+ @Override public UnmodifiableListIterator<E> listIterator(int index) {
+ checkPositionIndex(index, size);
+ final UnmodifiableListIterator<E> forward =
+ forwardList.listIterator(reversePosition(index));
+ return new UnmodifiableListIterator<E>() {
+ @Override public boolean hasNext() {
+ return forward.hasPrevious();
+ }
+
+ @Override public boolean hasPrevious() {
+ return forward.hasNext();
+ }
+
+ @Override public E next() {
+ return forward.previous();
+ }
+
+ @Override public int nextIndex() {
+ return reverseIndex(forward.previousIndex());
+ }
+
+ @Override public E previous() {
+ return forward.next();
+ }
+
+ @Override public int previousIndex() {
+ return reverseIndex(forward.nextIndex());
+ }
+ };
+ }
+
+ @Override public int size() {
+ return size;
+ }
+
+ @Override public boolean isEmpty() {
+ return forwardList.isEmpty();
+ }
+
+ @Override boolean isPartialView() {
+ return forwardList.isPartialView();
+ }
+ }
+
+ @Override public boolean equals(Object obj) {
+ return Lists.equalsImpl(this, obj);
+ }
+
+ @Override public int hashCode() {
+ return Lists.hashCodeImpl(this);
+ }
+
+ /*
+ * Serializes ImmutableLists as their logical contents. This ensures that
+ * implementation types do not leak into the serialized representation.
+ */
+ private static class SerializedForm implements Serializable {
+ final Object[] elements;
+ SerializedForm(Object[] elements) {
+ this.elements = elements;
+ }
+ Object readResolve() {
+ return copyOf(elements);
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws InvalidObjectException {
+ throw new InvalidObjectException("Use SerializedForm");
+ }
+
+ @Override Object writeReplace() {
+ return new SerializedForm(toArray());
+ }
+
+ /**
+ * Returns a new builder. The generated builder is equivalent to the builder
+ * created by the {@link Builder} constructor.
+ */
+ public static <E> Builder<E> builder() {
+ return new Builder<E>();
+ }
+
+ /**
+ * A builder for creating immutable list instances, especially {@code public
+ * static final} lists ("constant lists"). Example: <pre> {@code
+ *
+ * public static final ImmutableList<Color> GOOGLE_COLORS
+ * = new ImmutableList.Builder<Color>()
+ * .addAll(WEBSAFE_COLORS)
+ * .add(new Color(0, 191, 255))
+ * .build();}</pre>
+ *
+ * Builder instances can be reused; it is safe to call {@link #build} multiple
+ * times to build multiple lists in series. Each new list contains all the
+ * elements of the ones created before it.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static final class Builder<E> extends ImmutableCollection.Builder<E> {
+ private Object[] contents;
+ private int size;
+
+ /**
+ * 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 capacity to allow the specified number of elements to be added.
+ */
+ Builder<E> expandFor(int count) {
+ int minCapacity = size + count;
+ if (contents.length < minCapacity) {
+ this.contents = ObjectArrays.arraysCopyOf(
+ this.contents, expandedCapacity(contents.length, minCapacity));
+ }
+ return this;
+ }
+
+ /**
+ * Adds {@code element} to the {@code ImmutableList}.
+ *
+ * @param element the element to add
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code element} is null
+ */
+ @Override public Builder<E> add(E element) {
+ checkNotNull(element);
+ expandFor(1);
+ contents[size++] = element;
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableList}.
+ *
+ * @param elements the {@code Iterable} to add to the {@code ImmutableList}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ @Override public Builder<E> addAll(Iterable<? extends E> elements) {
+ if (elements instanceof Collection) {
+ Collection<?> collection = (Collection<?>) elements;
+ expandFor(collection.size());
+ }
+ super.addAll(elements);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableList}.
+ *
+ * @param elements the {@code Iterable} to add to the {@code ImmutableList}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ @Override public Builder<E> add(E... elements) {
+ for (int i = 0; i < elements.length; i++) {
+ checkElementNotNull(elements[i], i);
+ }
+ expandFor(elements.length);
+ System.arraycopy(elements, 0, contents, size, elements.length);
+ size += elements.length;
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableList}.
+ *
+ * @param elements the {@code Iterable} to add to the {@code ImmutableList}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ @Override public Builder<E> addAll(Iterator<? extends E> elements) {
+ super.addAll(elements);
+ return this;
+ }
+
+ /**
+ * Returns a newly-created {@code ImmutableList} based on the contents of
+ * 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));
+ }
+ }
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableListMultimap.java b/guava/src/com/google/common/collect/ImmutableListMultimap.java
new file mode 100644
index 0000000..98db0ed
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableListMultimap.java
@@ -0,0 +1,388 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Map.Entry;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable {@link ListMultimap} with reliable user-specified key and value
+ * iteration order. Does not permit null keys or values.
+ *
+ * <p>Unlike {@link Multimaps#unmodifiableListMultimap(ListMultimap)}, which is
+ * a <i>view</i> of a separate multimap which can still change, an instance of
+ * {@code ImmutableListMultimap} contains its own data and will <i>never</i>
+ * change. {@code ImmutableListMultimap} is convenient for
+ * {@code public static final} multimaps ("constant multimaps") and also lets
+ * you easily make a "defensive copy" of a multimap provided to your class by
+ * a caller.
+ *
+ * <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 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)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+public class ImmutableListMultimap<K, V>
+ extends ImmutableMultimap<K, V>
+ implements ListMultimap<K, V> {
+
+ /** Returns the empty multimap. */
+ // Casting is safe because the multimap will never hold any elements.
+ @SuppressWarnings("unchecked")
+ public static <K, V> ImmutableListMultimap<K, V> of() {
+ return (ImmutableListMultimap<K, V>) EmptyImmutableListMultimap.INSTANCE;
+ }
+
+ /**
+ * Returns an immutable multimap containing a single entry.
+ */
+ public static <K, V> ImmutableListMultimap<K, V> of(K k1, V v1) {
+ ImmutableListMultimap.Builder<K, V> builder
+ = ImmutableListMultimap.builder();
+ builder.put(k1, v1);
+ return builder.build();
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ */
+ public static <K, V> ImmutableListMultimap<K, V> of(K k1, V v1, K k2, V v2) {
+ ImmutableListMultimap.Builder<K, V> builder
+ = ImmutableListMultimap.builder();
+ builder.put(k1, v1);
+ builder.put(k2, v2);
+ return builder.build();
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ */
+ public static <K, V> ImmutableListMultimap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3) {
+ ImmutableListMultimap.Builder<K, V> builder
+ = ImmutableListMultimap.builder();
+ builder.put(k1, v1);
+ builder.put(k2, v2);
+ builder.put(k3, v3);
+ return builder.build();
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ */
+ public static <K, V> ImmutableListMultimap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+ ImmutableListMultimap.Builder<K, V> builder
+ = ImmutableListMultimap.builder();
+ builder.put(k1, v1);
+ builder.put(k2, v2);
+ builder.put(k3, v3);
+ builder.put(k4, v4);
+ return builder.build();
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ */
+ public static <K, V> ImmutableListMultimap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+ ImmutableListMultimap.Builder<K, V> builder
+ = ImmutableListMultimap.builder();
+ builder.put(k1, v1);
+ builder.put(k2, v2);
+ builder.put(k3, v3);
+ builder.put(k4, v4);
+ builder.put(k5, v5);
+ return builder.build();
+ }
+
+ // looking for of() with > 5 entries? Use the builder instead.
+
+ /**
+ * Returns a new builder. The generated builder is equivalent to the builder
+ * created by the {@link Builder} constructor.
+ */
+ public static <K, V> Builder<K, V> builder() {
+ return new Builder<K, V>();
+ }
+
+ /**
+ * A builder for creating immutable {@code ListMultimap} instances, especially
+ * {@code public static final} multimaps ("constant multimaps"). Example:
+ * <pre> {@code
+ *
+ * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
+ * new ImmutableListMultimap.Builder<String, Integer>()
+ * .put("one", 1)
+ * .putAll("several", 1, 2, 3)
+ * .putAll("many", 1, 2, 3, 4, 5)
+ * .build();}</pre>
+ *
+ * Builder instances can be reused; it is safe to call {@link #build} multiple
+ * times to build multiple multimaps in series. Each multimap contains the
+ * key-value mappings in the previously created multimaps.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static final class Builder<K, V>
+ extends ImmutableMultimap.Builder<K, V> {
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder
+ * generated by {@link ImmutableListMultimap#builder}.
+ */
+ public Builder() {}
+
+ @Override public Builder<K, V> put(K key, V value) {
+ super.put(key, value);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 11.0
+ */
+ @Override public Builder<K, V> put(
+ Entry<? extends K, ? extends V> entry) {
+ super.put(entry);
+ return this;
+ }
+
+ @Override public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
+ super.putAll(key, values);
+ return this;
+ }
+
+ @Override public Builder<K, V> putAll(K key, V... values) {
+ super.putAll(key, values);
+ return this;
+ }
+
+ @Override public Builder<K, V> putAll(
+ Multimap<? extends K, ? extends V> multimap) {
+ super.putAll(multimap);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 8.0
+ */
+ @Beta @Override
+ public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
+ super.orderKeysBy(keyComparator);
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 8.0
+ */
+ @Beta @Override
+ public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
+ super.orderValuesBy(valueComparator);
+ return this;
+ }
+
+ /**
+ * Returns a newly-created immutable list multimap.
+ */
+ @Override public ImmutableListMultimap<K, V> build() {
+ return (ImmutableListMultimap<K, V>) super.build();
+ }
+ }
+
+ /**
+ * Returns an immutable multimap containing the same mappings as {@code
+ * multimap}. The generated multimap's key and value orderings correspond to
+ * the iteration ordering of the {@code multimap.asMap()} view.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * @throws NullPointerException if any key or value in {@code multimap} is
+ * null
+ */
+ public static <K, V> ImmutableListMultimap<K, V> copyOf(
+ Multimap<? extends K, ? extends V> multimap) {
+ if (multimap.isEmpty()) {
+ return of();
+ }
+
+ // TODO(user): copy ImmutableSetMultimap by using asList() on the sets
+ if (multimap instanceof ImmutableListMultimap) {
+ @SuppressWarnings("unchecked") // safe since multimap is not writable
+ ImmutableListMultimap<K, V> kvMultimap
+ = (ImmutableListMultimap<K, V>) multimap;
+ if (!kvMultimap.isPartialView()) {
+ return kvMultimap;
+ }
+ }
+
+ ImmutableMap.Builder<K, ImmutableList<V>> builder = ImmutableMap.builder();
+ int size = 0;
+
+ for (Entry<? extends K, ? extends Collection<? extends V>> entry
+ : multimap.asMap().entrySet()) {
+ ImmutableList<V> list = ImmutableList.copyOf(entry.getValue());
+ if (!list.isEmpty()) {
+ builder.put(entry.getKey(), list);
+ size += list.size();
+ }
+ }
+
+ return new ImmutableListMultimap<K, V>(builder.build(), size);
+ }
+
+ ImmutableListMultimap(ImmutableMap<K, ImmutableList<V>> map, int size) {
+ super(map, size);
+ }
+
+ // views
+
+ /**
+ * Returns an immutable list of the values for the given key. If no mappings
+ * in the multimap have the provided key, an empty immutable list is
+ * returned. The values are in the same order as the parameters used to build
+ * this multimap.
+ */
+ @Override public ImmutableList<V> get(@Nullable K key) {
+ // This cast is safe as its type is known in constructor.
+ ImmutableList<V> list = (ImmutableList<V>) map.get(key);
+ return (list == null) ? ImmutableList.<V>of() : list;
+ }
+
+ private transient ImmutableListMultimap<V, K> inverse;
+
+ /**
+ * {@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.
+ *
+ * @since 11
+ */
+ @Beta
+ public ImmutableListMultimap<V, K> inverse() {
+ ImmutableListMultimap<V, K> result = inverse;
+ return (result == null) ? (inverse = invert()) : result;
+ }
+
+ private ImmutableListMultimap<V, K> invert() {
+ Builder<V, K> builder = builder();
+ for (Entry<K, V> entry : entries()) {
+ builder.put(entry.getValue(), entry.getKey());
+ }
+ ImmutableListMultimap<V, K> invertedMultimap = builder.build();
+ invertedMultimap.inverse = this;
+ return invertedMultimap;
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public ImmutableList<V> removeAll(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public ImmutableList<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @serialData number of distinct keys, and then for each distinct key: the
+ * key, the number of values for that key, and the key's values
+ */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMultimap(this, stream);
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ int keyCount = stream.readInt();
+ if (keyCount < 0) {
+ throw new InvalidObjectException("Invalid key count " + keyCount);
+ }
+ ImmutableMap.Builder<Object, ImmutableList<Object>> builder
+ = ImmutableMap.builder();
+ int tmpSize = 0;
+
+ for (int i = 0; i < keyCount; i++) {
+ Object key = stream.readObject();
+ int valueCount = stream.readInt();
+ if (valueCount <= 0) {
+ throw new InvalidObjectException("Invalid value count " + valueCount);
+ }
+
+ Object[] array = new Object[valueCount];
+ for (int j = 0; j < valueCount; j++) {
+ array[j] = stream.readObject();
+ }
+ builder.put(key, ImmutableList.copyOf(array));
+ tmpSize += valueCount;
+ }
+
+ ImmutableMap<Object, ImmutableList<Object>> tmpMap;
+ try {
+ tmpMap = builder.build();
+ } catch (IllegalArgumentException e) {
+ throw (InvalidObjectException)
+ new InvalidObjectException(e.getMessage()).initCause(e);
+ }
+
+ FieldSettersHolder.MAP_FIELD_SETTER.set(this, tmpMap);
+ FieldSettersHolder.SIZE_FIELD_SETTER.set(this, tmpSize);
+ }
+
+ @GwtIncompatible("Not needed in emulated source")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ImmutableMap.java b/guava/src/com/google/common/collect/ImmutableMap.java
new file mode 100644
index 0000000..05e3711
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableMap.java
@@ -0,0 +1,462 @@
+/*
+ * 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 static com.google.common.collect.Iterables.getOnlyElement;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable, hash-based {@link Map} with reliable user-specified iteration
+ * order. Does not permit null keys or values.
+ *
+ * <p>Unlike {@link Collections#unmodifiableMap}, which is a <i>view</i> of a
+ * separate map which can still change, an instance of {@code ImmutableMap}
+ * contains its own data and will <i>never</i> change. {@code ImmutableMap} is
+ * convenient for {@code public static final} maps ("constant maps") and also
+ * lets you easily make a "defensive copy" of a map provided to your class by a
+ * caller.
+ *
+ * <p><i>Performance notes:</i> unlike {@link HashMap}, {@code ImmutableMap} is
+ * not optimized for element types that have slow {@link Object#equals} or
+ * {@link Object#hashCode} implementations. You can get better performance by
+ * 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)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // we're overriding default serialization
+public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
+ /**
+ * Returns the empty map. This map behaves and performs comparably to
+ * {@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 (ImmutableMap<K, V>) EmptyImmutableMap.INSTANCE;
+ }
+
+ /**
+ * Returns an immutable map containing a single entry. This map behaves and
+ * performs comparably to {@link Collections#singletonMap} but will not accept
+ * a null key or value. It is preferable mainly for consistency and
+ * maintainability of your code.
+ */
+ public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
+ return new SingletonImmutableMap<K, V>(
+ checkNotNull(k1), checkNotNull(v1));
+ }
+
+ /**
+ * Returns an immutable map containing the given entries, in order.
+ *
+ * @throws IllegalArgumentException if duplicate keys are provided
+ */
+ public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) {
+ return new RegularImmutableMap<K, V>(entryOf(k1, v1), entryOf(k2, v2));
+ }
+
+ /**
+ * Returns an immutable map containing the given entries, in order.
+ *
+ * @throws IllegalArgumentException if duplicate keys are provided
+ */
+ public static <K, V> ImmutableMap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3) {
+ return new RegularImmutableMap<K, V>(
+ entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
+ }
+
+ /**
+ * Returns an immutable map containing the given entries, in order.
+ *
+ * @throws IllegalArgumentException if duplicate keys are provided
+ */
+ public static <K, V> ImmutableMap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+ return new RegularImmutableMap<K, V>(
+ entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4));
+ }
+
+ /**
+ * Returns an immutable map containing the given entries, in order.
+ *
+ * @throws IllegalArgumentException if duplicate keys are provided
+ */
+ public static <K, V> ImmutableMap<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 RegularImmutableMap<K, V>(entryOf(k1, v1),
+ entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5));
+ }
+
+ // looking for of() with > 5 entries? Use the builder instead.
+
+ /**
+ * Returns a new builder. The generated builder is equivalent to the builder
+ * created by the {@link Builder} constructor.
+ */
+ public static <K, V> Builder<K, V> builder() {
+ return new Builder<K, V>();
+ }
+
+ /**
+ * Verifies that {@code key} and {@code value} are non-null, and returns a new
+ * immutable entry with those values.
+ *
+ * <p>A call to {@link Map.Entry#setValue} on the returned entry will always
+ * 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);
+ }
+
+ /**
+ * A builder for creating immutable map instances, especially {@code public
+ * static final} maps ("constant maps"). Example: <pre> {@code
+ *
+ * static final ImmutableMap<String, Integer> WORD_TO_INT =
+ * new ImmutableMap.Builder<String, Integer>()
+ * .put("one", 1)
+ * .put("two", 2)
+ * .put("three", 3)
+ * .build();}</pre>
+ *
+ * For <i>small</i> immutable maps, the {@code ImmutableMap.of()} methods are
+ * even more convenient.
+ *
+ * <p>Builder instances can be reused - it is safe to call {@link #build}
+ * multiple times to build multiple maps in series. Each map is a superset of
+ * the maps created before it.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static class Builder<K, V> {
+ final ArrayList<Entry<K, V>> entries = Lists.newArrayList();
+
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder
+ * generated by {@link ImmutableMap#builder}.
+ */
+ public Builder() {}
+
+ /**
+ * Associates {@code key} with {@code value} in the built map. Duplicate
+ * keys are not allowed, and will cause {@link #build} to fail.
+ */
+ public Builder<K, V> put(K key, V value) {
+ entries.add(entryOf(key, value));
+ return this;
+ }
+
+ /**
+ * Adds the given {@code entry} to the map, making it immutable if
+ * necessary. Duplicate keys are not allowed, and will cause {@link #build}
+ * to fail.
+ *
+ * @since 11.0
+ */
+ public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
+ K key = entry.getKey();
+ V value = entry.getValue();
+ if (entry instanceof ImmutableEntry) {
+ checkNotNull(key);
+ checkNotNull(value);
+ @SuppressWarnings("unchecked") // all supported methods are covariant
+ Entry<K, V> immutableEntry = (Entry<K, V>) entry;
+ entries.add(immutableEntry);
+ } else {
+ // Directly calling entryOf(entry.getKey(), entry.getValue()) can cause
+ // compilation error in Eclipse.
+ entries.add(entryOf(key, value));
+ }
+ return this;
+ }
+
+ /**
+ * Associates all of the given map's keys and values in the built map.
+ * Duplicate keys are not allowed, and will cause {@link #build} to fail.
+ *
+ * @throws NullPointerException if any key or value in {@code map} is null
+ */
+ public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
+ entries.ensureCapacity(entries.size() + map.size());
+ for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ put(entry.getKey(), entry.getValue());
+ }
+ return this;
+ }
+
+ /*
+ * TODO(kevinb): Should build() and the ImmutableBiMap & ImmutableSortedMap
+ * versions throw an IllegalStateException instead?
+ */
+
+ /**
+ * Returns a newly-created immutable map.
+ *
+ * @throws IllegalArgumentException if duplicate keys were added
+ */
+ public ImmutableMap<K, V> build() {
+ return fromEntryList(entries);
+ }
+
+ private static <K, V> ImmutableMap<K, V> fromEntryList(
+ List<Entry<K, V>> entries) {
+ int size = entries.size();
+ switch (size) {
+ case 0:
+ return of();
+ case 1:
+ return new SingletonImmutableMap<K, V>(getOnlyElement(entries));
+ default:
+ Entry<?, ?>[] entryArray
+ = entries.toArray(new Entry<?, ?>[entries.size()]);
+ return new RegularImmutableMap<K, V>(entryArray);
+ }
+ }
+ }
+
+ /**
+ * Returns an immutable map containing the same entries as {@code map}. If
+ * {@code map} somehow contains entries with duplicate keys (for example, if
+ * it is a {@code SortedMap} whose comparator is not <i>consistent with
+ * equals</i>), the results of this method are undefined.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * @throws NullPointerException if any key or value in {@code map} is null
+ */
+ public static <K, V> ImmutableMap<K, V> copyOf(
+ Map<? extends K, ? extends V> map) {
+ if ((map instanceof ImmutableMap) && !(map instanceof ImmutableSortedMap)) {
+ // TODO(user): Make ImmutableMap.copyOf(immutableBiMap) call copyOf()
+ // on the ImmutableMap delegate(), rather than the bimap itself
+
+ @SuppressWarnings("unchecked") // safe since map is not writable
+ ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
+ if (!kvMap.isPartialView()) {
+ return kvMap;
+ }
+ }
+
+ @SuppressWarnings("unchecked") // we won't write to this array
+ Entry<K, V>[] entries = map.entrySet().toArray(new Entry[0]);
+ switch (entries.length) {
+ case 0:
+ return of();
+ case 1:
+ return new SingletonImmutableMap<K, V>(entryOf(
+ entries[0].getKey(), entries[0].getValue()));
+ default:
+ for (int i = 0; i < entries.length; i++) {
+ K k = entries[i].getKey();
+ V v = entries[i].getValue();
+ entries[i] = entryOf(k, v);
+ }
+ return new RegularImmutableMap<K, V>(entries);
+ }
+ }
+
+ ImmutableMap() {}
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final V put(K k, V v) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final V remove(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final void putAll(Map<? extends K, ? extends V> map) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ @Override
+ public boolean containsKey(@Nullable Object key) {
+ return get(key) != null;
+ }
+
+ @Override
+ public boolean containsValue(@Nullable Object value) {
+ return value != null && Maps.containsValueImpl(this, 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;
+
+ /**
+ * 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>(entrySet()) {
+ @Override ImmutableMap<K, V> map() {
+ return ImmutableMap.this;
+ }
+ };
+ }
+
+ private transient ImmutableCollection<V> values;
+
+ /**
+ * 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 = createValues() : result;
+ }
+
+ ImmutableCollection<V> createValues() {
+ return new ImmutableMapValues<K, V>() {
+ @Override ImmutableMap<K, V> map() {
+ return ImmutableMap.this;
+ }
+ };
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return Maps.equalsImpl(this, object);
+ }
+
+ abstract boolean isPartialView();
+
+ @Override public int hashCode() {
+ // not caching hash code since it could change if map values are mutable
+ // in a way that modifies their hash codes
+ return entrySet().hashCode();
+ }
+
+ @Override public String toString() {
+ return Maps.toStringImpl(this);
+ }
+
+ /**
+ * Serialized type for all ImmutableMap instances. It captures the logical
+ * contents and they are reconstructed using public factory methods. This
+ * ensures that the implementation types remain as implementation details.
+ */
+ static class SerializedForm implements Serializable {
+ private final Object[] keys;
+ private final Object[] values;
+ SerializedForm(ImmutableMap<?, ?> map) {
+ keys = new Object[map.size()];
+ values = new Object[map.size()];
+ int i = 0;
+ for (Entry<?, ?> entry : map.entrySet()) {
+ keys[i] = entry.getKey();
+ values[i] = entry.getValue();
+ i++;
+ }
+ }
+ Object readResolve() {
+ Builder<Object, Object> builder = new Builder<Object, Object>();
+ return createMap(builder);
+ }
+ Object createMap(Builder<Object, Object> builder) {
+ for (int i = 0; i < keys.length; i++) {
+ builder.put(keys[i], values[i]);
+ }
+ return builder.build();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ Object writeReplace() {
+ return new SerializedForm(this);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableMapEntrySet.java b/guava/src/com/google/common/collect/ImmutableMapEntrySet.java
new file mode 100644
index 0000000..a6aa6e0
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableMapEntrySet.java
@@ -0,0 +1,76 @@
+/*
+ * 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
new file mode 100644
index 0000000..56d1796
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableMapKeySet.java
@@ -0,0 +1,92 @@
+/*
+ * 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)
+abstract class ImmutableMapKeySet<K, V> extends TransformedImmutableSet<Entry<K, V>, K> {
+ ImmutableMapKeySet(ImmutableSet<Entry<K, V>> entrySet) {
+ super(entrySet);
+ }
+
+ ImmutableMapKeySet(ImmutableSet<Entry<K, V>> entrySet, int hashCode) {
+ super(entrySet, hashCode);
+ }
+
+ abstract ImmutableMap<K, V> map();
+
+ @Override
+ K transform(Entry<K, V> entry) {
+ return entry.getKey();
+ }
+
+ @Override
+ public boolean contains(@Nullable Object object) {
+ return map().containsKey(object);
+ }
+
+ @Override
+ boolean isPartialView() {
+ return true;
+ }
+
+ @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;
+ }
+ };
+ }
+
+ @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
new file mode 100644
index 0000000..d16285b
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableMapValues.java
@@ -0,0 +1,89 @@
+/*
+ * 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)
+abstract class ImmutableMapValues<K, V> extends ImmutableCollection<V> {
+ ImmutableMapValues() {}
+
+ abstract ImmutableMap<K, V> 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
new file mode 100644
index 0000000..8b6aa29
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableMultimap.java
@@ -0,0 +1,682 @@
+/*
+ * 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 java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+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 javax.annotation.Nullable;
+
+/**
+ * An immutable {@link Multimap}. Does not permit null keys or values.
+ *
+ * <p>Unlike {@link Multimaps#unmodifiableMultimap(Multimap)}, which is
+ * a <i>view</i> of a separate multimap which can still change, an instance of
+ * {@code ImmutableMultimap} contains its own data and will <i>never</i>
+ * change. {@code ImmutableMultimap} is convenient for
+ * {@code public static final} multimaps ("constant multimaps") and also lets
+ * you easily make a "defensive copy" of a multimap provided to your class by
+ * a caller.
+ *
+ * <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 class
+ * are guaranteed to be immutable.
+ *
+ * <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>
+ implements Multimap<K, V>, Serializable {
+
+ /** Returns an empty multimap. */
+ public static <K, V> ImmutableMultimap<K, V> of() {
+ return ImmutableListMultimap.of();
+ }
+
+ /**
+ * Returns an immutable multimap containing a single entry.
+ */
+ public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1) {
+ return ImmutableListMultimap.of(k1, v1);
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ */
+ public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1, K k2, V v2) {
+ return ImmutableListMultimap.of(k1, v1, k2, v2);
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ */
+ public static <K, V> ImmutableMultimap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3) {
+ return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3);
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ */
+ public static <K, V> ImmutableMultimap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+ return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4);
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ */
+ public static <K, V> ImmutableMultimap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+ return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
+ }
+
+ // looking for of() with > 5 entries? Use the builder instead.
+
+ /**
+ * Returns a new builder. The generated builder is equivalent to the builder
+ * created by the {@link Builder} constructor.
+ */
+ public static <K, V> Builder<K, V> builder() {
+ return new Builder<K, V>();
+ }
+
+ /**
+ * Multimap for {@link ImmutableMultimap.Builder} that maintains key and
+ * value orderings, allows duplicate values, and performs better than
+ * {@link LinkedListMultimap}.
+ */
+ private static class BuilderMultimap<K, V> extends AbstractMultimap<K, V> {
+ BuilderMultimap() {
+ super(new LinkedHashMap<K, Collection<V>>());
+ }
+ @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
+ *
+ * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
+ * new ImmutableMultimap.Builder<String, Integer>()
+ * .put("one", 1)
+ * .putAll("several", 1, 2, 3)
+ * .putAll("many", 1, 2, 3, 4, 5)
+ * .build();}</pre>
+ *
+ * Builder instances can be reused; it is safe to call {@link #build} multiple
+ * times to build multiple multimaps in series. Each multimap contains the
+ * key-value mappings in the previously created multimaps.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static class Builder<K, V> {
+ Multimap<K, V> builderMultimap = new BuilderMultimap<K, V>();
+ Comparator<? super K> keyComparator;
+ Comparator<? super V> valueComparator;
+
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder
+ * generated by {@link ImmutableMultimap#builder}.
+ */
+ public Builder() {}
+
+ /**
+ * Adds a key-value mapping to the built multimap.
+ */
+ public Builder<K, V> put(K key, V value) {
+ builderMultimap.put(checkNotNull(key), checkNotNull(value));
+ return this;
+ }
+
+ /**
+ * Adds an entry to the built multimap.
+ *
+ * @since 11.0
+ */
+ public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
+ builderMultimap.put(
+ checkNotNull(entry.getKey()), checkNotNull(entry.getValue()));
+ return this;
+ }
+
+ /**
+ * Stores a collection of values with the same key in the built multimap.
+ *
+ * @throws NullPointerException if {@code key}, {@code values}, or any
+ * element in {@code values} is null. The builder is left in an invalid
+ * state.
+ */
+ public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
+ Collection<V> valueList = builderMultimap.get(checkNotNull(key));
+ for (V value : values) {
+ valueList.add(checkNotNull(value));
+ }
+ return this;
+ }
+
+ /**
+ * Stores an array of values with the same key in the built multimap.
+ *
+ * @throws NullPointerException if the key or any value is null. The builder
+ * is left in an invalid state.
+ */
+ public Builder<K, V> putAll(K key, V... values) {
+ return putAll(key, Arrays.asList(values));
+ }
+
+ /**
+ * Stores another multimap's entries in the built multimap. The generated
+ * multimap's key and value orderings correspond to the iteration ordering
+ * of the {@code multimap.asMap()} view, with new keys and values following
+ * any existing keys and values.
+ *
+ * @throws NullPointerException if any key or value in {@code multimap} is
+ * null. The builder is left in an invalid state.
+ */
+ public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) {
+ for (Entry<? extends K, ? extends Collection<? extends V>> entry
+ : multimap.asMap().entrySet()) {
+ putAll(entry.getKey(), entry.getValue());
+ }
+ return this;
+ }
+
+ /**
+ * Specifies the ordering of the generated multimap's keys.
+ *
+ * @since 8.0
+ */
+ @Beta
+ public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
+ this.keyComparator = checkNotNull(keyComparator);
+ return this;
+ }
+
+ /**
+ * Specifies the ordering of the generated multimap's values for each key.
+ *
+ * @since 8.0
+ */
+ @Beta
+ public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
+ this.valueComparator = checkNotNull(valueComparator);
+ return this;
+ }
+
+ /**
+ * Returns a newly-created immutable multimap.
+ */
+ public ImmutableMultimap<K, V> build() {
+ if (valueComparator != null) {
+ for (Collection<V> values : builderMultimap.asMap().values()) {
+ List<V> list = (List <V>) values;
+ 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);
+ }
+ }
+
+ /**
+ * Returns an immutable multimap containing the same mappings as {@code
+ * multimap}. The generated multimap's key and value orderings correspond to
+ * the iteration ordering of the {@code multimap.asMap()} view.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * @throws NullPointerException if any key or value in {@code multimap} is
+ * null
+ */
+ public static <K, V> ImmutableMultimap<K, V> copyOf(
+ Multimap<? extends K, ? extends V> multimap) {
+ if (multimap instanceof ImmutableMultimap) {
+ @SuppressWarnings("unchecked") // safe since multimap is not writable
+ ImmutableMultimap<K, V> kvMultimap
+ = (ImmutableMultimap<K, V>) multimap;
+ if (!kvMultimap.isPartialView()) {
+ return kvMultimap;
+ }
+ }
+ return ImmutableListMultimap.copyOf(multimap);
+ }
+
+ final transient ImmutableMap<K, ? extends ImmutableCollection<V>> map;
+ final transient int size;
+
+ // These constants allow the deserialization code to set final fields. This
+ // holder class makes sure they are not initialized unless an instance is
+ // deserialized.
+ @GwtIncompatible("java serialization is not supported")
+ static class FieldSettersHolder {
+ static final Serialization.FieldSetter<ImmutableMultimap>
+ MAP_FIELD_SETTER = Serialization.getFieldSetter(
+ ImmutableMultimap.class, "map");
+ static final Serialization.FieldSetter<ImmutableMultimap>
+ SIZE_FIELD_SETTER = Serialization.getFieldSetter(
+ ImmutableMultimap.class, "size");
+ }
+
+ ImmutableMultimap(ImmutableMap<K, ? extends ImmutableCollection<V>> map,
+ int size) {
+ this.map = map;
+ this.size = size;
+ }
+
+ // mutators (not supported)
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public ImmutableCollection<V> removeAll(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public ImmutableCollection<V> replaceValues(K key,
+ Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns an immutable collection of the values for the given key. If no
+ * mappings in the multimap have the provided key, an empty immutable
+ * collection is returned. The values are in the same order as the parameters
+ * used to build this multimap.
+ */
+ @Override
+ public abstract ImmutableCollection<V> get(K key);
+
+ /**
+ * Returns an immutable multimap which is the inverse of this one. For every
+ * key-value mapping in the original, the result will have a mapping with
+ * key and value reversed.
+ *
+ * @since 11.0
+ */
+ @Beta
+ public abstract ImmutableMultimap<V, K> inverse();
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public boolean put(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public boolean putAll(K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public boolean remove(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ 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
+
+ /**
+ * Returns an immutable set of the distinct keys in this multimap. These keys
+ * are ordered according to when they first appeared during the construction
+ * of this multimap.
+ */
+ @Override
+ public ImmutableSet<K> keySet() {
+ return map.keySet();
+ }
+
+ /**
+ * Returns an immutable map that associates each key with its corresponding
+ * values in the multimap.
+ */
+ @Override
+ @SuppressWarnings("unchecked") // a widening cast
+ public ImmutableMap<K, Collection<V>> asMap() {
+ return (ImmutableMap) map;
+ }
+
+ private transient ImmutableCollection<Entry<K, V>> entries;
+
+ /**
+ * Returns an immutable collection of all key-value pairs in the multimap. Its
+ * iterator traverses the values for the first key, the values for the second
+ * key, and so on.
+ */
+ @Override
+ public ImmutableCollection<Entry<K, V>> entries() {
+ ImmutableCollection<Entry<K, V>> result = entries;
+ return (result == null)
+ ? (entries = new EntryCollection<K, V>(this)) : result;
+ }
+
+ private static class EntryCollection<K, V>
+ extends ImmutableCollection<Entry<K, V>> {
+ final ImmutableMultimap<K, V> multimap;
+
+ EntryCollection(ImmutableMultimap<K, V> multimap) {
+ this.multimap = multimap;
+ }
+
+ @Override public UnmodifiableIterator<Entry<K, V>> iterator() {
+ 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() {
+ return multimap.isPartialView();
+ }
+
+ @Override
+ public int size() {
+ return multimap.size();
+ }
+
+ @Override public boolean contains(Object object) {
+ if (object instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) object;
+ return multimap.containsEntry(entry.getKey(), entry.getValue());
+ }
+ return false;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private transient ImmutableMultiset<K> keys;
+
+ /**
+ * Returns a collection, which may contain duplicates, of all keys. The number
+ * of times a key appears in the returned multiset equals the number of
+ * mappings the key has in the multimap. Duplicate keys appear consecutively
+ * in the multiset's iteration order.
+ */
+ @Override
+ public ImmutableMultiset<K> keys() {
+ ImmutableMultiset<K> result = keys;
+ return (result == null) ? (keys = createKeys()) : result;
+ }
+
+ private 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 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
+ * key, and so on.
+ */
+ @Override
+ public ImmutableCollection<V> values() {
+ ImmutableCollection<V> result = values;
+ return (result == null) ? (values = new Values<V>(this)) : result;
+ }
+
+ private static class Values<V> extends ImmutableCollection<V> {
+ final ImmutableMultimap<?, V> multimap;
+
+ Values(ImmutableMultimap<?, V> multimap) {
+ this.multimap = multimap;
+ }
+
+ @Override public UnmodifiableIterator<V> iterator() {
+ return Maps.valueIterator(multimap.entries().iterator());
+ }
+
+ @Override
+ public int size() {
+ return multimap.size();
+ }
+
+ @Override boolean isPartialView() {
+ return true;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ImmutableMultiset.java b/guava/src/com/google/common/collect/ImmutableMultiset.java
new file mode 100644
index 0000000..b909315
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableMultiset.java
@@ -0,0 +1,596 @@
+/*
+ * 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.GwtCompatible;
+import com.google.common.primitives.Ints;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable hash-based multiset. Does not permit null elements.
+ *
+ * <p>Its iterator orders elements according to the first appearance of the
+ * element among the items passed to the factory method or builder. When the
+ * 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)
+ */
+@GwtCompatible(serializable = true)
+@SuppressWarnings("serial") // we're overriding default serialization
+// TODO(user): write an efficient asList() implementation
+public abstract class ImmutableMultiset<E> extends ImmutableCollection<E>
+ implements Multiset<E> {
+
+ /**
+ * Returns the empty immutable multiset.
+ */
+ @SuppressWarnings("unchecked") // all supported methods are covariant
+ public static <E> ImmutableMultiset<E> of() {
+ return (ImmutableMultiset<E>) EmptyImmutableMultiset.INSTANCE;
+ }
+
+ /**
+ * Returns an immutable multiset containing a single element.
+ *
+ * @throws NullPointerException if {@code element} is null
+ * @since 6.0 (source-compatible since 2.0)
+ */
+ @SuppressWarnings("unchecked") // generic array created but never written
+ public static <E> ImmutableMultiset<E> of(E element) {
+ return copyOfInternal(element);
+ }
+
+ /**
+ * Returns an immutable multiset containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ * @since 6.0 (source-compatible since 2.0)
+ */
+ @SuppressWarnings("unchecked") //
+ public static <E> ImmutableMultiset<E> of(E e1, E e2) {
+ return copyOfInternal(e1, e2);
+ }
+
+ /**
+ * Returns an immutable multiset containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ * @since 6.0 (source-compatible since 2.0)
+ */
+ @SuppressWarnings("unchecked") //
+ public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3) {
+ return copyOfInternal(e1, e2, e3);
+ }
+
+ /**
+ * Returns an immutable multiset containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ * @since 6.0 (source-compatible since 2.0)
+ */
+ @SuppressWarnings("unchecked") //
+ public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3, E e4) {
+ return copyOfInternal(e1, e2, e3, e4);
+ }
+
+ /**
+ * Returns an immutable multiset containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ * @since 6.0 (source-compatible since 2.0)
+ */
+ @SuppressWarnings("unchecked") //
+ public static <E> ImmutableMultiset<E> of(E e1, E e2, E e3, E e4, E e5) {
+ return copyOfInternal(e1, e2, e3, e4, e5);
+ }
+
+ /**
+ * Returns an immutable multiset containing the given elements, in order.
+ *
+ * @throws NullPointerException if any element is null
+ * @since 6.0 (source-compatible since 2.0)
+ */
+ @SuppressWarnings("unchecked") //
+ public static <E> ImmutableMultiset<E> of(
+ E e1, E e2, E e3, E e4, E e5, E e6, E... others) {
+ int size = others.length + 6;
+ List<E> all = new ArrayList<E>(size);
+ Collections.addAll(all, e1, e2, e3, e4, e5, e6);
+ Collections.addAll(all, others);
+ return copyOf(all);
+ }
+
+ /**
+ * 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}.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ * @since 6.0
+ */
+ public static <E> ImmutableMultiset<E> copyOf(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(Arrays.asList(2, 3, 1, 3))} yields
+ * a multiset with elements in the order {@code 2, 3, 3, 1}.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * <p><b>Note:</b> Despite what the method name suggests, if {@code elements}
+ * is an {@code ImmutableMultiset}, no copy will actually be performed, and
+ * the given multiset itself will be returned.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableMultiset<E> copyOf(
+ Iterable<? extends E> elements) {
+ if (elements instanceof ImmutableMultiset) {
+ @SuppressWarnings("unchecked") // all supported methods are covariant
+ ImmutableMultiset<E> result = (ImmutableMultiset<E>) elements;
+ if (!result.isPartialView()) {
+ return result;
+ }
+ }
+
+ Multiset<? extends E> multiset = (elements instanceof Multiset)
+ ? Multisets.cast(elements)
+ : LinkedHashMultiset.create(elements);
+
+ return copyOfInternal(multiset);
+ }
+
+ private static <E> ImmutableMultiset<E> copyOfInternal(E... elements) {
+ return copyOf(Arrays.asList(elements));
+ }
+
+ private static <E> ImmutableMultiset<E> copyOfInternal(
+ Multiset<? extends E> multiset) {
+ return copyFromEntries(multiset.entrySet());
+ }
+
+ static <E> ImmutableMultiset<E> copyFromEntries(
+ Collection<? extends Entry<? extends E>> entries) {
+ long size = 0;
+ ImmutableMap.Builder<E, Integer> builder = ImmutableMap.builder();
+ for (Entry<? extends E> entry : entries) {
+ int count = entry.getCount();
+ if (count > 0) {
+ // Since ImmutableMap.Builder throws an NPE if an element is null, no
+ // other null checks are needed.
+ builder.put(entry.getElement(), count);
+ size += count;
+ }
+ }
+
+ if (size == 0) {
+ return of();
+ }
+ return new RegularImmutableMultiset<E>(
+ builder.build(), Ints.saturatedCast(size));
+ }
+
+ /**
+ * 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(Arrays.asList(2, 3, 1, 3).iterator())}
+ * yields a multiset with elements in the order {@code 2, 3, 3, 1}.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableMultiset<E> copyOf(
+ Iterator<? extends E> elements) {
+ Multiset<E> multiset = LinkedHashMultiset.create();
+ Iterators.addAll(multiset, elements);
+ return copyOfInternal(multiset);
+ }
+
+ ImmutableMultiset() {}
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ final Iterator<Entry<E>> entryIterator = entrySet().iterator();
+ return new UnmodifiableIterator<E>() {
+ int remaining;
+ E element;
+
+ @Override
+ public boolean hasNext() {
+ return (remaining > 0) || entryIterator.hasNext();
+ }
+
+ @Override
+ public E next() {
+ if (remaining <= 0) {
+ Entry<E> entry = entryIterator.next();
+ element = entry.getElement();
+ remaining = entry.getCount();
+ }
+ remaining--;
+ return element;
+ }
+ };
+ }
+
+ @Override
+ public boolean contains(@Nullable Object object) {
+ return count(object) > 0;
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> targets) {
+ return elementSet().containsAll(targets);
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final int add(E element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final int remove(Object element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final int setCount(E element, int count) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final boolean setCount(E element, int oldCount, int newCount) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Multiset) {
+ Multiset<?> that = (Multiset<?>) object;
+ if (this.size() != that.size()) {
+ return false;
+ }
+ for (Entry<?> entry : that.entrySet()) {
+ if (count(entry.getElement()) != entry.getCount()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(entrySet());
+ }
+
+ @Override public String toString() {
+ return entrySet().toString();
+ }
+
+ private transient ImmutableSet<Entry<E>> entrySet;
+
+ @Override
+ public ImmutableSet<Entry<E>> entrySet() {
+ ImmutableSet<Entry<E>> es = entrySet;
+ return (es == null) ? (entrySet = createEntrySet()) : es;
+ }
+
+ abstract ImmutableSet<Entry<E>> createEntrySet();
+
+ abstract class EntrySet extends ImmutableSet<Entry<E>> {
+ @Override
+ boolean isPartialView() {
+ return ImmutableMultiset.this.isPartialView();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ if (o instanceof Entry) {
+ Entry<?> entry = (Entry<?>) o;
+ if (entry.getCount() <= 0) {
+ return false;
+ }
+ int count = count(entry.getElement());
+ return count == entry.getCount();
+ }
+ return false;
+ }
+
+ /*
+ * TODO(hhchan): Revert once we have a separate, manual emulation of this
+ * class.
+ */
+ @Override
+ public Object[] toArray() {
+ Object[] newArray = new Object[size()];
+ return toArray(newArray);
+ }
+
+ /*
+ * TODO(hhchan): Revert once we have a separate, manual emulation of this
+ * class.
+ */
+ @Override
+ public <T> T[] toArray(T[] other) {
+ int size = size();
+ if (other.length < size) {
+ other = ObjectArrays.newArray(other, size);
+ } else if (other.length > size) {
+ other[size] = null;
+ }
+
+ // Writes will produce ArrayStoreException when the toArray() doc requires
+ Object[] otherAsObjectArray = other;
+ int index = 0;
+ for (Entry<?> element : this) {
+ otherAsObjectArray[index++] = element;
+ }
+ return other;
+ }
+
+ @Override
+ public int hashCode() {
+ return ImmutableMultiset.this.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);
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ static class EntrySetSerializedForm<E> implements Serializable {
+ final ImmutableMultiset<E> multiset;
+
+ EntrySetSerializedForm(ImmutableMultiset<E> multiset) {
+ this.multiset = multiset;
+ }
+
+ Object readResolve() {
+ return multiset.entrySet();
+ }
+ }
+
+ private static class SerializedForm implements Serializable {
+ final Object[] elements;
+ final int[] counts;
+
+ SerializedForm(Multiset<?> multiset) {
+ int distinct = multiset.entrySet().size();
+ elements = new Object[distinct];
+ counts = new int[distinct];
+ int i = 0;
+ for (Entry<?> entry : multiset.entrySet()) {
+ elements[i] = entry.getElement();
+ counts[i] = entry.getCount();
+ i++;
+ }
+ }
+
+ Object readResolve() {
+ LinkedHashMultiset<Object> multiset =
+ LinkedHashMultiset.create(elements.length);
+ for (int i = 0; i < elements.length; i++) {
+ multiset.add(elements[i], counts[i]);
+ }
+ return ImmutableMultiset.copyOf(multiset);
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ // We can't label this with @Override, because it doesn't override anything
+ // in the GWT emulated version.
+ Object writeReplace() {
+ return new SerializedForm(this);
+ }
+
+ /**
+ * Returns a new builder. The generated builder is equivalent to the builder
+ * created by the {@link Builder} constructor.
+ */
+ public static <E> Builder<E> builder() {
+ return new Builder<E>();
+ }
+
+ /**
+ * A builder for creating immutable multiset instances, especially {@code
+ * public static final} multisets ("constant multisets"). Example:
+ * <pre> {@code
+ *
+ * public static final ImmutableMultiset<Bean> BEANS =
+ * new ImmutableMultiset.Builder<Bean>()
+ * .addCopies(Bean.COCOA, 4)
+ * .addCopies(Bean.GARDEN, 6)
+ * .addCopies(Bean.RED, 8)
+ * .addCopies(Bean.BLACK_EYED, 10)
+ * .build();}</pre>
+ *
+ * Builder instances can be reused; it is safe to call {@link #build} multiple
+ * times to build multiple multisets in series.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static class Builder<E> extends ImmutableCollection.Builder<E> {
+ final Multiset<E> contents;
+
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder
+ * generated by {@link ImmutableMultiset#builder}.
+ */
+ public Builder() {
+ this(LinkedHashMultiset.<E>create());
+ }
+
+ Builder(Multiset<E> contents) {
+ this.contents = contents;
+ }
+
+ /**
+ * Adds {@code element} to the {@code ImmutableMultiset}.
+ *
+ * @param element the element to add
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code element} is null
+ */
+ @Override public Builder<E> add(E element) {
+ contents.add(checkNotNull(element));
+ return this;
+ }
+
+ /**
+ * Adds a number of occurrences of an element to this {@code
+ * ImmutableMultiset}.
+ *
+ * @param element the element to add
+ * @param occurrences the number of occurrences of the element to add. May
+ * be zero, in which case no change will be made.
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code element} is null
+ * @throws IllegalArgumentException if {@code occurrences} is negative, or
+ * if this operation would result in more than {@link Integer#MAX_VALUE}
+ * occurrences of the element
+ */
+ public Builder<E> addCopies(E element, int occurrences) {
+ contents.add(checkNotNull(element), occurrences);
+ return this;
+ }
+
+ /**
+ * Adds or removes the necessary occurrences of an element such that the
+ * element attains the desired count.
+ *
+ * @param element the element to add or remove occurrences of
+ * @param count the desired count of the element in this multiset
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code element} is null
+ * @throws IllegalArgumentException if {@code count} is negative
+ */
+ public Builder<E> setCount(E element, int count) {
+ contents.setCount(checkNotNull(element), count);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableMultiset}.
+ *
+ * @param elements the elements to add
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ @Override public Builder<E> add(E... elements) {
+ super.add(elements);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableMultiset}.
+ *
+ * @param elements the {@code Iterable} to add to the {@code
+ * ImmutableMultiset}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ @Override public Builder<E> addAll(Iterable<? extends E> elements) {
+ if (elements instanceof Multiset) {
+ Multiset<? extends E> multiset = Multisets.cast(elements);
+ for (Entry<? extends E> entry : multiset.entrySet()) {
+ addCopies(entry.getElement(), entry.getCount());
+ }
+ } else {
+ super.addAll(elements);
+ }
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableMultiset}.
+ *
+ * @param elements the elements to add to the {@code ImmutableMultiset}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ @Override public Builder<E> addAll(Iterator<? extends E> elements) {
+ super.addAll(elements);
+ return this;
+ }
+
+ /**
+ * Returns a newly-created {@code ImmutableMultiset} based on the contents
+ * of the {@code Builder}.
+ */
+ @Override public ImmutableMultiset<E> build() {
+ return copyOf(contents);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableSet.java b/guava/src/com/google/common/collect/ImmutableSet.java
new file mode 100644
index 0000000..55417a3
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableSet.java
@@ -0,0 +1,626 @@
+/*
+ * 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.VisibleForTesting;
+import com.google.common.primitives.Ints;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A high-performance, immutable {@code Set} with reliable, user-specified
+ * iteration order. Does not permit null elements.
+ *
+ * <p>Unlike {@link Collections#unmodifiableSet}, which is a <i>view</i> of a
+ * separate collection that can still change, an instance of this class contains
+ * its own private data and will <i>never</i> change. This class is convenient
+ * for {@code public static final} sets ("constant sets") and also lets you
+ * easily make a "defensive copy" of a set provided to your class by a caller.
+ *
+ * <p><b>Warning:</b> Like most sets, an {@code ImmutableSet} will not function
+ * correctly if an element is modified after being placed in the set. For this
+ * reason, and to avoid general confusion, it is strongly recommended to place
+ * only immutable objects into this collection.
+ *
+ * <p>This class has been observed to perform significantly better than {@link
+ * HashSet} for objects with very fast {@link Object#hashCode} implementations
+ * (as a well-behaved immutable object should). While this class's factory
+ * methods create hash-based instances, the {@link ImmutableSortedSet} subclass
+ * performs binary searches instead.
+ *
+ * <p><b>Note:</b> Although this class is not final, it cannot be subclassed
+ * 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
+ * @author Nick Kralevich
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // we're overriding default serialization
+public abstract class ImmutableSet<E> extends ImmutableCollection<E>
+ implements Set<E> {
+ /**
+ * Returns the empty immutable set. This set behaves and performs comparably
+ * to {@link Collections#emptySet}, 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 <E> ImmutableSet<E> of() {
+ return (ImmutableSet<E>) EmptyImmutableSet.INSTANCE;
+ }
+
+ /**
+ * Returns an immutable set containing a single element. This set behaves and
+ * performs comparably to {@link Collections#singleton}, but will not accept
+ * a null element. It is preferable mainly for consistency and
+ * maintainability of your code.
+ */
+ public static <E> ImmutableSet<E> of(E element) {
+ return new SingletonImmutableSet<E>(element);
+ }
+
+ /**
+ * Returns an immutable set containing the given elements, in order. Repeated
+ * occurrences of an element (according to {@link Object#equals}) after the
+ * first are ignored.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ public static <E> ImmutableSet<E> of(E e1, E e2) {
+ return construct(2, e1, e2);
+ }
+
+ /**
+ * Returns an immutable set containing the given elements, in order. Repeated
+ * occurrences of an element (according to {@link Object#equals}) after the
+ * first are ignored.
+ *
+ * @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);
+ }
+
+ /**
+ * Returns an immutable set containing the given elements, in order. Repeated
+ * occurrences of an element (according to {@link Object#equals}) after the
+ * first are ignored.
+ *
+ * @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);
+ }
+
+ /**
+ * Returns an immutable set containing the given elements, in order. Repeated
+ * occurrences of an element (according to {@link Object#equals}) after the
+ * first are ignored.
+ *
+ * @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);
+ }
+
+ /**
+ * Returns an immutable set containing the given elements, in order. Repeated
+ * occurrences of an element (according to {@link Object#equals}) after the
+ * first are ignored.
+ *
+ * @throws NullPointerException if any element is null
+ * @since 3.0 (source-compatible since 2.0)
+ */
+ public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5, E e6,
+ E... others) {
+ final int paramCount = 6;
+ Object[] elements = new Object[paramCount + others.length];
+ elements[0] = e1;
+ elements[1] = e2;
+ elements[2] = e3;
+ elements[3] = e4;
+ elements[4] = e5;
+ elements[5] = e6;
+ System.arraycopy(others, 0, elements, paramCount, others.length);
+ return construct(elements.length, 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);
+ }
+ }
+ int tableSize = chooseTableSize(n);
+ Object[] table = new Object[tableSize];
+ int mask = tableSize - 1;
+ int hashCode = 0;
+ int uniques = 0;
+ for (int i = 0; i < n; i++) {
+ Object element = ObjectArrays.checkElementNotNull(elements[i], i);
+ int hash = element.hashCode();
+ for (int j = Hashing.smear(hash); ; j++) {
+ int index = j & mask;
+ Object value = table[index];
+ if (value == null) {
+ // Came to an empty slot. Put the element here.
+ elements[uniques++] = element;
+ table[index] = element;
+ hashCode += hash;
+ break;
+ } else if (value.equals(element)) {
+ break;
+ }
+ }
+ }
+ Arrays.fill(elements, uniques, n, null);
+ if (uniques == 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];
+ return new SingletonImmutableSet<E>(element, hashCode);
+ } else if (tableSize != chooseTableSize(uniques)) {
+ // Resize the table when the array includes too many duplicates.
+ // when this happens, we have already made a copy
+ return construct(uniques, elements);
+ } else {
+ Object[] uniqueElements = (uniques < elements.length)
+ ? ObjectArrays.arraysCopyOf(elements, uniques)
+ : elements;
+ return new RegularImmutableSet<E>(uniqueElements, hashCode, table, mask);
+ }
+ }
+
+ // 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);
+
+ /**
+ * 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.
+ */
+ @VisibleForTesting static int chooseTableSize(int setSize) {
+ // Correct the size for open addressing to match desired load factor.
+ 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;
+ }
+
+ // The table can't be completely full or we'll get infinite reprobes
+ checkArgument(setSize < MAX_TABLE_SIZE, "collection too large");
+ return MAX_TABLE_SIZE;
+ }
+
+ /**
+ * Returns an immutable set containing the given elements, in order. Repeated
+ * occurrences of an element (according to {@link Object#equals}) after the
+ * first are ignored.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ * @since 3.0
+ */
+ public static <E> ImmutableSet<E> copyOf(E[] elements) {
+ // TODO(benyu): could we delegate to
+ // copyFromCollection(Arrays.asList(elements))?
+ switch (elements.length) {
+ case 0:
+ return of();
+ case 1:
+ return of(elements[0]);
+ default:
+ return construct(elements.length, elements.clone());
+ }
+ }
+
+ /**
+ * Returns an immutable set containing the given elements, in order. Repeated
+ * occurrences of an element (according to {@link Object#equals}) after the
+ * first are ignored. This method iterates over {@code elements} at most once.
+ *
+ * <p>Note that if {@code s} is a {@code Set<String>}, then {@code
+ * ImmutableSet.copyOf(s)} returns an {@code ImmutableSet<String>} containing
+ * each of the strings in {@code s}, while {@code ImmutableSet.of(s)} returns
+ * a {@code ImmutableSet<Set<String>>} containing one element (the given set
+ * itself).
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
+ return (elements instanceof Collection)
+ ? copyOf(Collections2.cast(elements))
+ : copyOf(elements.iterator());
+ }
+
+ /**
+ * Returns an immutable set containing the given elements, in order. Repeated
+ * occurrences of an element (according to {@link Object#equals}) after the
+ * first are ignored.
+ *
+ * @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();
+ }
+ }
+
+ /**
+ * Returns an immutable set containing the given elements, in order. Repeated
+ * occurrences of an element (according to {@link Object#equals}) after the
+ * first are ignored. This method iterates over {@code elements} at most
+ * once.
+ *
+ * <p>Note that if {@code s} is a {@code Set<String>}, then {@code
+ * ImmutableSet.copyOf(s)} returns an {@code ImmutableSet<String>} containing
+ * each of the strings in {@code s}, while {@code ImmutableSet.of(s)} returns
+ * a {@code ImmutableSet<Set<String>>} containing one element (the given set
+ * itself).
+ *
+ * <p><b>Note:</b> Despite what the method name suggests, {@code copyOf} will
+ * return constant-space views, rather than linear-space copies, of some
+ * inputs known to be immutable. For some other immutable inputs, such as key
+ * sets of an {@code ImmutableMap}, it still performs a copy in order to avoid
+ * holding references to the values of the map. The heuristics used in this
+ * decision are undocumented and subject to change except that:
+ * <ul>
+ * <li>A full copy will be done of any {@code ImmutableSortedSet}.</li>
+ * <li>{@code ImmutableSet.copyOf()} is idempotent with respect to pointer
+ * equality.</li>
+ * </ul>
+ *
+ * <p>This method is safe to use even when {@code elements} is a synchronized
+ * or concurrent collection that is currently being modified by another
+ * thread.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ * @since 7.0 (source-compatible since 2.0)
+ */
+ public static <E> ImmutableSet<E> copyOf(Collection<? extends E> elements) {
+ if (elements instanceof ImmutableSet
+ && !(elements instanceof ImmutableSortedSet)) {
+ @SuppressWarnings("unchecked") // all supported methods are covariant
+ ImmutableSet<E> set = (ImmutableSet<E>) elements;
+ if (!set.isPartialView()) {
+ return set;
+ }
+ }
+ return copyFromCollection(elements);
+ }
+
+ private static <E> ImmutableSet<E> copyFromCollection(
+ Collection<? extends E> collection) {
+ Object[] elements = collection.toArray();
+ switch (elements.length) {
+ case 0:
+ return of();
+ case 1:
+ @SuppressWarnings("unchecked") // collection had only Es in it
+ E onlyElement = (E) elements[0];
+ return of(onlyElement);
+ default:
+ // safe to use the array without copying it
+ // as specified by Collection.toArray().
+ return construct(elements.length, elements);
+ }
+ }
+
+ ImmutableSet() {}
+
+ /** Returns {@code true} if the {@code hashCode()} method runs quickly. */
+ boolean isHashCodeFast() {
+ return false;
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof ImmutableSet
+ && isHashCodeFast()
+ && ((ImmutableSet<?>) object).isHashCodeFast()
+ && hashCode() != object.hashCode()) {
+ return false;
+ }
+ return Sets.equalsImpl(this, object);
+ }
+
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+
+ // This declaration is needed to make Set.iterator() and
+ // ImmutableCollection.iterator() consistent.
+ @Override public abstract UnmodifiableIterator<E> iterator();
+
+ abstract static class ArrayImmutableSet<E> extends ImmutableSet<E> {
+ // the elements (two or more) in the desired order.
+ final transient Object[] elements;
+
+ ArrayImmutableSet(Object[] elements) {
+ this.elements = elements;
+ }
+
+ @Override
+ public int size() {
+ return elements.length;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ return asList().iterator();
+ }
+
+ @Override public Object[] toArray() {
+ return asList().toArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return asList().toArray(array);
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ if (targets == this) {
+ return true;
+ }
+ if (!(targets instanceof ArrayImmutableSet)) {
+ return super.containsAll(targets);
+ }
+ if (targets.size() > size()) {
+ return false;
+ }
+ for (Object target : ((ArrayImmutableSet<?>) targets).elements) {
+ if (!contains(target)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override ImmutableList<E> createAsList() {
+ return new RegularImmutableAsList<E>(this, elements);
+ }
+ }
+
+ /*
+ * This class is used to serialize all ImmutableSet instances, except for
+ * ImmutableEnumSet/ImmutableSortedSet, regardless of implementation type. It
+ * captures their "logical contents" and they are reconstructed using public
+ * static factories. This is necessary to ensure that the existence of a
+ * particular implementation type is an implementation detail.
+ */
+ private static class SerializedForm implements Serializable {
+ final Object[] elements;
+ SerializedForm(Object[] elements) {
+ this.elements = elements;
+ }
+ Object readResolve() {
+ return copyOf(elements);
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ @Override Object writeReplace() {
+ return new SerializedForm(toArray());
+ }
+
+ /**
+ * Returns a new builder. The generated builder is equivalent to the builder
+ * created by the {@link Builder} constructor.
+ */
+ public static <E> Builder<E> builder() {
+ return new Builder<E>();
+ }
+
+ /**
+ * A builder for creating immutable set instances, especially {@code public
+ * static final} sets ("constant sets"). Example: <pre> {@code
+ *
+ * public static final ImmutableSet<Color> GOOGLE_COLORS =
+ * new ImmutableSet.Builder<Color>()
+ * .addAll(WEBSAFE_COLORS)
+ * .add(new Color(0, 191, 255))
+ * .build();}</pre>
+ *
+ * Builder instances can be reused; it is safe to call {@link #build} multiple
+ * times to build multiple sets in series. Each set is a superset of the set
+ * created before it.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static class Builder<E> extends ImmutableCollection.Builder<E> {
+ Object[] contents;
+ int size;
+
+ /**
+ * 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 capacity to allow the specified number of elements to be added.
+ */
+ Builder<E> expandFor(int count) {
+ int minCapacity = size + count;
+ if (contents.length < minCapacity) {
+ contents = ObjectArrays.arraysCopyOf(
+ contents, expandedCapacity(contents.length, minCapacity));
+ }
+ return this;
+ }
+
+ /**
+ * Adds {@code element} to the {@code ImmutableSet}. If the {@code
+ * ImmutableSet} already contains {@code element}, then {@code add} has no
+ * effect (only the previously added element is retained).
+ *
+ * @param element the element to add
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code element} is null
+ */
+ @Override public Builder<E> add(E element) {
+ expandFor(1);
+ contents[size++] = checkNotNull(element);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableSet},
+ * ignoring duplicate elements (only the first duplicate element is added).
+ *
+ * @param elements the elements to add
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ @Override public Builder<E> add(E... elements) {
+ for (int i = 0; i < elements.length; i++) {
+ ObjectArrays.checkElementNotNull(elements[i], i);
+ }
+ expandFor(elements.length);
+ System.arraycopy(elements, 0, contents, size, elements.length);
+ size += elements.length;
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableSet},
+ * ignoring duplicate elements (only the first duplicate element is added).
+ *
+ * @param elements the {@code Iterable} to add to the {@code ImmutableSet}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ @Override public Builder<E> addAll(Iterable<? extends E> elements) {
+ if (elements instanceof Collection) {
+ Collection<?> collection = (Collection<?>) elements;
+ expandFor(collection.size());
+ }
+ super.addAll(elements);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableSet},
+ * ignoring duplicate elements (only the first duplicate element is added).
+ *
+ * @param elements the elements to add to the {@code ImmutableSet}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a
+ * null element
+ */
+ @Override public Builder<E> addAll(Iterator<? extends E> elements) {
+ super.addAll(elements);
+ return this;
+ }
+
+ /**
+ * Returns a newly-created {@code ImmutableSet} based on the contents of
+ * 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;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableSetMultimap.java b/guava/src/com/google/common/collect/ImmutableSetMultimap.java
new file mode 100644
index 0000000..e184db4
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableSetMultimap.java
@@ -0,0 +1,510 @@
+/*
+ * 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;
+
+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;
+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;
+
+/**
+ * An immutable {@link SetMultimap} with reliable user-specified key and value
+ * iteration order. Does not permit null keys or values.
+ *
+ * <p>Unlike {@link Multimaps#unmodifiableSetMultimap(SetMultimap)}, which is
+ * a <i>view</i> of a separate multimap which can still change, an instance of
+ * {@code ImmutableSetMultimap} contains its own data and will <i>never</i>
+ * change. {@code ImmutableSetMultimap} is convenient for
+ * {@code public static final} multimaps ("constant multimaps") and also lets
+ * you easily make a "defensive copy" of a multimap provided to your class by
+ * a caller.
+ *
+ * <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 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)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+public class ImmutableSetMultimap<K, V>
+ extends ImmutableMultimap<K, V>
+ implements SetMultimap<K, V> {
+
+ /** Returns the empty multimap. */
+ // Casting is safe because the multimap will never hold any elements.
+ @SuppressWarnings("unchecked")
+ public static <K, V> ImmutableSetMultimap<K, V> of() {
+ return (ImmutableSetMultimap<K, V>) EmptyImmutableSetMultimap.INSTANCE;
+ }
+
+ /**
+ * Returns an immutable multimap containing a single entry.
+ */
+ public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1) {
+ ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
+ builder.put(k1, v1);
+ return builder.build();
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ * Repeated occurrences of an entry (according to {@link Object#equals}) after
+ * the first are ignored.
+ */
+ public static <K, V> ImmutableSetMultimap<K, V> of(K k1, V v1, K k2, V v2) {
+ ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
+ builder.put(k1, v1);
+ builder.put(k2, v2);
+ return builder.build();
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ * Repeated occurrences of an entry (according to {@link Object#equals}) after
+ * the first are ignored.
+ */
+ public static <K, V> ImmutableSetMultimap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3) {
+ ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
+ builder.put(k1, v1);
+ builder.put(k2, v2);
+ builder.put(k3, v3);
+ return builder.build();
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ * Repeated occurrences of an entry (according to {@link Object#equals}) after
+ * the first are ignored.
+ */
+ public static <K, V> ImmutableSetMultimap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+ ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
+ builder.put(k1, v1);
+ builder.put(k2, v2);
+ builder.put(k3, v3);
+ builder.put(k4, v4);
+ return builder.build();
+ }
+
+ /**
+ * Returns an immutable multimap containing the given entries, in order.
+ * Repeated occurrences of an entry (according to {@link Object#equals}) after
+ * the first are ignored.
+ */
+ public static <K, V> ImmutableSetMultimap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+ ImmutableSetMultimap.Builder<K, V> builder = ImmutableSetMultimap.builder();
+ builder.put(k1, v1);
+ builder.put(k2, v2);
+ builder.put(k3, v3);
+ builder.put(k4, v4);
+ builder.put(k5, v5);
+ return builder.build();
+ }
+
+ // looking for of() with > 5 entries? Use the builder instead.
+
+ /**
+ * Returns a new {@link Builder}.
+ */
+ public static <K, V> Builder<K, V> builder() {
+ return new Builder<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 AbstractMultimap<K, V> {
+ BuilderMultimap() {
+ super(new LinkedHashMap<K, Collection<V>>());
+ }
+ @Override Collection<V> createCollection() {
+ return Sets.newLinkedHashSet();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * 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
+ *
+ * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
+ * new ImmutableSetMultimap.Builder<String, Integer>()
+ * .put("one", 1)
+ * .putAll("several", 1, 2, 3)
+ * .putAll("many", 1, 2, 3, 4, 5)
+ * .build();}</pre>
+ *
+ * Builder instances can be reused; it is safe to call {@link #build} multiple
+ * times to build multiple multimaps in series. Each multimap contains the
+ * key-value mappings in the previously created multimaps.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static final class Builder<K, V>
+ extends ImmutableMultimap.Builder<K, V> {
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder
+ * generated by {@link ImmutableSetMultimap#builder}.
+ */
+ public Builder() {
+ builderMultimap = new BuilderMultimap<K, V>();
+ }
+
+ /**
+ * Adds a key-value mapping to the built multimap if it is not already
+ * present.
+ */
+ @Override public Builder<K, V> put(K key, V value) {
+ builderMultimap.put(checkNotNull(key), checkNotNull(value));
+ return this;
+ }
+
+ /**
+ * Adds an entry to the built multimap if it is not already present.
+ *
+ * @since 11.0
+ */
+ @Override public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
+ builderMultimap.put(
+ checkNotNull(entry.getKey()), checkNotNull(entry.getValue()));
+ return this;
+ }
+
+ @Override public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
+ Collection<V> collection = builderMultimap.get(checkNotNull(key));
+ for (V value : values) {
+ collection.add(checkNotNull(value));
+ }
+ return this;
+ }
+
+ @Override public Builder<K, V> putAll(K key, V... values) {
+ return putAll(key, Arrays.asList(values));
+ }
+
+ @Override public Builder<K, V> putAll(
+ Multimap<? extends K, ? extends V> multimap) {
+ for (Entry<? extends K, ? extends Collection<? extends V>> entry
+ : multimap.asMap().entrySet()) {
+ putAll(entry.getKey(), entry.getValue());
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 8.0
+ */
+ @Beta @Override
+ public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
+ this.keyComparator = checkNotNull(keyComparator);
+ 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()}
+ * 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.
+ @Beta @Override
+ public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
+ super.orderValuesBy(valueComparator);
+ return this;
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * Returns an immutable set multimap containing the same mappings as
+ * {@code multimap}. The generated multimap's key and value orderings
+ * correspond to the iteration ordering of the {@code multimap.asMap()} view.
+ * Repeated occurrences of an entry in the multimap after the first are
+ * ignored.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * @throws NullPointerException if any key or value in {@code multimap} is
+ * null
+ */
+ public static <K, V> ImmutableSetMultimap<K, V> copyOf(
+ 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) {
+ checkNotNull(multimap); // eager for GWT
+ if (multimap.isEmpty() && valueComparator == null) {
+ return of();
+ }
+
+ if (multimap instanceof ImmutableSetMultimap) {
+ @SuppressWarnings("unchecked") // safe since multimap is not writable
+ ImmutableSetMultimap<K, V> kvMultimap
+ = (ImmutableSetMultimap<K, V>) multimap;
+ if (!kvMultimap.isPartialView()) {
+ return kvMultimap;
+ }
+ }
+
+ ImmutableMap.Builder<K, ImmutableSet<V>> builder = ImmutableMap.builder();
+ int size = 0;
+
+ for (Entry<? extends K, ? extends Collection<? extends V>> entry
+ : multimap.asMap().entrySet()) {
+ K key = entry.getKey();
+ Collection<? extends V> values = entry.getValue();
+ ImmutableSet<V> set = (valueComparator == null)
+ ? ImmutableSet.copyOf(values)
+ : ImmutableSortedSet.copyOf(valueComparator, values);
+ if (!set.isEmpty()) {
+ builder.put(key, set);
+ size += set.size();
+ }
+ }
+
+ return new ImmutableSetMultimap<K, V>(
+ builder.build(), size, valueComparator);
+ }
+
+ // 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,
+ @Nullable Comparator<? super V> valueComparator) {
+ super(map, size);
+ this.emptySet = (valueComparator == null)
+ ? null : ImmutableSortedSet.<V>emptySet(valueComparator);
+ }
+
+ // views
+
+ /**
+ * Returns an immutable set of the values for the given key. If no mappings
+ * in the multimap have the provided key, an empty immutable set is returned.
+ * The values are in the same order as the parameters used to build this
+ * multimap.
+ */
+ @Override public ImmutableSet<V> get(@Nullable K key) {
+ // This cast is safe as its type is known in constructor.
+ ImmutableSet<V> set = (ImmutableSet<V>) map.get(key);
+ if (set != null) {
+ return set;
+ } else if (emptySet != null) {
+ return emptySet;
+ } else {
+ return ImmutableSet.<V>of();
+ }
+ }
+
+ private transient ImmutableSetMultimap<V, K> inverse;
+
+ /**
+ * {@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.
+ *
+ * @since 11.0
+ */
+ @Beta
+ public ImmutableSetMultimap<V, K> inverse() {
+ ImmutableSetMultimap<V, K> result = inverse;
+ return (result == null) ? (inverse = invert()) : result;
+ }
+
+ private ImmutableSetMultimap<V, K> invert() {
+ Builder<V, K> builder = builder();
+ for (Entry<K, V> entry : entries()) {
+ builder.put(entry.getValue(), entry.getKey());
+ }
+ ImmutableSetMultimap<V, K> invertedMultimap = builder.build();
+ invertedMultimap.inverse = this;
+ return invertedMultimap;
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public ImmutableSet<V> removeAll(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public ImmutableSet<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ private transient ImmutableSet<Entry<K, V>> entries;
+
+ /**
+ * Returns an immutable collection of all key-value pairs in the multimap.
+ * Its iterator traverses the values for the first key, the values for the
+ * second key, and so on.
+ */
+ // TODO(kevinb): Fix this so that two copies of the entries are not created.
+ @Override public ImmutableSet<Entry<K, V>> entries() {
+ ImmutableSet<Entry<K, V>> result = entries;
+ return (result == null)
+ ? (entries = ImmutableSet.copyOf(super.entries()))
+ : result;
+ }
+
+ /**
+ * @serialData number of distinct keys, and then for each distinct key: the
+ * key, the number of values for that key, and the key's values
+ */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMultimap(this, stream);
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ int keyCount = stream.readInt();
+ if (keyCount < 0) {
+ throw new InvalidObjectException("Invalid key count " + keyCount);
+ }
+ ImmutableMap.Builder<Object, ImmutableSet<Object>> builder
+ = ImmutableMap.builder();
+ int tmpSize = 0;
+
+ for (int i = 0; i < keyCount; i++) {
+ Object key = stream.readObject();
+ int valueCount = stream.readInt();
+ if (valueCount <= 0) {
+ throw new InvalidObjectException("Invalid value count " + valueCount);
+ }
+
+ Object[] array = new Object[valueCount];
+ for (int j = 0; j < valueCount; j++) {
+ array[j] = stream.readObject();
+ }
+ ImmutableSet<Object> valueSet = ImmutableSet.copyOf(array);
+ if (valueSet.size() != array.length) {
+ throw new InvalidObjectException(
+ "Duplicate key-value pairs exist for key " + key);
+ }
+ builder.put(key, valueSet);
+ tmpSize += valueCount;
+ }
+
+ ImmutableMap<Object, ImmutableSet<Object>> tmpMap;
+ try {
+ tmpMap = builder.build();
+ } catch (IllegalArgumentException e) {
+ throw (InvalidObjectException)
+ new InvalidObjectException(e.getMessage()).initCause(e);
+ }
+
+ FieldSettersHolder.MAP_FIELD_SETTER.set(this, tmpMap);
+ FieldSettersHolder.SIZE_FIELD_SETTER.set(this, tmpSize);
+ }
+
+ @GwtIncompatible("not needed in emulated source.")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ImmutableSortedAsList.java b/guava/src/com/google/common/collect/ImmutableSortedAsList.java
new file mode 100644
index 0000000..98aab41
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableSortedAsList.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.util.Comparator;
+
+import javax.annotation.Nullable;
+
+/**
+ * List returned by {@code ImmutableSortedSet.asList()} when the set isn't empty.
+ *
+ * @author Jared Levy
+ * @author Louis Wasserman
+ */
+@GwtCompatible(emulated = true)
+@SuppressWarnings("serial")
+final class ImmutableSortedAsList<E> extends RegularImmutableAsList<E>
+ implements SortedIterable<E> {
+ ImmutableSortedAsList(
+ ImmutableSortedSet<E> backingSet, ImmutableList<E> backingList) {
+ super(backingSet, backingList);
+ }
+
+ @Override
+ ImmutableSortedSet<E> delegateCollection() {
+ return (ImmutableSortedSet<E>) super.delegateCollection();
+ }
+
+ @Override public Comparator<? super E> comparator() {
+ return delegateCollection().comparator();
+ }
+
+ // Override indexOf() and lastIndexOf() to be O(log N) instead of O(N).
+
+ @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);
+
+ // 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 (index >= 0 && get(index).equals(target)) ? index : -1;
+ }
+
+ @GwtIncompatible("ImmutableSortedSet.indexOf")
+ @Override public int lastIndexOf(@Nullable Object target) {
+ return indexOf(target);
+ }
+
+ @Override
+ public boolean contains(Object target) {
+ // Necessary for ISS's with comparators inconsistent with equals.
+ return indexOf(target) >= 0;
+ }
+
+ @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();
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableSortedMap.java b/guava/src/com/google/common/collect/ImmutableSortedMap.java
new file mode 100644
index 0000000..bd2340d
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableSortedMap.java
@@ -0,0 +1,705 @@
+/*
+ * 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;
+
+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 com.google.common.annotations.GwtCompatible;
+
+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.SortedMap;
+import java.util.TreeMap;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable {@link SortedMap}. Does not permit null keys or values.
+ *
+ * <p>Unlike {@link Collections#unmodifiableSortedMap}, which is a <i>view</i>
+ * of a separate map which can still change, an instance of {@code
+ * ImmutableSortedMap} contains its own data and will <i>never</i> change.
+ * {@code ImmutableSortedMap} is convenient for {@code public static final} maps
+ * ("constant maps") and also lets you easily make a "defensive copy" of a map
+ * provided to your class by a caller.
+ *
+ * <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 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)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+public abstract class ImmutableSortedMap<K, V>
+ extends ImmutableSortedMapFauxverideShim<K, V> implements NavigableMap<K, V> {
+ /*
+ * TODO(kevinb): Confirm that ImmutableSortedMap is faster to construct and
+ * uses less memory than TreeMap; then say so in the class Javadoc.
+ */
+ 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());
+ }
+
+ 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);
+ }
+ }
+
+ /**
+ * Returns the empty sorted map.
+ */
+ @SuppressWarnings("unchecked")
+ // unsafe, comparator() returns a comparator on the specified type
+ // TODO(kevinb): evaluate whether or not of().comparator() should return null
+ public static <K, V> ImmutableSortedMap<K, V> of() {
+ return (ImmutableSortedMap<K, V>) NATURAL_EMPTY_MAP;
+ }
+
+ /**
+ * 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));
+ }
+
+ /**
+ * Returns an immutable sorted map containing the given entries, sorted by the
+ * natural ordering of their keys.
+ *
+ * @throws IllegalArgumentException if the two keys are equal according to
+ * their natural ordering
+ */
+ public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V>
+ of(K k1, V v1, K k2, V v2) {
+ return new Builder<K, V>(Ordering.natural())
+ .put(k1, v1).put(k2, v2).build();
+ }
+
+ /**
+ * Returns an immutable sorted map containing the given entries, sorted by the
+ * natural ordering of their keys.
+ *
+ * @throws IllegalArgumentException if any two keys are equal according to
+ * their natural ordering
+ */
+ public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V>
+ of(K k1, V v1, K k2, V v2, K k3, V v3) {
+ return new Builder<K, V>(Ordering.natural())
+ .put(k1, v1).put(k2, v2).put(k3, v3).build();
+ }
+
+ /**
+ * Returns an immutable sorted map containing the given entries, sorted by the
+ * natural ordering of their keys.
+ *
+ * @throws IllegalArgumentException if any two keys are equal according to
+ * their natural ordering
+ */
+ public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V>
+ of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+ return new Builder<K, V>(Ordering.natural())
+ .put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).build();
+ }
+
+ /**
+ * Returns an immutable sorted map containing the given entries, sorted by the
+ * natural ordering of their keys.
+ *
+ * @throws IllegalArgumentException if any two keys are equal according to
+ * their natural ordering
+ */
+ public static <K extends Comparable<? super K>, V> ImmutableSortedMap<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>(Ordering.natural())
+ .put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).build();
+ }
+
+ /**
+ * Returns an immutable map containing the same entries as {@code map}, sorted
+ * by the natural ordering of the keys.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * <p>This method is not type-safe, as it may be called on a map with keys
+ * that are not mutually comparable.
+ *
+ * @throws ClassCastException if the keys in {@code map} are not mutually
+ * comparable
+ * @throws NullPointerException if any key or value in {@code map} is null
+ * @throws IllegalArgumentException if any two keys are equal according to
+ * their natural ordering
+ */
+ public static <K, V> ImmutableSortedMap<K, V> copyOf(
+ Map<? extends K, ? extends V> map) {
+ // Hack around K not being a subtype of Comparable.
+ // Unsafe, see ImmutableSortedSetFauxverideShim.
+ @SuppressWarnings("unchecked")
+ Ordering<K> naturalOrder = (Ordering<K>) Ordering.<Comparable>natural();
+ return copyOfInternal(map, naturalOrder);
+ }
+
+ /**
+ * Returns an immutable map containing the same entries as {@code map}, with
+ * keys sorted by the provided comparator.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * @throws NullPointerException if any key or value in {@code map} is null
+ * @throws IllegalArgumentException if any two keys are equal according to the
+ * comparator
+ */
+ public static <K, V> ImmutableSortedMap<K, V> copyOf(
+ Map<? extends K, ? extends V> map, Comparator<? super K> comparator) {
+ return copyOfInternal(map, checkNotNull(comparator));
+ }
+
+ /**
+ * Returns an immutable map containing the same entries as the provided sorted
+ * map, with the same ordering.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * @throws NullPointerException if any key or value in {@code map} is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <K, V> ImmutableSortedMap<K, V> copyOfSorted(
+ SortedMap<K, ? extends V> map) {
+ Comparator<? super K> comparator = map.comparator();
+ if (comparator == null) {
+ // If map has a null comparator, the keys should have a natural ordering,
+ // even though K doesn't explicitly implement Comparable.
+ comparator = (Comparator<? super K>) NATURAL_ORDER;
+ }
+ return copyOfInternal(map, comparator);
+ }
+
+ private static <K, V> ImmutableSortedMap<K, V> copyOfInternal(
+ Map<? extends K, ? extends V> map, Comparator<? super K> comparator) {
+ boolean sameComparator = false;
+ if (map instanceof SortedMap) {
+ SortedMap<?, ?> sortedMap = (SortedMap<?, ?>) map;
+ Comparator<?> comparator2 = sortedMap.comparator();
+ sameComparator = (comparator2 == null)
+ ? comparator == NATURAL_ORDER
+ : comparator.equals(comparator2);
+ }
+
+ if (sameComparator && (map instanceof ImmutableSortedMap)) {
+ // TODO(kevinb): Prove that this cast is safe, even though
+ // Collections.unmodifiableSortedMap requires the same key type.
+ @SuppressWarnings("unchecked")
+ ImmutableSortedMap<K, V> kvMap = (ImmutableSortedMap<K, V>) map;
+ if (!kvMap.isPartialView()) {
+ return kvMap;
+ }
+ }
+
+ // "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
+ // raw type.
+ @SuppressWarnings("unchecked")
+ Entry<K, V>[] entries = map.entrySet().toArray(new Entry[0]);
+
+ for (int i = 0; i < entries.length; i++) {
+ Entry<K, V> entry = entries[i];
+ entries[i] = entryOf(entry.getKey(), entry.getValue());
+ }
+
+ List<Entry<K, V>> list = Arrays.asList(entries);
+
+ if (!sameComparator) {
+ sortEntries(list, comparator);
+ validateEntries(list, comparator);
+ }
+
+ return fromSortedEntries(comparator, list);
+ }
+
+ 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>>() {
+
+ @Override public int compare(Entry<K, V> entry1, Entry<K, V> entry2) {
+ return comparator.compare(entry1.getKey(), entry2.getKey());
+ }
+ };
+
+ Collections.sort(entries, entryComparator);
+ }
+
+ private static <K, V> void validateEntries(List<Entry<K, V>> entries,
+ Comparator<? super K> comparator) {
+ for (int i = 1; i < entries.size(); i++) {
+ if (comparator.compare(
+ entries.get(i - 1).getKey(), entries.get(i).getKey()) == 0) {
+ throw new IllegalArgumentException(
+ "Duplicate keys in mappings " + entries.get(i - 1) + " and "
+ + entries.get(i));
+ }
+ }
+ }
+
+ /**
+ * 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<K>, V> Builder<K, V> naturalOrder() {
+ return new Builder<K, V>(Ordering.natural());
+ }
+
+ /**
+ * Returns a builder that creates immutable sorted maps with an explicit
+ * comparator. If the comparator has a more general type than the map's keys,
+ * such as creating a {@code SortedMap<Integer, String>} with a {@code
+ * Comparator<Number>}, use the {@link Builder} constructor instead.
+ *
+ * @throws NullPointerException if {@code comparator} is null
+ */
+ public static <K, V> Builder<K, V> orderedBy(Comparator<K> comparator) {
+ return new Builder<K, V>(comparator);
+ }
+
+ /**
+ * 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<K>, V> Builder<K, V> reverseOrder() {
+ return new Builder<K, V>(Ordering.natural().reverse());
+ }
+
+ /**
+ * A builder for creating immutable sorted map instances, especially {@code
+ * public static final} maps ("constant maps"). Example: <pre> {@code
+ *
+ * static final ImmutableSortedMap<Integer, String> INT_TO_WORD =
+ * new ImmutableSortedMap.Builder<Integer, String>(Ordering.natural())
+ * .put(1, "one")
+ * .put(2, "two")
+ * .put(3, "three")
+ * .build();}</pre>
+ *
+ * For <i>small</i> immutable sorted maps, the {@code ImmutableSortedMap.of()}
+ * methods are even more convenient.
+ *
+ * <p>Builder instances can be reused - it is safe to call {@link #build}
+ * multiple times to build multiple maps in series. Each map is a superset of
+ * the maps created before it.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static class Builder<K, V> extends ImmutableMap.Builder<K, V> {
+ private final Comparator<? super K> comparator;
+
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder
+ * generated by {@link ImmutableSortedMap#orderedBy}.
+ */
+ public Builder(Comparator<? super K> comparator) {
+ this.comparator = checkNotNull(comparator);
+ }
+
+ /**
+ * Associates {@code key} with {@code value} in the built map. Duplicate
+ * keys, according to the comparator (which might be the keys' natural
+ * order), are not allowed, and will cause {@link #build} to fail.
+ */
+ @Override public Builder<K, V> put(K key, V value) {
+ entries.add(entryOf(key, value));
+ return this;
+ }
+
+ /**
+ * Adds the given {@code entry} to the map, making it immutable if
+ * necessary. Duplicate keys, according to the comparator (which might be
+ * the keys' natural order), are not allowed, and will cause {@link #build}
+ * to fail.
+ *
+ * @since 11.0
+ */
+ @Override public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
+ super.put(entry);
+ return this;
+ }
+
+ /**
+ * Associates all of the given map's keys and values in the built map.
+ * Duplicate keys, according to the comparator (which might be the keys'
+ * natural order), are not allowed, and will cause {@link #build} to fail.
+ *
+ * @throws NullPointerException if any key or value in {@code map} is null
+ */
+ @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
+ for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ put(entry.getKey(), entry.getValue());
+ }
+ return this;
+ }
+
+ /**
+ * Returns a newly-created immutable sorted map.
+ *
+ * @throws IllegalArgumentException if any two keys are equal according to
+ * the comparator (which might be the keys' natural order)
+ */
+ @Override public ImmutableSortedMap<K, V> build() {
+ sortEntries(entries, comparator);
+ validateEntries(entries, comparator);
+ return fromSortedEntries(comparator, entries);
+ }
+ }
+
+ ImmutableSortedMap() {
+ }
+
+ ImmutableSortedMap(ImmutableSortedMap<K, V> descendingMap) {
+ this.descendingMap = descendingMap;
+ }
+
+ @Override
+ public int size() {
+ return values().size();
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ return values().contains(value);
+ }
+
+ @Override boolean isPartialView() {
+ return keySet().isPartialView() || values().isPartialView();
+ }
+
+ /**
+ * 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();
+ }
+
+ /**
+ * Returns an immutable sorted set of the keys in this map.
+ */
+ @Override public abstract ImmutableSortedSet<K> keySet();
+
+ /**
+ * Returns an immutable collection of the values in this map, sorted by the
+ * ordering of the corresponding keys.
+ */
+ @Override public abstract ImmutableCollection<V> values();
+
+ /**
+ * Returns the comparator that orders the keys, which is
+ * {@link Ordering#natural()} when the natural ordering of the keys is used.
+ * Note that its behavior is not consistent with {@link TreeMap#comparator()},
+ * which returns {@code null} to indicate natural ordering.
+ */
+ @Override
+ public Comparator<? super K> comparator() {
+ return keySet().comparator();
+ }
+
+ @Override
+ public K firstKey() {
+ return keySet().first();
+ }
+
+ @Override
+ public K lastKey() {
+ return keySet().last();
+ }
+
+ /**
+ * This method returns a {@code ImmutableSortedMap}, consisting of the entries
+ * whose keys are less than {@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}.
+ */
+ @Override
+ public ImmutableSortedMap<K, V> headMap(K toKey) {
+ 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);
+
+ /**
+ * This method returns a {@code ImmutableSortedMap}, consisting of the entries
+ * whose keys ranges from {@code fromKey}, inclusive, to {@code toKey},
+ * exclusive.
+ *
+ * <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}.
+ */
+ @Override
+ public ImmutableSortedMap<K, V> subMap(K fromKey, K toKey) {
+ 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,
+ 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);
+ }
+
+ /**
+ * This method returns a {@code ImmutableSortedMap}, consisting of the entries
+ * whose keys are greater than or equals to {@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}.
+ */
+ @Override
+ public ImmutableSortedMap<K, V> tailMap(K fromKey) {
+ 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);
+ }
+
+ @Override
+ public final Entry<K, V> pollFirstEntry() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final Entry<K, V> pollLastEntry() {
+ throw new UnsupportedOperationException();
+ }
+
+ private transient ImmutableSortedMap<K, V> descendingMap;
+
+ @Override
+ public ImmutableSortedMap<K, V> descendingMap() {
+ ImmutableSortedMap<K, V> result = descendingMap;
+ if (result == null) {
+ result = descendingMap = createDescendingMap();
+ }
+ return result;
+ }
+
+ abstract ImmutableSortedMap<K, V> createDescendingMap();
+
+ @Override
+ public ImmutableSortedSet<K> navigableKeySet() {
+ return keySet();
+ }
+
+ @Override
+ public ImmutableSortedSet<K> descendingKeySet() {
+ return keySet().descendingSet();
+ }
+
+ /**
+ * Serialized type for all ImmutableSortedMap instances. It captures the
+ * logical contents and they are reconstructed using public factory methods.
+ * This ensures that the implementation types remain as implementation
+ * details.
+ */
+ private static class SerializedForm extends ImmutableMap.SerializedForm {
+ private final Comparator<Object> comparator;
+ @SuppressWarnings("unchecked")
+ SerializedForm(ImmutableSortedMap<?, ?> sortedMap) {
+ super(sortedMap);
+ comparator = (Comparator<Object>) sortedMap.comparator();
+ }
+ @Override Object readResolve() {
+ Builder<Object, Object> builder = new Builder<Object, Object>(comparator);
+ return createMap(builder);
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ @Override Object writeReplace() {
+ return new SerializedForm(this);
+ }
+
+ // This class is never actually serialized directly, but we have to make the
+ // warning go away (and suppressing would suppress for all nested classes too)
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ImmutableSortedMapFauxverideShim.java b/guava/src/com/google/common/collect/ImmutableSortedMapFauxverideShim.java
new file mode 100644
index 0000000..855f223
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableSortedMapFauxverideShim.java
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * "Overrides" the {@link ImmutableMap} static methods that lack
+ * {@link ImmutableSortedMap} equivalents with deprecated, exception-throwing
+ * versions. See {@link ImmutableSortedSetFauxverideShim} for details.
+ *
+ * @author Chris Povirk
+ */
+@GwtCompatible
+abstract class ImmutableSortedMapFauxverideShim<K, V>
+ extends ImmutableMap<K, V> {
+ /**
+ * Not supported. Use {@link ImmutableSortedMap#naturalOrder}, which offers
+ * better type-safety, instead. This method exists only to hide
+ * {@link ImmutableMap#builder} from consumers of {@code ImmutableSortedMap}.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated Use {@link ImmutableSortedMap#naturalOrder}, which offers
+ * better type-safety.
+ */
+ @Deprecated public static <K, V> ImmutableSortedMap.Builder<K, V> builder() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a map that may contain a
+ * non-{@code Comparable} key.</b> Proper calls will resolve to the version in
+ * {@code ImmutableSortedMap}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass a key of type {@code Comparable} to use {@link
+ * ImmutableSortedMap#of(Comparable, Object)}.</b>
+ */
+ @Deprecated public static <K, V> ImmutableSortedMap<K, V> of(K k1, V v1) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a map that may contain
+ * non-{@code Comparable} keys.</b> Proper calls will resolve to the version
+ * in {@code ImmutableSortedMap}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass keys of type {@code Comparable} to use {@link
+ * ImmutableSortedMap#of(Comparable, Object, Comparable, Object)}.</b>
+ */
+ @Deprecated public static <K, V> ImmutableSortedMap<K, V> of(
+ K k1, V v1, K k2, V v2) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a map that may contain
+ * non-{@code Comparable} keys.</b> Proper calls to will resolve to the
+ * version in {@code ImmutableSortedMap}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass keys of type {@code Comparable} to use {@link
+ * ImmutableSortedMap#of(Comparable, Object, Comparable, Object,
+ * Comparable, Object)}.</b>
+ */
+ @Deprecated public static <K, V> ImmutableSortedMap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a map that may contain
+ * non-{@code Comparable} keys.</b> Proper calls will resolve to the version
+ * in {@code ImmutableSortedMap}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass keys of type {@code Comparable} to use {@link
+ * ImmutableSortedMap#of(Comparable, Object, Comparable, Object,
+ * Comparable, Object, Comparable, Object)}.</b>
+ */
+ @Deprecated public static <K, V> ImmutableSortedMap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a map that may contain
+ * non-{@code Comparable} keys.</b> Proper calls will resolve to the version
+ * in {@code ImmutableSortedMap}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass keys of type {@code Comparable} to use {@link
+ * ImmutableSortedMap#of(Comparable, Object, Comparable, Object,
+ * Comparable, Object, Comparable, Object, Comparable, Object)}.</b>
+ */
+ @Deprecated public static <K, V> ImmutableSortedMap<K, V> of(
+ K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+ throw new UnsupportedOperationException();
+ }
+
+ // No copyOf() fauxveride; see ImmutableSortedSetFauxverideShim.
+}
diff --git a/guava/src/com/google/common/collect/ImmutableSortedMultiset.java b/guava/src/com/google/common/collect/ImmutableSortedMultiset.java
new file mode 100644
index 0000000..a64e5de
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableSortedMultiset.java
@@ -0,0 +1,574 @@
+/*
+ * 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 java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An immutable {@code SortedMultiset} that stores its elements in a sorted array. Some instances
+ * are ordered by an explicit comparator, while others follow the natural sort ordering of their
+ * elements. Either way, null elements are not supported.
+ *
+ * <p>Unlike {@link Multisets#unmodifiableSortedMultiset}, which is a <i>view</i> of a separate
+ * collection that can still change, an instance of {@code ImmutableSortedMultiset} contains its
+ * own private data and will <i>never</i> change. This class is convenient for {@code public static
+ * final} multisets ("constant multisets") and also lets you easily make a "defensive copy" of a
+ * set provided to your class by a caller.
+ *
+ * <p>The multisets returned by the {@link #headMultiset}, {@link #tailMultiset}, and
+ * {@link #subMultiset} methods share the same array as the original multiset, preventing that
+ * array from being garbage collected. If this is a concern, the data may be copied into a
+ * correctly-sized array by calling {@link #copyOfSorted}.
+ *
+ * <p><b>Note on element equivalence:</b> The {@link #contains(Object)},
+ * {@link #containsAll(Collection)}, and {@link #equals(Object)} implementations must check whether
+ * a provided object is equivalent to an element in the collection. Unlike most collections, an
+ * {@code ImmutableSortedMultiset} doesn't use {@link Object#equals} to determine if two elements
+ * are equivalent. Instead, with an explicit comparator, the following relation determines whether
+ * elements {@code x} and {@code y} are equivalent:
+ *
+ * <pre> {@code
+ *
+ * {(x, y) | comparator.compare(x, y) == 0}}</pre>
+ *
+ * With natural ordering of elements, the following relation determines whether two elements are
+ * equivalent:
+ *
+ * <pre> {@code
+ *
+ * {(x, y) | x.compareTo(y) == 0}}</pre>
+ *
+ * <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.
+ *
+ * <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>
+ implements SortedMultiset<E> {
+ // TODO(user): GWT compatibility
+
+ private static final Comparator<Comparable> NATURAL_ORDER = Ordering.natural();
+
+ private static final ImmutableSortedMultiset<Comparable> NATURAL_EMPTY_MULTISET =
+ new EmptyImmutableSortedMultiset<Comparable>(NATURAL_ORDER);
+
+ /**
+ * Returns the empty immutable sorted multiset.
+ */
+ @SuppressWarnings("unchecked")
+ public static <E> ImmutableSortedMultiset<E> of() {
+ return (ImmutableSortedMultiset) NATURAL_EMPTY_MULTISET;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the given elements sorted by their natural
+ * ordering.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2) {
+ return copyOf(Ordering.natural(), Arrays.asList(e1, e2));
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the given elements sorted by their natural
+ * ordering.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(E e1, E e2, E e3) {
+ return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3));
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the given elements sorted by their natural
+ * ordering.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(
+ E e1, E e2, E e3, E e4) {
+ return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4));
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the given elements sorted by their natural
+ * ordering.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> of(
+ 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 multiset containing the given elements sorted by their natural
+ * ordering.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ @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) {
+ int size = remaining.length + 6;
+ List<E> all = Lists.newArrayListWithCapacity(size);
+ Collections.addAll(all, e1, e2, e3, e4, e5, e6);
+ Collections.addAll(all, remaining);
+ return copyOf(Ordering.natural(), all);
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the given elements sorted by their natural
+ * ordering.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E extends Comparable<? super E>> ImmutableSortedMultiset<E> copyOf(E[] elements) {
+ return copyOf(Ordering.natural(), Arrays.asList(elements));
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the given elements sorted by their natural
+ * ordering. To create a copy of a {@code SortedMultiset} that preserves the
+ * comparator, call {@link #copyOfSorted} instead. This method iterates over {@code elements} at
+ * most once.
+ *
+ * <p>Note that if {@code s} is a {@code multiset<String>}, then {@code
+ * ImmutableSortedMultiset.copyOf(s)} returns an {@code ImmutableSortedMultiset<String>}
+ * containing each of the strings in {@code s}, while {@code ImmutableSortedMultiset.of(s)}
+ * returns an {@code ImmutableSortedMultiset<multiset<String>>} containing one element (the given
+ * multiset itself).
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
+ * safe to do so. The exact circumstances under which a copy will or will not be performed are
+ * undocumented and subject to change.
+ *
+ * <p>This method is not type-safe, as it may be called on elements that are not mutually
+ * comparable.
+ *
+ * @throws ClassCastException if the elements are not mutually comparable
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableSortedMultiset<E> copyOf(Iterable<? extends E> elements) {
+ // Hack around E not being a subtype of Comparable.
+ // Unsafe, see ImmutableSortedMultisetFauxverideShim.
+ @SuppressWarnings("unchecked")
+ Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural();
+ return copyOf(naturalOrder, elements);
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the given elements sorted by their natural
+ * ordering.
+ *
+ * <p>This method is not type-safe, as it may be called on elements that are not mutually
+ * comparable.
+ *
+ * @throws ClassCastException if the elements are not mutually comparable
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableSortedMultiset<E> copyOf(Iterator<? extends E> elements) {
+ // Hack around E not being a subtype of Comparable.
+ // Unsafe, see ImmutableSortedMultisetFauxverideShim.
+ @SuppressWarnings("unchecked")
+ Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural();
+ return copyOf(naturalOrder, elements);
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the given elements sorted by the given {@code
+ * Comparator}.
+ *
+ * @throws NullPointerException if {@code comparator} or any of {@code elements} is null
+ */
+ public static <E> ImmutableSortedMultiset<E> copyOf(
+ Comparator<? super E> comparator, Iterator<? extends E> elements) {
+ checkNotNull(comparator);
+ return new Builder<E>(comparator).addAll(elements).build();
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the given elements sorted by the given {@code
+ * Comparator}. This method iterates over {@code elements} at most once.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
+ * safe to do so. The exact circumstances under which a copy will or will not be performed are
+ * undocumented and subject to change.
+ *
+ * @throws NullPointerException if {@code comparator} or any of {@code elements} is null
+ */
+ 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());
+ }
+
+ /**
+ * Returns an immutable sorted multiset containing the elements of a sorted multiset, sorted by
+ * the same {@code Comparator}. That behavior differs from {@link #copyOf(Iterable)}, which
+ * always uses the natural ordering of the elements.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying the data when it is
+ * safe to do so. The exact circumstances under which a copy will or will not be performed are
+ * undocumented and subject to change.
+ *
+ * <p>This method is safe to use even when {@code sortedMultiset} is a synchronized or concurrent
+ * collection that is currently being modified by another thread.
+ *
+ * @throws NullPointerException if {@code sortedMultiset} or any of its elements is null
+ */
+ public static <E> ImmutableSortedMultiset<E> copyOfSorted(SortedMultiset<E> sortedMultiset) {
+ return copyOfSortedEntries(sortedMultiset.comparator(),
+ Lists.newArrayList(sortedMultiset.entrySet()));
+ }
+
+ private static <E> ImmutableSortedMultiset<E> copyOfSortedEntries(
+ Comparator<? super E> comparator, Collection<Entry<E>> entries) {
+ 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;
+ for (Entry<E> entry : entries) {
+ elementsBuilder.add(entry.getElement());
+ counts[i] = entry.getCount();
+ cumulativeCounts[i + 1] = cumulativeCounts[i] + counts[i];
+ i++;
+ }
+ return new RegularImmutableSortedMultiset<E>(
+ new RegularImmutableSortedSet<E>(elementsBuilder.build(), comparator),
+ counts, cumulativeCounts, 0, entries.size());
+ }
+
+ @SuppressWarnings("unchecked")
+ static <E> ImmutableSortedMultiset<E> emptyMultiset(Comparator<? super E> comparator) {
+ if (NATURAL_ORDER.equals(comparator)) {
+ return (ImmutableSortedMultiset) NATURAL_EMPTY_MULTISET;
+ }
+ return new EmptyImmutableSortedMultiset<E>(comparator);
+ }
+
+ ImmutableSortedMultiset() {}
+
+ @Override
+ public final Comparator<? super E> comparator() {
+ return elementSet().comparator();
+ }
+
+ @Override
+ public abstract ImmutableSortedSet<E> elementSet();
+
+ transient ImmutableSortedMultiset<E> descendingMultiset;
+
+ @Override
+ public ImmutableSortedMultiset<E> descendingMultiset() {
+ ImmutableSortedMultiset<E> result = descendingMultiset;
+ if (result == null) {
+ return descendingMultiset = new DescendingImmutableSortedMultiset<E>(this);
+ }
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final Entry<E> pollFirstEntry() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation is guaranteed to throw an {@link UnsupportedOperationException}.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public final Entry<E> pollLastEntry() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public abstract ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType);
+
+ @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);
+ }
+
+ @Override
+ public abstract ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType);
+
+ /**
+ * Returns a builder that creates immutable sorted multisets with an explicit comparator. If the
+ * comparator has a more general type than the set being generated, such as creating a {@code
+ * SortedMultiset<Integer>} with a {@code Comparator<Number>}, use the {@link Builder}
+ * constructor instead.
+ *
+ * @throws NullPointerException if {@code comparator} is null
+ */
+ public static <E> Builder<E> orderedBy(Comparator<E> comparator) {
+ return new Builder<E>(comparator);
+ }
+
+ /**
+ * Returns a builder that creates immutable sorted multisets 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<E>> Builder<E> reverseOrder() {
+ return new Builder<E>(Ordering.natural().reverse());
+ }
+
+ /**
+ * Returns a builder that creates immutable sorted multisets whose elements are ordered by their
+ * natural ordering. The sorted multisets use {@link 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<E>> Builder<E> naturalOrder() {
+ return new Builder<E>(Ordering.natural());
+ }
+
+ /**
+ * A builder for creating immutable multiset instances, especially {@code public static final}
+ * multisets ("constant multisets"). Example:
+ *
+ * <pre> {@code
+ *
+ * public static final ImmutableSortedMultiset<Bean> BEANS =
+ * new ImmutableSortedMultiset.Builder<Bean>()
+ * .addCopies(Bean.COCOA, 4)
+ * .addCopies(Bean.GARDEN, 6)
+ * .addCopies(Bean.RED, 8)
+ * .addCopies(Bean.BLACK_EYED, 10)
+ * .build();}</pre>
+ *
+ * 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;
+
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder generated by
+ * {@link ImmutableSortedMultiset#orderedBy(Comparator)}.
+ */
+ public Builder(Comparator<? super E> comparator) {
+ super(TreeMultiset.<E>create(comparator));
+ this.comparator = checkNotNull(comparator);
+ }
+
+ /**
+ * Adds {@code element} to the {@code ImmutableSortedMultiset}.
+ *
+ * @param element the element to add
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code element} is null
+ */
+ @Override
+ public Builder<E> add(E element) {
+ super.add(element);
+ return this;
+ }
+
+ /**
+ * Adds a number of occurrences of an element to this {@code ImmutableSortedMultiset}.
+ *
+ * @param element the element to add
+ * @param occurrences the number of occurrences of the element to add. May be zero, in which
+ * case no change will be made.
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code element} is null
+ * @throws IllegalArgumentException if {@code occurrences} is negative, or if this operation
+ * would result in more than {@link Integer#MAX_VALUE} occurrences of the element
+ */
+ @Override
+ public Builder<E> addCopies(E element, int occurrences) {
+ super.addCopies(element, occurrences);
+ return this;
+ }
+
+ /**
+ * Adds or removes the necessary occurrences of an element such that the element attains the
+ * desired count.
+ *
+ * @param element the element to add or remove occurrences of
+ * @param count the desired count of the element in this multiset
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code element} is null
+ * @throws IllegalArgumentException if {@code count} is negative
+ */
+ @Override
+ public Builder<E> setCount(E element, int count) {
+ super.setCount(element, count);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}.
+ *
+ * @param elements the elements to add
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a null element
+ */
+ @Override
+ public Builder<E> add(E... elements) {
+ super.add(elements);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}.
+ *
+ * @param elements the {@code Iterable} to add to the {@code ImmutableSortedMultiset}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a null element
+ */
+ @Override
+ public Builder<E> addAll(Iterable<? extends E> elements) {
+ super.addAll(elements);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableSortedMultiset}.
+ *
+ * @param elements the elements to add to the {@code ImmutableSortedMultiset}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} is null or contains a null element
+ */
+ @Override
+ public Builder<E> addAll(Iterator<? extends E> elements) {
+ super.addAll(elements);
+ return this;
+ }
+
+ /**
+ * Returns a newly-created {@code ImmutableSortedMultiset} based on the contents of the {@code
+ * Builder}.
+ */
+ @Override
+ public ImmutableSortedMultiset<E> build() {
+ return copyOfSorted((SortedMultiset<E>) contents);
+ }
+ }
+
+ private static final class SerializedForm implements Serializable {
+ Comparator comparator;
+ Object[] elements;
+ int[] counts;
+
+ SerializedForm(SortedMultiset<?> multiset) {
+ this.comparator = multiset.comparator();
+ int n = multiset.entrySet().size();
+ elements = new Object[n];
+ counts = new int[n];
+ int i = 0;
+ for (Entry<?> entry : multiset.entrySet()) {
+ elements[i] = entry.getElement();
+ counts[i] = entry.getCount();
+ i++;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ Object readResolve() {
+ int n = elements.length;
+ Builder<Object> builder = orderedBy(comparator);
+ for (int i = 0; i < n; i++) {
+ builder.addCopies(elements[i], counts[i]);
+ }
+ return builder.build();
+ }
+ }
+
+ @Override
+ Object writeReplace() {
+ return new SerializedForm(this);
+ }
+}
diff --git a/guava/src/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java b/guava/src/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java
new file mode 100644
index 0000000..e7d74c8
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java
@@ -0,0 +1,170 @@
+/*
+ * 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;
+
+/**
+ * "Overrides" the {@link ImmutableMultiset} static methods that lack
+ * {@link ImmutableSortedMultiset} equivalents with deprecated, exception-throwing versions. This
+ * prevents accidents like the following:
+ *
+ * <pre> {@code
+ *
+ * List<Object> objects = ...;
+ * // Sort them:
+ * Set<Object> sorted = ImmutableSortedMultiset.copyOf(objects);
+ * // BAD CODE! The returned multiset is actually an unsorted ImmutableMultiset!}</pre>
+ *
+ * While we could put the overrides in {@link ImmutableSortedMultiset} itself, it seems clearer to
+ * separate these "do not call" methods from those intended for normal use.
+ *
+ * @author Louis Wasserman
+ */
+abstract class ImmutableSortedMultisetFauxverideShim<E> extends ImmutableMultiset<E> {
+ /**
+ * Not supported. Use {@link ImmutableSortedMultiset#naturalOrder}, which offers better
+ * type-safety, instead. This method exists only to hide {@link ImmutableMultiset#builder} from
+ * consumers of {@code ImmutableSortedMultiset}.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated Use {@link ImmutableSortedMultiset#naturalOrder}, which offers better type-safety.
+ */
+ @Deprecated
+ public static <E> ImmutableSortedMultiset.Builder<E> builder() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code
+ * Comparable} element.</b> Proper calls will resolve to the version in {@code
+ * ImmutableSortedMultiset}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass a parameter of type {@code Comparable} to use
+ * {@link ImmutableSortedMultiset#of(Comparable)}.</b>
+ */
+ @Deprecated
+ public static <E> ImmutableSortedMultiset<E> of(E element) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code
+ * Comparable} element.</b> Proper calls will resolve to the version in {@code
+ * ImmutableSortedMultiset}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use
+ * {@link ImmutableSortedMultiset#of(Comparable, Comparable)}.</b>
+ */
+ @Deprecated
+ public static <E> ImmutableSortedMultiset<E> of(E e1, E e2) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code
+ * Comparable} element.</b> Proper calls will resolve to the version in {@code
+ * ImmutableSortedMultiset}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use
+ * {@link ImmutableSortedMultiset#of(Comparable, Comparable, Comparable)}.</b>
+ */
+ @Deprecated
+ public static <E> ImmutableSortedMultiset<E> of(E e1, E e2, E e3) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code
+ * Comparable} element.</b> Proper calls will resolve to the version in {@code
+ * ImmutableSortedMultiset}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link
+ * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable)}. </b>
+ */
+ @Deprecated
+ public static <E> ImmutableSortedMultiset<E> of(E e1, E e2, E e3, E e4) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code
+ * Comparable} element.</b> Proper calls will resolve to the version in {@code
+ * ImmutableSortedMultiset}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link
+ * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable,
+ * Comparable)} . </b>
+ */
+ @Deprecated
+ public static <E> ImmutableSortedMultiset<E> of(E e1, E e2, E e3, E e4, E e5) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a multiset that may contain a non-{@code
+ * Comparable} element.</b> Proper calls will resolve to the version in {@code
+ * ImmutableSortedMultiset}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link
+ * ImmutableSortedMultiset#of(Comparable, Comparable, Comparable, Comparable,
+ * Comparable, Comparable, Comparable...)} . </b>
+ */
+ @Deprecated
+ public static <E> ImmutableSortedMultiset<E> of(
+ E e1,
+ E e2,
+ E e3,
+ E e4,
+ E e5,
+ E e6,
+ E... remaining) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a multiset that may contain non-{@code
+ * Comparable} elements.</b> Proper calls will resolve to the version in {@code
+ * ImmutableSortedMultiset}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass parameters of type {@code Comparable} to use
+ * {@link ImmutableSortedMultiset#copyOf(Comparable[])}.</b>
+ */
+ @Deprecated
+ public static <E> ImmutableSortedMultiset<E> copyOf(E[] elements) {
+ throw new UnsupportedOperationException();
+ }
+
+ /*
+ * We would like to include an unsupported "<E> copyOf(Iterable<E>)" here, providing only the
+ * properly typed "<E extends Comparable<E>> copyOf(Iterable<E>)" in ImmutableSortedMultiset (and
+ * likewise for the Iterator equivalent). However, due to a change in Sun's interpretation of the
+ * JLS (as described at http://bugs.sun.com/view_bug.do?bug_id=6182950), the OpenJDK 7 compiler
+ * available as of this writing rejects our attempts. To maintain compatibility with that version
+ * and with any other compilers that interpret the JLS similarly, there is no definition of
+ * copyOf() here, and the definition in ImmutableSortedMultiset matches that in
+ * ImmutableMultiset.
+ *
+ * The result is that ImmutableSortedMultiset.copyOf() may be called on non-Comparable elements.
+ * We have not discovered a better solution. In retrospect, the static factory methods should
+ * have gone in a separate class so that ImmutableSortedMultiset wouldn't "inherit"
+ * too-permissive factory methods from ImmutableMultiset.
+ */
+}
diff --git a/guava/src/com/google/common/collect/ImmutableSortedSet.java b/guava/src/com/google/common/collect/ImmutableSortedSet.java
new file mode 100644
index 0000000..2180e29
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableSortedSet.java
@@ -0,0 +1,845 @@
+/*
+ * 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.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;
+import java.io.Serializable;
+import java.util.ArrayList;
+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.NavigableSet;
+import java.util.SortedSet;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable {@code SortedSet} that stores its elements in a sorted array.
+ * Some instances are ordered by an explicit comparator, while others follow the
+ * natural sort ordering of their elements. Either way, null elements are not
+ * supported.
+ *
+ * <p>Unlike {@link Collections#unmodifiableSortedSet}, which is a <i>view</i>
+ * of a separate collection that can still change, an instance of {@code
+ * ImmutableSortedSet} contains its own private data and will <i>never</i>
+ * change. This class is convenient for {@code public static final} sets
+ * ("constant sets") and also lets you easily make a "defensive copy" of a set
+ * provided to your class by a caller.
+ *
+ * <p>The sets returned by the {@link #headSet}, {@link #tailSet}, and
+ * {@link #subSet} methods share the same array as the original set, preventing
+ * that array from being garbage collected. If this is a concern, the data may
+ * be copied into a correctly-sized array by calling {@link #copyOfSorted}.
+ *
+ * <p><b>Note on element equivalence:</b> The {@link #contains(Object)},
+ * {@link #containsAll(Collection)}, and {@link #equals(Object)}
+ * implementations must check whether a provided object is equivalent to an
+ * element in the collection. Unlike most collections, an
+ * {@code ImmutableSortedSet} doesn't use {@link Object#equals} to determine if
+ * two elements are equivalent. Instead, with an explicit comparator, the
+ * following relation determines whether elements {@code x} and {@code y} are
+ * equivalent: <pre> {@code
+ *
+ * {(x, y) | comparator.compare(x, y) == 0}}</pre>
+ *
+ * With natural ordering of elements, the following relation determines whether
+ * two elements are equivalent: <pre> {@code
+ *
+ * {(x, y) | x.compareTo(y) == 0}}</pre>
+ *
+ * <b>Warning:</b> Like most sets, an {@code ImmutableSortedSet} will not
+ * function correctly if an element is modified after being placed in the set.
+ * For this reason, and to avoid general confusion, it is strongly recommended
+ * to place only immutable objects into this collection.
+ *
+ * <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>.
+ *
+ * @see ImmutableSet
+ * @author Jared Levy
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library; implements {@code NavigableSet} since 12.0)
+ */
+// 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> {
+
+ private static final Comparator<Comparable> NATURAL_ORDER =
+ Ordering.natural();
+
+ private static final ImmutableSortedSet<Comparable> NATURAL_EMPTY_SET =
+ new EmptyImmutableSortedSet<Comparable>(NATURAL_ORDER);
+
+ @SuppressWarnings("unchecked")
+ private static <E> ImmutableSortedSet<E> emptySet() {
+ return (ImmutableSortedSet<E>) NATURAL_EMPTY_SET;
+ }
+
+ static <E> ImmutableSortedSet<E> emptySet(
+ Comparator<? super E> comparator) {
+ if (NATURAL_ORDER.equals(comparator)) {
+ return emptySet();
+ } else {
+ return new EmptyImmutableSortedSet<E>(comparator);
+ }
+ }
+
+ /**
+ * Returns the empty immutable sorted set.
+ */
+ public static <E> ImmutableSortedSet<E> of() {
+ return emptySet();
+ }
+
+ /**
+ * Returns an immutable sorted set containing a single element.
+ */
+ public static <E extends Comparable<? super E>> ImmutableSortedSet<E> of(
+ E element) {
+ return new RegularImmutableSortedSet<E>(
+ ImmutableList.of(element), Ordering.natural());
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * their natural ordering. When multiple elements are equivalent according to
+ * {@link Comparable#compareTo}, only the first one specified is included.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable<? super E>> ImmutableSortedSet<E> of(
+ E e1, E e2) {
+ return copyOf(Ordering.natural(), Arrays.asList(e1, e2));
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * their natural ordering. When multiple elements are equivalent according to
+ * {@link Comparable#compareTo}, only the first one specified is included.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable<? super E>> ImmutableSortedSet<E> of(
+ E e1, E e2, E e3) {
+ return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3));
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * their natural ordering. When multiple elements are equivalent according to
+ * {@link Comparable#compareTo}, only the first one specified is included.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable<? super E>> ImmutableSortedSet<E> of(
+ E e1, E e2, E e3, E e4) {
+ return copyOf(Ordering.natural(), Arrays.asList(e1, e2, e3, e4));
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * their natural ordering. When multiple elements are equivalent according to
+ * {@link Comparable#compareTo}, only the first one specified is included.
+ *
+ * @throws NullPointerException if any element is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable<? super E>> ImmutableSortedSet<E> of(
+ 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
+ * {@link Comparable#compareTo}, only the first one specified is included.
+ *
+ * @throws NullPointerException if any element is null
+ * @since 3.0 (source-compatible since 2.0)
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable<? super E>> ImmutableSortedSet<E> of(
+ E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) {
+ int size = remaining.length + 6;
+ 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);
+ }
+
+ // TODO(kevinb): Consider factory methods that reject duplicates
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * their natural ordering. When multiple elements are equivalent according to
+ * {@link Comparable#compareTo}, only the first one specified is included.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ * @since 3.0
+ */
+ public static <E extends Comparable<? super E>> ImmutableSortedSet<E> copyOf(
+ E[] elements) {
+ return copyOf(Ordering.natural(), Arrays.asList(elements));
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * their natural ordering. When multiple elements are equivalent according to
+ * {@code compareTo()}, only the first one specified is included. To create a
+ * copy of a {@code SortedSet} that preserves the comparator, call {@link
+ * #copyOfSorted} instead. This method iterates over {@code elements} at most
+ * once.
+
+ *
+ * <p>Note that if {@code s} is a {@code Set<String>}, then {@code
+ * ImmutableSortedSet.copyOf(s)} returns an {@code ImmutableSortedSet<String>}
+ * containing each of the strings in {@code s}, while {@code
+ * ImmutableSortedSet.of(s)} returns an {@code
+ * ImmutableSortedSet<Set<String>>} containing one element (the given set
+ * itself).
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * <p>This method is not type-safe, as it may be called on elements that are
+ * not mutually comparable.
+ *
+ * @throws ClassCastException if the elements are not mutually comparable
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableSortedSet<E> copyOf(
+ Iterable<? extends E> elements) {
+ // Hack around E not being a subtype of Comparable.
+ // Unsafe, see ImmutableSortedSetFauxverideShim.
+ @SuppressWarnings("unchecked")
+ Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural();
+ return copyOf(naturalOrder, elements);
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * their natural ordering. When multiple elements are equivalent according to
+ * {@code compareTo()}, only the first one specified is included. To create a
+ * copy of a {@code SortedSet} that preserves the comparator, call
+ * {@link #copyOfSorted} instead. This method iterates over {@code elements}
+ * at most once.
+ *
+ * <p>Note that if {@code s} is a {@code Set<String>}, then
+ * {@code ImmutableSortedSet.copyOf(s)} returns an
+ * {@code ImmutableSortedSet<String>} containing each of the strings in
+ * {@code s}, while {@code ImmutableSortedSet.of(s)} returns an
+ * {@code ImmutableSortedSet<Set<String>>} containing one element (the given
+ * set itself).
+ *
+ * <p><b>Note:</b> Despite what the method name suggests, if {@code elements}
+ * is an {@code ImmutableSortedSet}, it may be returned instead of a copy.
+ *
+ * <p>This method is not type-safe, as it may be called on elements that are
+ * not mutually comparable.
+ *
+ * <p>This method is safe to use even when {@code elements} is a synchronized
+ * or concurrent collection that is currently being modified by another
+ * thread.
+ *
+ * @throws ClassCastException if the elements are not mutually comparable
+ * @throws NullPointerException if any of {@code elements} is null
+ * @since 7.0 (source-compatible since 2.0)
+ */
+ public static <E> ImmutableSortedSet<E> copyOf(
+ Collection<? extends E> elements) {
+ // Hack around E not being a subtype of Comparable.
+ // Unsafe, see ImmutableSortedSetFauxverideShim.
+ @SuppressWarnings("unchecked")
+ Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural();
+ return copyOf(naturalOrder, elements);
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * their natural ordering. When multiple elements are equivalent according to
+ * {@code compareTo()}, only the first one specified is included.
+ *
+ * <p>This method is not type-safe, as it may be called on elements that are
+ * not mutually comparable.
+ *
+ * @throws ClassCastException if the elements are not mutually comparable
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableSortedSet<E> copyOf(
+ Iterator<? extends E> elements) {
+ // Hack around E not being a subtype of Comparable.
+ // Unsafe, see ImmutableSortedSetFauxverideShim.
+ @SuppressWarnings("unchecked")
+ Ordering<E> naturalOrder = (Ordering<E>) Ordering.<Comparable>natural();
+ return copyOf(naturalOrder, elements);
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * the given {@code Comparator}. When multiple elements are equivalent
+ * according to {@code compareTo()}, only the first one specified is
+ * included.
+ *
+ * @throws NullPointerException if {@code comparator} or any of
+ * {@code elements} is null
+ */
+ public static <E> ImmutableSortedSet<E> copyOf(
+ Comparator<? super E> comparator, Iterator<? extends E> elements) {
+ return copyOf(comparator, Lists.newArrayList(elements));
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * the given {@code Comparator}. When multiple elements are equivalent
+ * according to {@code compare()}, only the first one specified is
+ * included. This method iterates over {@code elements} at most once.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * @throws NullPointerException if {@code comparator} or any of {@code
+ * elements} is null
+ */
+ 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);
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * the given {@code Comparator}. When multiple elements are equivalent
+ * according to {@code compareTo()}, only the first one specified is
+ * included.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * <p>This method is safe to use even when {@code elements} is a synchronized
+ * or concurrent collection that is currently being modified by another
+ * thread.
+ *
+ * @throws NullPointerException if {@code comparator} or any of
+ * {@code elements} is null
+ * @since 7.0 (source-compatible since 2.0)
+ */
+ public static <E> ImmutableSortedSet<E> copyOf(
+ Comparator<? super E> comparator, Collection<? extends E> elements) {
+ return copyOf(comparator, (Iterable<? extends E>) elements);
+ }
+
+ /**
+ * Returns an immutable sorted set containing the elements of a sorted set,
+ * sorted by the same {@code Comparator}. That behavior differs from {@link
+ * #copyOf(Iterable)}, which always uses the natural ordering of the
+ * elements.
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ *
+ * <p>This method is safe to use even when {@code sortedSet} is a synchronized
+ * or concurrent collection that is currently being modified by another
+ * thread.
+ *
+ * @throws NullPointerException if {@code sortedSet} or any of its elements
+ * is null
+ */
+ public static <E> ImmutableSortedSet<E> copyOfSorted(SortedSet<E> sortedSet) {
+ Comparator<? super E> comparator = SortedIterables.comparator(sortedSet);
+ E[] elements = (E[]) sortedSet.toArray();
+ if (elements.length == 0) {
+ return emptySet(comparator);
+ } else {
+ return new RegularImmutableSortedSet<E>(
+ ImmutableList.<E>asImmutableList(elements), comparator);
+ }
+ }
+
+ /**
+ * 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;
+ }
+ }
+ Arrays.fill(contents, uniques, n, null);
+ return uniques;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Returns a builder that creates immutable sorted sets with an explicit
+ * comparator. If the comparator has a more general type than the set being
+ * generated, such as creating a {@code SortedSet<Integer>} with a
+ * {@code Comparator<Number>}, use the {@link Builder} constructor instead.
+ *
+ * @throws NullPointerException if {@code comparator} is null
+ */
+ public static <E> Builder<E> orderedBy(Comparator<E> comparator) {
+ return new Builder<E>(comparator);
+ }
+
+ /**
+ * 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<E>> Builder<E> reverseOrder() {
+ return new Builder<E>(Ordering.natural().reverse());
+ }
+
+ /**
+ * Returns a builder that creates immutable sorted sets whose elements are
+ * ordered by their natural ordering. The sorted sets use {@link
+ * 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<E>> Builder<E> naturalOrder() {
+ return new Builder<E>(Ordering.natural());
+ }
+
+ /**
+ * A builder for creating immutable sorted set instances, especially {@code
+ * public static final} sets ("constant sets"), with a given comparator.
+ * Example: <pre> {@code
+ *
+ * public static final ImmutableSortedSet<Number> LUCKY_NUMBERS =
+ * new ImmutableSortedSet.Builder<Number>(ODDS_FIRST_COMPARATOR)
+ * .addAll(SINGLE_DIGIT_PRIMES)
+ * .add(42)
+ * .build();}</pre>
+ *
+ * Builder instances can be reused; it is safe to call {@link #build} multiple
+ * times to build multiple sets in series. Each set is a superset of the set
+ * created before it.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public static final class Builder<E> extends ImmutableSet.Builder<E> {
+ private final Comparator<? super E> comparator;
+
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder
+ * generated by {@link ImmutableSortedSet#orderedBy}.
+ */
+ public Builder(Comparator<? super E> comparator) {
+ this.comparator = checkNotNull(comparator);
+ }
+
+ /**
+ * Adds {@code element} to the {@code ImmutableSortedSet}. If the
+ * {@code ImmutableSortedSet} already contains {@code element}, then
+ * {@code add} has no effect. (only the previously added element
+ * is retained).
+ *
+ * @param element the element to add
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code element} is null
+ */
+ @Override public Builder<E> add(E element) {
+ super.add(element);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableSortedSet},
+ * ignoring duplicate elements (only the first duplicate element is added).
+ *
+ * @param elements the elements to add
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} contains a null element
+ */
+ @Override public Builder<E> add(E... elements) {
+ super.add(elements);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableSortedSet},
+ * ignoring duplicate elements (only the first duplicate element is added).
+ *
+ * @param elements the elements to add to the {@code ImmutableSortedSet}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} contains a null element
+ */
+ @Override public Builder<E> addAll(Iterable<? extends E> elements) {
+ super.addAll(elements);
+ return this;
+ }
+
+ /**
+ * Adds each element of {@code elements} to the {@code ImmutableSortedSet},
+ * ignoring duplicate elements (only the first duplicate element is added).
+ *
+ * @param elements the elements to add to the {@code ImmutableSortedSet}
+ * @return this {@code Builder} object
+ * @throws NullPointerException if {@code elements} contains a null element
+ */
+ @Override public Builder<E> addAll(Iterator<? extends E> elements) {
+ super.addAll(elements);
+ return this;
+ }
+
+ /**
+ * Returns a newly-created {@code ImmutableSortedSet} based on the contents
+ * 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;
+ }
+ }
+
+ int unsafeCompare(Object a, Object b) {
+ return unsafeCompare(comparator, a, b);
+ }
+
+ static int unsafeCompare(
+ Comparator<?> comparator, Object a, Object b) {
+ // 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 unsafeComparator.compare(a, b);
+ }
+
+ final transient Comparator<? super E> comparator;
+
+ ImmutableSortedSet(Comparator<? super E> comparator) {
+ this.comparator = comparator;
+ }
+
+ /**
+ * Returns the comparator that orders the elements, which is
+ * {@link Ordering#natural()} when the natural ordering of the
+ * elements is used. Note that its behavior is not consistent with
+ * {@link SortedSet#comparator()}, which returns {@code null} to indicate
+ * natural ordering.
+ */
+ @Override
+ public Comparator<? super E> comparator() {
+ return comparator;
+ }
+
+ @Override // needed to unify the iterator() methods in Collection and SortedIterable
+ public abstract UnmodifiableIterator<E> iterator();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method returns a serializable {@code ImmutableSortedSet}.
+ *
+ * <p>The {@link SortedSet#headSet} documentation states that a subset of a
+ * subset throws an {@link IllegalArgumentException} if passed a
+ * {@code toElement} greater than an earlier {@code toElement}. However, this
+ * method doesn't throw an exception in that situation, but instead keeps the
+ * original {@code toElement}.
+ */
+ @Override
+ public ImmutableSortedSet<E> headSet(E toElement) {
+ return headSet(toElement, false);
+ }
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override
+ public ImmutableSortedSet<E> headSet(E toElement, boolean inclusive) {
+ return headSetImpl(checkNotNull(toElement), inclusive);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method returns a serializable {@code ImmutableSortedSet}.
+ *
+ * <p>The {@link SortedSet#subSet} documentation states that a subset of a
+ * subset throws an {@link IllegalArgumentException} if passed a
+ * {@code fromElement} smaller than an earlier {@code fromElement}. However,
+ * this method doesn't throw an exception in that situation, but instead keeps
+ * the original {@code fromElement}. Similarly, this method keeps the
+ * original {@code toElement}, instead of throwing an exception, if passed a
+ * {@code toElement} greater than an earlier {@code toElement}.
+ */
+ @Override
+ public ImmutableSortedSet<E> subSet(E fromElement, E toElement) {
+ return subSet(fromElement, true, toElement, false);
+ }
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override
+ public ImmutableSortedSet<E> subSet(
+ E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ checkNotNull(fromElement);
+ checkNotNull(toElement);
+ checkArgument(comparator.compare(fromElement, toElement) <= 0);
+ return subSetImpl(fromElement, fromInclusive, toElement, toInclusive);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method returns a serializable {@code ImmutableSortedSet}.
+ *
+ * <p>The {@link SortedSet#tailSet} documentation states that a subset of a
+ * subset throws an {@link IllegalArgumentException} if passed a
+ * {@code fromElement} smaller than an earlier {@code fromElement}. However,
+ * this method doesn't throw an exception in that situation, but instead keeps
+ * the original {@code fromElement}.
+ */
+ @Override
+ public ImmutableSortedSet<E> tailSet(E fromElement) {
+ return tailSet(fromElement, true);
+ }
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override
+ public ImmutableSortedSet<E> tailSet(E fromElement, boolean inclusive) {
+ return tailSetImpl(checkNotNull(fromElement), inclusive);
+ }
+
+ /*
+ * These methods perform most headSet, subSet, and tailSet logic, besides
+ * parameter validation.
+ */
+ abstract ImmutableSortedSet<E> headSetImpl(E toElement, boolean inclusive);
+
+ abstract ImmutableSortedSet<E> subSetImpl(
+ E fromElement, boolean fromInclusive, E toElement, boolean toInclusive);
+
+ abstract ImmutableSortedSet<E> tailSetImpl(E fromElement, boolean inclusive);
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override
+ public E lower(E e) {
+ return Iterables.getFirst(headSet(e, false).descendingSet(), null);
+ }
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override
+ public E floor(E e) {
+ return Iterables.getFirst(headSet(e, true).descendingSet(), 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);
+ }
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override
+ public final E pollFirst() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @since 12.0
+ */
+ @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() {
+ ImmutableSortedSet<E> result = descendingSet;
+ if (result == null) {
+ result = descendingSet = createDescendingSet();
+ result.descendingSet = this;
+ }
+ return result;
+ }
+
+ @GwtIncompatible("NavigableSet")
+ abstract ImmutableSortedSet<E> createDescendingSet();
+
+ /**
+ * @since 12.0
+ */
+ @GwtIncompatible("NavigableSet")
+ @Override
+ public UnmodifiableIterator<E> descendingIterator() {
+ return descendingSet().iterator();
+ }
+
+ /**
+ * Returns the position of an element within the set, or -1 if not present.
+ */
+ abstract int indexOf(@Nullable Object target);
+
+ /*
+ * This class is used to serialize all ImmutableSortedSet instances,
+ * regardless of implementation type. It captures their "logical contents"
+ * only. This is necessary to ensure that the existence of a particular
+ * implementation type is an implementation detail.
+ */
+ private static class SerializedForm<E> implements Serializable {
+ final Comparator<? super E> comparator;
+ final Object[] elements;
+
+ public SerializedForm(Comparator<? super E> comparator, Object[] elements) {
+ this.comparator = comparator;
+ this.elements = elements;
+ }
+
+ @SuppressWarnings("unchecked")
+ Object readResolve() {
+ return new Builder<E>(comparator).add((E[]) elements).build();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws InvalidObjectException {
+ throw new InvalidObjectException("Use SerializedForm");
+ }
+
+ @Override Object writeReplace() {
+ return new SerializedForm<E>(comparator, toArray());
+ }
+}
+
diff --git a/guava/src/com/google/common/collect/ImmutableSortedSetFauxverideShim.java b/guava/src/com/google/common/collect/ImmutableSortedSetFauxverideShim.java
new file mode 100644
index 0000000..302e912
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableSortedSetFauxverideShim.java
@@ -0,0 +1,167 @@
+/*
+ * 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;
+
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * "Overrides" the {@link ImmutableSet} static methods that lack
+ * {@link ImmutableSortedSet} equivalents with deprecated, exception-throwing
+ * versions. This prevents accidents like the following: <pre> {@code
+ *
+ * List<Object> objects = ...;
+ * // Sort them:
+ * Set<Object> sorted = ImmutableSortedSet.copyOf(objects);
+ * // BAD CODE! The returned set is actually an unsorted ImmutableSet!}</pre>
+ *
+ * While we could put the overrides in {@link ImmutableSortedSet} itself, it
+ * seems clearer to separate these "do not call" methods from those intended for
+ * normal use.
+ *
+ * @author Chris Povirk
+ */
+@GwtCompatible
+abstract class ImmutableSortedSetFauxverideShim<E> extends ImmutableSet<E> {
+ /**
+ * Not supported. Use {@link ImmutableSortedSet#naturalOrder}, which offers
+ * better type-safety, instead. This method exists only to hide
+ * {@link ImmutableSet#builder} from consumers of {@code ImmutableSortedSet}.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated Use {@link ImmutableSortedSet#naturalOrder}, which offers
+ * better type-safety.
+ */
+ @Deprecated public static <E> ImmutableSortedSet.Builder<E> builder() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a set that may contain a
+ * non-{@code Comparable} element.</b> Proper calls will resolve to the
+ * version in {@code ImmutableSortedSet}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass a parameter of type {@code Comparable} to use {@link
+ * ImmutableSortedSet#of(Comparable)}.</b>
+ */
+ @Deprecated public static <E> ImmutableSortedSet<E> of(E element) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a set that may contain a
+ * non-{@code Comparable} element.</b> Proper calls will resolve to the
+ * version in {@code ImmutableSortedSet}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link
+ * ImmutableSortedSet#of(Comparable, Comparable)}.</b>
+ */
+ @Deprecated public static <E> ImmutableSortedSet<E> of(E e1, E e2) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a set that may contain a
+ * non-{@code Comparable} element.</b> Proper calls will resolve to the
+ * version in {@code ImmutableSortedSet}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link
+ * ImmutableSortedSet#of(Comparable, Comparable, Comparable)}.</b>
+ */
+ @Deprecated public static <E> ImmutableSortedSet<E> of(E e1, E e2, E e3) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a set that may contain a
+ * non-{@code Comparable} element.</b> Proper calls will resolve to the
+ * version in {@code ImmutableSortedSet}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link
+ * ImmutableSortedSet#of(Comparable, Comparable, Comparable, Comparable)}.
+ * </b>
+ */
+ @Deprecated public static <E> ImmutableSortedSet<E> of(
+ E e1, E e2, E e3, E e4) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a set that may contain a
+ * non-{@code Comparable} element.</b> Proper calls will resolve to the
+ * version in {@code ImmutableSortedSet}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link
+ * ImmutableSortedSet#of(
+ * Comparable, Comparable, Comparable, Comparable, Comparable)}. </b>
+ */
+ @Deprecated public static <E> ImmutableSortedSet<E> of(
+ E e1, E e2, E e3, E e4, E e5) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a set that may contain a
+ * non-{@code Comparable} element.</b> Proper calls will resolve to the
+ * version in {@code ImmutableSortedSet}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass the parameters of type {@code Comparable} to use {@link
+ * ImmutableSortedSet#of(Comparable, Comparable, Comparable, Comparable,
+ * Comparable, Comparable, Comparable...)}. </b>
+ */
+ @Deprecated public static <E> ImmutableSortedSet<E> of(
+ E e1, E e2, E e3, E e4, E e5, E e6, E... remaining) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not supported. <b>You are attempting to create a set that may contain
+ * non-{@code Comparable} elements.</b> Proper calls will resolve to the
+ * version in {@code ImmutableSortedSet}, not this dummy version.
+ *
+ * @throws UnsupportedOperationException always
+ * @deprecated <b>Pass parameters of type {@code Comparable} to use {@link
+ * ImmutableSortedSet#copyOf(Comparable[])}.</b>
+ */
+ @Deprecated public static <E> ImmutableSortedSet<E> copyOf(E[] elements) {
+ throw new UnsupportedOperationException();
+ }
+
+ /*
+ * We would like to include an unsupported "<E> copyOf(Iterable<E>)" here,
+ * providing only the properly typed
+ * "<E extends Comparable<E>> copyOf(Iterable<E>)" in ImmutableSortedSet (and
+ * likewise for the Iterator equivalent). However, due to a change in Sun's
+ * interpretation of the JLS (as described at
+ * http://bugs.sun.com/view_bug.do?bug_id=6182950), the OpenJDK 7 compiler
+ * available as of this writing rejects our attempts. To maintain
+ * compatibility with that version and with any other compilers that interpret
+ * the JLS similarly, there is no definition of copyOf() here, and the
+ * definition in ImmutableSortedSet matches that in ImmutableSet.
+ *
+ * The result is that ImmutableSortedSet.copyOf() may be called on
+ * non-Comparable elements. We have not discovered a better solution. In
+ * retrospect, the static factory methods should have gone in a separate class
+ * so that ImmutableSortedSet wouldn't "inherit" too-permissive factory
+ * methods from ImmutableSet.
+ */
+}
diff --git a/guava/src/com/google/common/collect/ImmutableTable.java b/guava/src/com/google/common/collect/ImmutableTable.java
new file mode 100644
index 0000000..331a51e
--- /dev/null
+++ b/guava/src/com/google/common/collect/ImmutableTable.java
@@ -0,0 +1,336 @@
+/*
+ * 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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable {@link Table} with reliable user-specified iteration order.
+ * Does not permit null keys or values.
+ *
+ * <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 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
+ * @since 11.0
+ */
+@GwtCompatible
+// TODO(gak): make serializable
+public abstract class ImmutableTable<R, C, V> implements Table<R, C, V> {
+ /** Returns an empty immutable table. */
+ @SuppressWarnings("unchecked")
+ public static final <R, C, V> ImmutableTable<R, C, V> of() {
+ return (ImmutableTable<R, C, V>) EmptyImmutableTable.INSTANCE;
+ }
+
+ /** Returns an immutable table containing a single cell. */
+ public static final <R, C, V> ImmutableTable<R, C, V> of(R rowKey,
+ C columnKey, V value) {
+ return new SingletonImmutableTable<R, C, V>(rowKey, columnKey, value);
+ }
+
+ /**
+ * Returns an immutable copy of the provided table.
+ *
+ * <p>The {@link Table#cellSet()} iteration order of the provided table
+ * determines the iteration ordering of all views in the returned table. Note
+ * that some views of the original table and the copied table may have
+ * different iteration orders. For more control over the ordering, create a
+ * {@link Builder} and call {@link Builder#orderRowsBy},
+ * {@link Builder#orderColumnsBy}, and {@link Builder#putAll}
+ *
+ * <p>Despite the method name, this method attempts to avoid actually copying
+ * the data when it is safe to do so. The exact circumstances under which a
+ * copy will or will not be performed are undocumented and subject to change.
+ */
+ public static final <R, C, V> ImmutableTable<R, C, V> copyOf(
+ Table<? extends R, ? extends C, ? extends V> table) {
+ if (table instanceof ImmutableTable) {
+ @SuppressWarnings("unchecked")
+ ImmutableTable<R, C, V> parameterizedTable
+ = (ImmutableTable<R, C, V>) table;
+ return parameterizedTable;
+ } else {
+ int size = table.size();
+ switch (size) {
+ case 0:
+ return of();
+ case 1:
+ Cell<? extends R, ? extends C, ? extends V> onlyCell
+ = Iterables.getOnlyElement(table.cellSet());
+ return ImmutableTable.<R, C, V>of(onlyCell.getRowKey(),
+ onlyCell.getColumnKey(), onlyCell.getValue());
+ default:
+ ImmutableSet.Builder<Cell<R, C, V>> cellSetBuilder
+ = ImmutableSet.builder();
+ for (Cell<? extends R, ? extends C, ? extends V> cell :
+ table.cellSet()) {
+ /*
+ * Must cast to be able to create a Cell<R, C, V> rather than a
+ * Cell<? extends R, ? extends C, ? extends V>
+ */
+ cellSetBuilder.add(cellOf((R) cell.getRowKey(),
+ (C) cell.getColumnKey(), (V) cell.getValue()));
+ }
+ return RegularImmutableTable.forCells(cellSetBuilder.build());
+ }
+ }
+ }
+
+ /**
+ * Returns a new builder. The generated builder is equivalent to the builder
+ * created by the {@link Builder#ImmutableTable.Builder()} constructor.
+ */
+ public static final <R, C, V> Builder<R, C, V> builder() {
+ return new Builder<R, C, V>();
+ }
+
+ /**
+ * Verifies that {@code rowKey}, {@code columnKey} and {@code value} are
+ * non-null, and returns a new entry with those values.
+ */
+ static <R, C, V> Cell<R, C, V> cellOf(R rowKey, C columnKey, V value) {
+ return Tables.immutableCell(checkNotNull(rowKey), checkNotNull(columnKey),
+ checkNotNull(value));
+ }
+
+ /**
+ * A builder for creating immutable table instances, especially {@code public
+ * static final} tables ("constant tables"). Example: <pre> {@code
+ *
+ * static final ImmutableTable<Integer, Character, String> SPREADSHEET =
+ * new ImmutableTable.Builder<Integer, Character, String>()
+ * .put(1, 'A', "foo")
+ * .put(1, 'B', "bar")
+ * .put(2, 'A', "baz")
+ * .build();}</pre>
+ *
+ * <p>By default, the order in which cells are added to the builder determines
+ * the iteration ordering of all views in the returned table, with {@link
+ * #putAll} following the {@link Table#cellSet()} iteration order. However, if
+ * {@link #orderRowsBy} or {@link #orderColumnsBy} is called, the views are
+ * sorted by the supplied comparators.
+ *
+ * For empty or single-cell immutable tables, {@link #of()} and
+ * {@link #of(Object, Object, Object)} are even more convenient.
+ *
+ * <p>Builder instances can be reused - it is safe to call {@link #build}
+ * multiple times to build multiple tables in series. Each table is a superset
+ * of the tables created before it.
+ *
+ * @since 11.0
+ */
+ public static final class Builder<R, C, V> {
+ private final List<Cell<R, C, V>> cells = Lists.newArrayList();
+ private Comparator<? super R> rowComparator;
+ private Comparator<? super C> columnComparator;
+
+ /**
+ * Creates a new builder. The returned builder is equivalent to the builder
+ * generated by {@link ImmutableTable#builder}.
+ */
+ public Builder() {}
+
+ /**
+ * Specifies the ordering of the generated table's rows.
+ */
+ public Builder<R, C, V> orderRowsBy(Comparator<? super R> rowComparator) {
+ this.rowComparator = checkNotNull(rowComparator);
+ return this;
+ }
+
+ /**
+ * Specifies the ordering of the generated table's columns.
+ */
+ public Builder<R, C, V> orderColumnsBy(
+ Comparator<? super C> columnComparator) {
+ this.columnComparator = checkNotNull(columnComparator);
+ return this;
+ }
+
+ /**
+ * Associates the ({@code rowKey}, {@code columnKey}) pair with {@code
+ * value} in the built table. Duplicate key pairs are not allowed and will
+ * cause {@link #build} to fail.
+ */
+ public Builder<R, C, V> put(R rowKey, C columnKey, V value) {
+ cells.add(cellOf(rowKey, columnKey, value));
+ return this;
+ }
+
+ /**
+ * Adds the given {@code cell} to the table, making it immutable if
+ * necessary. Duplicate key pairs are not allowed and will cause {@link
+ * #build} to fail.
+ */
+ public Builder<R, C, V> put(
+ Cell<? extends R, ? extends C, ? extends V> cell) {
+ if (cell instanceof Tables.ImmutableCell) {
+ checkNotNull(cell.getRowKey());
+ checkNotNull(cell.getColumnKey());
+ checkNotNull(cell.getValue());
+ @SuppressWarnings("unchecked") // all supported methods are covariant
+ Cell<R, C, V> immutableCell = (Cell<R, C, V>) cell;
+ cells.add(immutableCell);
+ } else {
+ put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
+ }
+ return this;
+ }
+
+ /**
+ * Associates all of the given table's keys and values in the built table.
+ * Duplicate row key column key pairs are not allowed, and will cause
+ * {@link #build} to fail.
+ *
+ * @throws NullPointerException if any key or value in {@code table} is null
+ */
+ public Builder<R, C, V> putAll(
+ Table<? extends R, ? extends C, ? extends V> table) {
+ for (Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) {
+ put(cell);
+ }
+ return this;
+ }
+
+ /**
+ * Returns a newly-created immutable table.
+ *
+ * @throws IllegalArgumentException if duplicate key pairs were added
+ */
+ public ImmutableTable<R, C, V> build() {
+ int size = cells.size();
+ switch (size) {
+ case 0:
+ return of();
+ case 1:
+ return new SingletonImmutableTable<R, C, V>(
+ Iterables.getOnlyElement(cells));
+ default:
+ return RegularImmutableTable.forCells(
+ cells, rowComparator, columnComparator);
+ }
+ }
+ }
+
+ ImmutableTable() {}
+
+ @Override public abstract ImmutableSet<Cell<R, C, V>> cellSet();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws NullPointerException if {@code columnKey} is {@code null}
+ */
+ @Override public abstract ImmutableMap<R, V> column(C columnKey);
+
+ @Override public abstract ImmutableSet<C> columnKeySet();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <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();
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws NullPointerException if {@code rowKey} is {@code null}
+ */
+ @Override public abstract ImmutableMap<C, V> row(R rowKey);
+
+ @Override public abstract ImmutableSet<R> rowKeySet();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <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();
+
+ /**
+ * Guaranteed to throw an exception and leave the table unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public final void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the table unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public final V put(R rowKey, C columnKey, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the table unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public final void putAll(
+ Table<? extends R, ? extends C, ? extends V> table) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the table unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @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) {
+ Table<?, ?, ?> that = (Table<?, ?, ?>) obj;
+ return this.cellSet().equals(that.cellSet());
+ } else {
+ return false;
+ }
+ }
+
+ @Override public int hashCode() {
+ return cellSet().hashCode();
+ }
+
+ @Override public String toString() {
+ return rowMap().toString();
+ }
+}
diff --git a/guava/src/com/google/common/collect/Interner.java b/guava/src/com/google/common/collect/Interner.java
new file mode 100644
index 0000000..cd5e930
--- /dev/null
+++ b/guava/src/com/google/common/collect/Interner.java
@@ -0,0 +1,44 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+/**
+ * Provides equivalent behavior to {@link String#intern} for other immutable
+ * types.
+ *
+ * @author Kevin Bourrillion
+ * @since 3.0
+ */
+@Beta
+public interface Interner<E> {
+ /**
+ * Chooses and returns the representative instance for any of a collection of
+ * instances that are equal to each other. If two {@linkplain Object#equals
+ * equal} inputs are given to this method, both calls will return the same
+ * instance. That is, {@code intern(a).equals(a)} always holds, and {@code
+ * intern(a) == intern(b)} if and only if {@code a.equals(b)}. Note that
+ * {@code intern(a)} is permitted to return one instance now and a different
+ * instance later if the original interned instance was garbage-collected.
+ *
+ * <p><b>Warning:</b> do not use with mutable objects.
+ *
+ * @throws NullPointerException if {@code sample} is null
+ */
+ E intern(E sample);
+}
diff --git a/guava/src/com/google/common/collect/Interners.java b/guava/src/com/google/common/collect/Interners.java
new file mode 100644
index 0000000..bd592d6
--- /dev/null
+++ b/guava/src/com/google/common/collect/Interners.java
@@ -0,0 +1,136 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Function;
+import com.google.common.collect.MapMakerInternalMap.ReferenceEntry;
+
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Contains static methods pertaining to instances of {@link Interner}.
+ *
+ * @author Kevin Bourrillion
+ * @since 3.0
+ */
+@Beta
+public final class Interners {
+ private Interners() {}
+
+ /**
+ * Returns a new thread-safe interner which retains a strong reference to each instance it has
+ * interned, thus preventing these instances from being garbage-collected. If this retention is
+ * acceptable, this implementation may perform better than {@link #newWeakInterner}. Note that
+ * unlike {@link String#intern}, using this interner does not consume memory in the permanent
+ * generation.
+ */
+ public static <E> Interner<E> newStrongInterner() {
+ final ConcurrentMap<E, E> map = new MapMaker().makeMap();
+ return new Interner<E>() {
+ @Override public E intern(E sample) {
+ E canonical = map.putIfAbsent(checkNotNull(sample), sample);
+ return (canonical == null) ? sample : canonical;
+ }
+ };
+ }
+
+ /**
+ * 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> {
+ // MapMaker is our friend, we know about this type
+ private final MapMakerInternalMap<E, Dummy> map = new MapMaker()
+ .weakKeys()
+ .keyEquivalence(Equivalence.equals())
+ .makeCustomMap();
+
+ @Override public E intern(E sample) {
+ while (true) {
+ // trying to read the canonical...
+ ReferenceEntry<E, Dummy> entry = map.getEntry(sample);
+ if (entry != null) {
+ E canonical = entry.getKey();
+ if (canonical != null) { // only matters if weak/soft keys are used
+ return canonical;
+ }
+ }
+
+ // didn't see it, trying to put it instead...
+ Dummy sneaky = map.putIfAbsent(sample, Dummy.VALUE);
+ if (sneaky == null) {
+ return sample;
+ } else {
+ /* Someone beat us to it! Trying again...
+ *
+ * Technically this loop not guaranteed to terminate, so theoretically (extremely
+ * unlikely) this thread might starve, but even then, there is always going to be another
+ * thread doing progress here.
+ */
+ }
+ }
+ }
+
+ private enum Dummy { VALUE }
+ }
+
+ /**
+ * Returns a function that delegates to the {@link Interner#intern} method of the given interner.
+ *
+ * @since 8.0
+ */
+ public static <E> Function<E, E> asFunction(Interner<E> interner) {
+ return new InternerFunction<E>(checkNotNull(interner));
+ }
+
+ private static class InternerFunction<E> implements Function<E, E> {
+
+ private final Interner<E> interner;
+
+ public InternerFunction(Interner<E> interner) {
+ this.interner = interner;
+ }
+
+ @Override public E apply(E input) {
+ return interner.intern(input);
+ }
+
+ @Override public int hashCode() {
+ return interner.hashCode();
+ }
+
+ @Override public boolean equals(Object other) {
+ if (other instanceof InternerFunction) {
+ InternerFunction<?> that = (InternerFunction<?>) other;
+ return interner.equals(that.interner);
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/Iterables.java b/guava/src/com/google/common/collect/Iterables.java
new file mode 100644
index 0000000..0dddd6b
--- /dev/null
+++ b/guava/src/com/google/common/collect/Iterables.java
@@ -0,0 +1,1071 @@
+/*
+ * 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.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.Preconditions;
+import com.google.common.base.Predicate;
+
+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.NoSuchElementException;
+import java.util.Queue;
+import java.util.RandomAccess;
+import java.util.Set;
+import java.util.SortedSet;
+
+import javax.annotation.Nullable;
+
+/**
+ * This class contains static utility methods that operate on or return objects
+ * of type {@code Iterable}. Except as noted, each method has a corresponding
+ * {@link Iterator}-based method in the {@link Iterators} class.
+ *
+ * <p><i>Performance notes:</i> Unless otherwise noted, all of the iterables
+ * 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)
+ */
+@GwtCompatible(emulated = true)
+public final class Iterables {
+ private Iterables() {}
+
+ /** Returns an unmodifiable view of {@code iterable}. */
+ public static <T> Iterable<T> unmodifiableIterable(
+ final Iterable<T> iterable) {
+ checkNotNull(iterable);
+ if (iterable instanceof UnmodifiableIterable ||
+ iterable instanceof ImmutableCollection) {
+ return iterable;
+ }
+ return new UnmodifiableIterable<T>(iterable);
+ }
+
+ /**
+ * Simply returns its argument.
+ *
+ * @deprecated no need to use this
+ * @since 10.0
+ */
+ @Deprecated public static <E> Iterable<E> unmodifiableIterable(
+ ImmutableCollection<E> iterable) {
+ return checkNotNull(iterable);
+ }
+
+ private static final class UnmodifiableIterable<T> extends FluentIterable<T> {
+ private final Iterable<T> iterable;
+
+ private UnmodifiableIterable(Iterable<T> iterable) {
+ this.iterable = iterable;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return Iterators.unmodifiableIterator(iterable.iterator());
+ }
+
+ @Override
+ public String toString() {
+ return iterable.toString();
+ }
+ // no equals and hashCode; it would break the contract!
+ }
+
+ /**
+ * Returns the number of elements in {@code iterable}.
+ */
+ public static int size(Iterable<?> iterable) {
+ return (iterable instanceof Collection)
+ ? ((Collection<?>) iterable).size()
+ : Iterators.size(iterable.iterator());
+ }
+
+ /**
+ * Returns {@code true} if {@code iterable} contains 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;
+ try {
+ return collection.contains(element);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+ return Iterators.contains(iterable.iterator(), element);
+ }
+
+ /**
+ * Removes, from an iterable, every element that belongs to the provided
+ * collection.
+ *
+ * <p>This method calls {@link Collection#removeAll} if {@code iterable} is a
+ * collection, and {@link Iterators#removeAll} otherwise.
+ *
+ * @param removeFrom the iterable to (potentially) remove elements from
+ * @param elementsToRemove the elements to remove
+ * @return {@code true} if any element was removed from {@code iterable}
+ */
+ public static boolean removeAll(
+ Iterable<?> removeFrom, Collection<?> elementsToRemove) {
+ return (removeFrom instanceof Collection)
+ ? ((Collection<?>) removeFrom).removeAll(checkNotNull(elementsToRemove))
+ : Iterators.removeAll(removeFrom.iterator(), elementsToRemove);
+ }
+
+ /**
+ * Removes, from an iterable, every element that does not belong to the
+ * provided collection.
+ *
+ * <p>This method calls {@link Collection#retainAll} if {@code iterable} is a
+ * collection, and {@link Iterators#retainAll} otherwise.
+ *
+ * @param removeFrom the iterable to (potentially) remove elements from
+ * @param elementsToRetain the elements to retain
+ * @return {@code true} if any element was removed from {@code iterable}
+ */
+ public static boolean retainAll(
+ Iterable<?> removeFrom, Collection<?> elementsToRetain) {
+ return (removeFrom instanceof Collection)
+ ? ((Collection<?>) removeFrom).retainAll(checkNotNull(elementsToRetain))
+ : Iterators.retainAll(removeFrom.iterator(), elementsToRetain);
+ }
+
+ /**
+ * Removes, from an iterable, every element that satisfies the provided
+ * predicate.
+ *
+ * @param removeFrom the iterable to (potentially) remove elements from
+ * @param predicate a predicate that determines whether an element should
+ * be removed
+ * @return {@code true} if any elements were removed from the iterable
+ *
+ * @throws UnsupportedOperationException if the iterable does not support
+ * {@code remove()}.
+ * @since 2.0
+ */
+ public static <T> boolean removeIf(
+ Iterable<T> removeFrom, Predicate<? super T> predicate) {
+ if (removeFrom instanceof RandomAccess && removeFrom instanceof List) {
+ return removeIfFromRandomAccessList(
+ (List<T>) removeFrom, checkNotNull(predicate));
+ }
+ return Iterators.removeIf(removeFrom.iterator(), predicate);
+ }
+
+ private static <T> boolean removeIfFromRandomAccessList(
+ List<T> list, Predicate<? super T> predicate) {
+ // Note: Not all random access lists support set() so we need to deal with
+ // those that don't and attempt the slower remove() based solution.
+ int from = 0;
+ int to = 0;
+
+ for (; from < list.size(); from++) {
+ T element = list.get(from);
+ if (!predicate.apply(element)) {
+ if (from > to) {
+ try {
+ list.set(to, element);
+ } catch (UnsupportedOperationException e) {
+ slowRemoveIfForRemainingElements(list, predicate, to, from);
+ return true;
+ }
+ }
+ to++;
+ }
+ }
+
+ // Clear the tail of any remaining items
+ list.subList(to, list.size()).clear();
+ return from != to;
+ }
+
+ private static <T> void slowRemoveIfForRemainingElements(List<T> list,
+ Predicate<? super T> predicate, int to, int from) {
+ // Here we know that:
+ // * (to < from) and that both are valid indices.
+ // * Everything with (index < to) should be kept.
+ // * Everything with (to <= index < from) should be removed.
+ // * The element with (index == from) should be kept.
+ // * Everything with (index > from) has not been checked yet.
+
+ // Check from the end of the list backwards (minimize expected cost of
+ // moving elements when remove() is called). Stop before 'from' because
+ // we already know that should be kept.
+ for (int n = list.size() - 1; n > from; n--) {
+ if (predicate.apply(list.get(n))) {
+ list.remove(n);
+ }
+ }
+ // And now remove everything in the range [to, from) (going backwards).
+ for (int n = from - 1; n >= to; n--) {
+ list.remove(n);
+ }
+ }
+
+ /**
+ * Determines whether two iterables contain equal elements in the same order.
+ * More specifically, this method returns {@code true} if {@code iterable1}
+ * and {@code iterable2} contain the same number of elements and every element
+ * of {@code iterable1} is equal to the corresponding element of
+ * {@code iterable2}.
+ */
+ public static boolean elementsEqual(
+ Iterable<?> iterable1, Iterable<?> iterable2) {
+ return Iterators.elementsEqual(iterable1.iterator(), iterable2.iterator());
+ }
+
+ /**
+ * Returns a string representation of {@code iterable}, with the format
+ * {@code [e1, e2, ..., en]}.
+ */
+ public static String toString(Iterable<?> iterable) {
+ return Iterators.toString(iterable.iterator());
+ }
+
+ /**
+ * Returns the single element contained in {@code iterable}.
+ *
+ * @throws NoSuchElementException if the iterable is empty
+ * @throws IllegalArgumentException if the iterable contains multiple
+ * elements
+ */
+ public static <T> T getOnlyElement(Iterable<T> iterable) {
+ return Iterators.getOnlyElement(iterable.iterator());
+ }
+
+ /**
+ * Returns the single element contained in {@code iterable}, or {@code
+ * defaultValue} if the iterable is empty.
+ *
+ * @throws IllegalArgumentException if the iterator contains multiple
+ * elements
+ */
+ public static <T> T getOnlyElement(
+ Iterable<? extends T> iterable, @Nullable T defaultValue) {
+ return Iterators.getOnlyElement(iterable.iterator(), defaultValue);
+ }
+
+ /**
+ * Copies an iterable's elements into an array.
+ *
+ * @param iterable the iterable to copy
+ * @param type the type of the elements
+ * @return a newly-allocated array into which all the elements of the iterable
+ * have been copied
+ */
+ @GwtIncompatible("Array.newInstance(Class, int)")
+ public static <T> T[] toArray(Iterable<? extends T> iterable, Class<T> type) {
+ Collection<? extends T> collection = toCollection(iterable);
+ T[] array = ObjectArrays.newArray(type, collection.size());
+ return collection.toArray(array);
+ }
+
+ /**
+ * Copies an iterable's elements into an array.
+ *
+ * @param iterable the iterable to copy
+ * @return a newly-allocated array into which all the elements of the iterable
+ * have been copied
+ */
+ static Object[] toArray(Iterable<?> iterable) {
+ return toCollection(iterable).toArray();
+ }
+
+ /**
+ * Converts an iterable into a collection. If the iterable is already a
+ * collection, it is returned. Otherwise, an {@link java.util.ArrayList} is
+ * created with the contents of the iterable in the same iteration order.
+ */
+ private static <E> Collection<E> toCollection(Iterable<E> iterable) {
+ return (iterable instanceof Collection)
+ ? (Collection<E>) iterable
+ : Lists.newArrayList(iterable.iterator());
+ }
+
+ /**
+ * Adds all elements in {@code iterable} to {@code collection}.
+ *
+ * @return {@code true} if {@code collection} was modified as a result of this
+ * operation.
+ */
+ public static <T> boolean addAll(
+ Collection<T> addTo, Iterable<? extends T> elementsToAdd) {
+ if (elementsToAdd instanceof Collection) {
+ Collection<? extends T> c = Collections2.cast(elementsToAdd);
+ return addTo.addAll(c);
+ }
+ return Iterators.addAll(addTo, elementsToAdd.iterator());
+ }
+
+ /**
+ * Returns the number of elements in the specified iterable that equal the
+ * specified object. This implementation avoids a full iteration when the
+ * iterable is a {@link Multiset} or {@link Set}.
+ *
+ * @see Collections#frequency
+ */
+ public static int frequency(Iterable<?> iterable, @Nullable Object element) {
+ if ((iterable instanceof Multiset)) {
+ return ((Multiset<?>) iterable).count(element);
+ }
+ if ((iterable instanceof Set)) {
+ return ((Set<?>) iterable).contains(element) ? 1 : 0;
+ }
+ return Iterators.frequency(iterable.iterator(), element);
+ }
+
+ /**
+ * Returns an iterable whose iterators cycle indefinitely over the elements of
+ * {@code 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 {@code iterable}. The iterator's
+ * {@code hasNext()} method returns {@code true} until {@code 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.
+ *
+ * <p>To cycle over the iterable {@code n} times, use the following:
+ * {@code Iterables.concat(Collections.nCopies(n, iterable))}
+ */
+ public static <T> Iterable<T> cycle(final Iterable<T> iterable) {
+ checkNotNull(iterable);
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return Iterators.cycle(iterable);
+ }
+ @Override public String toString() {
+ return iterable.toString() + " (cycled)";
+ }
+ };
+ }
+
+ /**
+ * Returns an iterable whose iterators cycle indefinitely over the provided
+ * elements.
+ *
+ * <p>After {@code remove} is invoked on a generated iterator, the removed
+ * element will no longer appear in either that iterator or any other iterator
+ * created from the same source iterable. That is, this method behaves exactly
+ * as {@code Iterables.cycle(Lists.newArrayList(elements))}. The iterator's
+ * {@code hasNext} method returns {@code true} until all of the original
+ * elements have been removed.
+ *
+ * <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.
+ *
+ * <p>To cycle over the elements {@code n} times, use the following:
+ * {@code Iterables.concat(Collections.nCopies(n, Arrays.asList(elements)))}
+ */
+ public static <T> Iterable<T> cycle(T... elements) {
+ return cycle(Lists.newArrayList(elements));
+ }
+
+ /**
+ * Combines two iterables into a single iterable. The returned iterable has an
+ * iterator that traverses the elements in {@code a}, followed by the elements
+ * in {@code b}. The source iterators are not polled until necessary.
+ *
+ * <p>The returned iterable's iterator supports {@code remove()} when the
+ * corresponding input iterator supports it.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Iterable<T> concat(
+ Iterable<? extends T> a, Iterable<? extends T> b) {
+ checkNotNull(a);
+ checkNotNull(b);
+ return concat(Arrays.asList(a, b));
+ }
+
+ /**
+ * Combines three iterables into a single iterable. The returned iterable has
+ * an iterator that traverses the elements in {@code a}, followed by the
+ * elements in {@code b}, followed by the elements in {@code c}. The source
+ * iterators are not polled until necessary.
+ *
+ * <p>The returned iterable's iterator supports {@code remove()} when the
+ * corresponding input iterator supports it.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Iterable<T> concat(Iterable<? extends T> a,
+ Iterable<? extends T> b, Iterable<? extends T> c) {
+ checkNotNull(a);
+ checkNotNull(b);
+ checkNotNull(c);
+ return concat(Arrays.asList(a, b, c));
+ }
+
+ /**
+ * Combines four iterables into a single iterable. The returned iterable has
+ * an iterator that traverses the elements in {@code a}, followed by the
+ * elements in {@code b}, followed by the elements in {@code c}, followed by
+ * the elements in {@code d}. The source iterators are not polled until
+ * necessary.
+ *
+ * <p>The returned iterable's iterator supports {@code remove()} when the
+ * corresponding input iterator supports it.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Iterable<T> concat(Iterable<? extends T> a,
+ Iterable<? extends T> b, Iterable<? extends T> c,
+ Iterable<? extends T> d) {
+ checkNotNull(a);
+ checkNotNull(b);
+ checkNotNull(c);
+ checkNotNull(d);
+ return concat(Arrays.asList(a, b, c, d));
+ }
+
+ /**
+ * Combines multiple iterables into a single iterable. The returned iterable
+ * has an iterator that traverses the elements of each iterable in
+ * {@code inputs}. The input iterators are not polled until necessary.
+ *
+ * <p>The returned iterable's iterator supports {@code remove()} when the
+ * corresponding input iterator supports it.
+ *
+ * @throws NullPointerException if any of the provided iterables is null
+ */
+ public static <T> Iterable<T> concat(Iterable<? extends T>... inputs) {
+ return concat(ImmutableList.copyOf(inputs));
+ }
+
+ /**
+ * Combines multiple iterables into a single iterable. The returned iterable
+ * has an iterator that traverses the elements of each iterable in
+ * {@code inputs}. The input iterators are not polled until necessary.
+ *
+ * <p>The returned iterable's iterator supports {@code remove()} when the
+ * corresponding input iterator supports it. The methods of the returned
+ * iterable may throw {@code NullPointerException} if any of the input
+ * iterators is null.
+ */
+ public static <T> Iterable<T> concat(
+ final Iterable<? extends Iterable<? extends T>> inputs) {
+ checkNotNull(inputs);
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return Iterators.concat(iterators(inputs));
+ }
+ };
+ }
+
+ /**
+ * Returns an iterator over the iterators of the given iterables.
+ */
+ private static <T> UnmodifiableIterator<Iterator<? extends T>> iterators(
+ Iterable<? extends Iterable<? extends T>> iterables) {
+ final Iterator<? extends Iterable<? extends T>> iterableIterator =
+ iterables.iterator();
+ return new UnmodifiableIterator<Iterator<? extends T>>() {
+ @Override
+ public boolean hasNext() {
+ return iterableIterator.hasNext();
+ }
+ @Override
+ public Iterator<? extends T> next() {
+ return iterableIterator.next().iterator();
+ }
+ };
+ }
+
+ /**
+ * Divides an iterable into unmodifiable sublists of the given size (the final
+ * iterable may be smaller). For example, partitioning an iterable containing
+ * {@code [a, b, c, d, e]} with a partition size of 3 yields {@code
+ * [[a, b, c], [d, e]]} -- an outer iterable containing two inner lists of
+ * three and two elements, all in the original order.
+ *
+ * <p>Iterators returned by the returned iterable do not support the {@link
+ * Iterator#remove()} method. The returned lists implement {@link
+ * RandomAccess}, whether or not the input list does.
+ *
+ * <p><b>Note:</b> if {@code iterable} is a {@link List}, use {@link
+ * Lists#partition(List, int)} instead.
+ *
+ * @param iterable the iterable to return a partitioned view of
+ * @param size the desired size of each partition (the last may be smaller)
+ * @return an iterable of unmodifiable lists containing the elements of {@code
+ * iterable} divided into partitions
+ * @throws IllegalArgumentException if {@code size} is nonpositive
+ */
+ public static <T> Iterable<List<T>> partition(
+ final Iterable<T> iterable, final int size) {
+ checkNotNull(iterable);
+ checkArgument(size > 0);
+ return new FluentIterable<List<T>>() {
+ @Override
+ public Iterator<List<T>> iterator() {
+ return Iterators.partition(iterable.iterator(), size);
+ }
+ };
+ }
+
+ /**
+ * Divides an iterable into unmodifiable sublists of the given size, padding
+ * the final iterable with null values if necessary. For example, partitioning
+ * an iterable containing {@code [a, b, c, d, e]} with a partition size of 3
+ * yields {@code [[a, b, c], [d, e, null]]} -- an outer iterable containing
+ * two inner lists of three elements each, all in the original order.
+ *
+ * <p>Iterators returned by the returned iterable do not support the {@link
+ * Iterator#remove()} method.
+ *
+ * @param iterable the iterable to return a partitioned view of
+ * @param size the desired size of each partition
+ * @return an iterable of unmodifiable lists containing the elements of {@code
+ * iterable} divided into partitions (the final iterable may have
+ * trailing null elements)
+ * @throws IllegalArgumentException if {@code size} is nonpositive
+ */
+ public static <T> Iterable<List<T>> paddedPartition(
+ final Iterable<T> iterable, final int size) {
+ checkNotNull(iterable);
+ checkArgument(size > 0);
+ return new FluentIterable<List<T>>() {
+ @Override
+ public Iterator<List<T>> iterator() {
+ return Iterators.paddedPartition(iterable.iterator(), size);
+ }
+ };
+ }
+
+ /**
+ * Returns the elements of {@code unfiltered} that satisfy a predicate. The
+ * resulting iterable's iterator does not support {@code remove()}.
+ */
+ public static <T> Iterable<T> filter(
+ final Iterable<T> unfiltered, final Predicate<? super T> predicate) {
+ checkNotNull(unfiltered);
+ checkNotNull(predicate);
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return Iterators.filter(unfiltered.iterator(), predicate);
+ }
+ };
+ }
+
+ /**
+ * Returns all instances of class {@code type} in {@code unfiltered}. The
+ * returned iterable has elements whose class is {@code type} or a subclass of
+ * {@code type}. The returned iterable's iterator does not support
+ * {@code remove()}.
+ *
+ * @param unfiltered an iterable containing objects of any type
+ * @param type the type of elements desired
+ * @return an unmodifiable iterable containing all elements of the original
+ * iterable that were of the requested type
+ */
+ @GwtIncompatible("Class.isInstance")
+ public static <T> Iterable<T> filter(
+ final Iterable<?> unfiltered, final Class<T> type) {
+ checkNotNull(unfiltered);
+ checkNotNull(type);
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return Iterators.filter(unfiltered.iterator(), type);
+ }
+ };
+ }
+
+ /**
+ * Returns {@code true} if any element in {@code iterable} satisfies the predicate.
+ */
+ public static <T> boolean any(
+ Iterable<T> iterable, Predicate<? super T> predicate) {
+ return Iterators.any(iterable.iterator(), predicate);
+ }
+
+ /**
+ * Returns {@code true} if every element in {@code iterable} satisfies the
+ * predicate. If {@code iterable} is empty, {@code true} is returned.
+ */
+ public static <T> boolean all(
+ Iterable<T> iterable, Predicate<? super T> predicate) {
+ return Iterators.all(iterable.iterator(), predicate);
+ }
+
+ /**
+ * 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.
+ *
+ * @throws NoSuchElementException if no element in {@code iterable} matches
+ * the given predicate
+ */
+ public static <T> T find(Iterable<T> iterable,
+ Predicate<? super T> predicate) {
+ return Iterators.find(iterable.iterator(), predicate);
+ }
+
+ /**
+ * Returns the first element in {@code iterable} that satisfies the given
+ * predicate, or {@code defaultValue} if none found. Note that this can
+ * usually be handled more naturally using {@code
+ * tryFind(iterable, predicate).or(defaultValue)}.
+ *
+ * @since 7.0
+ */
+ public static <T> T find(Iterable<? extends T> iterable,
+ Predicate<? super T> predicate, @Nullable T defaultValue) {
+ return Iterators.find(iterable.iterator(), predicate, defaultValue);
+ }
+
+ /**
+ * Returns an {@link Optional} containing the first element in {@code
+ * 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 {@code iterable}, a
+ * NullPointerException will be thrown.
+ *
+ * @since 11.0
+ */
+ public static <T> Optional<T> tryFind(Iterable<T> iterable,
+ Predicate<? super T> predicate) {
+ return Iterators.tryFind(iterable.iterator(), predicate);
+ }
+
+ /**
+ * Returns the index in {@code iterable} of the first element that satisfies
+ * the provided {@code predicate}, or {@code -1} if the Iterable has no such
+ * elements.
+ *
+ * <p>More formally, returns the lowest index {@code i} such that
+ * {@code predicate.apply(Iterables.get(iterable, i))} returns {@code true},
+ * or {@code -1} if there is no such index.
+ *
+ * @since 2.0
+ */
+ public static <T> int indexOf(
+ Iterable<T> iterable, Predicate<? super T> predicate) {
+ return Iterators.indexOf(iterable.iterator(), predicate);
+ }
+
+ /**
+ * Returns an iterable that applies {@code function} to each element of {@code
+ * fromIterable}.
+ *
+ * <p>The returned iterable's iterator supports {@code remove()} if the
+ * provided iterator does. After a successful {@code remove()} call,
+ * {@code fromIterable} no longer contains the corresponding element.
+ *
+ * <p>If the input {@code Iterable} is known to be a {@code List} or other
+ * {@code Collection}, consider {@link Lists#transform} and {@link
+ * Collections2#transform}.
+ */
+ public static <F, T> Iterable<T> transform(final Iterable<F> fromIterable,
+ final Function<? super F, ? extends T> function) {
+ checkNotNull(fromIterable);
+ checkNotNull(function);
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return Iterators.transform(fromIterable.iterator(), function);
+ }
+ };
+ }
+
+ /**
+ * Returns the element at the specified position in an iterable.
+ *
+ * @param position position of the element to return
+ * @return the element at the specified position in {@code iterable}
+ * @throws IndexOutOfBoundsException if {@code position} is negative or
+ * greater than or equal to the size of {@code iterable}
+ */
+ public static <T> T get(Iterable<T> iterable, int position) {
+ checkNotNull(iterable);
+ if (iterable instanceof List) {
+ return ((List<T>) iterable).get(position);
+ }
+
+ if (iterable instanceof Collection) {
+ // Can check both ends
+ Collection<T> collection = (Collection<T>) iterable;
+ Preconditions.checkElementIndex(position, collection.size());
+ } else {
+ // Can only check the lower end
+ checkNonnegativeIndex(position);
+ }
+ return Iterators.get(iterable.iterator(), position);
+ }
+
+ private static void checkNonnegativeIndex(int position) {
+ if (position < 0) {
+ throw new IndexOutOfBoundsException(
+ "position cannot be negative: " + position);
+ }
+ }
+
+ /**
+ * Returns the element at the specified position in an iterable or a default
+ * value otherwise.
+ *
+ * @param position position of the element to return
+ * @param defaultValue the default value to return if {@code position} is
+ * greater than or equal to the size of the iterable
+ * @return the element at the specified position in {@code iterable} or
+ * {@code defaultValue} if {@code iterable} contains fewer than
+ * {@code position + 1} elements.
+ * @throws IndexOutOfBoundsException if {@code position} is negative
+ * @since 4.0
+ */
+ public static <T> T get(Iterable<? extends T> iterable, int position, @Nullable T defaultValue) {
+ checkNotNull(iterable);
+ checkNonnegativeIndex(position);
+
+ try {
+ return get(iterable, position);
+ } catch (IndexOutOfBoundsException e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the first element in {@code iterable} or {@code defaultValue} if
+ * the iterable is empty. The {@link Iterators} analog to this method is
+ * {@link Iterators#getNext}.
+ *
+ * @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
+ */
+ public static <T> T getFirst(Iterable<? extends T> iterable, @Nullable T defaultValue) {
+ return Iterators.getNext(iterable.iterator(), defaultValue);
+ }
+
+ /**
+ * Returns the last element of {@code iterable}.
+ *
+ * @return the last element of {@code iterable}
+ * @throws NoSuchElementException if the iterable is empty
+ */
+ public static <T> T getLast(Iterable<T> iterable) {
+ // TODO(kevinb): Support a concurrently modified collection?
+ if (iterable instanceof List) {
+ List<T> list = (List<T>) iterable;
+ if (list.isEmpty()) {
+ throw new NoSuchElementException();
+ }
+ return getLastInNonemptyList(list);
+ }
+
+ /*
+ * 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<T> sortedSet = (SortedSet<T>) iterable;
+ return sortedSet.last();
+ }
+
+ return Iterators.getLast(iterable.iterator());
+ }
+
+ /**
+ * Returns the last element of {@code iterable} or {@code defaultValue} if
+ * the iterable is empty.
+ *
+ * @param defaultValue the value to return if {@code iterable} is empty
+ * @return the last element of {@code iterable} or the default value
+ * @since 3.0
+ */
+ public static <T> T getLast(Iterable<? extends T> iterable, @Nullable T defaultValue) {
+ if (iterable instanceof Collection) {
+ Collection<? extends T> collection = Collections2.cast(iterable);
+ if (collection.isEmpty()) {
+ return defaultValue;
+ }
+ }
+
+ if (iterable instanceof List) {
+ List<? extends T> list = Lists.cast(iterable);
+ return getLastInNonemptyList(list);
+ }
+
+ /*
+ * 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<? extends T> sortedSet = Sets.cast(iterable);
+ return sortedSet.last();
+ }
+
+ return Iterators.getLast(iterable.iterator(), defaultValue);
+ }
+
+ private static <T> T getLastInNonemptyList(List<T> list) {
+ return list.get(list.size() - 1);
+ }
+
+ /**
+ * Returns a view of {@code iterable} that skips its first
+ * {@code numberToSkip} elements. If {@code iterable} contains fewer than
+ * {@code numberToSkip} elements, the returned iterable skips all of its
+ * elements.
+ *
+ * <p>Modifications to the underlying {@link Iterable} before a call to
+ * {@code iterator()} are reflected in the returned iterator. That is, the
+ * iterator skips the first {@code numberToSkip} elements that exist when the
+ * {@code Iterator} is created, not when {@code skip()} is called.
+ *
+ * <p>The returned iterable's iterator supports {@code remove()} if the
+ * iterator of the underlying iterable supports it. Note that it is
+ * <i>not</i> possible to delete the last skipped element by immediately
+ * calling {@code remove()} on that iterator, as the {@code Iterator}
+ * contract states that a call to {@code remove()} before a call to
+ * {@code next()} will throw an {@link IllegalStateException}.
+ *
+ * @since 3.0
+ */
+ public static <T> Iterable<T> skip(final Iterable<T> iterable,
+ final int numberToSkip) {
+ checkNotNull(iterable);
+ checkArgument(numberToSkip >= 0, "number to skip cannot be negative");
+
+ if (iterable instanceof List) {
+ final List<T> list = (List<T>) iterable;
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ // TODO(kevinb): Support a concurrently modified collection?
+ return (numberToSkip >= list.size())
+ ? Iterators.<T>emptyIterator()
+ : list.subList(numberToSkip, list.size()).iterator();
+ }
+ };
+ }
+
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ final Iterator<T> iterator = iterable.iterator();
+
+ Iterators.advance(iterator, numberToSkip);
+
+ /*
+ * We can't just return the iterator because an immediate call to its
+ * remove() method would remove one of the skipped elements instead of
+ * throwing an IllegalStateException.
+ */
+ return new Iterator<T>() {
+ boolean atStart = true;
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ try {
+ return iterator.next();
+ } finally {
+ atStart = false;
+ }
+ }
+
+ @Override
+ public void remove() {
+ if (atStart) {
+ throw new IllegalStateException();
+ }
+ iterator.remove();
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Creates an iterable with the first {@code limitSize} elements of the given
+ * iterable. If the original iterable does not contain that many elements, the
+ * returned iterator will have the same behavior as the original iterable. The
+ * returned iterable's iterator supports {@code remove()} if the original
+ * iterator does.
+ *
+ * @param iterable the iterable to limit
+ * @param limitSize the maximum number of elements in the returned iterator
+ * @throws IllegalArgumentException if {@code limitSize} is negative
+ * @since 3.0
+ */
+ public static <T> Iterable<T> limit(
+ final Iterable<T> iterable, final int limitSize) {
+ checkNotNull(iterable);
+ checkArgument(limitSize >= 0, "limit is negative");
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return Iterators.limit(iterable.iterator(), limitSize);
+ }
+ };
+ }
+
+ /**
+ * Returns a view of the supplied iterable that wraps each generated
+ * {@link Iterator} through {@link Iterators#consumingIterator(Iterator)}.
+ *
+ * <p>Note: If {@code iterable} is a {@link Queue}, the returned iterable will
+ * get entries from {@link Queue#remove()} since {@link Queue}'s iteration
+ * order is undefined. Calling {@link Iterator#hasNext()} on a generated
+ * iterator from the returned iterable may cause an item to be immediately
+ * dequeued for return on a subsequent call to {@link Iterator#next()}.
+ *
+ * @param iterable the iterable to wrap
+ * @return a view of the supplied iterable that wraps each generated iterator
+ * through {@link Iterators#consumingIterator(Iterator)}; for queues,
+ * an iterable that generates iterators that return and consume the
+ * queue's elements in queue order
+ *
+ * @see Iterators#consumingIterator(Iterator)
+ * @since 2.0
+ */
+ public static <T> Iterable<T> consumingIterable(final Iterable<T> iterable) {
+ if (iterable instanceof Queue) {
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return new ConsumingQueueIterator<T>((Queue<T>) iterable);
+ }
+ };
+ }
+
+ checkNotNull(iterable);
+
+ return new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return Iterators.consumingIterator(iterable.iterator());
+ }
+ };
+ }
+
+ private static class ConsumingQueueIterator<T> extends AbstractIterator<T> {
+ private final Queue<T> queue;
+
+ private ConsumingQueueIterator(Queue<T> queue) {
+ this.queue = queue;
+ }
+
+ @Override public T computeNext() {
+ try {
+ return queue.remove();
+ } catch (NoSuchElementException e) {
+ return endOfData();
+ }
+ }
+ }
+
+ // Methods only in Iterables, not in Iterators
+
+ /**
+ * Determines if the given iterable contains no elements.
+ *
+ * <p>There is no precise {@link Iterator} equivalent to this method, since
+ * one can only ask an iterator whether it has any elements <i>remaining</i>
+ * (which one does using {@link Iterator#hasNext}).
+ *
+ * @return {@code true} if the iterable contains no elements
+ */
+ public static boolean isEmpty(Iterable<?> iterable) {
+ if (iterable instanceof Collection) {
+ return ((Collection<?>) iterable).isEmpty();
+ }
+ return !iterable.iterator().hasNext();
+ }
+
+ /**
+ * Returns an iterable over the merged contents of all given
+ * {@code iterables}. Equivalent entries will not be de-duplicated.
+ *
+ * <p>Callers must ensure that the source {@code iterables} are in
+ * non-descending order as this method does not sort its input.
+ *
+ * <p>For any equivalent elements across all {@code iterables}, it is
+ * undefined which element is returned first.
+ *
+ * @since 11.0
+ */
+ @Beta
+ public static <T> Iterable<T> mergeSorted(
+ final Iterable<? extends Iterable<? extends T>> iterables,
+ final Comparator<? super T> comparator) {
+ checkNotNull(iterables, "iterables");
+ checkNotNull(comparator, "comparator");
+ Iterable<T> iterable = new FluentIterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return Iterators.mergeSorted(
+ Iterables.transform(iterables, Iterables.<T>toIterator()),
+ comparator);
+ }
+ };
+ return new UnmodifiableIterable<T>(iterable);
+ }
+
+ // TODO(user): Is this the best place for this? Move to fluent functions?
+ // Useful as a public method?
+ private static <T> Function<Iterable<? extends T>, Iterator<? extends T>>
+ toIterator() {
+ return new Function<Iterable<? extends T>, Iterator<? extends T>>() {
+ @Override
+ public Iterator<? extends T> apply(Iterable<? extends T> iterable) {
+ return iterable.iterator();
+ }
+ };
+ }
+}
diff --git a/guava/src/com/google/common/collect/Iterators.java b/guava/src/com/google/common/collect/Iterators.java
new file mode 100644
index 0000000..39e60dd
--- /dev/null
+++ b/guava/src/com/google/common/collect/Iterators.java
@@ -0,0 +1,1427 @@
+/*
+ * 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 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.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+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;
+
+import javax.annotation.Nullable;
+
+/**
+ * This class contains static utility methods that operate on or return objects
+ * of type {@link Iterator}. Except as noted, each method has a corresponding
+ * {@link Iterable}-based method in the {@link Iterables} class.
+ *
+ * <p><i>Performance notes:</i> Unless otherwise noted, all of the iterators
+ * 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)
+ */
+@GwtCompatible(emulated = true)
+public final class Iterators {
+ private Iterators() {}
+
+ static final UnmodifiableListIterator<Object> EMPTY_LIST_ITERATOR
+ = new UnmodifiableListIterator<Object>() {
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+ @Override
+ 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;
+ }
+ };
+
+ /**
+ * Returns the empty iterator.
+ *
+ * <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;
+ }
+
+ private static final Iterator<Object> EMPTY_MODIFIABLE_ITERATOR =
+ new Iterator<Object>() {
+ @Override public boolean hasNext() {
+ return false;
+ }
+
+ @Override public Object next() {
+ throw new NoSuchElementException();
+ }
+
+ @Override public void remove() {
+ throw new IllegalStateException();
+ }
+ };
+
+ /**
+ * Returns the empty {@code Iterator} that throws
+ * {@link IllegalStateException} instead of
+ * {@link UnsupportedOperationException} on a call to
+ * {@link Iterator#remove()}.
+ */
+ // Casting to any type is safe since there are no actual elements.
+ @SuppressWarnings("unchecked")
+ static <T> Iterator<T> emptyModifiableIterator() {
+ return (Iterator<T>) EMPTY_MODIFIABLE_ITERATOR;
+ }
+
+ /** Returns an unmodifiable view of {@code iterator}. */
+ public static <T> UnmodifiableIterator<T> unmodifiableIterator(
+ final Iterator<T> iterator) {
+ checkNotNull(iterator);
+ if (iterator instanceof UnmodifiableIterator) {
+ return (UnmodifiableIterator<T>) iterator;
+ }
+ return new UnmodifiableIterator<T>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ @Override
+ public T next() {
+ return iterator.next();
+ }
+ };
+ }
+
+ /**
+ * Simply returns its argument.
+ *
+ * @deprecated no need to use this
+ * @since 10.0
+ */
+ @Deprecated public static <T> UnmodifiableIterator<T> unmodifiableIterator(
+ UnmodifiableIterator<T> iterator) {
+ return checkNotNull(iterator);
+ }
+
+ /** Returns an unmodifiable view of {@code iterator}. */
+ static <T> UnmodifiableListIterator<T> unmodifiableListIterator(
+ final ListIterator<T> iterator) {
+ checkNotNull(iterator);
+ if (iterator instanceof UnmodifiableListIterator) {
+ return (UnmodifiableListIterator<T>) iterator;
+ }
+ return new UnmodifiableListIterator<T>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ @Override
+ public boolean hasPrevious() {
+ return iterator.hasPrevious();
+ }
+ @Override
+ public T next() {
+ return iterator.next();
+ }
+ @Override
+ public T previous() {
+ return iterator.previous();
+ }
+ @Override
+ public int nextIndex() {
+ return iterator.nextIndex();
+ }
+ @Override
+ public int previousIndex() {
+ return iterator.previousIndex();
+ }
+ };
+ }
+
+ /**
+ * Returns the number of elements remaining in {@code iterator}. The iterator
+ * will be left exhausted: its {@code hasNext()} method will return
+ * {@code false}.
+ */
+ public static int size(Iterator<?> iterator) {
+ int count = 0;
+ while (iterator.hasNext()) {
+ iterator.next();
+ count++;
+ }
+ return count;
+ }
+
+ /**
+ * Returns {@code true} if {@code iterator} contains {@code element}.
+ */
+ public static boolean contains(Iterator<?> iterator, @Nullable Object element)
+ {
+ if (element == null) {
+ while (iterator.hasNext()) {
+ if (iterator.next() == null) {
+ return true;
+ }
+ }
+ } else {
+ while (iterator.hasNext()) {
+ if (element.equals(iterator.next())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Traverses an iterator and removes every element that belongs to the
+ * provided collection. The iterator will be left exhausted: its
+ * {@code hasNext()} method will return {@code false}.
+ *
+ * @param removeFrom the iterator to (potentially) remove elements from
+ * @param elementsToRemove the elements to remove
+ * @return {@code true} if any element was removed from {@code iterator}
+ */
+ public static boolean removeAll(
+ Iterator<?> removeFrom, Collection<?> elementsToRemove) {
+ checkNotNull(elementsToRemove);
+ boolean modified = false;
+ while (removeFrom.hasNext()) {
+ if (elementsToRemove.contains(removeFrom.next())) {
+ removeFrom.remove();
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ /**
+ * Removes every element that satisfies the provided predicate from the
+ * iterator. The iterator will be left exhausted: its {@code hasNext()}
+ * method will return {@code false}.
+ *
+ * @param removeFrom the iterator to (potentially) remove elements from
+ * @param predicate a predicate that determines whether an element should
+ * be removed
+ * @return {@code true} if any elements were removed from the iterator
+ * @since 2.0
+ */
+ public static <T> boolean removeIf(
+ Iterator<T> removeFrom, Predicate<? super T> predicate) {
+ checkNotNull(predicate);
+ boolean modified = false;
+ while (removeFrom.hasNext()) {
+ if (predicate.apply(removeFrom.next())) {
+ removeFrom.remove();
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ /**
+ * Traverses an iterator and removes every element that does not belong to the
+ * provided collection. The iterator will be left exhausted: its
+ * {@code hasNext()} method will return {@code false}.
+ *
+ * @param removeFrom the iterator to (potentially) remove elements from
+ * @param elementsToRetain the elements to retain
+ * @return {@code true} if any element was removed from {@code iterator}
+ */
+ public static boolean retainAll(
+ Iterator<?> removeFrom, Collection<?> elementsToRetain) {
+ checkNotNull(elementsToRetain);
+ boolean modified = false;
+ while (removeFrom.hasNext()) {
+ if (!elementsToRetain.contains(removeFrom.next())) {
+ removeFrom.remove();
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ /**
+ * Determines whether two iterators contain equal elements in the same order.
+ * More specifically, this method returns {@code true} if {@code iterator1}
+ * and {@code iterator2} contain the same number of elements and every element
+ * of {@code iterator1} is equal to the corresponding element of
+ * {@code iterator2}.
+ *
+ * <p>Note that this will modify the supplied iterators, since they will have
+ * been advanced some number of elements forward.
+ */
+ public static boolean elementsEqual(
+ Iterator<?> iterator1, Iterator<?> iterator2) {
+ while (iterator1.hasNext()) {
+ if (!iterator2.hasNext()) {
+ return false;
+ }
+ Object o1 = iterator1.next();
+ Object o2 = iterator2.next();
+ if (!Objects.equal(o1, o2)) {
+ return false;
+ }
+ }
+ return !iterator2.hasNext();
+ }
+
+ /**
+ * Returns a string representation of {@code iterator}, with the format
+ * {@code [e1, e2, ..., en]}. The iterator will be left exhausted: its
+ * {@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();
+ }
+
+ /**
+ * Returns the single element contained in {@code iterator}.
+ *
+ * @throws NoSuchElementException if the iterator is empty
+ * @throws IllegalArgumentException if the iterator contains multiple
+ * elements. The state of the iterator is unspecified.
+ */
+ public static <T> T getOnlyElement(Iterator<T> iterator) {
+ T first = iterator.next();
+ if (!iterator.hasNext()) {
+ return first;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("expected one element but was: <" + first);
+ for (int i = 0; i < 4 && iterator.hasNext(); i++) {
+ sb.append(", " + iterator.next());
+ }
+ if (iterator.hasNext()) {
+ sb.append(", ...");
+ }
+ sb.append('>');
+
+ throw new IllegalArgumentException(sb.toString());
+ }
+
+ /**
+ * Returns the single element contained in {@code iterator}, or {@code
+ * defaultValue} if the iterator is empty.
+ *
+ * @throws IllegalArgumentException if the iterator contains multiple
+ * elements. The state of the iterator is unspecified.
+ */
+ public static <T> T getOnlyElement(Iterator<? extends T> iterator, @Nullable T defaultValue) {
+ return iterator.hasNext() ? getOnlyElement(iterator) : defaultValue;
+ }
+
+ /**
+ * Copies an iterator's elements into an array. The iterator will be left
+ * exhausted: its {@code hasNext()} method will return {@code false}.
+ *
+ * @param iterator the iterator to copy
+ * @param type the type of the elements
+ * @return a newly-allocated array into which all the elements of the iterator
+ * have been copied
+ */
+ @GwtIncompatible("Array.newInstance(Class, int)")
+ public static <T> T[] toArray(
+ Iterator<? extends T> iterator, Class<T> type) {
+ List<T> list = Lists.newArrayList(iterator);
+ return Iterables.toArray(list, type);
+ }
+
+ /**
+ * Adds all elements in {@code iterator} to {@code collection}. The iterator
+ * will be left exhausted: its {@code hasNext()} method will return
+ * {@code false}.
+ *
+ * @return {@code true} if {@code collection} was modified as a result of this
+ * operation
+ */
+ public static <T> boolean addAll(
+ Collection<T> addTo, Iterator<? extends T> iterator) {
+ checkNotNull(addTo);
+ boolean wasModified = false;
+ while (iterator.hasNext()) {
+ wasModified |= addTo.add(iterator.next());
+ }
+ return wasModified;
+ }
+
+ /**
+ * Returns the number of elements in the specified iterator that equal the
+ * specified object. The iterator will be left exhausted: its
+ * {@code hasNext()} method will return {@code false}.
+ *
+ * @see Collections#frequency
+ */
+ public static int frequency(Iterator<?> iterator, @Nullable Object element) {
+ int result = 0;
+ if (element == null) {
+ while (iterator.hasNext()) {
+ if (iterator.next() == null) {
+ result++;
+ }
+ }
+ } else {
+ while (iterator.hasNext()) {
+ if (element.equals(iterator.next())) {
+ result++;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns an iterator that cycles indefinitely over the elements of {@code
+ * iterable}.
+ *
+ * <p>The returned iterator supports {@code remove()} if the provided iterator
+ * does. After {@code remove()} is called, subsequent cycles omit the removed
+ * element, which is no longer in {@code iterable}. The iterator's
+ * {@code hasNext()} method returns {@code true} until {@code 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 static <T> Iterator<T> cycle(final Iterable<T> iterable) {
+ checkNotNull(iterable);
+ return new Iterator<T>() {
+ Iterator<T> iterator = emptyIterator();
+ Iterator<T> removeFrom;
+
+ @Override
+ public boolean hasNext() {
+ if (!iterator.hasNext()) {
+ iterator = iterable.iterator();
+ }
+ return iterator.hasNext();
+ }
+ @Override
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ removeFrom = iterator;
+ return iterator.next();
+ }
+ @Override
+ public void remove() {
+ checkState(removeFrom != null,
+ "no calls to next() since last call to remove()");
+ removeFrom.remove();
+ removeFrom = null;
+ }
+ };
+ }
+
+ /**
+ * Returns an iterator that cycles indefinitely over the provided elements.
+ *
+ * <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.
+ *
+ * <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 static <T> Iterator<T> cycle(T... elements) {
+ return cycle(Lists.newArrayList(elements));
+ }
+
+ /**
+ * Combines two iterators into a single iterator. The returned iterator
+ * iterates across the elements in {@code a}, followed by the elements in
+ * {@code b}. The source iterators are not polled until necessary.
+ *
+ * <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,
+ Iterator<? extends T> b) {
+ checkNotNull(a);
+ checkNotNull(b);
+ return concat(Arrays.asList(a, b).iterator());
+ }
+
+ /**
+ * Combines three iterators into a single iterator. The returned iterator
+ * iterates across the elements in {@code a}, followed by the elements in
+ * {@code b}, followed by the elements in {@code c}. The source iterators
+ * are not polled until necessary.
+ *
+ * <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,
+ Iterator<? extends T> b, Iterator<? extends T> c) {
+ checkNotNull(a);
+ checkNotNull(b);
+ checkNotNull(c);
+ return concat(Arrays.asList(a, b, c).iterator());
+ }
+
+ /**
+ * Combines four iterators into a single iterator. The returned iterator
+ * iterates across the elements in {@code a}, followed by the elements in
+ * {@code b}, followed by the elements in {@code c}, followed by the elements
+ * in {@code d}. The source iterators are not polled until necessary.
+ *
+ * <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,
+ Iterator<? extends T> b, Iterator<? extends T> c,
+ Iterator<? extends T> d) {
+ checkNotNull(a);
+ checkNotNull(b);
+ checkNotNull(c);
+ checkNotNull(d);
+ return concat(Arrays.asList(a, b, c, d).iterator());
+ }
+
+ /**
+ * Combines multiple iterators into a single iterator. The returned iterator
+ * iterates across the elements of each iterator in {@code inputs}. The input
+ * iterators are not polled until necessary.
+ *
+ * <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) {
+ return concat(ImmutableList.copyOf(inputs).iterator());
+ }
+
+ /**
+ * Combines multiple iterators into a single iterator. The returned iterator
+ * iterates across the elements of each iterator in {@code inputs}. The input
+ * iterators are not polled until necessary.
+ *
+ * <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) {
+ checkNotNull(inputs);
+ return new Iterator<T>() {
+ Iterator<? extends T> current = emptyIterator();
+ Iterator<? extends T> removeFrom;
+
+ @Override
+ public boolean hasNext() {
+ // http://code.google.com/p/google-collections/issues/detail?id=151
+ // current.hasNext() might be relatively expensive, worth minimizing.
+ boolean currentHasNext;
+ // checkNotNull eager for GWT
+ // note: it must be here & not where 'current' is assigned,
+ // because otherwise we'll have called inputs.next() before throwing
+ // the first NPE, and the next time around we'll call inputs.next()
+ // again, incorrectly moving beyond the error.
+ while (!(currentHasNext = checkNotNull(current).hasNext())
+ && inputs.hasNext()) {
+ current = inputs.next();
+ }
+ return currentHasNext;
+ }
+ @Override
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ removeFrom = current;
+ return current.next();
+ }
+ @Override
+ public void remove() {
+ checkState(removeFrom != null,
+ "no calls to next() since last call to remove()");
+ removeFrom.remove();
+ removeFrom = null;
+ }
+ };
+ }
+
+ /**
+ * Divides an iterator into unmodifiable sublists of the given size (the final
+ * list may be smaller). For example, partitioning an iterator containing
+ * {@code [a, b, c, d, e]} with a partition size of 3 yields {@code
+ * [[a, b, c], [d, e]]} -- an outer iterator containing two inner lists of
+ * three and two elements, all in the original order.
+ *
+ * <p>The returned lists implement {@link java.util.RandomAccess}.
+ *
+ * @param iterator the iterator to return a partitioned view of
+ * @param size the desired size of each partition (the last may be smaller)
+ * @return an iterator of immutable lists containing the elements of {@code
+ * iterator} divided into partitions
+ * @throws IllegalArgumentException if {@code size} is nonpositive
+ */
+ public static <T> UnmodifiableIterator<List<T>> partition(
+ Iterator<T> iterator, int size) {
+ return partitionImpl(iterator, size, false);
+ }
+
+ /**
+ * Divides an iterator into unmodifiable sublists of the given size, padding
+ * the final iterator with null values if necessary. For example, partitioning
+ * an iterator containing {@code [a, b, c, d, e]} with a partition size of 3
+ * yields {@code [[a, b, c], [d, e, null]]} -- an outer iterator containing
+ * two inner lists of three elements each, all in the original order.
+ *
+ * <p>The returned lists implement {@link java.util.RandomAccess}.
+ *
+ * @param iterator the iterator to return a partitioned view of
+ * @param size the desired size of each partition
+ * @return an iterator of immutable lists containing the elements of {@code
+ * iterator} divided into partitions (the final iterable may have
+ * trailing null elements)
+ * @throws IllegalArgumentException if {@code size} is nonpositive
+ */
+ public static <T> UnmodifiableIterator<List<T>> paddedPartition(
+ Iterator<T> iterator, int size) {
+ return partitionImpl(iterator, size, true);
+ }
+
+ private static <T> UnmodifiableIterator<List<T>> partitionImpl(
+ final Iterator<T> iterator, final int size, final boolean pad) {
+ checkNotNull(iterator);
+ checkArgument(size > 0);
+ return new UnmodifiableIterator<List<T>>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ @Override
+ public List<T> next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ Object[] array = new Object[size];
+ int count = 0;
+ for (; count < size && iterator.hasNext(); count++) {
+ array[count] = iterator.next();
+ }
+ for (int i = count; i < size; i++) {
+ array[i] = null; // for GWT
+ }
+
+ @SuppressWarnings("unchecked") // we only put Ts in it
+ List<T> list = Collections.unmodifiableList(
+ (List<T>) Arrays.asList(array));
+ return (pad || count == size) ? list : list.subList(0, count);
+ }
+ };
+ }
+
+ /**
+ * Returns the elements of {@code unfiltered} that satisfy a predicate.
+ */
+ public static <T> UnmodifiableIterator<T> filter(
+ final Iterator<T> unfiltered, final Predicate<? super T> predicate) {
+ checkNotNull(unfiltered);
+ checkNotNull(predicate);
+ return new AbstractIterator<T>() {
+ @Override protected T computeNext() {
+ while (unfiltered.hasNext()) {
+ T element = unfiltered.next();
+ if (predicate.apply(element)) {
+ return element;
+ }
+ }
+ return endOfData();
+ }
+ };
+ }
+
+ /**
+ * Returns all instances of class {@code type} in {@code unfiltered}. The
+ * returned iterator has elements whose class is {@code type} or a subclass of
+ * {@code type}.
+ *
+ * @param unfiltered an iterator containing objects of any type
+ * @param type the type of elements desired
+ * @return an unmodifiable iterator containing all elements of the original
+ * iterator that were of the requested type
+ */
+ @SuppressWarnings("unchecked") // can cast to <T> because non-Ts are removed
+ @GwtIncompatible("Class.isInstance")
+ public static <T> UnmodifiableIterator<T> filter(
+ Iterator<?> unfiltered, Class<T> type) {
+ return (UnmodifiableIterator<T>)
+ filter(unfiltered, Predicates.instanceOf(type));
+ }
+
+ /**
+ * Returns {@code true} if one or more elements returned by {@code iterator}
+ * satisfy the given predicate.
+ */
+ public static <T> boolean any(
+ Iterator<T> iterator, Predicate<? super T> predicate) {
+ checkNotNull(predicate);
+ while (iterator.hasNext()) {
+ T element = iterator.next();
+ if (predicate.apply(element)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if every element returned by {@code iterator}
+ * satisfies the given predicate. If {@code iterator} is empty, {@code true}
+ * is returned.
+ */
+ public static <T> boolean all(
+ Iterator<T> iterator, Predicate<? super T> predicate) {
+ checkNotNull(predicate);
+ while (iterator.hasNext()) {
+ T element = iterator.next();
+ if (!predicate.apply(element)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns the first element in {@code iterator} that satisfies the given
+ * 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.
+ *
+ * @throws NoSuchElementException if no element in {@code iterator} matches
+ * the given predicate
+ */
+ public static <T> T find(
+ Iterator<T> iterator, Predicate<? super T> predicate) {
+ return filter(iterator, predicate).next();
+ }
+
+ /**
+ * Returns the first element in {@code iterator} that satisfies the given
+ * predicate. If no such element is found, {@code defaultValue} will be
+ * returned from this method and the iterator will be left exhausted: its
+ * {@code hasNext()} method will return {@code false}. Note that this can
+ * usually be handled more naturally using {@code
+ * tryFind(iterator, predicate).or(defaultValue)}.
+ *
+ * @since 7.0
+ */
+ public static <T> T find(Iterator<? extends T> iterator, Predicate<? super T> predicate,
+ @Nullable T defaultValue) {
+ UnmodifiableIterator<? extends T> filteredIterator = filter(iterator, predicate);
+ return filteredIterator.hasNext() ? filteredIterator.next() : defaultValue;
+ }
+
+ /**
+ * Returns an {@link Optional} containing the first element in {@code
+ * iterator} that satisfies the given predicate, if such an element exists. If
+ * no such element is found, an empty {@link Optional} will be returned from
+ * this method and the the iterator will be left exhausted: its {@code
+ * hasNext()} method will return {@code false}.
+ *
+ * <p><b>Warning:</b> avoid using a {@code predicate} that matches {@code
+ * null}. If {@code null} is matched in {@code iterator}, a
+ * NullPointerException will be thrown.
+ *
+ * @since 11.0
+ */
+ public static <T> Optional<T> tryFind(
+ Iterator<T> iterator, Predicate<? super T> predicate) {
+ UnmodifiableIterator<T> filteredIterator = filter(iterator, predicate);
+ return filteredIterator.hasNext()
+ ? Optional.of(filteredIterator.next())
+ : Optional.<T>absent();
+ }
+
+ /**
+ * Returns the index in {@code iterator} of the first element that satisfies
+ * the provided {@code predicate}, or {@code -1} if the Iterator has no such
+ * elements.
+ *
+ * <p>More formally, returns the lowest index {@code i} such that
+ * {@code predicate.apply(Iterators.get(iterator, i))} returns {@code true},
+ * or {@code -1} if there is no such index.
+ *
+ * <p>If -1 is returned, the iterator will be left exhausted: its
+ * {@code hasNext()} method will return {@code false}. Otherwise,
+ * the iterator will be set to the element which satisfies the
+ * {@code predicate}.
+ *
+ * @since 2.0
+ */
+ public static <T> int indexOf(
+ Iterator<T> iterator, Predicate<? super T> predicate) {
+ checkNotNull(predicate, "predicate");
+ int i = 0;
+ while (iterator.hasNext()) {
+ T current = iterator.next();
+ if (predicate.apply(current)) {
+ return i;
+ }
+ i++;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns an iterator that applies {@code function} to each element of {@code
+ * fromIterator}.
+ *
+ * <p>The returned iterator supports {@code remove()} if the provided iterator
+ * does. After a successful {@code remove()} call, {@code fromIterator} no
+ * longer contains the corresponding element.
+ */
+ public static <F, T> Iterator<T> transform(final Iterator<F> fromIterator,
+ final Function<? super F, ? extends T> function) {
+ checkNotNull(function);
+ return new TransformedIterator<F, T>(fromIterator) {
+ @Override
+ T transform(F from) {
+ return function.apply(from);
+ }
+ };
+ }
+
+ /**
+ * Advances {@code iterator} {@code position + 1} times, returning the
+ * element at the {@code position}th position.
+ *
+ * @param position position of the element to return
+ * @return the element at the specified position in {@code iterator}
+ * @throws IndexOutOfBoundsException if {@code position} is negative or
+ * greater than or equal to the number of elements remaining in
+ * {@code iterator}
+ */
+ public static <T> T get(Iterator<T> iterator, int position) {
+ checkNonnegative(position);
+
+ int skipped = 0;
+ while (iterator.hasNext()) {
+ T t = iterator.next();
+ if (skipped++ == position) {
+ return t;
+ }
+ }
+
+ throw new IndexOutOfBoundsException("position (" + position
+ + ") must be less than the number of elements that remained ("
+ + skipped + ")");
+ }
+
+ private static void checkNonnegative(int position) {
+ if (position < 0) {
+ throw new IndexOutOfBoundsException("position (" + position
+ + ") must not be negative");
+ }
+ }
+
+ /**
+ * Advances {@code iterator} {@code position + 1} times, returning the
+ * element at the {@code position}th position or {@code defaultValue}
+ * otherwise.
+ *
+ * @param position position of the element to return
+ * @param defaultValue the default value to return if the iterator is empty
+ * or if {@code position} is greater than the number of elements
+ * remaining in {@code iterator}
+ * @return the element at the specified position in {@code iterator} or
+ * {@code defaultValue} if {@code iterator} produces fewer than
+ * {@code position + 1} elements.
+ * @throws IndexOutOfBoundsException if {@code position} is negative
+ * @since 4.0
+ */
+ public static <T> T get(Iterator<? extends T> iterator, int position, @Nullable T defaultValue) {
+ checkNonnegative(position);
+
+ try {
+ return get(iterator, position);
+ } catch (IndexOutOfBoundsException e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Returns the next element in {@code iterator} or {@code defaultValue} if
+ * the iterator is empty. The {@link Iterables} analog to this method is
+ * {@link Iterables#getFirst}.
+ *
+ * @param defaultValue the default value to return if the iterator is empty
+ * @return the next element of {@code iterator} or the default value
+ * @since 7.0
+ */
+ public static <T> T getNext(Iterator<? extends T> iterator, @Nullable T defaultValue) {
+ return iterator.hasNext() ? iterator.next() : defaultValue;
+ }
+
+ /**
+ * Advances {@code iterator} to the end, returning the last element.
+ *
+ * @return the last element of {@code iterator}
+ * @throws NoSuchElementException if the iterator is empty
+ */
+ public static <T> T getLast(Iterator<T> iterator) {
+ while (true) {
+ T current = iterator.next();
+ if (!iterator.hasNext()) {
+ return current;
+ }
+ }
+ }
+
+ /**
+ * Advances {@code iterator} to the end, returning the last element or
+ * {@code defaultValue} if the iterator is empty.
+ *
+ * @param defaultValue the default value to return if the iterator is empty
+ * @return the last element of {@code iterator}
+ * @since 3.0
+ */
+ public static <T> T getLast(Iterator<? extends T> iterator, @Nullable T defaultValue) {
+ return iterator.hasNext() ? getLast(iterator) : defaultValue;
+ }
+
+ /**
+ * 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 skipped
+ * @since 3.0
+ * @deprecated This method has been renamed to {@link #advance(java.util.Iterator, int) advance}.
+ * This method is scheduled to be deleted in Guava 14.0.
+ */
+ @Beta
+ @Deprecated
+ public static int skip(Iterator<?> iterator, int numberToSkip) {
+ return advance(iterator, numberToSkip);
+ }
+
+ /**
+ * Calls {@code next()} on {@code iterator}, either {@code numberToAdvance} 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})
+ */
+ public static int advance(Iterator<?> iterator, int numberToAdvance) {
+ checkNotNull(iterator);
+ checkArgument(numberToAdvance >= 0, "number to advance cannot be negative");
+
+ int i;
+ for (i = 0; i < numberToAdvance && iterator.hasNext(); i++) {
+ iterator.next();
+ }
+ return i;
+ }
+
+ /**
+ * Creates an iterator returning the first {@code limitSize} elements of the
+ * given iterator. If the original iterator does not contain that many
+ * elements, the returned iterator will have the same behavior as the original
+ * iterator. The returned iterator supports {@code remove()} if the original
+ * iterator does.
+ *
+ * @param iterator the iterator to limit
+ * @param limitSize the maximum number of elements in the returned iterator
+ * @throws IllegalArgumentException if {@code limitSize} is negative
+ * @since 3.0
+ */
+ public static <T> Iterator<T> limit(
+ final Iterator<T> iterator, final int limitSize) {
+ checkNotNull(iterator);
+ checkArgument(limitSize >= 0, "limit is negative");
+ return new Iterator<T>() {
+ private int count;
+
+ @Override
+ public boolean hasNext() {
+ return count < limitSize && iterator.hasNext();
+ }
+
+ @Override
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ count++;
+ return iterator.next();
+ }
+
+ @Override
+ public void remove() {
+ iterator.remove();
+ }
+ };
+ }
+
+ /**
+ * Returns a view of the supplied {@code iterator} that removes each element
+ * from the supplied {@code iterator} as it is returned.
+ *
+ * <p>The provided iterator must support {@link Iterator#remove()} or
+ * else the returned iterator will fail on the first call to {@code
+ * next}.
+ *
+ * @param iterator the iterator to remove and return elements from
+ * @return an iterator that removes and returns elements from the
+ * supplied iterator
+ * @since 2.0
+ */
+ public static <T> Iterator<T> consumingIterator(final Iterator<T> iterator) {
+ checkNotNull(iterator);
+ return new UnmodifiableIterator<T>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public T next() {
+ T next = iterator.next();
+ iterator.remove();
+ return next;
+ }
+ };
+ }
+
+ // Methods only in Iterators, not in Iterables
+
+ /**
+ * Clears the iterator using its remove method.
+ */
+ static void clear(Iterator<?> iterator) {
+ checkNotNull(iterator);
+ while (iterator.hasNext()) {
+ iterator.next();
+ iterator.remove();
+ }
+ }
+
+ /**
+ * Returns an iterator containing the elements 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><b>Note:</b> It is often preferable to represent your data using a
+ * collection type, for example using {@link Arrays#asList(Object[])}, making
+ * this method unnecessary.
+ *
+ * <p>The {@code Iterable} equivalent of this method is either {@link
+ * Arrays#asList(Object[])}, {@link ImmutableList#copyOf(Object[])}},
+ * or {@link ImmutableList#of}.
+ */
+ public static <T> UnmodifiableIterator<T> forArray(final T... array) {
+ // TODO(kevinb): compare performance with Arrays.asList(array).iterator().
+ checkNotNull(array); // eager for GWT.
+ return new AbstractIndexedListIterator<T>(array.length) {
+ @Override protected T get(int index) {
+ return array[index];
+ }
+ };
+ }
+
+ /**
+ * Returns a list iterator containing the elements in the specified range of
+ * {@code array} in order, starting at the specified index.
+ *
+ * <p>The {@code Iterable} equivalent of this method is {@code
+ * Arrays.asList(array).subList(offset, offset + length).listIterator(index)}.
+ */
+ static <T> UnmodifiableListIterator<T> forArray(
+ final T[] array, final int offset, int length, int index) {
+ checkArgument(length >= 0);
+ int end = offset + length;
+
+ // Technically we should give a slightly more descriptive error on overflow
+ Preconditions.checkPositionIndexes(offset, end, array.length);
+
+ /*
+ * We can't use call the two-arg constructor with arguments (offset, end)
+ * because the returned Iterator is a ListIterator that may be moved back
+ * past the beginning of the iteration.
+ */
+ return new AbstractIndexedListIterator<T>(length, index) {
+ @Override protected T get(int index) {
+ return array[offset + index];
+ }
+ };
+ }
+
+ /**
+ * Returns an iterator containing only {@code value}.
+ *
+ * <p>The {@link Iterable} equivalent of this method is {@link
+ * Collections#singleton}.
+ */
+ public static <T> UnmodifiableIterator<T> singletonIterator(
+ @Nullable final T value) {
+ return new UnmodifiableIterator<T>() {
+ boolean done;
+ @Override
+ public boolean hasNext() {
+ return !done;
+ }
+ @Override
+ public T next() {
+ if (done) {
+ throw new NoSuchElementException();
+ }
+ done = true;
+ return value;
+ }
+ };
+ }
+
+ /**
+ * Adapts an {@code Enumeration} to the {@code Iterator} interface.
+ *
+ * <p>This method has no equivalent in {@link Iterables} because viewing an
+ * {@code Enumeration} as an {@code Iterable} is impossible. However, the
+ * contents can be <i>copied</i> into a collection using {@link
+ * Collections#list}.
+ */
+ public static <T> UnmodifiableIterator<T> forEnumeration(
+ final Enumeration<T> enumeration) {
+ checkNotNull(enumeration);
+ return new UnmodifiableIterator<T>() {
+ @Override
+ public boolean hasNext() {
+ return enumeration.hasMoreElements();
+ }
+ @Override
+ public T next() {
+ return enumeration.nextElement();
+ }
+ };
+ }
+
+ /**
+ * Adapts an {@code Iterator} to the {@code Enumeration} interface.
+ *
+ * <p>The {@code Iterable} equivalent of this method is either {@link
+ * Collections#enumeration} (if you have a {@link Collection}), or
+ * {@code Iterators.asEnumeration(collection.iterator())}.
+ */
+ public static <T> Enumeration<T> asEnumeration(final Iterator<T> iterator) {
+ checkNotNull(iterator);
+ return new Enumeration<T>() {
+ @Override
+ public boolean hasMoreElements() {
+ return iterator.hasNext();
+ }
+ @Override
+ public T nextElement() {
+ return iterator.next();
+ }
+ };
+ }
+
+ /**
+ * Implementation of PeekingIterator that avoids peeking unless necessary.
+ */
+ private static class PeekingImpl<E> implements PeekingIterator<E> {
+
+ private final Iterator<? extends E> iterator;
+ private boolean hasPeeked;
+ private E peekedElement;
+
+ public PeekingImpl(Iterator<? extends E> iterator) {
+ this.iterator = checkNotNull(iterator);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return hasPeeked || iterator.hasNext();
+ }
+
+ @Override
+ public E next() {
+ if (!hasPeeked) {
+ return iterator.next();
+ }
+ E result = peekedElement;
+ hasPeeked = false;
+ peekedElement = null;
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ checkState(!hasPeeked, "Can't remove after you've peeked at next");
+ iterator.remove();
+ }
+
+ @Override
+ public E peek() {
+ if (!hasPeeked) {
+ peekedElement = iterator.next();
+ hasPeeked = true;
+ }
+ return peekedElement;
+ }
+ }
+
+ /**
+ * Returns a {@code PeekingIterator} backed by the given iterator.
+ *
+ * <p>Calls to the {@code peek} method with no intervening calls to {@code
+ * next} do not affect the iteration, and hence return the same object each
+ * time. A subsequent call to {@code next} is guaranteed to return the same
+ * object again. For example: <pre> {@code
+ *
+ * PeekingIterator<String> peekingIterator =
+ * Iterators.peekingIterator(Iterators.forArray("a", "b"));
+ * String a1 = peekingIterator.peek(); // returns "a"
+ * String a2 = peekingIterator.peek(); // also returns "a"
+ * String a3 = peekingIterator.next(); // also returns "a"}</pre>
+ *
+ * Any structural changes to the underlying iteration (aside from those
+ * performed by the iterator's own {@link PeekingIterator#remove()} method)
+ * will leave the iterator in an undefined state.
+ *
+ * <p>The returned iterator does not support removal after peeking, as
+ * explained by {@link PeekingIterator#remove()}.
+ *
+ * <p>Note: If the given iterator is already a {@code PeekingIterator},
+ * it <i>might</i> be returned to the caller, although this is neither
+ * guaranteed to occur nor required to be consistent. For example, this
+ * method <i>might</i> choose to pass through recognized implementations of
+ * {@code PeekingIterator} when the behavior of the implementation is
+ * known to meet the contract guaranteed by this method.
+ *
+ * <p>There is no {@link Iterable} equivalent to this method, so use this
+ * method to wrap each individual iterator as it is generated.
+ *
+ * @param iterator the backing iterator. The {@link PeekingIterator} assumes
+ * ownership of this iterator, so users should cease making direct calls
+ * to it after calling this method.
+ * @return a peeking iterator backed by that iterator. Apart from the
+ * additional {@link PeekingIterator#peek()} method, this iterator behaves
+ * exactly the same as {@code iterator}.
+ */
+ public static <T> PeekingIterator<T> peekingIterator(
+ Iterator<? extends T> iterator) {
+ if (iterator instanceof PeekingImpl) {
+ // Safe to cast <? extends T> to <T> because PeekingImpl only uses T
+ // covariantly (and cannot be subclassed to add non-covariant uses).
+ @SuppressWarnings("unchecked")
+ PeekingImpl<T> peeking = (PeekingImpl<T>) iterator;
+ return peeking;
+ }
+ return new PeekingImpl<T>(iterator);
+ }
+
+ /**
+ * Simply returns its argument.
+ *
+ * @deprecated no need to use this
+ * @since 10.0
+ */
+ @Deprecated public static <T> PeekingIterator<T> peekingIterator(
+ PeekingIterator<T> iterator) {
+ return checkNotNull(iterator);
+ }
+
+ /**
+ * Returns an iterator over the merged contents of all given
+ * {@code iterators}, traversing every element of the input iterators.
+ * Equivalent entries will not be de-duplicated.
+ *
+ * <p>Callers must ensure that the source {@code iterators} are in
+ * non-descending order as this method does not sort its input.
+ *
+ * <p>For any equivalent elements across all {@code iterators}, it is
+ * undefined which element is returned first.
+ *
+ * @since 11.0
+ */
+ @Beta
+ public static <T> UnmodifiableIterator<T> mergeSorted(
+ Iterable<? extends Iterator<? extends T>> iterators,
+ Comparator<? super T> comparator) {
+ checkNotNull(iterators, "iterators");
+ checkNotNull(comparator, "comparator");
+
+ return new MergingIterator<T>(iterators, comparator);
+ }
+
+ /**
+ * An iterator that performs a lazy N-way merge, calculating the next value
+ * each time the iterator is polled. This amortizes the sorting cost over the
+ * iteration and requires less memory than sorting all elements at once.
+ *
+ * <p>Retrieving a single element takes approximately O(log(M)) time, where M
+ * is the number of iterators. (Retrieving all elements takes approximately
+ * O(N*log(M)) time, where N is the total number of elements.)
+ */
+ private static class MergingIterator<T> extends AbstractIterator<T> {
+ final Queue<PeekingIterator<T>> queue;
+ final Comparator<? super T> comparator;
+
+ public MergingIterator(Iterable<? extends Iterator<? extends T>> iterators,
+ Comparator<? super T> itemComparator) {
+ this.comparator = itemComparator;
+
+ // A comparator that's used by the heap, allowing the heap
+ // to be sorted based on the top of each iterator.
+ Comparator<PeekingIterator<T>> heapComparator =
+ new Comparator<PeekingIterator<T>>() {
+ @Override
+ public int compare(PeekingIterator<T> o1, PeekingIterator<T> o2) {
+ return comparator.compare(o1.peek(), o2.peek());
+ }
+ };
+
+ queue = new PriorityQueue<PeekingIterator<T>>(2, heapComparator);
+
+ for (Iterator<? extends T> iterator : iterators) {
+ if (iterator.hasNext()) {
+ queue.add(Iterators.peekingIterator(iterator));
+ }
+ }
+ }
+
+ @Override
+ protected T computeNext() {
+ if (queue.isEmpty()) {
+ return endOfData();
+ }
+
+ PeekingIterator<T> nextIter = queue.poll();
+ T next = nextIter.next();
+
+ if (nextIter.hasNext()) {
+ queue.add(nextIter);
+ }
+
+ 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/LexicographicalOrdering.java b/guava/src/com/google/common/collect/LexicographicalOrdering.java
new file mode 100644
index 0000000..0d993e4
--- /dev/null
+++ b/guava/src/com/google/common/collect/LexicographicalOrdering.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import javax.annotation.Nullable;
+
+/**
+ * An ordering which sorts iterables by comparing corresponding elements
+ * pairwise.
+ */
+@GwtCompatible(serializable = true)
+final class LexicographicalOrdering<T>
+ extends Ordering<Iterable<T>> implements Serializable {
+ final Ordering<? super T> elementOrder;
+
+ LexicographicalOrdering(Ordering<? super T> elementOrder) {
+ this.elementOrder = elementOrder;
+ }
+
+ @Override public int compare(
+ Iterable<T> leftIterable, Iterable<T> rightIterable) {
+ Iterator<T> left = leftIterable.iterator();
+ Iterator<T> right = rightIterable.iterator();
+ while (left.hasNext()) {
+ if (!right.hasNext()) {
+ return LEFT_IS_GREATER; // because it's longer
+ }
+ int result = elementOrder.compare(left.next(), right.next());
+ if (result != 0) {
+ return result;
+ }
+ }
+ if (right.hasNext()) {
+ return RIGHT_IS_GREATER; // because it's longer
+ }
+ return 0;
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof LexicographicalOrdering) {
+ LexicographicalOrdering<?> that = (LexicographicalOrdering<?>) object;
+ return this.elementOrder.equals(that.elementOrder);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return elementOrder.hashCode() ^ 2075626741; // meaningless
+ }
+
+ @Override public String toString() {
+ return elementOrder + ".lexicographical()";
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/LinkedHashMultimap.java b/guava/src/com/google/common/collect/LinkedHashMultimap.java
new file mode 100644
index 0000000..b50cc78
--- /dev/null
+++ b/guava/src/com/google/common/collect/LinkedHashMultimap.java
@@ -0,0 +1,615 @@
+/*
+ * 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 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.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;
+
+/**
+ * Implementation of {@code Multimap} that does not allow duplicate key-value
+ * entries and that returns collections whose iterators follow the ordering in
+ * which the data was added to the multimap.
+ *
+ * <p>The collections returned by {@code keySet}, {@code keys}, and {@code
+ * asMap} iterate through the keys in the order they were first added to the
+ * multimap. Similarly, {@code get}, {@code removeAll}, and {@code
+ * replaceValues} return collections that iterate through the values in the
+ * order they were added. The collections generated by {@code entries} and
+ * {@code values} iterate across the key-value mappings in the order they were
+ * added to the multimap.
+ *
+ * <p>The iteration ordering of the collections generated by {@code keySet},
+ * {@code keys}, and {@code asMap} has a few subtleties. As long as the set of
+ * keys remains unchanged, adding or removing mappings does not affect the key
+ * iteration order. However, if you remove all values associated with a key and
+ * then add the key back to the multimap, that key will come last in the key
+ * iteration order.
+ *
+ * <p>The multimap does not store duplicate key-value pairs. Adding a new
+ * key-value pair equal to an existing key-value pair has no effect.
+ *
+ * <p>Keys and values may be null. All optional multimap methods are supported,
+ * and all returned views are modifiable.
+ *
+ * <p>This class is not threadsafe when any concurrent operations update the
+ * multimap. Concurrent read operations will work correctly. To allow concurrent
+ * 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> {
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Constructs an empty {@code LinkedHashMultimap} with enough capacity to hold
+ * the specified numbers of keys and values without rehashing.
+ *
+ * @param expectedKeys the expected number of distinct keys
+ * @param expectedValuesPerKey the expected average number of values per key
+ * @throws IllegalArgumentException if {@code expectedKeys} or {@code
+ * expectedValuesPerKey} is negative
+ */
+ public static <K, V> LinkedHashMultimap<K, V> create(
+ int expectedKeys, int expectedValuesPerKey) {
+ return new LinkedHashMultimap<K, V>(
+ Maps.capacity(expectedKeys),
+ Maps.capacity(expectedValuesPerKey));
+ }
+
+ /**
+ * Constructs a {@code LinkedHashMultimap} with the same mappings as the
+ * specified multimap. If a key-value mapping appears multiple times in the
+ * input multimap, it only appears once in the constructed multimap. The new
+ * multimap has the same {@link Multimap#entries()} iteration order as the
+ * input multimap, except for excluding duplicate mappings.
+ *
+ * @param multimap the multimap whose contents are copied to this multimap
+ */
+ 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);
+ }
+
+ private static <K, V> void succeedsInValueSet(ValueSetLink<K, V> pred, ValueSetLink<K, V> succ) {
+ pred.setSuccessorInValueSet(succ);
+ succ.setPredecessorInValueSet(pred);
+ }
+
+ private static <K, V> void succeedsInMultimap(
+ ValueEntry<K, V> pred, ValueEntry<K, V> succ) {
+ pred.setSuccessorInMultimap(succ);
+ succ.setPredecessorInMultimap(pred);
+ }
+
+ private static <K, V> void deleteFromValueSet(ValueSetLink<K, V> entry) {
+ succeedsInValueSet(entry.getPredecessorInValueSet(), entry.getSuccessorInValueSet());
+ }
+
+ private static <K, V> void deleteFromMultimap(ValueEntry<K, V> entry) {
+ succeedsInMultimap(entry.getPredecessorInMultimap(), entry.getSuccessorInMultimap());
+ }
+
+ /**
+ * 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.
+ */
+ private 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;
+
+ ValueEntry<K, V> predecessorInMultimap;
+ ValueEntry<K, V> successorInMultimap;
+
+ ValueEntry(@Nullable K key, @Nullable V value, int valueHash,
+ @Nullable ValueEntry<K, V> nextInValueSetHashRow) {
+ this.key = key;
+ this.value = value;
+ this.valueHash = valueHash;
+ this.nextInValueSetHashRow = nextInValueSetHashRow;
+ }
+
+ @Override
+ public K getKey() {
+ return key;
+ }
+
+ @Override
+ public V getValue() {
+ return value;
+ }
+
+ @Override
+ public ValueSetLink<K, V> getPredecessorInValueSet() {
+ return predecessorInValueSet;
+ }
+
+ @Override
+ public ValueSetLink<K, V> getSuccessorInValueSet() {
+ return successorInValueSet;
+ }
+
+ @Override
+ public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
+ predecessorInValueSet = entry;
+ }
+
+ @Override
+ public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
+ successorInValueSet = entry;
+ }
+
+ public ValueEntry<K, V> getPredecessorInMultimap() {
+ return predecessorInMultimap;
+ }
+
+ public ValueEntry<K, V> getSuccessorInMultimap() {
+ return successorInMultimap;
+ }
+
+ public void setSuccessorInMultimap(ValueEntry<K, V> multimapSuccessor) {
+ this.successorInMultimap = multimapSuccessor;
+ }
+
+ public void setPredecessorInMultimap(ValueEntry<K, V> multimapPredecessor) {
+ this.predecessorInMultimap = multimapPredecessor;
+ }
+ }
+
+ private static final int DEFAULT_KEY_CAPACITY = 16;
+ private static final int DEFAULT_VALUE_SET_CAPACITY = 2;
+
+ private static final int MAX_VALUE_SET_TABLE_SIZE = Ints.MAX_POWER_OF_TWO;
+
+ @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);
+ }
+
+ /**
+ * {@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>(valueSetCapacity);
+ }
+
+ /**
+ * {@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);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>If {@code values} is not empty and the multimap already contains a
+ * mapping for {@code key}, the {@code keySet()} ordering is unchanged.
+ * However, the provided values always come last in the {@link #entries()} and
+ * {@link #values()} iteration orderings.
+ */
+ @Override
+ public Set<V> replaceValues(K key, Iterable<? extends V> values) {
+ return super.replaceValues(key, values);
+ }
+
+ /**
+ * Returns a set of all key-value pairs. Changes to the returned set will
+ * update the underlying multimap, and vice versa. The entries set does not
+ * support the {@code add} or {@code addAll} operations.
+ *
+ * <p>The iterator generated by the returned set traverses the entries in the
+ * order they were added to the multimap.
+ *
+ * <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 Set<Map.Entry<K, V>> entries() {
+ return super.entries();
+ }
+
+ /**
+ * Returns a collection of all values in the multimap. Changes to the returned
+ * collection will update the underlying multimap, and vice versa.
+ *
+ * <p>The iterator generated by the returned collection traverses the values
+ * in the order they were added to the multimap.
+ */
+ @Override public Collection<V> values() {
+ 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;
+ private 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 = Integer.highestOneBit(Math.max(expectedValues, 2) - 1) << 1;
+ if (tableSize < 0) {
+ tableSize = MAX_VALUE_SET_TABLE_SIZE;
+ }
+
+ @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;
+ }
+
+ /**
+ * The threshold above which the hash table should be rebuilt.
+ */
+ @VisibleForTesting int threshold() {
+ return hashTable.length; // load factor of 1.0
+ }
+
+ @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 (size > threshold() && hashTable.length < MAX_VALUE_SET_TABLE_SIZE) {
+ @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>> createEntryIterator() {
+ 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);
+ }
+
+ /**
+ * @serialData the expected values per key, the number of distinct keys,
+ * the number of entries, and the entries in order
+ */
+ @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.writeObject(entry.getKey());
+ stream.writeObject(entry.getValue());
+ }
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ 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")
+ K key = (K) stream.readObject();
+ @SuppressWarnings("unchecked")
+ V value = (V) stream.readObject();
+ map.get(key).add(value);
+ }
+ setMap(map);
+ }
+
+ @GwtIncompatible("java serialization not supported")
+ private static final long serialVersionUID = 1;
+}
diff --git a/guava/src/com/google/common/collect/LinkedHashMultiset.java b/guava/src/com/google/common/collect/LinkedHashMultiset.java
new file mode 100644
index 0000000..9b8c45b
--- /dev/null
+++ b/guava/src/com/google/common/collect/LinkedHashMultiset.java
@@ -0,0 +1,113 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.LinkedHashMap;
+
+/**
+ * A {@code Multiset} implementation with predictable iteration order. Its
+ * iterator orders elements according to when the first occurrence of the
+ * element was added. When the multiset contains multiple instances of an
+ * 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
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // we're overriding default serialization
+public final class LinkedHashMultiset<E> extends AbstractMapBasedMultiset<E> {
+
+ /**
+ * Creates a new, empty {@code LinkedHashMultiset} using the default initial
+ * capacity.
+ */
+ public static <E> LinkedHashMultiset<E> create() {
+ return new LinkedHashMultiset<E>();
+ }
+
+ /**
+ * Creates a new, empty {@code LinkedHashMultiset} with the specified expected
+ * number of distinct elements.
+ *
+ * @param distinctElements the expected number of distinct elements
+ * @throws IllegalArgumentException if {@code distinctElements} is negative
+ */
+ public static <E> LinkedHashMultiset<E> create(int distinctElements) {
+ return new LinkedHashMultiset<E>(distinctElements);
+ }
+
+ /**
+ * Creates a new {@code LinkedHashMultiset} containing the specified elements.
+ *
+ * <p>This implementation is highly efficient when {@code elements} is itself
+ * a {@link Multiset}.
+ *
+ * @param elements the elements that the multiset should contain
+ */
+ public static <E> LinkedHashMultiset<E> create(
+ Iterable<? extends E> elements) {
+ LinkedHashMultiset<E> multiset =
+ create(Multisets.inferDistinctElements(elements));
+ Iterables.addAll(multiset, elements);
+ return multiset;
+ }
+
+ private LinkedHashMultiset() {
+ super(new LinkedHashMap<E, Count>());
+ }
+
+ private LinkedHashMultiset(int distinctElements) {
+ // Could use newLinkedHashMapWithExpectedSize() if it existed
+ super(new LinkedHashMap<E, Count>(Maps.capacity(distinctElements)));
+ }
+
+ /**
+ * @serialData 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 {
+ stream.defaultWriteObject();
+ Serialization.writeMultiset(this, stream);
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ int distinctElements = Serialization.readCount(stream);
+ setBackingMap(new LinkedHashMap<E, Count>(
+ Maps.capacity(distinctElements)));
+ Serialization.populateMultiset(this, stream, distinctElements);
+ }
+
+ @GwtIncompatible("not needed in emulated source")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/LinkedListMultimap.java b/guava/src/com/google/common/collect/LinkedListMultimap.java
new file mode 100644
index 0000000..79127b7
--- /dev/null
+++ b/guava/src/com/google/common/collect/LinkedListMultimap.java
@@ -0,0 +1,995 @@
+/*
+ * 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.checkState;
+import static java.util.Collections.unmodifiableList;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.AbstractSequentialList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An implementation of {@code ListMultimap} that supports deterministic
+ * iteration order for both keys and values. The iteration order is preserved
+ * across non-distinct key values. For example, for the following multimap
+ * definition: <pre> {@code
+ *
+ * Multimap<K, V> multimap = LinkedListMultimap.create();
+ * multimap.put(key1, foo);
+ * multimap.put(key2, bar);
+ * multimap.put(key1, baz);}</pre>
+ *
+ * ... the iteration order for {@link #keys()} is {@code [key1, key2, key1]},
+ * and similarly for {@link #entries()}. Unlike {@link LinkedHashMultimap}, the
+ * iteration order is kept consistent between keys, entries and values. For
+ * example, calling: <pre> {@code
+ *
+ * map.remove(key1, foo);}</pre>
+ *
+ * changes the entries iteration order to {@code [key2=bar, key1=baz]} and the
+ * key iteration order to {@code [key2, key1]}. The {@link #entries()} iterator
+ * returns mutable map entries, and {@link #replaceValues} attempts to preserve
+ * iteration order as much as possible.
+ *
+ * <p>The collections returned by {@link #keySet()} and {@link #asMap} iterate
+ * through the keys in the order they were first added to the multimap.
+ * Similarly, {@link #get}, {@link #removeAll}, and {@link #replaceValues}
+ * return collections that iterate through the values in the order they were
+ * added. The collections generated by {@link #entries()}, {@link #keys()}, and
+ * {@link #values} iterate across the key-value mappings in the order they were
+ * added to the multimap.
+ *
+ * <p>The {@link #values()} and {@link #entries()} methods both return a
+ * {@code List}, instead of the {@code Collection} specified by the {@link
+ * ListMultimap} interface.
+ *
+ * <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 modified while an
+ * iteration over any of those collections is in progress, except through the
+ * iterator's methods, the results of the iteration are undefined.
+ *
+ * <p>Keys and values may be null. All optional multimap methods are supported,
+ * and all returned views are modifiable.
+ *
+ * <p>This class is not threadsafe when any concurrent operations update the
+ * 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 Mike Bostock
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+public class LinkedListMultimap<K, V>
+ implements ListMultimap<K, V>, Serializable {
+ /*
+ * Order is maintained using a linked list containing all key-value pairs. In
+ * addition, a series of disjoint linked lists of "siblings", each containing
+ * the values for a specific key, is used to implement {@link
+ * ValueForKeyIterator} in constant time.
+ */
+
+ private static final class Node<K, V> {
+ final K key;
+ V value;
+ Node<K, V> next; // the next node (with any key)
+ Node<K, V> previous; // the previous node (with any key)
+ Node<K, V> nextSibling; // the next node with the same key
+ Node<K, V> previousSibling; // the previous node with the same key
+
+ Node(@Nullable K key, @Nullable V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override public String toString() {
+ return key + "=" + value;
+ }
+ }
+
+ private transient Node<K, V> head; // the head for all keys
+ private transient Node<K, V> tail; // the tail for all keys
+ 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
+ * capacity.
+ */
+ public static <K, V> LinkedListMultimap<K, V> create() {
+ return new LinkedListMultimap<K, V>();
+ }
+
+ /**
+ * Constructs an empty {@code LinkedListMultimap} with enough capacity to hold
+ * the specified number of keys without rehashing.
+ *
+ * @param expectedKeys the expected number of distinct keys
+ * @throws IllegalArgumentException if {@code expectedKeys} is negative
+ */
+ public static <K, V> LinkedListMultimap<K, V> create(int expectedKeys) {
+ return new LinkedListMultimap<K, V>(expectedKeys);
+ }
+
+ /**
+ * Constructs a {@code LinkedListMultimap} with the same mappings as the
+ * specified {@code Multimap}. The new multimap has the same
+ * {@link Multimap#entries()} iteration order as the input multimap.
+ *
+ * @param multimap the multimap whose contents are copied to this multimap
+ */
+ public static <K, V> LinkedListMultimap<K, V> create(
+ Multimap<? extends K, ? extends V> multimap) {
+ return new LinkedListMultimap<K, V>(multimap);
+ }
+
+ LinkedListMultimap() {
+ keyCount = LinkedHashMultiset.create();
+ keyToKeyHead = Maps.newHashMap();
+ keyToKeyTail = Maps.newHashMap();
+ }
+
+ private LinkedListMultimap(int expectedKeys) {
+ keyCount = LinkedHashMultiset.create(expectedKeys);
+ keyToKeyHead = Maps.newHashMapWithExpectedSize(expectedKeys);
+ keyToKeyTail = Maps.newHashMapWithExpectedSize(expectedKeys);
+ }
+
+ private LinkedListMultimap(Multimap<? extends K, ? extends V> multimap) {
+ this(multimap.keySet().size());
+ putAll(multimap);
+ }
+
+ /**
+ * Adds a new node for the specified key-value pair before the specified
+ * {@code nextSibling} element, or at the end of the list if {@code
+ * nextSibling} is null. Note: if {@code nextSibling} is specified, it MUST be
+ * for an node for the same {@code key}!
+ */
+ private Node<K, V> addNode(
+ @Nullable K key, @Nullable V value, @Nullable Node<K, V> nextSibling) {
+ Node<K, V> node = new Node<K, V>(key, value);
+ if (head == null) { // empty list
+ head = tail = node;
+ keyToKeyHead.put(key, node);
+ keyToKeyTail.put(key, node);
+ } else if (nextSibling == null) { // non-empty list, add to tail
+ tail.next = node;
+ node.previous = tail;
+ Node<K, V> keyTail = keyToKeyTail.get(key);
+ if (keyTail == null) { // first for this key
+ keyToKeyHead.put(key, node);
+ } else {
+ keyTail.nextSibling = node;
+ node.previousSibling = keyTail;
+ }
+ keyToKeyTail.put(key, node);
+ tail = node;
+ } else { // non-empty list, insert before nextSibling
+ node.previous = nextSibling.previous;
+ node.previousSibling = nextSibling.previousSibling;
+ node.next = nextSibling;
+ node.nextSibling = nextSibling;
+ if (nextSibling.previousSibling == null) { // nextSibling was key head
+ keyToKeyHead.put(key, node);
+ } else {
+ nextSibling.previousSibling.nextSibling = node;
+ }
+ if (nextSibling.previous == null) { // nextSibling was head
+ head = node;
+ } else {
+ nextSibling.previous.next = node;
+ }
+ nextSibling.previous = node;
+ nextSibling.previousSibling = node;
+ }
+ keyCount.add(key);
+ return node;
+ }
+
+ /**
+ * Removes the specified node from the linked list. This method is only
+ * intended to be used from the {@code Iterator} classes. See also {@link
+ * LinkedListMultimap#removeAllNodes(Object)}.
+ */
+ private void removeNode(Node<K, V> node) {
+ if (node.previous != null) {
+ node.previous.next = node.next;
+ } else { // node was head
+ head = node.next;
+ }
+ if (node.next != null) {
+ node.next.previous = node.previous;
+ } else { // node was tail
+ tail = node.previous;
+ }
+ 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 {
+ keyToKeyHead.remove(node.key); // don't leak a key-null entry
+ }
+ 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. */
+ private void removeAllNodes(@Nullable Object key) {
+ for (Iterator<V> i = new ValueForKeyIterator(key); i.hasNext();) {
+ i.next();
+ i.remove();
+ }
+ }
+
+ /** Helper method for verifying that an iterator element is present. */
+ private static void checkElement(@Nullable Object node) {
+ if (node == null) {
+ throw new NoSuchElementException();
+ }
+ }
+
+ /** An {@code Iterator} over all nodes. */
+ private class NodeIterator implements ListIterator<Node<K, V>> {
+ int nextIndex;
+ Node<K, V> next;
+ Node<K, V> current;
+ Node<K, V> previous;
+
+ NodeIterator() {
+ next = head;
+ }
+ NodeIterator(int index) {
+ int size = size();
+ Preconditions.checkPositionIndex(index, size);
+ if (index >= (size / 2)) {
+ previous = tail;
+ nextIndex = size;
+ while (index++ < size) {
+ previous();
+ }
+ } else {
+ next = head;
+ while (index-- > 0) {
+ next();
+ }
+ }
+ current = null;
+ }
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+ @Override
+ public Node<K, V> next() {
+ checkElement(next);
+ previous = current = next;
+ next = next.next;
+ nextIndex++;
+ return current;
+ }
+ @Override
+ public void remove() {
+ checkState(current != null);
+ if (current != next) { // after call to next()
+ previous = current.previous;
+ nextIndex--;
+ } else { // after call to previous()
+ next = current.next;
+ }
+ removeNode(current);
+ current = null;
+ }
+ @Override
+ public boolean hasPrevious() {
+ return previous != null;
+ }
+ @Override
+ public Node<K, V> previous() {
+ checkElement(previous);
+ next = current = previous;
+ previous = previous.previous;
+ nextIndex--;
+ return current;
+ }
+ @Override
+ public int nextIndex() {
+ return nextIndex;
+ }
+ @Override
+ public int previousIndex() {
+ return nextIndex - 1;
+ }
+ @Override
+ public void set(Node<K, V> e) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ public void add(Node<K, V> e) {
+ throw new UnsupportedOperationException();
+ }
+ void setValue(V value) {
+ checkState(current != null);
+ current.value = value;
+ }
+ }
+
+ /** An {@code Iterator} over distinct keys in key head order. */
+ private class DistinctKeyIterator implements Iterator<K> {
+ final Set<K> seenKeys = Sets.<K>newHashSetWithExpectedSize(keySet().size());
+ Node<K, V> next = head;
+ Node<K, V> current;
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+ @Override
+ public K next() {
+ checkElement(next);
+ current = next;
+ seenKeys.add(current.key);
+ do { // skip ahead to next unseen key
+ next = next.next;
+ } while ((next != null) && !seenKeys.add(next.key));
+ return current.key;
+ }
+ @Override
+ public void remove() {
+ checkState(current != null);
+ removeAllNodes(current.key);
+ current = null;
+ }
+ }
+
+ /** A {@code ListIterator} over values for a specified key. */
+ private class ValueForKeyIterator implements ListIterator<V> {
+ final Object key;
+ int nextIndex;
+ Node<K, V> next;
+ Node<K, V> current;
+ Node<K, V> previous;
+
+ /** Constructs a new iterator over all values for the specified key. */
+ ValueForKeyIterator(@Nullable Object key) {
+ this.key = key;
+ next = keyToKeyHead.get(key);
+ }
+
+ /**
+ * Constructs a new iterator over all values for the specified key starting
+ * at the specified index. This constructor is optimized so that it starts
+ * at either the head or the tail, depending on which is closer to the
+ * specified index. This allows adds to the tail to be done in constant
+ * time.
+ *
+ * @throws IndexOutOfBoundsException if index is invalid
+ */
+ public ValueForKeyIterator(@Nullable Object key, int index) {
+ int size = keyCount.count(key);
+ Preconditions.checkPositionIndex(index, size);
+ if (index >= (size / 2)) {
+ previous = keyToKeyTail.get(key);
+ nextIndex = size;
+ while (index++ < size) {
+ previous();
+ }
+ } else {
+ next = keyToKeyHead.get(key);
+ while (index-- > 0) {
+ next();
+ }
+ }
+ this.key = key;
+ current = null;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public V next() {
+ checkElement(next);
+ previous = current = next;
+ next = next.nextSibling;
+ nextIndex++;
+ return current.value;
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return previous != null;
+ }
+
+ @Override
+ public V previous() {
+ checkElement(previous);
+ next = current = previous;
+ previous = previous.previousSibling;
+ nextIndex--;
+ return current.value;
+ }
+
+ @Override
+ public int nextIndex() {
+ return nextIndex;
+ }
+
+ @Override
+ public int previousIndex() {
+ return nextIndex - 1;
+ }
+
+ @Override
+ public void remove() {
+ checkState(current != null);
+ if (current != next) { // after call to next()
+ previous = current.previousSibling;
+ nextIndex--;
+ } else { // after call to previous()
+ next = current.nextSibling;
+ }
+ removeNode(current);
+ current = null;
+ }
+
+ @Override
+ public void set(V value) {
+ checkState(current != null);
+ current.value = value;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void add(V value) {
+ previous = addNode((K) key, value, next);
+ nextIndex++;
+ current = null;
+ }
+ }
+
+ // Query Operations
+
+ @Override
+ public int size() {
+ return keyCount.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return head == null;
+ }
+
+ @Override
+ public boolean containsKey(@Nullable Object key) {
+ return keyToKeyHead.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(@Nullable Object value) {
+ for (Iterator<Node<K, V>> i = new NodeIterator(); i.hasNext();) {
+ if (Objects.equal(i.next().value, value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
+ for (Iterator<V> i = new ValueForKeyIterator(key); i.hasNext();) {
+ if (Objects.equal(i.next(), value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Modification Operations
+
+ /**
+ * Stores a key-value pair in the multimap.
+ *
+ * @param key key to store in the multimap
+ * @param value value to store in the multimap
+ * @return {@code true} always
+ */
+ @Override
+ public boolean put(@Nullable K key, @Nullable V value) {
+ addNode(key, value, null);
+ return true;
+ }
+
+ @Override
+ public boolean remove(@Nullable Object key, @Nullable Object value) {
+ Iterator<V> values = new ValueForKeyIterator(key);
+ while (values.hasNext()) {
+ if (Objects.equal(values.next(), value)) {
+ values.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Bulk Operations
+
+ @Override
+ public boolean putAll(@Nullable K key, Iterable<? extends V> values) {
+ boolean changed = false;
+ for (V value : values) {
+ changed |= put(key, value);
+ }
+ return changed;
+ }
+
+ @Override
+ public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ boolean changed = false;
+ for (Entry<? extends K, ? extends V> entry : multimap.entries()) {
+ changed |= put(entry.getKey(), entry.getValue());
+ }
+ return changed;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>If any entries for the specified {@code key} already exist in the
+ * multimap, their values are changed in-place without affecting the iteration
+ * order.
+ *
+ * <p>The returned list is immutable and implements
+ * {@link java.util.RandomAccess}.
+ */
+ @Override
+ public List<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
+ List<V> oldValues = getCopy(key);
+ ListIterator<V> keyValues = new ValueForKeyIterator(key);
+ Iterator<? extends V> newValues = values.iterator();
+
+ // Replace existing values, if any.
+ while (keyValues.hasNext() && newValues.hasNext()) {
+ keyValues.next();
+ keyValues.set(newValues.next());
+ }
+
+ // Remove remaining old values, if any.
+ while (keyValues.hasNext()) {
+ keyValues.next();
+ keyValues.remove();
+ }
+
+ // Add remaining new values, if any.
+ while (newValues.hasNext()) {
+ keyValues.add(newValues.next());
+ }
+
+ return oldValues;
+ }
+
+ private List<V> getCopy(@Nullable Object key) {
+ return unmodifiableList(Lists.newArrayList(new ValueForKeyIterator(key)));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned list is immutable and implements
+ * {@link java.util.RandomAccess}.
+ */
+ @Override
+ public List<V> removeAll(@Nullable Object key) {
+ List<V> oldValues = getCopy(key);
+ removeAllNodes(key);
+ return oldValues;
+ }
+
+ @Override
+ public void clear() {
+ head = null;
+ tail = null;
+ keyCount.clear();
+ keyToKeyHead.clear();
+ keyToKeyTail.clear();
+ }
+
+ // Views
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>If the multimap is modified while an iteration over the list is in
+ * progress (except through the iterator's own {@code add}, {@code set} or
+ * {@code remove} operations) the results of the iteration are undefined.
+ *
+ * <p>The returned list is not serializable and does not have random access.
+ */
+ @Override
+ public List<V> get(final @Nullable K key) {
+ return new AbstractSequentialList<V>() {
+ @Override public int size() {
+ return keyCount.count(key);
+ }
+ @Override public ListIterator<V> listIterator(int index) {
+ return new ValueForKeyIterator(key, index);
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return Iterators.removeAll(iterator(), c);
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ return Iterators.retainAll(iterator(), c);
+ }
+ };
+ }
+
+ private transient Set<K> keySet;
+
+ @Override
+ public Set<K> keySet() {
+ Set<K> result = keySet;
+ if (result == null) {
+ keySet = result = new Sets.ImprovedAbstractSet<K>() {
+ @Override public int size() {
+ return keyCount.elementSet().size();
+ }
+ @Override public Iterator<K> iterator() {
+ return new DistinctKeyIterator();
+ }
+ @Override public boolean contains(Object key) { // for performance
+ return containsKey(key);
+ }
+ @Override
+ public boolean remove(Object o) { // for performance
+ return !LinkedListMultimap.this.removeAll(o).isEmpty();
+ }
+ };
+ }
+ return result;
+ }
+
+ private transient Multiset<K> keys;
+
+ @Override
+ public Multiset<K> keys() {
+ Multiset<K> result = keys;
+ if (result == null) {
+ keys = result = new MultisetView();
+ }
+ return result;
+ }
+
+ private class MultisetView extends AbstractMultiset<K> {
+ @Override
+ public int size() {
+ return keyCount.size();
+ }
+
+ @Override
+ public int count(Object element) {
+ return keyCount.count(element);
+ }
+
+ @Override
+ Iterator<Entry<K>> entryIterator() {
+ return new TransformedIterator<K, Entry<K>>(new DistinctKeyIterator()) {
+ @Override
+ Entry<K> transform(final K key) {
+ return new Multisets.AbstractEntry<K>() {
+ @Override
+ public K getElement() {
+ return key;
+ }
+
+ @Override
+ public int getCount() {
+ return keyCount.count(key);
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ int distinctElements() {
+ return elementSet().size();
+ }
+
+ @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 remove(@Nullable Object key, int occurrences) {
+ checkArgument(occurrences >= 0);
+ int oldCount = count(key);
+ Iterator<V> values = new ValueForKeyIterator(key);
+ while ((occurrences-- > 0) && values.hasNext()) {
+ values.next();
+ values.remove();
+ }
+ return oldCount;
+ }
+
+ @Override
+ public Set<K> elementSet() {
+ return keySet();
+ }
+
+ @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;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The iterator generated by the returned collection traverses the values
+ * in the order they were added to the multimap. Because the values may have
+ * duplicates and follow the insertion ordering, this method returns a {@link
+ * List}, instead of the {@link Collection} specified in the {@link
+ * ListMultimap} interface.
+ */
+ @Override
+ public List<V> values() {
+ List<V> result = valuesList;
+ if (result == null) {
+ valuesList = result = new AbstractSequentialList<V>() {
+ @Override public int 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) {
+ @Override
+ V transform(Node<K, V> node) {
+ return node.value;
+ }
+
+ @Override
+ public void set(V value) {
+ nodes.setValue(value);
+ }
+ };
+ }
+ };
+ }
+ return result;
+ }
+
+ private static <K, V> Entry<K, V> createEntry(final Node<K, V> node) {
+ return new AbstractMapEntry<K, V>() {
+ @Override public K getKey() {
+ return node.key;
+ }
+ @Override public V getValue() {
+ return node.value;
+ }
+ @Override public V setValue(V value) {
+ V oldValue = node.value;
+ node.value = value;
+ return oldValue;
+ }
+ };
+ }
+
+ private transient List<Entry<K, V>> entries;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The iterator generated by the returned collection traverses the entries
+ * in the order they were added to the multimap. Because the entries may have
+ * duplicates and follow the insertion ordering, this method returns a {@link
+ * List}, instead of the {@link Collection} specified in the {@link
+ * ListMultimap} interface.
+ *
+ * <p>An entry's {@link Entry#getKey} method always returns the same key,
+ * regardless of what happens subsequently. As long as the corresponding
+ * key-value mapping is not removed from the multimap, {@link Entry#getValue}
+ * returns the value from the multimap, which may change over time, and {@link
+ * Entry#setValue} modifies that value. Removing the mapping from the
+ * multimap does not alter the value returned by {@code getValue()}, though a
+ * subsequent {@code setValue()} call won't update the multimap but will lead
+ * to a revised value being returned by {@code getValue()}.
+ */
+ @Override
+ public List<Entry<K, V>> entries() {
+ List<Entry<K, V>> result = entries;
+ if (result == null) {
+ entries = result = new AbstractSequentialList<Entry<K, V>>() {
+ @Override public int 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)) {
+ @Override
+ Entry<K, V> transform(Node<K, V> node) {
+ return createEntry(node);
+ }
+ };
+ }
+ };
+ }
+ return result;
+ }
+
+ 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 keyCount.elementSet().size();
+ }
+
+ @Override
+ Multimap<K, V> multimap() {
+ return LinkedListMultimap.this;
+ }
+
+ @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;
+ }
+
+ @Override public Collection<V> getValue() {
+ return LinkedListMultimap.this.get(key);
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+
+ return result;
+ }
+
+ // Comparison and hashing
+
+ /**
+ * Compares the specified object to this multimap for equality.
+ *
+ * <p>Two {@code ListMultimap} instances are equal if, for each key, they
+ * contain the same values in the same order. If the value orderings disagree,
+ * the multimaps will not be considered equal.
+ */
+ @Override public boolean equals(@Nullable Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (other instanceof Multimap) {
+ Multimap<?, ?> that = (Multimap<?, ?>) other;
+ return this.asMap().equals(that.asMap());
+ }
+ return false;
+ }
+
+ /**
+ * Returns the hash code for this multimap.
+ *
+ * <p>The hash code of a multimap is defined as the hash code of the map view,
+ * as returned by {@link Multimap#asMap}.
+ */
+ @Override public int hashCode() {
+ return asMap().hashCode();
+ }
+
+ /**
+ * Returns a string representation of the multimap, generated by calling
+ * {@code toString} on the map returned by {@link Multimap#asMap}.
+ *
+ * @return a string representation of the multimap
+ */
+ @Override public String toString() {
+ return asMap().toString();
+ }
+
+ /**
+ * @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(size());
+ for (Entry<K, V> entry : entries()) {
+ stream.writeObject(entry.getKey());
+ stream.writeObject(entry.getValue());
+ }
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ 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
+ K key = (K) stream.readObject();
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ V value = (V) stream.readObject();
+ put(key, value);
+ }
+ }
+
+ @GwtIncompatible("java serialization not supported")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ListMultimap.java b/guava/src/com/google/common/collect/ListMultimap.java
new file mode 100644
index 0000000..a83b81a
--- /dev/null
+++ b/guava/src/com/google/common/collect/ListMultimap.java
@@ -0,0 +1,96 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+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.
+ *
+ * <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)
+ */
+@GwtCompatible
+public interface ListMultimap<K, V> extends Multimap<K, V> {
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because the values for a given key may have duplicates and follow the
+ * insertion ordering, this method returns a {@link List}, instead of the
+ * {@link java.util.Collection} specified in the {@link Multimap} interface.
+ */
+ @Override
+ List<V> get(@Nullable K key);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because the values for a given key may have duplicates and follow the
+ * insertion ordering, this method returns a {@link List}, instead of the
+ * {@link java.util.Collection} specified in the {@link Multimap} interface.
+ */
+ @Override
+ List<V> removeAll(@Nullable Object key);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because the values for a given key may have duplicates and follow the
+ * insertion ordering, this method returns a {@link List}, instead of the
+ * {@link java.util.Collection} specified in the {@link Multimap} interface.
+ */
+ @Override
+ List<V> replaceValues(K key, Iterable<? extends V> values);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Though the method signature doesn't say so explicitly, the returned map
+ * has {@link List} values.
+ */
+ @Override
+ Map<K, Collection<V>> asMap();
+
+ /**
+ * Compares the specified object to this multimap for equality.
+ *
+ * <p>Two {@code ListMultimap} instances are equal if, for each key, they
+ * contain the same values in the same order. If the value orderings disagree,
+ * the multimaps will not be considered equal.
+ *
+ * <p>An empty {@code ListMultimap} is equal to any other empty {@code
+ * Multimap}, including an empty {@code SetMultimap}.
+ */
+ @Override
+ boolean equals(@Nullable Object obj);
+}
diff --git a/guava/src/com/google/common/collect/Lists.java b/guava/src/com/google/common/collect/Lists.java
new file mode 100644
index 0000000..4f400fb
--- /dev/null
+++ b/guava/src/com/google/common/collect/Lists.java
@@ -0,0 +1,1073 @@
+/*
+ * 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.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.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;
+import com.google.common.primitives.Ints;
+
+import java.io.Serializable;
+import java.util.AbstractList;
+import java.util.AbstractSequentialList;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+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} and {@link Maps}.
+ *
+ * <p>See the Guava User Guide article on <a href=
+ * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Lists">
+ * {@code Lists}</a>.
+ *
+ * @author Kevin Bourrillion
+ * @author Mike Bostock
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(emulated = true)
+public final class Lists {
+ private Lists() {}
+
+ // ArrayList
+
+ /**
+ * Creates a <i>mutable</i>, empty {@code ArrayList} instance.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableList#of()} instead.
+ *
+ * @return a new, empty {@code ArrayList}
+ */
+ @GwtCompatible(serializable = true)
+ public static <E> ArrayList<E> newArrayList() {
+ return new ArrayList<E>();
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
+ * elements.
+ *
+ * <p><b>Note:</b> if mutability is not required and the elements are
+ * non-null, use an overload of {@link ImmutableList#of()} (for varargs) or
+ * {@link ImmutableList#copyOf(Object[])} (for an array) instead.
+ *
+ * @param elements the elements that the list should contain, in order
+ * @return a new {@code ArrayList} containing those elements
+ */
+ @GwtCompatible(serializable = true)
+ public static <E> ArrayList<E> newArrayList(E... elements) {
+ checkNotNull(elements); // for GWT
+ // Avoid integer overflow when a large array is passed in
+ int capacity = computeArrayListCapacity(elements.length);
+ ArrayList<E> list = new ArrayList<E>(capacity);
+ Collections.addAll(list, elements);
+ return list;
+ }
+
+ @VisibleForTesting static int computeArrayListCapacity(int arraySize) {
+ checkArgument(arraySize >= 0);
+
+ // TODO(kevinb): Figure out the right behavior, and document it
+ return Ints.saturatedCast(5L + arraySize + (arraySize / 10));
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
+ * elements.
+ *
+ * <p><b>Note:</b> if mutability is not required and the elements are
+ * non-null, use {@link ImmutableList#copyOf(Iterator)} instead.
+ *
+ * @param elements the elements that the list should contain, in order
+ * @return a new {@code ArrayList} containing those elements
+ */
+ @GwtCompatible(serializable = true)
+ public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
+ checkNotNull(elements); // for GWT
+ // Let ArrayList's sizing logic work, if possible
+ return (elements instanceof Collection)
+ ? new ArrayList<E>(Collections2.cast(elements))
+ : newArrayList(elements.iterator());
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
+ * elements.
+ *
+ * <p><b>Note:</b> if mutability is not required and the elements are
+ * non-null, use {@link ImmutableList#copyOf(Iterator)} instead.
+ *
+ * @param elements the elements that the list should contain, in order
+ * @return a new {@code ArrayList} containing those elements
+ */
+ @GwtCompatible(serializable = true)
+ public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
+ checkNotNull(elements); // for GWT
+ ArrayList<E> list = newArrayList();
+ while (elements.hasNext()) {
+ list.add(elements.next());
+ }
+ return list;
+ }
+
+ /**
+ * Creates an {@code ArrayList} instance backed by an array of the
+ * <i>exact</i> size specified; equivalent to
+ * {@link ArrayList#ArrayList(int)}.
+ *
+ * <p><b>Note:</b> if you know the exact size your list will be, consider
+ * using a fixed-size list ({@link Arrays#asList(Object[])}) or an {@link
+ * ImmutableList} instead of a growable {@link ArrayList}.
+ *
+ * <p><b>Note:</b> If you have only an <i>estimate</i> of the eventual size of
+ * the list, consider padding this estimate by a suitable amount, or simply
+ * use {@link #newArrayListWithExpectedSize(int)} instead.
+ *
+ * @param initialArraySize the exact size of the initial backing array for
+ * the returned array list ({@code ArrayList} documentation calls this
+ * value the "capacity")
+ * @return a new, empty {@code ArrayList} which is guaranteed not to resize
+ * itself unless its size reaches {@code initialArraySize + 1}
+ * @throws IllegalArgumentException if {@code initialArraySize} is negative
+ */
+ @GwtCompatible(serializable = true)
+ public static <E> ArrayList<E> newArrayListWithCapacity(
+ int initialArraySize) {
+ checkArgument(initialArraySize >= 0); // for GWT.
+ return new ArrayList<E>(initialArraySize);
+ }
+
+ /**
+ * Creates an {@code ArrayList} instance sized appropriately to hold an
+ * <i>estimated</i> number of elements without resizing. A small amount of
+ * padding is added in case the estimate is low.
+ *
+ * <p><b>Note:</b> If you know the <i>exact</i> number of elements the list
+ * will hold, or prefer to calculate your own amount of padding, refer to
+ * {@link #newArrayListWithCapacity(int)}.
+ *
+ * @param estimatedSize an estimate of the eventual {@link List#size()} of
+ * the new list
+ * @return a new, empty {@code ArrayList}, sized appropriately to hold the
+ * estimated number of elements
+ * @throws IllegalArgumentException if {@code estimatedSize} is negative
+ */
+ @GwtCompatible(serializable = true)
+ public static <E> ArrayList<E> newArrayListWithExpectedSize(
+ int estimatedSize) {
+ return new ArrayList<E>(computeArrayListCapacity(estimatedSize));
+ }
+
+ // LinkedList
+
+ /**
+ * Creates an empty {@code LinkedList} instance.
+ *
+ * <p><b>Note:</b> if you need an immutable empty {@link List}, use
+ * {@link ImmutableList#of()} instead.
+ *
+ * @return a new, empty {@code LinkedList}
+ */
+ @GwtCompatible(serializable = true)
+ public static <E> LinkedList<E> newLinkedList() {
+ return new LinkedList<E>();
+ }
+
+ /**
+ * Creates a {@code LinkedList} instance containing the given elements.
+ *
+ * @param elements the elements that the list should contain, in order
+ * @return a new {@code LinkedList} containing those elements
+ */
+ @GwtCompatible(serializable = true)
+ public static <E> LinkedList<E> newLinkedList(
+ Iterable<? extends E> elements) {
+ LinkedList<E> list = newLinkedList();
+ for (E element : elements) {
+ list.add(element);
+ }
+ return list;
+ }
+
+ /**
+ * 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
+ * Arrays#asList}, the returned list is unmodifiable.
+ *
+ * <p>This is useful when a varargs method needs to use a signature such as
+ * {@code (Foo firstFoo, Foo... moreFoos)}, in order to avoid overload
+ * ambiguity or to enforce a minimum argument count.
+ *
+ * <p>The returned list is serializable and implements {@link RandomAccess}.
+ *
+ * @param first the first element
+ * @param rest an array of additional elements, possibly empty
+ * @return an unmodifiable list containing the specified elements
+ */
+ public static <E> List<E> asList(@Nullable E first, E[] rest) {
+ return new OnePlusArrayList<E>(first, rest);
+ }
+
+ /** @see Lists#asList(Object, Object[]) */
+ private static class OnePlusArrayList<E> extends AbstractList<E>
+ implements Serializable, RandomAccess {
+ final E first;
+ final E[] rest;
+
+ OnePlusArrayList(@Nullable E first, E[] rest) {
+ this.first = first;
+ this.rest = checkNotNull(rest);
+ }
+ @Override public int size() {
+ return rest.length + 1;
+ }
+ @Override public E get(int index) {
+ // check explicitly so the IOOBE will have the right message
+ checkElementIndex(index, size());
+ return (index == 0) ? first : rest[index - 1];
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns an unmodifiable list containing the specified first and second
+ * 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 Arrays#asList}, the returned list is unmodifiable.
+ *
+ * <p>This is useful when a varargs method needs to use a signature such as
+ * {@code (Foo firstFoo, Foo secondFoo, Foo... moreFoos)}, in order to avoid
+ * overload ambiguity or to enforce a minimum argument count.
+ *
+ * <p>The returned list is serializable and implements {@link RandomAccess}.
+ *
+ * @param first the first element
+ * @param second the second element
+ * @param rest an array of additional elements, possibly empty
+ * @return an unmodifiable list containing the specified elements
+ */
+ public static <E> List<E> asList(
+ @Nullable E first, @Nullable E second, E[] rest) {
+ return new TwoPlusArrayList<E>(first, second, rest);
+ }
+
+ /** @see Lists#asList(Object, Object, Object[]) */
+ private static class TwoPlusArrayList<E> extends AbstractList<E>
+ implements Serializable, RandomAccess {
+ final E first;
+ final E second;
+ final E[] rest;
+
+ TwoPlusArrayList(@Nullable E first, @Nullable E second, E[] rest) {
+ this.first = first;
+ this.second = second;
+ this.rest = checkNotNull(rest);
+ }
+ @Override public int size() {
+ return rest.length + 2;
+ }
+ @Override public E get(int index) {
+ switch (index) {
+ case 0:
+ return first;
+ case 1:
+ return second;
+ default:
+ // check explicitly so the IOOBE will have the right message
+ checkElementIndex(index, size());
+ return rest[index - 2];
+ }
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * 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
+ * versa.
+ *
+ * <p>Since functions are not reversible, the transform is one-way and new
+ * items cannot be stored in the returned list. The {@code add},
+ * {@code addAll} and {@code set} methods are unsupported in the returned
+ * list.
+ *
+ * <p>The function is applied lazily, invoked when needed. This is necessary
+ * for the returned list to be a view, but it means that the function will be
+ * applied many times for bulk operations like {@link List#contains} and
+ * {@link List#hashCode}. For this to perform well, {@code function} should be
+ * fast. To avoid lazy evaluation when the returned list doesn't need to be a
+ * 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.
+ *
+ * <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) {
+ return (fromList instanceof RandomAccess)
+ ? new TransformingRandomAccessList<F, T>(fromList, function)
+ : new TransformingSequentialList<F, T>(fromList, function);
+ }
+
+ /**
+ * Implementation of a sequential transforming list.
+ *
+ * @see Lists#transform
+ */
+ private static class TransformingSequentialList<F, T>
+ extends AbstractSequentialList<T> implements Serializable {
+ final List<F> fromList;
+ final Function<? super F, ? extends T> function;
+
+ TransformingSequentialList(
+ List<F> fromList, Function<? super F, ? extends T> function) {
+ this.fromList = checkNotNull(fromList);
+ this.function = checkNotNull(function);
+ }
+ /**
+ * The default implementation inherited is based on iteration and removal of
+ * each element which can be overkill. That's why we forward this call
+ * directly to the backing list.
+ */
+ @Override public void clear() {
+ fromList.clear();
+ }
+ @Override public int size() {
+ return fromList.size();
+ }
+ @Override public ListIterator<T> listIterator(final int 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
+ public void remove() {
+ delegate.remove();
+ }
+
+ @Override
+ public void set(T e) {
+ throw new UnsupportedOperationException("not supported");
+ }
+ };
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Implementation of a transforming random access list. We try to make as many
+ * of these methods pass-through to the source list as possible so that the
+ * performance characteristics of the source list and transformed list are
+ * similar.
+ *
+ * @see Lists#transform
+ */
+ private static class TransformingRandomAccessList<F, T>
+ extends AbstractList<T> implements RandomAccess, Serializable {
+ final List<F> fromList;
+ final Function<? super F, ? extends T> function;
+
+ TransformingRandomAccessList(
+ List<F> fromList, Function<? super F, ? extends T> function) {
+ this.fromList = checkNotNull(fromList);
+ this.function = checkNotNull(function);
+ }
+ @Override public void clear() {
+ fromList.clear();
+ }
+ @Override public T get(int index) {
+ return function.apply(fromList.get(index));
+ }
+ @Override public boolean isEmpty() {
+ return fromList.isEmpty();
+ }
+ @Override public T remove(int index) {
+ return function.apply(fromList.remove(index));
+ }
+ @Override public int size() {
+ return fromList.size();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns consecutive {@linkplain List#subList(int, int) sublists} of a list,
+ * each of the same size (the final list may be smaller). For example,
+ * partitioning a list containing {@code [a, b, c, d, e]} with a partition
+ * size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer list containing
+ * two inner lists of three and two elements, all in the original order.
+ *
+ * <p>The outer list is unmodifiable, but reflects the latest state of the
+ * source list. The inner lists are sublist views of the original list,
+ * produced on demand using {@link List#subList(int, int)}, and are subject
+ * to all the usual caveats about modification as explained in that API.
+ *
+ * @param list the list to return consecutive sublists of
+ * @param size the desired size of each sublist (the last may be
+ * smaller)
+ * @return a list of consecutive sublists
+ * @throws IllegalArgumentException if {@code partitionSize} is nonpositive
+ */
+ public static <T> List<List<T>> partition(List<T> list, int size) {
+ checkNotNull(list);
+ checkArgument(size > 0);
+ return (list instanceof RandomAccess)
+ ? new RandomAccessPartition<T>(list, size)
+ : new Partition<T>(list, size);
+ }
+
+ private static class Partition<T> extends AbstractList<List<T>> {
+ final List<T> list;
+ final int size;
+
+ Partition(List<T> list, int size) {
+ this.list = list;
+ this.size = size;
+ }
+
+ @Override public List<T> get(int index) {
+ int listSize = size();
+ checkElementIndex(index, listSize);
+ int start = index * size;
+ int end = Math.min(start + size, list.size());
+ return list.subList(start, end);
+ }
+
+ @Override public int size() {
+ // TODO(user): refactor to common.math.IntMath.divide
+ int result = list.size() / size;
+ if (result * size != list.size()) {
+ result++;
+ }
+ return result;
+ }
+
+ @Override public boolean isEmpty() {
+ return list.isEmpty();
+ }
+ }
+
+ private static class RandomAccessPartition<T> extends Partition<T>
+ implements RandomAccess {
+ RandomAccessPartition(List<T> list, int size) {
+ super(list, size);
+ }
+ }
+
+ /**
+ * Returns a view of the specified string as an immutable list of {@code
+ * Character} values.
+ *
+ * @since 7.0
+ */
+ @Beta public static ImmutableList<Character> charactersOf(String string) {
+ return new StringAsImmutableList(checkNotNull(string));
+ }
+
+ @SuppressWarnings("serial") // serialized using ImmutableList serialization
+ private static final class StringAsImmutableList
+ extends ImmutableList<Character> {
+
+ private final String string;
+
+ StringAsImmutableList(String string) {
+ this.string = string;
+ }
+
+ @Override public int indexOf(@Nullable Object object) {
+ return (object instanceof Character)
+ ? string.indexOf((Character) object) : -1;
+ }
+
+ @Override public int lastIndexOf(@Nullable Object object) {
+ return (object instanceof Character)
+ ? string.lastIndexOf((Character) object) : -1;
+ }
+
+ @Override public ImmutableList<Character> subList(
+ int fromIndex, int toIndex) {
+ checkPositionIndexes(fromIndex, toIndex, size()); // for GWT
+ return charactersOf(string.substring(fromIndex, toIndex));
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public Character get(int index) {
+ checkElementIndex(index, size()); // for GWT
+ return string.charAt(index);
+ }
+
+ @Override public int size() {
+ return string.length();
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof List)) {
+ return false;
+ }
+ List<?> list = (List<?>) obj;
+ int n = string.length();
+ if (n != list.size()) {
+ return false;
+ }
+ Iterator<?> iterator = list.iterator();
+ for (int i = 0; i < n; i++) {
+ Object elem = iterator.next();
+ if (!(elem instanceof Character)
+ || ((Character) elem).charValue() != string.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ int hash = 0;
+
+ @Override public int hashCode() {
+ int h = hash;
+ if (h == 0) {
+ h = 1;
+ for (int i = 0; i < string.length(); i++) {
+ h = h * 31 + string.charAt(i);
+ }
+ hash = h;
+ }
+ return h;
+ }
+ }
+
+ /**
+ * Returns a view of the specified {@code CharSequence} as a {@code
+ * List<Character>}, viewing {@code sequence} as a sequence of Unicode code
+ * units. The view does not support any modification operations, but reflects
+ * any changes to the underlying character sequence.
+ *
+ * @param sequence the character sequence to view as a {@code List} of
+ * characters
+ * @return an {@code List<Character>} view of the character sequence
+ * @since 7.0
+ */
+ @Beta public static List<Character> charactersOf(CharSequence sequence) {
+ return new CharSequenceAsList(checkNotNull(sequence));
+ }
+
+ private static final class CharSequenceAsList
+ extends AbstractList<Character> {
+ private final CharSequence sequence;
+
+ CharSequenceAsList(CharSequence sequence) {
+ this.sequence = sequence;
+ }
+
+ @Override public Character get(int index) {
+ checkElementIndex(index, size()); // for GWT
+ return sequence.charAt(index);
+ }
+
+ @Override public boolean contains(@Nullable Object o) {
+ return indexOf(o) >= 0;
+ }
+
+ @Override public int indexOf(@Nullable Object o) {
+ if (o instanceof Character) {
+ char c = (Character) o;
+ for (int i = 0; i < sequence.length(); i++) {
+ if (sequence.charAt(i) == c) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override public int lastIndexOf(@Nullable Object o) {
+ if (o instanceof Character) {
+ char c = ((Character) o).charValue();
+ for (int i = sequence.length() - 1; i >= 0; i--) {
+ if (sequence.charAt(i) == c) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override public int size() {
+ return sequence.length();
+ }
+
+ @Override public List<Character> subList(int fromIndex, int toIndex) {
+ checkPositionIndexes(fromIndex, toIndex, size()); // for GWT
+ return charactersOf(sequence.subSequence(fromIndex, toIndex));
+ }
+
+ @Override public int hashCode() {
+ int hash = 1;
+ for (int i = 0; i < sequence.length(); i++) {
+ hash = hash * 31 + sequence.charAt(i);
+ }
+ return hash;
+ }
+
+ @Override public boolean equals(@Nullable Object o) {
+ if (!(o instanceof List)) {
+ return false;
+ }
+ List<?> list = (List<?>) o;
+ int n = sequence.length();
+ if (n != list.size()) {
+ return false;
+ }
+ Iterator<?> iterator = list.iterator();
+ for (int i = 0; i < n; i++) {
+ Object elem = iterator.next();
+ if (!(elem instanceof Character)
+ || ((Character) elem).charValue() != sequence.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Returns a reversed view of the specified list. For example, {@code
+ * Lists.reverse(Arrays.asList(1, 2, 3))} returns a list containing {@code 3,
+ * 2, 1}. The returned list is backed by this list, so changes in the returned
+ * list are reflected in this list, and vice-versa. The returned list supports
+ * all of the optional list operations supported by this list.
+ *
+ * <p>The returned list is random-access if the specified list is random
+ * access.
+ *
+ * @since 7.0
+ */
+ public static <T> List<T> reverse(List<T> list) {
+ if (list instanceof ReverseList) {
+ return ((ReverseList<T>) list).getForwardList();
+ } else if (list instanceof RandomAccess) {
+ return new RandomAccessReverseList<T>(list);
+ } else {
+ return new ReverseList<T>(list);
+ }
+ }
+
+ private static class ReverseList<T> extends AbstractList<T> {
+ private final List<T> forwardList;
+
+ ReverseList(List<T> forwardList) {
+ this.forwardList = checkNotNull(forwardList);
+ }
+
+ List<T> getForwardList() {
+ return forwardList;
+ }
+
+ private int reverseIndex(int index) {
+ int size = size();
+ checkElementIndex(index, size);
+ return (size - 1) - index;
+ }
+
+ private int reversePosition(int index) {
+ int size = size();
+ checkPositionIndex(index, size);
+ return size - index;
+ }
+
+ @Override public void add(int index, @Nullable T element) {
+ forwardList.add(reversePosition(index), element);
+ }
+
+ @Override public void clear() {
+ forwardList.clear();
+ }
+
+ @Override public T remove(int index) {
+ return forwardList.remove(reverseIndex(index));
+ }
+
+ @Override protected void removeRange(int fromIndex, int toIndex) {
+ subList(fromIndex, toIndex).clear();
+ }
+
+ @Override public T set(int index, @Nullable T element) {
+ return forwardList.set(reverseIndex(index), element);
+ }
+
+ @Override public T get(int index) {
+ return forwardList.get(reverseIndex(index));
+ }
+
+ @Override public boolean isEmpty() {
+ return forwardList.isEmpty();
+ }
+
+ @Override public int size() {
+ return forwardList.size();
+ }
+
+ @Override public boolean contains(@Nullable Object o) {
+ return forwardList.contains(o);
+ }
+
+ @Override public boolean containsAll(Collection<?> c) {
+ return forwardList.containsAll(c);
+ }
+
+ @Override public List<T> subList(int fromIndex, int toIndex) {
+ checkPositionIndexes(fromIndex, toIndex, size());
+ return reverse(forwardList.subList(
+ reversePosition(toIndex), reversePosition(fromIndex)));
+ }
+
+ @Override public int indexOf(@Nullable Object o) {
+ int index = forwardList.lastIndexOf(o);
+ return (index >= 0) ? reverseIndex(index) : -1;
+ }
+
+ @Override public int lastIndexOf(@Nullable Object o) {
+ int index = forwardList.indexOf(o);
+ return (index >= 0) ? reverseIndex(index) : -1;
+ }
+
+ @Override public Iterator<T> iterator() {
+ return listIterator();
+ }
+
+ @Override public ListIterator<T> listIterator(int index) {
+ int start = reversePosition(index);
+ final ListIterator<T> forwardIterator = forwardList.listIterator(start);
+ return new ListIterator<T>() {
+
+ boolean canRemove;
+ boolean canSet;
+
+ @Override public void add(T e) {
+ forwardIterator.add(e);
+ forwardIterator.previous();
+ canSet = canRemove = false;
+ }
+
+ @Override public boolean hasNext() {
+ return forwardIterator.hasPrevious();
+ }
+
+ @Override public boolean hasPrevious() {
+ return forwardIterator.hasNext();
+ }
+
+ @Override public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ canSet = canRemove = true;
+ return forwardIterator.previous();
+ }
+
+ @Override public int nextIndex() {
+ return reversePosition(forwardIterator.nextIndex());
+ }
+
+ @Override public T previous() {
+ if (!hasPrevious()) {
+ throw new NoSuchElementException();
+ }
+ canSet = canRemove = true;
+ return forwardIterator.next();
+ }
+
+ @Override public int previousIndex() {
+ return nextIndex() - 1;
+ }
+
+ @Override public void remove() {
+ checkState(canRemove);
+ forwardIterator.remove();
+ canRemove = canSet = false;
+ }
+
+ @Override public void set(T e) {
+ checkState(canSet);
+ forwardIterator.set(e);
+ }
+ };
+ }
+ }
+
+ private static class RandomAccessReverseList<T> extends ReverseList<T>
+ implements RandomAccess {
+ RandomAccessReverseList(List<T> forwardList) {
+ super(forwardList);
+ }
+ }
+
+ /**
+ * An implementation of {@link List#hashCode()}.
+ */
+ static int hashCodeImpl(List<?> list){
+ int hashCode = 1;
+ for (Object o : list) {
+ hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
+ }
+ return hashCode;
+ }
+
+ /**
+ * An implementation of {@link List#equals(Object)}.
+ */
+ static boolean equalsImpl(List<?> list, @Nullable Object object) {
+ if (object == checkNotNull(list)) {
+ return true;
+ }
+ if (!(object instanceof List)) {
+ return false;
+ }
+
+ List<?> o = (List<?>) object;
+
+ return list.size() == o.size()
+ && Iterators.elementsEqual(list.iterator(), o.iterator());
+ }
+
+ /**
+ * An implementation of {@link List#addAll(int, Collection)}.
+ */
+ static <E> boolean addAllImpl(
+ List<E> list, int index, Iterable<? extends E> elements) {
+ boolean changed = false;
+ ListIterator<E> listIterator = list.listIterator(index);
+ for (E e : elements) {
+ listIterator.add(e);
+ changed = true;
+ }
+ return changed;
+ }
+
+ /**
+ * An implementation of {@link List#indexOf(Object)}.
+ */
+ static int indexOfImpl(List<?> list, @Nullable Object element){
+ ListIterator<?> listIterator = list.listIterator();
+ while (listIterator.hasNext()) {
+ if (Objects.equal(element, listIterator.next())) {
+ return listIterator.previousIndex();
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * An implementation of {@link List#lastIndexOf(Object)}.
+ */
+ static int lastIndexOfImpl(List<?> list, @Nullable Object element){
+ ListIterator<?> listIterator = list.listIterator(list.size());
+ while (listIterator.hasPrevious()) {
+ if (Objects.equal(element, listIterator.previous())) {
+ return listIterator.nextIndex();
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns an implementation of {@link List#listIterator(int)}.
+ */
+ static <E> ListIterator<E> listIteratorImpl(List<E> list, int index) {
+ return new AbstractListWrapper<E>(list).listIterator(index);
+ }
+
+ /**
+ * An implementation of {@link List#subList(int, int)}.
+ */
+ static <E> List<E> subListImpl(
+ final List<E> list, int fromIndex, int toIndex) {
+ List<E> wrapper;
+ if (list instanceof RandomAccess) {
+ wrapper = new RandomAccessListWrapper<E>(list) {
+ @Override public ListIterator<E> listIterator(int index) {
+ return backingList.listIterator(index);
+ }
+
+ private static final long serialVersionUID = 0;
+ };
+ } else {
+ wrapper = new AbstractListWrapper<E>(list) {
+ @Override public ListIterator<E> listIterator(int index) {
+ return backingList.listIterator(index);
+ }
+
+ private static final long serialVersionUID = 0;
+ };
+ }
+ return wrapper.subList(fromIndex, toIndex);
+ }
+
+ private static class AbstractListWrapper<E> extends AbstractList<E> {
+ final List<E> backingList;
+
+ AbstractListWrapper(List<E> backingList) {
+ this.backingList = checkNotNull(backingList);
+ }
+
+ @Override public void add(int index, E element) {
+ backingList.add(index, element);
+ }
+
+ @Override public boolean addAll(int index, Collection<? extends E> c) {
+ return backingList.addAll(index, c);
+ }
+
+ @Override public E get(int index) {
+ return backingList.get(index);
+ }
+
+ @Override public E remove(int index) {
+ return backingList.remove(index);
+ }
+
+ @Override public E set(int index, E element) {
+ return backingList.set(index, element);
+ }
+
+ @Override public boolean contains(Object o) {
+ return backingList.contains(o);
+ }
+
+ @Override public int size() {
+ return backingList.size();
+ }
+ }
+
+ private static class RandomAccessListWrapper<E>
+ extends AbstractListWrapper<E> implements RandomAccess {
+ RandomAccessListWrapper(List<E> backingList) {
+ 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/MapConstraint.java b/guava/src/com/google/common/collect/MapConstraint.java
new file mode 100644
index 0000000..b2f1e80
--- /dev/null
+++ b/guava/src/com/google/common/collect/MapConstraint.java
@@ -0,0 +1,65 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+
+/**
+ * A constraint on the keys and values that may be added to a {@code Map} or
+ * {@code Multimap}. For example, {@link MapConstraints#notNull()}, which
+ * prevents a map from including any null keys or values, could be implemented
+ * like this: <pre> {@code
+ *
+ * public void checkKeyValue(Object key, Object value) {
+ * if (key == null || value == null) {
+ * throw new NullPointerException();
+ * }
+ * }}</pre>
+ *
+ * In order to be effective, constraints should be deterministic; that is, they
+ * should not depend on state that can change (such as external state, random
+ * variables, and time) and should only depend on the value of the passed-in key
+ * and value. A non-deterministic constraint cannot reliably enforce that all
+ * the collection's elements meet the constraint, since the constraint is only
+ * enforced when elements are added.
+ *
+ * @author Mike Bostock
+ * @see MapConstraints
+ * @see Constraint
+ * @since 3.0
+ */
+@GwtCompatible
+@Beta
+public interface MapConstraint<K, V> {
+ /**
+ * Throws a suitable {@code RuntimeException} if the specified key or value is
+ * illegal. Typically this is either a {@link NullPointerException}, an
+ * {@link IllegalArgumentException}, or a {@link ClassCastException}, though
+ * an application-specific exception class may be used if appropriate.
+ */
+ void checkKeyValue(@Nullable K key, @Nullable V value);
+
+ /**
+ * Returns a brief human readable description of this constraint, such as
+ * "Not null".
+ */
+ @Override
+ String toString();
+}
diff --git a/guava/src/com/google/common/collect/MapConstraints.java b/guava/src/com/google/common/collect/MapConstraints.java
new file mode 100644
index 0000000..11351bb
--- /dev/null
+++ b/guava/src/com/google/common/collect/MapConstraints.java
@@ -0,0 +1,783 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+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.SortedSet;
+
+import javax.annotation.Nullable;
+
+/**
+ * Factory and utilities pertaining to the {@code MapConstraint} interface.
+ *
+ * @see Constraints
+ * @author Mike Bostock
+ * @since 3.0
+ */
+@Beta
+@GwtCompatible
+public final class MapConstraints {
+ private MapConstraints() {}
+
+ /**
+ * Returns a constraint that verifies that neither the key nor the value is
+ * null. If either is null, a {@link NullPointerException} is thrown.
+ */
+ public static MapConstraint<Object, Object> notNull() {
+ return NotNullMapConstraint.INSTANCE;
+ }
+
+ // enum singleton pattern
+ private enum NotNullMapConstraint implements MapConstraint<Object, Object> {
+ INSTANCE;
+
+ @Override
+ public void checkKeyValue(Object key, Object value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ }
+
+ @Override public String toString() {
+ return "Not null";
+ }
+ }
+
+ /**
+ * Returns a constrained view of the specified map, using the specified
+ * constraint. Any operations that add new mappings will call the provided
+ * constraint. However, this method does not verify that existing mappings
+ * satisfy the constraint.
+ *
+ * <p>The returned map is not serializable.
+ *
+ * @param map the map to constrain
+ * @param constraint the constraint that validates added entries
+ * @return a constrained view of the specified map
+ */
+ public static <K, V> Map<K, V> constrainedMap(
+ Map<K, V> map, MapConstraint<? super K, ? super V> constraint) {
+ return new ConstrainedMap<K, V>(map, constraint);
+ }
+
+ /**
+ * Returns a constrained view of the specified multimap, using the specified
+ * constraint. Any operations that add new mappings will call the provided
+ * constraint. However, this method does not verify that existing mappings
+ * satisfy the constraint.
+ *
+ * <p>Note that the generated multimap's {@link Multimap#removeAll} and
+ * {@link Multimap#replaceValues} methods return collections that are not
+ * constrained.
+ *
+ * <p>The returned multimap is not serializable.
+ *
+ * @param multimap the multimap to constrain
+ * @param constraint the constraint that validates added entries
+ * @return a constrained view of the multimap
+ */
+ public static <K, V> Multimap<K, V> constrainedMultimap(
+ Multimap<K, V> multimap, MapConstraint<? super K, ? super V> constraint) {
+ return new ConstrainedMultimap<K, V>(multimap, constraint);
+ }
+
+ /**
+ * Returns a constrained view of the specified list multimap, using the
+ * specified constraint. Any operations that add new mappings will call the
+ * provided constraint. However, this method does not verify that existing
+ * mappings satisfy the constraint.
+ *
+ * <p>Note that the generated multimap's {@link Multimap#removeAll} and
+ * {@link Multimap#replaceValues} methods return collections that are not
+ * constrained.
+ *
+ * <p>The returned multimap is not serializable.
+ *
+ * @param multimap the multimap to constrain
+ * @param constraint the constraint that validates added entries
+ * @return a constrained view of the specified multimap
+ */
+ public static <K, V> ListMultimap<K, V> constrainedListMultimap(
+ ListMultimap<K, V> multimap,
+ MapConstraint<? super K, ? super V> constraint) {
+ return new ConstrainedListMultimap<K, V>(multimap, constraint);
+ }
+
+ /**
+ * Returns a constrained view of the specified set multimap, using the
+ * specified constraint. Any operations that add new mappings will call the
+ * provided constraint. However, this method does not verify that existing
+ * mappings satisfy the constraint.
+ *
+ * <p>Note that the generated multimap's {@link Multimap#removeAll} and
+ * {@link Multimap#replaceValues} methods return collections that are not
+ * constrained.
+ * <p>The returned multimap is not serializable.
+ *
+ * @param multimap the multimap to constrain
+ * @param constraint the constraint that validates added entries
+ * @return a constrained view of the specified multimap
+ */
+ public static <K, V> SetMultimap<K, V> constrainedSetMultimap(
+ SetMultimap<K, V> multimap,
+ MapConstraint<? super K, ? super V> constraint) {
+ return new ConstrainedSetMultimap<K, V>(multimap, constraint);
+ }
+
+ /**
+ * Returns a constrained view of the specified sorted-set multimap, using the
+ * specified constraint. Any operations that add new mappings will call the
+ * provided constraint. However, this method does not verify that existing
+ * mappings satisfy the constraint.
+ *
+ * <p>Note that the generated multimap's {@link Multimap#removeAll} and
+ * {@link Multimap#replaceValues} methods return collections that are not
+ * constrained.
+ * <p>The returned multimap is not serializable.
+ *
+ * @param multimap the multimap to constrain
+ * @param constraint the constraint that validates added entries
+ * @return a constrained view of the specified multimap
+ */
+ public static <K, V> SortedSetMultimap<K, V> constrainedSortedSetMultimap(
+ SortedSetMultimap<K, V> multimap,
+ MapConstraint<? super K, ? super V> constraint) {
+ return new ConstrainedSortedSetMultimap<K, V>(multimap, constraint);
+ }
+
+ /**
+ * Returns a constrained view of the specified entry, using the specified
+ * constraint. The {@link Entry#setValue} operation will be verified with the
+ * constraint.
+ *
+ * @param entry the entry to constrain
+ * @param constraint the constraint for the entry
+ * @return a constrained view of the specified entry
+ */
+ private static <K, V> Entry<K, V> constrainedEntry(
+ final Entry<K, V> entry,
+ final MapConstraint<? super K, ? super V> constraint) {
+ checkNotNull(entry);
+ checkNotNull(constraint);
+ return new ForwardingMapEntry<K, V>() {
+ @Override protected Entry<K, V> delegate() {
+ return entry;
+ }
+ @Override public V setValue(V value) {
+ constraint.checkKeyValue(getKey(), value);
+ return entry.setValue(value);
+ }
+ };
+ }
+
+ /**
+ * Returns a constrained view of the specified {@code asMap} entry, using the
+ * specified constraint. The {@link Entry#setValue} operation will be verified
+ * with the constraint, and the collection returned by {@link Entry#getValue}
+ * will be similarly constrained.
+ *
+ * @param entry the {@code asMap} entry to constrain
+ * @param constraint the constraint for the entry
+ * @return a constrained view of the specified entry
+ */
+ private static <K, V> Entry<K, Collection<V>> constrainedAsMapEntry(
+ final Entry<K, Collection<V>> entry,
+ final MapConstraint<? super K, ? super V> constraint) {
+ checkNotNull(entry);
+ checkNotNull(constraint);
+ return new ForwardingMapEntry<K, Collection<V>>() {
+ @Override protected Entry<K, Collection<V>> delegate() {
+ return entry;
+ }
+ @Override public Collection<V> getValue() {
+ return Constraints.constrainedTypePreservingCollection(
+ entry.getValue(), new Constraint<V>() {
+ @Override
+ public V checkElement(V value) {
+ constraint.checkKeyValue(getKey(), value);
+ return value;
+ }
+ });
+ }
+ };
+ }
+
+ /**
+ * Returns a constrained view of the specified set of {@code asMap} entries,
+ * using the specified constraint. The {@link Entry#setValue} operation will
+ * be verified with the constraint, and the collection returned by {@link
+ * Entry#getValue} will be similarly constrained. The {@code add} and {@code
+ * addAll} operations simply forward to the underlying set, which throws an
+ * {@link UnsupportedOperationException} per the multimap specification.
+ *
+ * @param entries the entries to constrain
+ * @param constraint the constraint for the entries
+ * @return a constrained view of the entries
+ */
+ private static <K, V> Set<Entry<K, Collection<V>>> constrainedAsMapEntries(
+ Set<Entry<K, Collection<V>>> entries,
+ MapConstraint<? super K, ? super V> constraint) {
+ return new ConstrainedAsMapEntries<K, V>(entries, constraint);
+ }
+
+ /**
+ * Returns a constrained view of the specified collection (or set) of entries,
+ * using the specified constraint. The {@link Entry#setValue} operation will
+ * be verified with the constraint, along with add operations on the returned
+ * collection. The {@code add} and {@code addAll} operations simply forward to
+ * the underlying collection, which throws an {@link
+ * UnsupportedOperationException} per the map and multimap specification.
+ *
+ * @param entries the entries to constrain
+ * @param constraint the constraint for the entries
+ * @return a constrained view of the specified entries
+ */
+ private static <K, V> Collection<Entry<K, V>> constrainedEntries(
+ Collection<Entry<K, V>> entries,
+ MapConstraint<? super K, ? super V> constraint) {
+ if (entries instanceof Set) {
+ return constrainedEntrySet((Set<Entry<K, V>>) entries, constraint);
+ }
+ return new ConstrainedEntries<K, V>(entries, constraint);
+ }
+
+ /**
+ * Returns a constrained view of the specified set of entries, using the
+ * specified constraint. The {@link Entry#setValue} operation will be verified
+ * with the constraint, along with add operations on the returned set. The
+ * {@code add} and {@code addAll} operations simply forward to the underlying
+ * set, which throws an {@link UnsupportedOperationException} per the map and
+ * multimap specification.
+ *
+ * <p>The returned multimap is not serializable.
+ *
+ * @param entries the entries to constrain
+ * @param constraint the constraint for the entries
+ * @return a constrained view of the specified entries
+ */
+ private static <K, V> Set<Entry<K, V>> constrainedEntrySet(
+ Set<Entry<K, V>> entries,
+ MapConstraint<? super K, ? super V> constraint) {
+ return new ConstrainedEntrySet<K, V>(entries, constraint);
+ }
+
+ /** @see MapConstraints#constrainedMap */
+ static class ConstrainedMap<K, V> extends ForwardingMap<K, V> {
+ private final Map<K, V> delegate;
+ final MapConstraint<? super K, ? super V> constraint;
+ private transient Set<Entry<K, V>> entrySet;
+
+ ConstrainedMap(
+ Map<K, V> delegate, MapConstraint<? super K, ? super V> constraint) {
+ this.delegate = checkNotNull(delegate);
+ this.constraint = checkNotNull(constraint);
+ }
+ @Override protected Map<K, V> delegate() {
+ return delegate;
+ }
+ @Override public Set<Entry<K, V>> entrySet() {
+ Set<Entry<K, V>> result = entrySet;
+ if (result == null) {
+ entrySet = result =
+ constrainedEntrySet(delegate.entrySet(), constraint);
+ }
+ return result;
+ }
+ @Override public V put(K key, V value) {
+ constraint.checkKeyValue(key, value);
+ return delegate.put(key, value);
+ }
+ @Override public void putAll(Map<? extends K, ? extends V> map) {
+ delegate.putAll(checkMap(map, constraint));
+ }
+ }
+
+ /**
+ * Returns a constrained view of the specified bimap, using the specified
+ * constraint. Any operations that modify the bimap will have the associated
+ * keys and values verified with the constraint.
+ *
+ * <p>The returned bimap is not serializable.
+ *
+ * @param map the bimap to constrain
+ * @param constraint the constraint that validates added entries
+ * @return a constrained view of the specified bimap
+ */
+ public static <K, V> BiMap<K, V> constrainedBiMap(
+ BiMap<K, V> map, MapConstraint<? super K, ? super V> constraint) {
+ return new ConstrainedBiMap<K, V>(map, null, constraint);
+ }
+
+ /** @see MapConstraints#constrainedBiMap */
+ private static class ConstrainedBiMap<K, V> extends ConstrainedMap<K, V>
+ implements BiMap<K, V> {
+ /*
+ * We could switch to racy single-check lazy init and remove volatile, but
+ * there's a downside. That's because this field is also written in the
+ * constructor. Without volatile, the constructor's write of the existing
+ * inverse BiMap could occur after inverse()'s read of the field's initial
+ * null value, leading inverse() to overwrite the existing inverse with a
+ * doubly indirect version. This wouldn't be catastrophic, but it's
+ * something to keep in mind if we make the change.
+ *
+ * Note that UnmodifiableBiMap *does* use racy single-check lazy init.
+ * TODO(cpovirk): pick one and standardize
+ */
+ volatile BiMap<V, K> inverse;
+
+ ConstrainedBiMap(BiMap<K, V> delegate, @Nullable BiMap<V, K> inverse,
+ MapConstraint<? super K, ? super V> constraint) {
+ super(delegate, constraint);
+ this.inverse = inverse;
+ }
+
+ @Override protected BiMap<K, V> delegate() {
+ return (BiMap<K, V>) super.delegate();
+ }
+
+ @Override
+ public V forcePut(K key, V value) {
+ constraint.checkKeyValue(key, value);
+ return delegate().forcePut(key, value);
+ }
+
+ @Override
+ public BiMap<V, K> inverse() {
+ if (inverse == null) {
+ inverse = new ConstrainedBiMap<V, K>(delegate().inverse(), this,
+ new InverseConstraint<V, K>(constraint));
+ }
+ return inverse;
+ }
+
+ @Override public Set<V> values() {
+ return delegate().values();
+ }
+ }
+
+ /** @see MapConstraints#constrainedBiMap */
+ private static class InverseConstraint<K, V> implements MapConstraint<K, V> {
+ final MapConstraint<? super V, ? super K> constraint;
+
+ public InverseConstraint(MapConstraint<? super V, ? super K> constraint) {
+ this.constraint = checkNotNull(constraint);
+ }
+ @Override
+ public void checkKeyValue(K key, V value) {
+ constraint.checkKeyValue(value, key);
+ }
+ }
+
+ /** @see MapConstraints#constrainedMultimap */
+ private static class ConstrainedMultimap<K, V>
+ extends ForwardingMultimap<K, V> {
+ final MapConstraint<? super K, ? super V> constraint;
+ final Multimap<K, V> delegate;
+ transient Collection<Entry<K, V>> entries;
+ transient Map<K, Collection<V>> asMap;
+
+ public ConstrainedMultimap(Multimap<K, V> delegate,
+ MapConstraint<? super K, ? super V> constraint) {
+ this.delegate = checkNotNull(delegate);
+ this.constraint = checkNotNull(constraint);
+ }
+
+ @Override protected Multimap<K, V> delegate() {
+ return delegate;
+ }
+
+ @Override public Map<K, Collection<V>> asMap() {
+ Map<K, Collection<V>> result = asMap;
+ if (result == null) {
+ final Map<K, Collection<V>> asMapDelegate = delegate.asMap();
+
+ asMap = result = new ForwardingMap<K, Collection<V>>() {
+ Set<Entry<K, Collection<V>>> entrySet;
+ Collection<Collection<V>> values;
+
+ @Override protected Map<K, Collection<V>> delegate() {
+ return asMapDelegate;
+ }
+
+ @Override public Set<Entry<K, Collection<V>>> entrySet() {
+ Set<Entry<K, Collection<V>>> result = entrySet;
+ if (result == null) {
+ entrySet = result = constrainedAsMapEntries(
+ asMapDelegate.entrySet(), constraint);
+ }
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public Collection<V> get(Object key) {
+ try {
+ Collection<V> collection = ConstrainedMultimap.this.get((K) key);
+ return collection.isEmpty() ? null : collection;
+ } catch (ClassCastException e) {
+ return null; // key wasn't a K
+ }
+ }
+
+ @Override public Collection<Collection<V>> values() {
+ Collection<Collection<V>> result = values;
+ if (result == null) {
+ values = result = new ConstrainedAsMapValues<K, V>(
+ delegate().values(), entrySet());
+ }
+ return result;
+ }
+
+ @Override public boolean containsValue(Object o) {
+ return values().contains(o);
+ }
+ };
+ }
+ return result;
+ }
+
+ @Override public Collection<Entry<K, V>> entries() {
+ Collection<Entry<K, V>> result = entries;
+ if (result == null) {
+ entries = result = constrainedEntries(delegate.entries(), constraint);
+ }
+ return result;
+ }
+
+ @Override public Collection<V> get(final K key) {
+ return Constraints.constrainedTypePreservingCollection(
+ delegate.get(key), new Constraint<V>() {
+ @Override
+ public V checkElement(V value) {
+ constraint.checkKeyValue(key, value);
+ return value;
+ }
+ });
+ }
+
+ @Override public boolean put(K key, V value) {
+ constraint.checkKeyValue(key, value);
+ return delegate.put(key, value);
+ }
+
+ @Override public boolean putAll(K key, Iterable<? extends V> values) {
+ return delegate.putAll(key, checkValues(key, values, constraint));
+ }
+
+ @Override public boolean putAll(
+ Multimap<? extends K, ? extends V> multimap) {
+ boolean changed = false;
+ for (Entry<? extends K, ? extends V> entry : multimap.entries()) {
+ changed |= put(entry.getKey(), entry.getValue());
+ }
+ return changed;
+ }
+
+ @Override public Collection<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ return delegate.replaceValues(key, checkValues(key, values, constraint));
+ }
+ }
+
+ /** @see ConstrainedMultimap#asMap */
+ private static class ConstrainedAsMapValues<K, V>
+ extends ForwardingCollection<Collection<V>> {
+ final Collection<Collection<V>> delegate;
+ final Set<Entry<K, Collection<V>>> entrySet;
+
+ /**
+ * @param entrySet map entries, linking each key with its corresponding
+ * values, that already enforce the constraint
+ */
+ ConstrainedAsMapValues(Collection<Collection<V>> delegate,
+ Set<Entry<K, Collection<V>>> entrySet) {
+ this.delegate = delegate;
+ this.entrySet = entrySet;
+ }
+ @Override protected Collection<Collection<V>> delegate() {
+ return delegate;
+ }
+
+ @Override public Iterator<Collection<V>> iterator() {
+ final Iterator<Entry<K, Collection<V>>> iterator = entrySet.iterator();
+ return new Iterator<Collection<V>>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ @Override
+ public Collection<V> next() {
+ return iterator.next().getValue();
+ }
+ @Override
+ public void remove() {
+ iterator.remove();
+ }
+ };
+ }
+
+ @Override public Object[] toArray() {
+ return standardToArray();
+ }
+ @Override public <T> T[] toArray(T[] array) {
+ return standardToArray(array);
+ }
+ @Override public boolean contains(Object o) {
+ return standardContains(o);
+ }
+ @Override public boolean containsAll(Collection<?> c) {
+ return standardContainsAll(c);
+ }
+ @Override public boolean remove(Object o) {
+ return standardRemove(o);
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return standardRemoveAll(c);
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ return standardRetainAll(c);
+ }
+ }
+
+ /** @see MapConstraints#constrainedEntries */
+ private static class ConstrainedEntries<K, V>
+ extends ForwardingCollection<Entry<K, V>> {
+ final MapConstraint<? super K, ? super V> constraint;
+ final Collection<Entry<K, V>> entries;
+
+ ConstrainedEntries(Collection<Entry<K, V>> entries,
+ MapConstraint<? super K, ? super V> constraint) {
+ this.entries = entries;
+ this.constraint = constraint;
+ }
+ @Override protected Collection<Entry<K, V>> delegate() {
+ return entries;
+ }
+
+ @Override public Iterator<Entry<K, V>> iterator() {
+ final Iterator<Entry<K, V>> iterator = entries.iterator();
+ return new ForwardingIterator<Entry<K, V>>() {
+ @Override public Entry<K, V> next() {
+ return constrainedEntry(iterator.next(), constraint);
+ }
+ @Override protected Iterator<Entry<K, V>> delegate() {
+ return iterator;
+ }
+ };
+ }
+
+ // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
+
+ @Override public Object[] toArray() {
+ return standardToArray();
+ }
+ @Override public <T> T[] toArray(T[] array) {
+ return standardToArray(array);
+ }
+ @Override public boolean contains(Object o) {
+ return Maps.containsEntryImpl(delegate(), o);
+ }
+ @Override public boolean containsAll(Collection<?> c) {
+ return standardContainsAll(c);
+ }
+ @Override public boolean remove(Object o) {
+ return Maps.removeEntryImpl(delegate(), o);
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return standardRemoveAll(c);
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ return standardRetainAll(c);
+ }
+ }
+
+ /** @see MapConstraints#constrainedEntrySet */
+ static class ConstrainedEntrySet<K, V>
+ extends ConstrainedEntries<K, V> implements Set<Entry<K, V>> {
+ ConstrainedEntrySet(Set<Entry<K, V>> entries,
+ MapConstraint<? super K, ? super V> constraint) {
+ super(entries, constraint);
+ }
+
+ // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
+
+ @Override public boolean equals(@Nullable Object object) {
+ return Sets.equalsImpl(this, object);
+ }
+
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+ }
+
+ /** @see MapConstraints#constrainedAsMapEntries */
+ static class ConstrainedAsMapEntries<K, V>
+ extends ForwardingSet<Entry<K, Collection<V>>> {
+ private final MapConstraint<? super K, ? super V> constraint;
+ private final Set<Entry<K, Collection<V>>> entries;
+
+ ConstrainedAsMapEntries(Set<Entry<K, Collection<V>>> entries,
+ MapConstraint<? super K, ? super V> constraint) {
+ this.entries = entries;
+ this.constraint = constraint;
+ }
+
+ @Override protected Set<Entry<K, Collection<V>>> delegate() {
+ return entries;
+ }
+
+ @Override public Iterator<Entry<K, Collection<V>>> iterator() {
+ final Iterator<Entry<K, Collection<V>>> iterator = entries.iterator();
+ return new ForwardingIterator<Entry<K, Collection<V>>>() {
+ @Override public Entry<K, Collection<V>> next() {
+ return constrainedAsMapEntry(iterator.next(), constraint);
+ }
+ @Override protected Iterator<Entry<K, Collection<V>>> delegate() {
+ return iterator;
+ }
+ };
+ }
+
+ // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
+
+ @Override public Object[] toArray() {
+ return standardToArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return standardToArray(array);
+ }
+
+ @Override public boolean contains(Object o) {
+ return Maps.containsEntryImpl(delegate(), o);
+ }
+
+ @Override public boolean containsAll(Collection<?> c) {
+ return standardContainsAll(c);
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return standardEquals(object);
+ }
+
+ @Override public int hashCode() {
+ return standardHashCode();
+ }
+
+ @Override public boolean remove(Object o) {
+ return Maps.removeEntryImpl(delegate(), o);
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ return standardRemoveAll(c);
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ return standardRetainAll(c);
+ }
+ }
+
+ private static class ConstrainedListMultimap<K, V>
+ extends ConstrainedMultimap<K, V> implements ListMultimap<K, V> {
+ ConstrainedListMultimap(ListMultimap<K, V> delegate,
+ MapConstraint<? super K, ? super V> constraint) {
+ super(delegate, constraint);
+ }
+ @Override public List<V> get(K key) {
+ return (List<V>) super.get(key);
+ }
+ @Override public List<V> removeAll(Object key) {
+ return (List<V>) super.removeAll(key);
+ }
+ @Override public List<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ return (List<V>) super.replaceValues(key, values);
+ }
+ }
+
+ private static class ConstrainedSetMultimap<K, V>
+ extends ConstrainedMultimap<K, V> implements SetMultimap<K, V> {
+ ConstrainedSetMultimap(SetMultimap<K, V> delegate,
+ MapConstraint<? super K, ? super V> constraint) {
+ super(delegate, constraint);
+ }
+ @Override public Set<V> get(K key) {
+ return (Set<V>) super.get(key);
+ }
+ @Override public Set<Map.Entry<K, V>> entries() {
+ return (Set<Map.Entry<K, V>>) super.entries();
+ }
+ @Override public Set<V> removeAll(Object key) {
+ return (Set<V>) super.removeAll(key);
+ }
+ @Override public Set<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ return (Set<V>) super.replaceValues(key, values);
+ }
+ }
+
+ private static class ConstrainedSortedSetMultimap<K, V>
+ extends ConstrainedSetMultimap<K, V> implements SortedSetMultimap<K, V> {
+ ConstrainedSortedSetMultimap(SortedSetMultimap<K, V> delegate,
+ MapConstraint<? super K, ? super V> constraint) {
+ super(delegate, constraint);
+ }
+ @Override public SortedSet<V> get(K key) {
+ return (SortedSet<V>) super.get(key);
+ }
+ @Override public SortedSet<V> removeAll(Object key) {
+ return (SortedSet<V>) super.removeAll(key);
+ }
+ @Override public SortedSet<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ return (SortedSet<V>) super.replaceValues(key, values);
+ }
+ @Override
+ public Comparator<? super V> valueComparator() {
+ return ((SortedSetMultimap<K, V>) delegate()).valueComparator();
+ }
+ }
+
+ private static <K, V> Collection<V> checkValues(K key,
+ Iterable<? extends V> values,
+ MapConstraint<? super K, ? super V> constraint) {
+ Collection<V> copy = Lists.newArrayList(values);
+ for (V value : copy) {
+ constraint.checkKeyValue(key, value);
+ }
+ return copy;
+ }
+
+ private static <K, V> Map<K, V> checkMap(Map<? extends K, ? extends V> map,
+ MapConstraint<? super K, ? super V> constraint) {
+ Map<K, V> copy = new LinkedHashMap<K, V>(map);
+ for (Entry<K, V> entry : copy.entrySet()) {
+ constraint.checkKeyValue(entry.getKey(), entry.getValue());
+ }
+ return copy;
+ }
+}
diff --git a/guava/src/com/google/common/collect/MapDifference.java b/guava/src/com/google/common/collect/MapDifference.java
new file mode 100644
index 0000000..484cf67
--- /dev/null
+++ b/guava/src/com/google/common/collect/MapDifference.java
@@ -0,0 +1,114 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * An object representing the differences between two maps.
+ *
+ * @author Kevin Bourrillion
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public interface MapDifference<K, V> {
+ /**
+ * Returns {@code true} if there are no differences between the two maps;
+ * that is, if the maps are equal.
+ */
+ boolean areEqual();
+
+ /**
+ * Returns an unmodifiable map containing the entries from the left map whose
+ * keys are not present in the right map.
+ */
+ Map<K, V> entriesOnlyOnLeft();
+
+ /**
+ * Returns an unmodifiable map containing the entries from the right map whose
+ * keys are not present in the left map.
+ */
+ Map<K, V> entriesOnlyOnRight();
+
+ /**
+ * Returns an unmodifiable map containing the entries that appear in both
+ * maps; that is, the intersection of the two maps.
+ */
+ Map<K, V> entriesInCommon();
+
+ /**
+ * Returns an unmodifiable map describing keys that appear in both maps, but
+ * with different values.
+ */
+ Map<K, ValueDifference<V>> entriesDiffering();
+
+ /**
+ * Compares the specified object with this instance for equality. Returns
+ * {@code true} if the given object is also a {@code MapDifference} and the
+ * values returned by the {@link #entriesOnlyOnLeft()}, {@link
+ * #entriesOnlyOnRight()}, {@link #entriesInCommon()} and {@link
+ * #entriesDiffering()} of the two instances are equal.
+ */
+ @Override
+ boolean equals(@Nullable Object object);
+
+ /**
+ * Returns the hash code for this instance. This is defined as the hash code
+ * of <pre> {@code
+ *
+ * Arrays.asList(entriesOnlyOnLeft(), entriesOnlyOnRight(),
+ * entriesInCommon(), entriesDiffering())}</pre>
+ */
+ @Override
+ int hashCode();
+
+ /**
+ * A difference between the mappings from two maps with the same key. The
+ * {@link #leftValue} and {@link #rightValue} are not equal, and one but not
+ * both of them may be null.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ interface ValueDifference<V> {
+ /**
+ * Returns the value from the left map (possibly null).
+ */
+ V leftValue();
+
+ /**
+ * Returns the value from the right map (possibly null).
+ */
+ V rightValue();
+
+ /**
+ * Two instances are considered equal if their {@link #leftValue()}
+ * values are equal and their {@link #rightValue()} values are also equal.
+ */
+ @Override boolean equals(@Nullable Object other);
+
+ /**
+ * The hash code equals the value
+ * {@code Arrays.asList(leftValue(), rightValue()).hashCode()}.
+ */
+ @Override int hashCode();
+ }
+
+}
diff --git a/guava/src/com/google/common/collect/MapMaker.java b/guava/src/com/google/common/collect/MapMaker.java
new file mode 100644
index 0000000..d96e237
--- /dev/null
+++ b/guava/src/com/google/common/collect/MapMaker.java
@@ -0,0 +1,887 @@
+/*
+ * 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;
+
+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 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.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Ticker;
+import com.google.common.collect.ComputingConcurrentHashMap.ComputingMapAdapter;
+import com.google.common.collect.MapMakerInternalMap.Strength;
+
+import java.io.Serializable;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nullable;
+
+/**
+ * <p>A builder of {@link ConcurrentMap} instances having any combination of the following features:
+ *
+ * <ul>
+ * <li>keys or values automatically wrapped in {@linkplain WeakReference weak} or {@linkplain
+ * SoftReference soft} references
+ * <li>notification of evicted (or otherwise removed) entries
+ * <li>on-demand computation of values for keys not already present
+ * </ul>
+ *
+ * <p>Usage example: <pre> {@code
+ *
+ * ConcurrentMap<Key, Graph> graphs = new MapMaker()
+ * .concurrencyLevel(4)
+ * .weakKeys()
+ * .makeComputingMap(
+ * new Function<Key, Graph>() {
+ * public Graph apply(Key key) {
+ * return createExpensiveGraph(key);
+ * }
+ * });}</pre>
+ *
+ * These features are all optional; {@code new MapMaker().makeMap()} returns a valid concurrent map
+ * that behaves similarly to a {@link ConcurrentHashMap}.
+ *
+ * <p>The returned map is implemented as a hash table with similar performance characteristics to
+ * {@link ConcurrentHashMap}. It supports all optional operations of the {@code ConcurrentMap}
+ * 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} 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
+ * created, it is undefined which of these changes, if any, are reflected in that iterator. These
+ * iterators never throw {@link ConcurrentModificationException}.
+ *
+ * <p>If soft or weak references were requested, it is possible for a key or value present in the
+ * the map to be reclaimed by the garbage collector. If this happens, the entry automatically
+ * disappears from the map. A partially-reclaimed entry is never exposed to the user. Any {@link
+ * java.util.Map.Entry} instance retrieved from the map's {@linkplain Map#entrySet entry set} is a
+ * snapshot of that entry's state at the time of retrieval; such entries do, however, support {@link
+ * java.util.Map.Entry#setValue}, which simply calls {@link Map#put} on the entry's key.
+ *
+ * <p>The maps produced by {@code MapMaker} are serializable, and the deserialized maps retain all
+ * the configuration properties of the original map. During deserialization, if the original map had
+ * used soft or weak references, the entries are reconstructed as they were, but it's not unlikely
+ * they'll be quickly garbage-collected before they are ever accessed.
+ *
+ * <p>{@code new MapMaker().weakKeys().makeMap()} is a recommended replacement for {@link
+ * java.util.WeakHashMap}, but note that it compares keys using object identity whereas {@code
+ * WeakHashMap} uses {@link Object#equals}.
+ *
+ * @author Bob Lee
+ * @author Charles Fry
+ * @author Kevin Bourrillion
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(emulated = true)
+public final class MapMaker extends GenericMapMaker<Object, Object> {
+ private static final int DEFAULT_INITIAL_CAPACITY = 16;
+ private static final int DEFAULT_CONCURRENCY_LEVEL = 4;
+ private static final int DEFAULT_EXPIRATION_NANOS = 0;
+
+ static final int UNSET_INT = -1;
+
+ // TODO(kevinb): dispense with this after benchmarking
+ boolean useCustomMap;
+
+ int initialCapacity = UNSET_INT;
+ int concurrencyLevel = UNSET_INT;
+ int maximumSize = UNSET_INT;
+
+ Strength keyStrength;
+ Strength valueStrength;
+
+ long expireAfterWriteNanos = UNSET_INT;
+ long expireAfterAccessNanos = UNSET_INT;
+
+ RemovalCause nullRemovalCause;
+
+ Equivalence<Object> keyEquivalence;
+
+ Ticker ticker;
+
+ /**
+ * Constructs a new {@code MapMaker} instance with default settings, including strong keys, strong
+ * values, and no automatic eviction of any kind.
+ */
+ public MapMaker() {}
+
+ /**
+ * 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} or {@link #softKeys} is specified, and {@link Equivalence#equals()}
+ * otherwise. The only place this is used is in {@link Interners.WeakInterner}.
+ */
+ @GwtIncompatible("To be supported")
+ @Override
+ MapMaker keyEquivalence(Equivalence<Object> equivalence) {
+ checkState(keyEquivalence == null, "key equivalence was already set to %s", keyEquivalence);
+ keyEquivalence = checkNotNull(equivalence);
+ this.useCustomMap = true;
+ return this;
+ }
+
+ Equivalence<Object> getKeyEquivalence() {
+ return firstNonNull(keyEquivalence, getKeyStrength().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
+ * avoids the need for expensive resizing operations later, but setting this value unnecessarily
+ * high wastes memory.
+ *
+ * @throws IllegalArgumentException if {@code initialCapacity} is negative
+ * @throws IllegalStateException if an initial capacity was already set
+ */
+ @Override
+ public MapMaker initialCapacity(int initialCapacity) {
+ checkState(this.initialCapacity == UNSET_INT, "initial capacity was already set to %s",
+ this.initialCapacity);
+ checkArgument(initialCapacity >= 0);
+ this.initialCapacity = initialCapacity;
+ return this;
+ }
+
+ int getInitialCapacity() {
+ return (initialCapacity == UNSET_INT) ? DEFAULT_INITIAL_CAPACITY : initialCapacity;
+ }
+
+ /**
+ * Specifies the maximum number of entries the map may contain. Note that the map <b>may evict an
+ * entry before this limit is exceeded</b>. As the map size grows close to the maximum, the map
+ * evicts entries that are less likely to be used again. For example, the map may evict an entry
+ * because it hasn't been used recently or very often.
+ *
+ * <p>When {@code size} is zero, elements can be successfully added to the map, but are evicted
+ * immediately. This has the same effect as invoking {@link #expireAfterWrite
+ * expireAfterWrite}{@code (0, unit)} or {@link #expireAfterAccess expireAfterAccess}{@code (0,
+ * unit)}. It can be useful in testing, or to disable caching temporarily without a code change.
+ *
+ * <p>Caching functionality in {@code MapMaker} is being moved to
+ * {@link com.google.common.cache.CacheBuilder}.
+ *
+ * @param size the maximum size of the map
+ * @throws IllegalArgumentException if {@code size} is negative
+ * @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}.
+ */
+ @Deprecated
+ @Override
+ MapMaker maximumSize(int size) {
+ checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
+ this.maximumSize);
+ checkArgument(size >= 0, "maximum size must not be negative");
+ this.maximumSize = size;
+ this.useCustomMap = true;
+ if (maximumSize == 0) {
+ // SIZE trumps EXPIRED
+ this.nullRemovalCause = RemovalCause.SIZE;
+ }
+ return this;
+ }
+
+ /**
+ * Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The
+ * table is internally partitioned to try to permit the indicated number of concurrent updates
+ * without contention. Because assignment of entries to these partitions is not necessarily
+ * uniform, the actual concurrency observed may vary. Ideally, you should choose a value to
+ * accommodate as many threads as will ever concurrently modify the table. Using a significantly
+ * 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 map
+ * at a time, but since read operations can proceed concurrently, this still yields higher
+ * concurrency than full synchronization. Defaults to 4.
+ *
+ * <p><b>Note:</b> Prior to Guava release 9.0, the default was 16. It is possible the default will
+ * change again 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
+ */
+ @Override
+ public MapMaker concurrencyLevel(int concurrencyLevel) {
+ checkState(this.concurrencyLevel == UNSET_INT, "concurrency level was already set to %s",
+ this.concurrencyLevel);
+ checkArgument(concurrencyLevel > 0);
+ this.concurrencyLevel = concurrencyLevel;
+ return this;
+ }
+
+ int getConcurrencyLevel() {
+ return (concurrencyLevel == UNSET_INT) ? DEFAULT_CONCURRENCY_LEVEL : concurrencyLevel;
+ }
+
+ /**
+ * Specifies that each key (not value) stored in the map should be wrapped in a {@link
+ * WeakReference} (by default, strong references are used).
+ *
+ * <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 WeakReference
+ */
+ @GwtIncompatible("java.lang.ref.WeakReference")
+ @Override
+ public MapMaker weakKeys() {
+ 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);
+ if (strength != Strength.STRONG) {
+ // STRONG could be used during deserialization.
+ useCustomMap = true;
+ }
+ return this;
+ }
+
+ Strength getKeyStrength() {
+ return firstNonNull(keyStrength, 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).
+ *
+ * <p>Weak values will be garbage collected once they are weakly reachable. This makes them a poor
+ * candidate for caching; consider {@link #softValues} instead.
+ *
+ * <p><b>Warning:</b> when this method is used, the resulting map will use identity ({@code ==})
+ * comparison to determine equality of values. This technically violates the specifications of
+ * the methods {@link Map#containsValue containsValue},
+ * {@link ConcurrentMap#remove(Object, Object) remove(Object, Object)} and
+ * {@link ConcurrentMap#replace(Object, Object, Object) replace(K, V, V)}, and may not be what you
+ * expect.
+ *
+ * @throws IllegalStateException if the value strength was already set
+ * @see WeakReference
+ */
+ @GwtIncompatible("java.lang.ref.WeakReference")
+ @Override
+ public MapMaker weakValues() {
+ return setValueStrength(Strength.WEAK);
+ }
+
+ /**
+ * Specifies that each value (not key) 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> in most circumstances it is better to set a per-cache {@linkplain
+ * #maximumSize maximum size} instead of using soft references. You should only use this method if
+ * you are well familiar with the practical consequences of soft references.
+ *
+ * <p><b>Warning:</b> when this method is used, the resulting map will use identity ({@code ==})
+ * comparison to determine equality of values. This technically violates the specifications of
+ * the methods {@link Map#containsValue containsValue},
+ * {@link ConcurrentMap#remove(Object, Object) remove(Object, Object)} and
+ * {@link ConcurrentMap#replace(Object, Object, Object) replace(K, V, V)}, and may not be what you
+ * expect.
+ *
+ * @throws IllegalStateException if the value strength was already set
+ * @see SoftReference
+ */
+ @GwtIncompatible("java.lang.ref.SoftReference")
+ @Override
+ public MapMaker softValues() {
+ return setValueStrength(Strength.SOFT);
+ }
+
+ MapMaker setValueStrength(Strength strength) {
+ checkState(valueStrength == null, "Value strength was already set to %s", valueStrength);
+ valueStrength = checkNotNull(strength);
+ if (strength != Strength.STRONG) {
+ // STRONG could be used during deserialization.
+ useCustomMap = true;
+ }
+ return this;
+ }
+
+ Strength getValueStrength() {
+ return firstNonNull(valueStrength, Strength.STRONG);
+ }
+
+ /**
+ * 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.
+ *
+ * <p>When {@code duration} is zero, elements can be successfully added to the map, but are
+ * evicted immediately. This has a very similar effect to invoking {@link #maximumSize
+ * maximumSize}{@code (0)}. It can be useful in testing, or to disable caching temporarily without
+ * a code change.
+ *
+ * <p>Expired entries may be counted by {@link Map#size}, but will never be visible to read or
+ * write operations. Expired entries are currently cleaned up during write operations, or during
+ * occasional read operations in the absense of writes; though this behavior may change in the
+ * future.
+ *
+ * @param duration the length of time after an entry is created that it should be automatically
+ * removed
+ * @param unit the unit that {@code duration} is expressed in
+ * @throws IllegalArgumentException if {@code duration} is negative
+ * @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}.
+ */
+ @Deprecated
+ @Override
+ MapMaker expireAfterWrite(long duration, TimeUnit unit) {
+ checkExpiration(duration, unit);
+ this.expireAfterWriteNanos = unit.toNanos(duration);
+ if (duration == 0 && this.nullRemovalCause == null) {
+ // SIZE trumps EXPIRED
+ this.nullRemovalCause = RemovalCause.EXPIRED;
+ }
+ useCustomMap = true;
+ return this;
+ }
+
+ private void checkExpiration(long duration, TimeUnit unit) {
+ checkState(expireAfterWriteNanos == UNSET_INT, "expireAfterWrite was already set to %s ns",
+ expireAfterWriteNanos);
+ checkState(expireAfterAccessNanos == UNSET_INT, "expireAfterAccess was already set to %s ns",
+ expireAfterAccessNanos);
+ checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
+ }
+
+ long getExpireAfterWriteNanos() {
+ return (expireAfterWriteNanos == UNSET_INT) ? DEFAULT_EXPIRATION_NANOS : expireAfterWriteNanos;
+ }
+
+ /**
+ * Specifies that each entry should be automatically removed from the map once a fixed duration
+ * has elapsed after the entry's last read or write access.
+ *
+ * <p>When {@code duration} is zero, elements can be successfully added to the map, but are
+ * evicted immediately. This has a very similar effect to invoking {@link #maximumSize
+ * maximumSize}{@code (0)}. It can be useful in testing, or to disable caching temporarily without
+ * a code change.
+ *
+ * <p>Expired entries may be counted by {@link Map#size}, but will never be visible to read or
+ * write operations. Expired entries are currently cleaned up during write operations, or during
+ * occasional read operations in the absense of writes; though this behavior may change in the
+ * future.
+ *
+ * @param duration the length of time after an entry is last accessed that it should be
+ * automatically removed
+ * @param unit the unit that {@code duration} is expressed in
+ * @throws IllegalArgumentException if {@code duration} is negative
+ * @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}.
+ */
+ @Deprecated
+ @GwtIncompatible("To be supported")
+ @Override
+ MapMaker expireAfterAccess(long duration, TimeUnit unit) {
+ checkExpiration(duration, unit);
+ this.expireAfterAccessNanos = unit.toNanos(duration);
+ if (duration == 0 && this.nullRemovalCause == null) {
+ // SIZE trumps EXPIRED
+ this.nullRemovalCause = RemovalCause.EXPIRED;
+ }
+ useCustomMap = true;
+ return this;
+ }
+
+ long getExpireAfterAccessNanos() {
+ return (expireAfterAccessNanos == UNSET_INT)
+ ? DEFAULT_EXPIRATION_NANOS : expireAfterAccessNanos;
+ }
+
+ Ticker getTicker() {
+ return firstNonNull(ticker, Ticker.systemTicker());
+ }
+
+ /**
+ * Specifies a listener instance, which all maps built using this {@code MapMaker} will notify
+ * each time an entry is removed from the map by any means.
+ *
+ * <p>Each map built by this map maker 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 during invocations of any of that map's public methods (even read-only
+ * methods).
+ *
+ * <p><b>Important note:</b> Instead of returning <i>this</i> as a {@code MapMaker} instance,
+ * this method returns {@code GenericMapMaker<K, V>}. From this point on, either the original
+ * reference or the returned reference may be used to complete configuration and build the map,
+ * but only the "generic" one is type-safe. That is, it will properly prevent you from building
+ * maps whose key or value types are incompatible with the types accepted by the listener already
+ * provided; the {@code MapMaker} type cannot do this. For best results, simply use the standard
+ * method-chaining idiom, as illustrated in the documentation at top, configuring a {@code
+ * MapMaker} and building your {@link Map} all in a single statement.
+ *
+ * <p><b>Warning:</b> if you ignore the above advice, and use this {@code MapMaker} to build a map
+ * or 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
+ * @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}.
+ */
+ @Deprecated
+ @GwtIncompatible("To be supported")
+ <K, V> GenericMapMaker<K, V> removalListener(RemovalListener<K, V> listener) {
+ checkState(this.removalListener == null);
+
+ // safely limiting the kinds of maps this can produce
+ @SuppressWarnings("unchecked")
+ GenericMapMaker<K, V> me = (GenericMapMaker<K, V>) this;
+ me.removalListener = checkNotNull(listener);
+ useCustomMap = true;
+ return me;
+ }
+
+ /**
+ * Builds a thread-safe map, without on-demand computation of values. This method does not alter
+ * the state of this {@code MapMaker} instance, so it can be invoked again to create multiple
+ * independent maps.
+ *
+ * <p>The bulk operations {@code putAll}, {@code equals}, and {@code clear} are not guaranteed to
+ * be performed atomically on the returned map. Additionally, {@code size} and {@code
+ * containsValue} are implemented as bulk read operations, and thus may fail to observe concurrent
+ * writes.
+ *
+ * @return a serializable concurrent map having the requested features
+ */
+ @Override
+ public <K, V> ConcurrentMap<K, V> makeMap() {
+ if (!useCustomMap) {
+ return new ConcurrentHashMap<K, V>(getInitialCapacity(), 0.75f, getConcurrencyLevel());
+ }
+ return (nullRemovalCause == null)
+ ? new MapMakerInternalMap<K, V>(this)
+ : new NullConcurrentMap<K, V>(this);
+ }
+
+ /**
+ * Returns a MapMakerInternalMap for the benefit of internal callers that use features of
+ * that class not exposed through ConcurrentMap.
+ */
+ @Override
+ @GwtIncompatible("MapMakerInternalMap")
+ <K, V> MapMakerInternalMap<K, V> makeCustomMap() {
+ return new MapMakerInternalMap<K, V>(this);
+ }
+
+ /**
+ * Builds a map that supports atomic, on-demand computation of values. {@link Map#get} either
+ * returns an already-computed value for the given key, atomically computes it using the supplied
+ * function, or, if another thread is currently computing the value for this key, simply waits for
+ * that thread to finish and returns its computed value. Note that the function may be executed
+ * concurrently by multiple threads, but only for distinct keys.
+ *
+ * <p>New code should use {@link com.google.common.cache.CacheBuilder}, which supports
+ * {@linkplain com.google.common.cache.CacheStats statistics} collection, introduces the
+ * {@link com.google.common.cache.CacheLoader} interface for loading entries into the cache
+ * (allowing checked exceptions to be thrown in the process), and more cleanly separates
+ * computation from the cache's {@code Map} view.
+ *
+ * <p>If an entry's value has not finished computing yet, query methods besides {@code get} return
+ * immediately as if an entry doesn't exist. In other words, an entry isn't externally visible
+ * until the value's computation completes.
+ *
+ * <p>{@link Map#get} on the returned map will never return {@code null}. It may throw:
+ *
+ * <ul>
+ * <li>{@link NullPointerException} if the key is null or the computing function returns a null
+ * result
+ * <li>{@link ComputationException} if an exception was thrown by the computing function. If that
+ * exception is already of type {@link ComputationException} it is propagated directly; otherwise
+ * it is wrapped.
+ * </ul>
+ *
+ * <p><b>Note:</b> Callers of {@code get} <i>must</i> ensure that the key argument is of type
+ * {@code K}. The {@code get} method accepts {@code Object}, so the key type is not checked at
+ * compile time. Passing an object of a type other than {@code K} can result in that object being
+ * unsafely passed to the computing function as type {@code K}, and unsafely stored in the map.
+ *
+ * <p>If {@link Map#put} is called before a computation completes, other threads waiting on the
+ * computation will wake up and return the stored value.
+ *
+ * <p>This method does not alter the state of this {@code MapMaker} instance, so it can be invoked
+ * again to create multiple independent maps.
+ *
+ * <p>Insertion, removal, update, and access operations on the returned map safely execute
+ * concurrently by multiple threads. Iterators on the returned map are weakly consistent,
+ * returning elements reflecting the state of the map at some point at or since the creation of
+ * the iterator. They do not throw {@link ConcurrentModificationException}, and may proceed
+ * concurrently with other operations.
+ *
+ * <p>The bulk operations {@code putAll}, {@code equals}, and {@code clear} are not guaranteed to
+ * be performed atomically on the returned map. Additionally, {@code size} and {@code
+ * containsValue} are implemented as bulk read operations, and thus may fail to observe concurrent
+ * writes.
+ *
+ * @param computingFunction the function used to compute new values
+ * @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.
+ * <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)
+ ? new ComputingMapAdapter<K, V>(this, computingFunction)
+ : new NullComputingConcurrentMap<K, V>(this, computingFunction);
+ }
+
+ /**
+ * Returns a string representation for this MapMaker instance. The exact form of the returned
+ * string is not specificed.
+ */
+ @Override
+ public String toString() {
+ Objects.ToStringHelper s = Objects.toStringHelper(this);
+ if (initialCapacity != UNSET_INT) {
+ s.add("initialCapacity", initialCapacity);
+ }
+ if (concurrencyLevel != UNSET_INT) {
+ s.add("concurrencyLevel", concurrencyLevel);
+ }
+ if (maximumSize != UNSET_INT) {
+ s.add("maximumSize", maximumSize);
+ }
+ if (expireAfterWriteNanos != UNSET_INT) {
+ s.add("expireAfterWrite", expireAfterWriteNanos + "ns");
+ }
+ if (expireAfterAccessNanos != UNSET_INT) {
+ s.add("expireAfterAccess", expireAfterAccessNanos + "ns");
+ }
+ if (keyStrength != null) {
+ s.add("keyStrength", Ascii.toLowerCase(keyStrength.toString()));
+ }
+ if (valueStrength != null) {
+ s.add("valueStrength", Ascii.toLowerCase(valueStrength.toString()));
+ }
+ if (keyEquivalence != null) {
+ s.addValue("keyEquivalence");
+ }
+ if (removalListener != null) {
+ s.addValue("removalListener");
+ }
+ return s.toString();
+ }
+
+ /**
+ * An object that can receive a notification when an entry is removed from a map. The removal
+ * resulting in notification could have occured to an entry being manually removed or replaced, or
+ * due to eviction resulting from timed expiration, exceeding a maximum size, or garbage
+ * collection.
+ *
+ * <p>An instance may be called concurrently by multiple threads to process different entries.
+ * Implementations of this interface should avoid performing blocking calls or synchronizing on
+ * shared resources.
+ *
+ * @param <K> the most general type of keys this listener can listen for; for
+ * example {@code Object} if any key is acceptable
+ * @param <V> the most general type of values this listener can listen for; for
+ * example {@code Object} if any key is acceptable
+ */
+ interface RemovalListener<K, V> {
+ /**
+ * Notifies the listener that a removal occurred at some point in the past.
+ */
+ void onRemoval(RemovalNotification<K, V> notification);
+ }
+
+ /**
+ * A notification of the removal of a single entry. The key or value may be null if it was already
+ * garbage collected.
+ *
+ * <p>Like other {@code Map.Entry} instances associated with MapMaker, this class holds strong
+ * references to the key and value, regardless of the type of references the map may be using.
+ */
+ static final class RemovalNotification<K, V> extends ImmutableEntry<K, V> {
+ private static final long serialVersionUID = 0;
+
+ private final RemovalCause cause;
+
+ RemovalNotification(@Nullable K key, @Nullable V value, RemovalCause cause) {
+ super(key, value);
+ this.cause = cause;
+ }
+
+ /**
+ * Returns the cause for which the entry was removed.
+ */
+ public RemovalCause getCause() {
+ return cause;
+ }
+
+ /**
+ * Returns {@code true} if there was an automatic removal due to eviction (the cause is neither
+ * {@link RemovalCause#EXPLICIT} nor {@link RemovalCause#REPLACED}).
+ */
+ public boolean wasEvicted() {
+ return cause.wasEvicted();
+ }
+ }
+
+ /**
+ * The reason why an entry was removed.
+ */
+ enum RemovalCause {
+ /**
+ * The entry was manually removed by the user. This can result from the user invoking
+ * {@link Map#remove}, {@link ConcurrentMap#remove}, or {@link java.util.Iterator#remove}.
+ */
+ EXPLICIT {
+ @Override
+ boolean wasEvicted() {
+ return false;
+ }
+ },
+
+ /**
+ * The entry itself was not actually removed, but its value was replaced by the user. This can
+ * result from the user invoking {@link Map#put}, {@link Map#putAll},
+ * {@link ConcurrentMap#replace(Object, Object)}, or
+ * {@link ConcurrentMap#replace(Object, Object, Object)}.
+ */
+ REPLACED {
+ @Override
+ boolean wasEvicted() {
+ return false;
+ }
+ },
+
+ /**
+ * 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
+ boolean wasEvicted() {
+ return true;
+ }
+ },
+
+ /**
+ * The entry's expiration timestamp has passed. This can occur when using {@link
+ * #expireAfterWrite} or {@link #expireAfterAccess}.
+ */
+ EXPIRED {
+ @Override
+ boolean wasEvicted() {
+ return true;
+ }
+ },
+
+ /**
+ * The entry was evicted due to size constraints. This can occur when using {@link
+ * #maximumSize}.
+ */
+ SIZE {
+ @Override
+ boolean wasEvicted() {
+ return true;
+ }
+ };
+
+ /**
+ * Returns {@code true} if there was an automatic removal due to eviction (the cause is neither
+ * {@link #EXPLICIT} nor {@link #REPLACED}).
+ */
+ abstract boolean wasEvicted();
+ }
+
+ /** A map that is always empty and evicts on insertion. */
+ static class NullConcurrentMap<K, V> extends AbstractMap<K, V>
+ implements ConcurrentMap<K, V>, Serializable {
+ private static final long serialVersionUID = 0;
+
+ private final RemovalListener<K, V> removalListener;
+ private final RemovalCause removalCause;
+
+ NullConcurrentMap(MapMaker mapMaker) {
+ removalListener = mapMaker.getRemovalListener();
+ removalCause = mapMaker.nullRemovalCause;
+ }
+
+ // implements ConcurrentMap
+
+ @Override
+ public boolean containsKey(@Nullable Object key) {
+ return false;
+ }
+
+ @Override
+ public boolean containsValue(@Nullable Object value) {
+ return false;
+ }
+
+ @Override
+ public V get(@Nullable Object key) {
+ return null;
+ }
+
+ void notifyRemoval(K key, V value) {
+ RemovalNotification<K, V> notification =
+ new RemovalNotification<K, V>(key, value, removalCause);
+ removalListener.onRemoval(notification);
+ }
+
+ @Override
+ public V put(K key, V value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ notifyRemoval(key, value);
+ return null;
+ }
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ return put(key, value);
+ }
+
+ @Override
+ public V remove(@Nullable Object key) {
+ return null;
+ }
+
+ @Override
+ public boolean remove(@Nullable Object key, @Nullable Object value) {
+ return false;
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ return null;
+ }
+
+ @Override
+ public boolean replace(K key, @Nullable V oldValue, V newValue) {
+ checkNotNull(key);
+ checkNotNull(newValue);
+ return false;
+ }
+
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ return Collections.emptySet();
+ }
+ }
+
+ /** Computes on retrieval and evicts the result. */
+ static final class NullComputingConcurrentMap<K, V> extends NullConcurrentMap<K, V> {
+ private static final long serialVersionUID = 0;
+
+ final Function<? super K, ? extends V> computingFunction;
+
+ NullComputingConcurrentMap(
+ MapMaker mapMaker, Function<? super K, ? extends V> computingFunction) {
+ super(mapMaker);
+ this.computingFunction = checkNotNull(computingFunction);
+ }
+
+ @SuppressWarnings("unchecked") // unsafe, which is why Cache is preferred
+ @Override
+ public V get(Object k) {
+ K key = (K) k;
+ V value = compute(key);
+ checkNotNull(value, computingFunction + " returned null for key " + key + ".");
+ notifyRemoval(key, value);
+ return value;
+ }
+
+ private V compute(K key) {
+ checkNotNull(key);
+ try {
+ return computingFunction.apply(key);
+ } catch (ComputationException e) {
+ throw e;
+ } catch (Throwable t) {
+ throw new ComputationException(t);
+ }
+ }
+ }
+
+}
diff --git a/guava/src/com/google/common/collect/MapMakerInternalMap.java b/guava/src/com/google/common/collect/MapMakerInternalMap.java
new file mode 100644
index 0000000..ac7b371
--- /dev/null
+++ b/guava/src/com/google/common/collect/MapMakerInternalMap.java
@@ -0,0 +1,4081 @@
+/*
+ * 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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+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.Ticker;
+import com.google.common.collect.GenericMapMaker.NullListener;
+import com.google.common.collect.MapMaker.RemovalCause;
+import com.google.common.collect.MapMaker.RemovalListener;
+import com.google.common.collect.MapMaker.RemovalNotification;
+import com.google.common.primitives.Ints;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+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;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+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;
+
+/**
+ * The concurrent hash map implementation built by {@link MapMaker}.
+ *
+ * <p>This implementation is heavily derived from revision 1.96 of <a
+ * href="http://tinyurl.com/ConcurrentHashMap">ConcurrentHashMap.java</a>.
+ *
+ * @author Bob Lee
+ * @author Charles Fry
+ * @author Doug Lea ({@code ConcurrentHashMap})
+ */
+class MapMakerInternalMap<K, V>
+ extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable {
+
+ /*
+ * The basic strategy is to subdivide the table among Segments, each of which itself is a
+ * concurrently readable hash table. The map supports non-blocking reads and concurrent writes
+ * across different segments.
+ *
+ * If a maximum size is specified, a best-effort bounding is performed per segment, using a
+ * page-replacement algorithm to determine which entries to evict when the capacity has been
+ * exceeded.
+ *
+ * The page replacement algorithm's data structures are kept casually consistent with the map. The
+ * ordering of writes to a segment is sequentially consistent. An update to the map and recording
+ * of reads may not be immediately reflected on the algorithm's data structures. These structures
+ * are guarded by a lock and operations are applied in batches to avoid lock contention. The
+ * penalty of applying the batches is spread across threads so that the amortized cost is slightly
+ * higher than performing just the operation without enforcing the capacity constraint.
+ *
+ * This implementation uses a per-segment queue to record a memento of the additions, removals,
+ * and accesses that were performed on the map. The queue is drained on writes and when it exceeds
+ * its capacity threshold.
+ *
+ * The Least Recently Used page replacement algorithm was chosen due to its simplicity, high hit
+ * rate, and ability to be implemented with O(1) time complexity. The initial LRU implementation
+ * operates per-segment rather than globally for increased implementation simplicity. We expect
+ * the cache hit rate to be similar to that of a global LRU algorithm.
+ */
+
+ // Constants
+
+ /**
+ * The maximum capacity, used if a higher value is implicitly specified by either of the
+ * constructors with arguments. MUST be a power of two <= 1<<30 to ensure that entries are
+ * indexable using ints.
+ */
+ static final int MAXIMUM_CAPACITY = Ints.MAX_POWER_OF_TWO;
+
+ /** The maximum number of segments to allow; used to bound constructor arguments. */
+ static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
+
+ /** Number of (unsynchronized) retries in the containsValue method. */
+ static final int CONTAINS_VALUE_RETRIES = 3;
+
+ /**
+ * Number of cache access operations that can be buffered per segment before the cache's recency
+ * ordering information is updated. This is used to avoid lock contention by recording a memento
+ * of reads and delaying a lock acquisition until the threshold is crossed or a mutation occurs.
+ *
+ * <p>This must be a (2^n)-1 as it is used as a mask.
+ */
+ static final int DRAIN_THRESHOLD = 0x3F;
+
+ /**
+ * Maximum number of entries to be drained in a single cleanup run. This applies independently to
+ * the cleanup queue and both reference queues.
+ */
+ // TODO(fry): empirically optimize this
+ static final int DRAIN_MAX = 16;
+
+ static final long CLEANUP_EXECUTOR_DELAY_SECS = 60;
+
+ // Fields
+
+ private static final Logger logger = Logger.getLogger(MapMakerInternalMap.class.getName());
+
+ /**
+ * Mask value for indexing into segments. The upper bits of a key's hash code are used to choose
+ * the segment.
+ */
+ final transient int segmentMask;
+
+ /**
+ * Shift value for indexing within segments. Helps prevent entries that end up in the same segment
+ * from also ending up in the same bucket.
+ */
+ final transient int segmentShift;
+
+ /** The segments, each of which is a specialized hash table. */
+ final transient Segment<K, V>[] segments;
+
+ /** The concurrency level. */
+ final int concurrencyLevel;
+
+ /** Strategy for comparing keys. */
+ final Equivalence<Object> keyEquivalence;
+
+ /** Strategy for comparing values. */
+ final Equivalence<Object> valueEquivalence;
+
+ /** Strategy for referencing keys. */
+ final Strength keyStrength;
+
+ /** Strategy for referencing values. */
+ final Strength valueStrength;
+
+ /** The maximum size of this map. MapMaker.UNSET_INT if there is no maximum. */
+ final int maximumSize;
+
+ /** How long after the last access to an entry the map will retain that entry. */
+ final long expireAfterAccessNanos;
+
+ /** How long after the last write to an entry the map will retain that entry. */
+ final long expireAfterWriteNanos;
+
+ /** Entries waiting to be consumed by the removal listener. */
+ // TODO(fry): define a new type which creates event objects and automates the clear logic
+ final Queue<RemovalNotification<K, V>> removalNotificationQueue;
+
+ /**
+ * A listener that is invoked when an entry is removed due to expiration or garbage collection of
+ * soft/weak entries.
+ */
+ final RemovalListener<K, V> removalListener;
+
+ /** Factory used to create new entries. */
+ final transient EntryFactory entryFactory;
+
+ /** Measures time in a testable way. */
+ final Ticker ticker;
+
+ /**
+ * Creates a new, empty map with the specified strategy, initial capacity and concurrency level.
+ */
+ MapMakerInternalMap(MapMaker builder) {
+ concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS);
+
+ keyStrength = builder.getKeyStrength();
+ valueStrength = builder.getValueStrength();
+
+ keyEquivalence = builder.getKeyEquivalence();
+ valueEquivalence = valueStrength.defaultEquivalence();
+
+ maximumSize = builder.maximumSize;
+ expireAfterAccessNanos = builder.getExpireAfterAccessNanos();
+ expireAfterWriteNanos = builder.getExpireAfterWriteNanos();
+
+ entryFactory = EntryFactory.getFactory(keyStrength, expires(), evictsBySize());
+ ticker = builder.getTicker();
+
+ removalListener = builder.getRemovalListener();
+ removalNotificationQueue = (removalListener == NullListener.INSTANCE)
+ ? MapMakerInternalMap.<RemovalNotification<K, V>>discardingQueue()
+ : new ConcurrentLinkedQueue<RemovalNotification<K, V>>();
+
+ int initialCapacity = Math.min(builder.getInitialCapacity(), MAXIMUM_CAPACITY);
+ if (evictsBySize()) {
+ initialCapacity = Math.min(initialCapacity, maximumSize);
+ }
+
+ // Find power-of-two sizes best matching arguments. Constraints:
+ // (segmentCount <= maximumSize)
+ // && (concurrencyLevel > maximumSize || segmentCount > concurrencyLevel)
+ int segmentShift = 0;
+ int segmentCount = 1;
+ while (segmentCount < concurrencyLevel
+ && (!evictsBySize() || segmentCount * 2 <= maximumSize)) {
+ ++segmentShift;
+ segmentCount <<= 1;
+ }
+ this.segmentShift = 32 - segmentShift;
+ segmentMask = segmentCount - 1;
+
+ this.segments = newSegmentArray(segmentCount);
+
+ int segmentCapacity = initialCapacity / segmentCount;
+ if (segmentCapacity * segmentCount < initialCapacity) {
+ ++segmentCapacity;
+ }
+
+ int segmentSize = 1;
+ while (segmentSize < segmentCapacity) {
+ segmentSize <<= 1;
+ }
+
+ if (evictsBySize()) {
+ // Ensure sum of segment max sizes = overall max size
+ int maximumSegmentSize = maximumSize / segmentCount + 1;
+ int remainder = maximumSize % segmentCount;
+ for (int i = 0; i < this.segments.length; ++i) {
+ if (i == remainder) {
+ maximumSegmentSize--;
+ }
+ this.segments[i] =
+ createSegment(segmentSize, maximumSegmentSize);
+ }
+ } else {
+ for (int i = 0; i < this.segments.length; ++i) {
+ this.segments[i] =
+ createSegment(segmentSize, MapMaker.UNSET_INT);
+ }
+ }
+ }
+
+ boolean evictsBySize() {
+ return maximumSize != MapMaker.UNSET_INT;
+ }
+
+ boolean expires() {
+ return expiresAfterWrite() || expiresAfterAccess();
+ }
+
+ boolean expiresAfterWrite() {
+ return expireAfterWriteNanos > 0;
+ }
+
+ boolean expiresAfterAccess() {
+ return expireAfterAccessNanos > 0;
+ }
+
+ boolean usesKeyReferences() {
+ return keyStrength != Strength.STRONG;
+ }
+
+ boolean usesValueReferences() {
+ return valueStrength != Strength.STRONG;
+ }
+
+ enum Strength {
+ /*
+ * TODO(kevinb): If we strongly reference the value and aren't computing, we needn't wrap the
+ * value. This could save ~8 bytes per entry.
+ */
+
+ STRONG {
+ @Override
+ <K, V> ValueReference<K, V> referenceValue(
+ Segment<K, V> segment, ReferenceEntry<K, V> entry, V value) {
+ return new StrongValueReference<K, V>(value);
+ }
+
+ @Override
+ Equivalence<Object> defaultEquivalence() {
+ return Equivalence.equals();
+ }
+ },
+
+ SOFT {
+ @Override
+ <K, V> ValueReference<K, V> referenceValue(
+ Segment<K, V> segment, ReferenceEntry<K, V> entry, V value) {
+ return new SoftValueReference<K, V>(segment.valueReferenceQueue, value, entry);
+ }
+
+ @Override
+ Equivalence<Object> defaultEquivalence() {
+ return Equivalence.identity();
+ }
+ },
+
+ WEAK {
+ @Override
+ <K, V> ValueReference<K, V> referenceValue(
+ Segment<K, V> segment, ReferenceEntry<K, V> entry, V value) {
+ return new WeakValueReference<K, V>(segment.valueReferenceQueue, value, entry);
+ }
+
+ @Override
+ Equivalence<Object> defaultEquivalence() {
+ return Equivalence.identity();
+ }
+ };
+
+ /**
+ * Creates a reference for the given value according to this value strength.
+ */
+ abstract <K, V> ValueReference<K, V> referenceValue(
+ Segment<K, V> segment, ReferenceEntry<K, V> entry, V value);
+
+ /**
+ * Returns the default equivalence strategy used to compare and hash keys or values referenced
+ * at this strength. This strategy will be used unless the user explicitly specifies an
+ * alternate strategy.
+ */
+ abstract Equivalence<Object> defaultEquivalence();
+ }
+
+ /**
+ * Creates new entries.
+ */
+ enum EntryFactory {
+ STRONG {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new StrongEntry<K, V>(key, hash, next);
+ }
+ },
+ STRONG_EXPIRABLE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new StrongExpirableEntry<K, V>(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;
+ }
+ },
+ STRONG_EVICTABLE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new StrongEvictableEntry<K, V>(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;
+ }
+ },
+ STRONG_EXPIRABLE_EVICTABLE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new StrongExpirableEvictableEntry<K, V>(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;
+ }
+ },
+
+ 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(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new WeakEntry<K, V>(segment.keyReferenceQueue, key, hash, next);
+ }
+ },
+ WEAK_EXPIRABLE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new WeakExpirableEntry<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;
+ }
+ },
+ WEAK_EVICTABLE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new WeakEvictableEntry<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;
+ }
+ },
+ WEAK_EXPIRABLE_EVICTABLE {
+ @Override
+ <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return new WeakExpirableEvictableEntry<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;
+ }
+ };
+
+ /**
+ * Masks used to compute indices in the following table.
+ */
+ static final int EXPIRABLE_MASK = 1;
+ static final int EVICTABLE_MASK = 2;
+
+ /**
+ * Look-up table for factories. First dimension is the reference type. The second dimension is
+ * the result of OR-ing the feature masks.
+ */
+ static final EntryFactory[][] factories = {
+ { STRONG, STRONG_EXPIRABLE, STRONG_EVICTABLE, STRONG_EXPIRABLE_EVICTABLE },
+ { SOFT, SOFT_EXPIRABLE, SOFT_EVICTABLE, SOFT_EXPIRABLE_EVICTABLE },
+ { WEAK, WEAK_EXPIRABLE, WEAK_EVICTABLE, WEAK_EXPIRABLE_EVICTABLE }
+ };
+
+ static EntryFactory getFactory(Strength keyStrength, boolean expireAfterWrite,
+ boolean evictsBySize) {
+ int flags = (expireAfterWrite ? EXPIRABLE_MASK : 0) | (evictsBySize ? EVICTABLE_MASK : 0);
+ return factories[keyStrength.ordinal()][flags];
+ }
+
+ /**
+ * Creates a new entry.
+ *
+ * @param segment to create the entry for
+ * @param key of the entry
+ * @param hash of the key
+ * @param next entry in the same bucket
+ */
+ abstract <K, V> ReferenceEntry<K, V> newEntry(
+ Segment<K, V> segment, K key, int hash, @Nullable ReferenceEntry<K, V> next);
+
+ /**
+ * Copies an entry, assigning it a new {@code next} entry.
+ *
+ * @param original the entry to copy
+ * @param newNext entry in the same bucket
+ */
+ @GuardedBy("Segment.this")
+ <K, V> ReferenceEntry<K, V> copyEntry(
+ Segment<K, V> segment, ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
+ return newEntry(segment, original.getKey(), original.getHash(), newNext);
+ }
+
+ @GuardedBy("Segment.this")
+ <K, V> void copyExpirableEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
+ // TODO(fry): when we link values instead of entries this method can go
+ // away, as can connectExpirables, nullifyExpirable.
+ newEntry.setExpirationTime(original.getExpirationTime());
+
+ connectExpirables(original.getPreviousExpirable(), newEntry);
+ connectExpirables(newEntry, original.getNextExpirable());
+
+ nullifyExpirable(original);
+ }
+
+ @GuardedBy("Segment.this")
+ <K, V> void copyEvictableEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
+ // TODO(fry): when we link values instead of entries this method can go
+ // away, as can connectEvictables, nullifyEvictable.
+ connectEvictables(original.getPreviousEvictable(), newEntry);
+ connectEvictables(newEntry, original.getNextEvictable());
+
+ nullifyEvictable(original);
+ }
+ }
+
+ /**
+ * A reference to a value.
+ */
+ interface ValueReference<K, V> {
+ /**
+ * Gets the value. Does not block or throw exceptions.
+ */
+ V get();
+
+ /**
+ * Waits for a value that may still be computing. Unlike get(), this method can block (in the
+ * case of FutureValueReference).
+ *
+ * @throws ExecutionException if the computing thread throws an exception
+ */
+ V waitForValue() throws ExecutionException;
+
+ /**
+ * Returns the entry associated with this value reference, or {@code null} if this value
+ * reference is independent of any entry.
+ */
+ ReferenceEntry<K, V> getEntry();
+
+ /**
+ * 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);
+
+ /**
+ * Clears this reference object.
+ *
+ * @param newValue the new value reference which will replace this one; this is only used during
+ * computation to immediately notify blocked threads of the new value
+ */
+ void clear(@Nullable ValueReference<K, V> newValue);
+
+ /**
+ * Returns {@code true} if the value type is a computing reference (regardless of whether or not
+ * computation has completed). This is necessary to distiguish between partially-collected
+ * entries and computing entries, which need to be cleaned up differently.
+ */
+ boolean isComputingReference();
+ }
+
+ /**
+ * Placeholder. Indicates that the value hasn't been set yet.
+ */
+ static final ValueReference<Object, Object> UNSET = new ValueReference<Object, Object>() {
+ @Override
+ public Object get() {
+ return null;
+ }
+
+ @Override
+ public ReferenceEntry<Object, Object> getEntry() {
+ return null;
+ }
+
+ @Override
+ public ValueReference<Object, Object> copyFor(ReferenceQueue<Object> queue,
+ @Nullable Object value, ReferenceEntry<Object, Object> entry) {
+ return this;
+ }
+
+ @Override
+ public boolean isComputingReference() {
+ return false;
+ }
+
+ @Override
+ public Object waitForValue() {
+ return null;
+ }
+
+ @Override
+ public void clear(ValueReference<Object, Object> newValue) {}
+ };
+
+ /**
+ * Singleton placeholder that indicates a value is being computed.
+ */
+ @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value
+ static <K, V> ValueReference<K, V> unset() {
+ return (ValueReference<K, V>) UNSET;
+ }
+
+ /**
+ * An entry in a reference map.
+ *
+ * Entries in the map can be in the following states:
+ *
+ * Valid:
+ * - Live: valid key/value are set
+ * - Computing: computation is pending
+ *
+ * Invalid:
+ * - Expired: time expired (key/value may still be set)
+ * - Collected: key/value was partially collected, but not yet cleaned up
+ */
+ interface ReferenceEntry<K, V> {
+ /**
+ * Gets the value reference from this entry.
+ */
+ ValueReference<K, V> getValueReference();
+
+ /**
+ * Sets the value reference for this entry.
+ */
+ void setValueReference(ValueReference<K, V> valueReference);
+
+ /**
+ * Gets the next entry in the chain.
+ */
+ ReferenceEntry<K, V> getNext();
+
+ /**
+ * Gets the entry's hash.
+ */
+ int getHash();
+
+ /**
+ * Gets the key for this entry.
+ */
+ K getKey();
+
+ /*
+ * Used by entries that are expirable. Expirable entries are maintained in a doubly-linked list.
+ * New entries are added at the tail of the list at write time; stale entries are expired from
+ * the head of the list.
+ */
+
+ /**
+ * Gets the entry expiration time in ns.
+ */
+ long getExpirationTime();
+
+ /**
+ * Sets the entry expiration time in ns.
+ */
+ void setExpirationTime(long time);
+
+ /**
+ * Gets the next entry in the recency list.
+ */
+ ReferenceEntry<K, V> getNextExpirable();
+
+ /**
+ * Sets the next entry in the recency list.
+ */
+ void setNextExpirable(ReferenceEntry<K, V> next);
+
+ /**
+ * Gets the previous entry in the recency list.
+ */
+ ReferenceEntry<K, V> getPreviousExpirable();
+
+ /**
+ * Sets the previous entry in the recency list.
+ */
+ void setPreviousExpirable(ReferenceEntry<K, V> previous);
+
+ /*
+ * Implemented by entries that are evictable. Evictable entries are maintained in a
+ * doubly-linked list. New entries are added at the tail of the list at write time and stale
+ * entries are expired from the head of the list.
+ */
+
+ /**
+ * Gets the next entry in the recency list.
+ */
+ ReferenceEntry<K, V> getNextEvictable();
+
+ /**
+ * Sets the next entry in the recency list.
+ */
+ void setNextEvictable(ReferenceEntry<K, V> next);
+
+ /**
+ * Gets the previous entry in the recency list.
+ */
+ ReferenceEntry<K, V> getPreviousEvictable();
+
+ /**
+ * Sets the previous entry in the recency list.
+ */
+ void setPreviousEvictable(ReferenceEntry<K, V> previous);
+ }
+
+ private enum NullEntry implements ReferenceEntry<Object, Object> {
+ INSTANCE;
+
+ @Override
+ public ValueReference<Object, Object> getValueReference() {
+ return null;
+ }
+
+ @Override
+ public void setValueReference(ValueReference<Object, Object> valueReference) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getNext() {
+ return null;
+ }
+
+ @Override
+ public int getHash() {
+ return 0;
+ }
+
+ @Override
+ public Object getKey() {
+ return null;
+ }
+
+ @Override
+ public long getExpirationTime() {
+ return 0;
+ }
+
+ @Override
+ public void setExpirationTime(long time) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getNextExpirable() {
+ return this;
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<Object, Object> next) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getPreviousExpirable() {
+ return this;
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<Object, Object> previous) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getNextEvictable() {
+ return this;
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<Object, Object> next) {}
+
+ @Override
+ public ReferenceEntry<Object, Object> getPreviousEvictable() {
+ return this;
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<Object, Object> previous) {}
+ }
+
+ abstract static class AbstractReferenceEntry<K, V> implements ReferenceEntry<K, V> {
+ @Override
+ public ValueReference<K, V> getValueReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setValueReference(ValueReference<K, V> valueReference) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getHash() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public K getKey() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getExpirationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value
+ static <K, V> ReferenceEntry<K, V> nullEntry() {
+ return (ReferenceEntry<K, V>) NullEntry.INSTANCE;
+ }
+
+ static final Queue<? extends Object> DISCARDING_QUEUE = new AbstractQueue<Object>() {
+ @Override
+ public boolean offer(Object o) {
+ return true;
+ }
+
+ @Override
+ public Object peek() {
+ return null;
+ }
+
+ @Override
+ public Object poll() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public Iterator<Object> iterator() {
+ return Iterators.emptyIterator();
+ }
+ };
+
+ /**
+ * Queue that discards all elements.
+ */
+ @SuppressWarnings("unchecked") // impl never uses a parameter or returns any non-null value
+ static <E> Queue<E> discardingQueue() {
+ return (Queue) DISCARDING_QUEUE;
+ }
+
+ /*
+ * Note: All of this duplicate code sucks, but it saves a lot of memory. If only Java had mixins!
+ * To maintain this code, make a change for the strong reference type. Then, cut and paste, and
+ * replace "Strong" with "Soft" or "Weak" within the pasted text. The primary difference is that
+ * strong entries store the key reference directly while soft and weak entries delegate to their
+ * respective superclasses.
+ */
+
+ /**
+ * Used for strongly-referenced keys.
+ */
+ static class StrongEntry<K, V> implements ReferenceEntry<K, V> {
+ final K key;
+
+ StrongEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ this.key = key;
+ this.hash = hash;
+ this.next = next;
+ }
+
+ @Override
+ public K getKey() {
+ return this.key;
+ }
+
+ // null expiration
+
+ @Override
+ public long getExpirationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // null eviction
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // The code below is exactly the same for each entry type.
+
+ final int hash;
+ final ReferenceEntry<K, V> next;
+ volatile ValueReference<K, V> valueReference = unset();
+
+ @Override
+ public ValueReference<K, V> getValueReference() {
+ return valueReference;
+ }
+
+ @Override
+ public void setValueReference(ValueReference<K, V> valueReference) {
+ ValueReference<K, V> previous = this.valueReference;
+ this.valueReference = valueReference;
+ previous.clear(valueReference);
+ }
+
+ @Override
+ public int getHash() {
+ return hash;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNext() {
+ return next;
+ }
+ }
+
+ static final class StrongExpirableEntry<K, V> extends StrongEntry<K, V>
+ implements ReferenceEntry<K, V> {
+ StrongExpirableEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(key, hash, next);
+ }
+
+ // The code below is exactly the same for each expirable entry type.
+
+ volatile long time = Long.MAX_VALUE;
+
+ @Override
+ public long getExpirationTime() {
+ return time;
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ this.time = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ return nextExpirable;
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ this.nextExpirable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ return previousExpirable;
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ this.previousExpirable = previous;
+ }
+ }
+
+ static final class StrongEvictableEntry<K, V>
+ extends StrongEntry<K, V> implements ReferenceEntry<K, V> {
+ StrongEvictableEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(key, hash, next);
+ }
+
+ // The code below is exactly the same for each evictable entry type.
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ return nextEvictable;
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ this.nextEvictable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ return previousEvictable;
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ this.previousEvictable = previous;
+ }
+ }
+
+ static final class StrongExpirableEvictableEntry<K, V>
+ extends StrongEntry<K, V> implements ReferenceEntry<K, V> {
+ StrongExpirableEvictableEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(key, hash, next);
+ }
+
+ // The code below is exactly the same for each expirable entry type.
+
+ volatile long time = Long.MAX_VALUE;
+
+ @Override
+ public long getExpirationTime() {
+ return time;
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ this.time = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ return nextExpirable;
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ this.nextExpirable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ return previousExpirable;
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ this.previousExpirable = previous;
+ }
+
+ // The code below is exactly the same for each evictable entry type.
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ return nextEvictable;
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ this.nextEvictable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ return previousEvictable;
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ this.previousEvictable = previous;
+ }
+ }
+
+ /**
+ * Used for softly-referenced keys.
+ */
+ static class SoftEntry<K, V> extends SoftReference<K> implements ReferenceEntry<K, V> {
+ SoftEntry(ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(key, queue);
+ this.hash = hash;
+ this.next = next;
+ }
+
+ @Override
+ public K getKey() {
+ return get();
+ }
+
+ // null expiration
+ @Override
+ public long getExpirationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // null eviction
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // The code below is exactly the same for each entry type.
+
+ final int hash;
+ final ReferenceEntry<K, V> next;
+ volatile ValueReference<K, V> valueReference = unset();
+
+ @Override
+ public ValueReference<K, V> getValueReference() {
+ return valueReference;
+ }
+
+ @Override
+ public void setValueReference(ValueReference<K, V> valueReference) {
+ ValueReference<K, V> previous = this.valueReference;
+ this.valueReference = valueReference;
+ previous.clear(valueReference);
+ }
+
+ @Override
+ public int getHash() {
+ return hash;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNext() {
+ return next;
+ }
+ }
+
+ static final class SoftExpirableEntry<K, V>
+ extends SoftEntry<K, V> implements ReferenceEntry<K, V> {
+ SoftExpirableEntry(
+ ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(queue, key, hash, next);
+ }
+
+ // The code below is exactly the same for each expirable entry type.
+
+ volatile long time = Long.MAX_VALUE;
+
+ @Override
+ public long getExpirationTime() {
+ return time;
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ this.time = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ return nextExpirable;
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ this.nextExpirable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ return previousExpirable;
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ this.previousExpirable = previous;
+ }
+ }
+
+ static final class SoftEvictableEntry<K, V>
+ extends SoftEntry<K, V> implements ReferenceEntry<K, V> {
+ SoftEvictableEntry(
+ ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(queue, key, hash, next);
+ }
+
+ // The code below is exactly the same for each evictable entry type.
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ return nextEvictable;
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ this.nextEvictable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ return previousEvictable;
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ this.previousEvictable = previous;
+ }
+ }
+
+ static final class SoftExpirableEvictableEntry<K, V>
+ extends SoftEntry<K, V> implements ReferenceEntry<K, V> {
+ SoftExpirableEvictableEntry(
+ ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(queue, key, hash, next);
+ }
+
+ // The code below is exactly the same for each expirable entry type.
+
+ volatile long time = Long.MAX_VALUE;
+
+ @Override
+ public long getExpirationTime() {
+ return time;
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ this.time = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ return nextExpirable;
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ this.nextExpirable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ return previousExpirable;
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ this.previousExpirable = previous;
+ }
+
+ // The code below is exactly the same for each evictable entry type.
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ return nextEvictable;
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ this.nextEvictable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ return previousEvictable;
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ this.previousEvictable = previous;
+ }
+ }
+
+ /**
+ * Used for weakly-referenced keys.
+ */
+ static class WeakEntry<K, V> extends WeakReference<K> implements ReferenceEntry<K, V> {
+ WeakEntry(ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(key, queue);
+ this.hash = hash;
+ this.next = next;
+ }
+
+ @Override
+ public K getKey() {
+ return get();
+ }
+
+ // null expiration
+
+ @Override
+ public long getExpirationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // null eviction
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ throw new UnsupportedOperationException();
+ }
+
+ // The code below is exactly the same for each entry type.
+
+ final int hash;
+ final ReferenceEntry<K, V> next;
+ volatile ValueReference<K, V> valueReference = unset();
+
+ @Override
+ public ValueReference<K, V> getValueReference() {
+ return valueReference;
+ }
+
+ @Override
+ public void setValueReference(ValueReference<K, V> valueReference) {
+ ValueReference<K, V> previous = this.valueReference;
+ this.valueReference = valueReference;
+ previous.clear(valueReference);
+ }
+
+ @Override
+ public int getHash() {
+ return hash;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getNext() {
+ return next;
+ }
+ }
+
+ static final class WeakExpirableEntry<K, V>
+ extends WeakEntry<K, V> implements ReferenceEntry<K, V> {
+ WeakExpirableEntry(
+ ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(queue, key, hash, next);
+ }
+
+ // The code below is exactly the same for each expirable entry type.
+
+ volatile long time = Long.MAX_VALUE;
+
+ @Override
+ public long getExpirationTime() {
+ return time;
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ this.time = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ return nextExpirable;
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ this.nextExpirable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ return previousExpirable;
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ this.previousExpirable = previous;
+ }
+ }
+
+ static final class WeakEvictableEntry<K, V>
+ extends WeakEntry<K, V> implements ReferenceEntry<K, V> {
+ WeakEvictableEntry(
+ ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(queue, key, hash, next);
+ }
+
+ // The code below is exactly the same for each evictable entry type.
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ return nextEvictable;
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ this.nextEvictable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ return previousEvictable;
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ this.previousEvictable = previous;
+ }
+ }
+
+ static final class WeakExpirableEvictableEntry<K, V>
+ extends WeakEntry<K, V> implements ReferenceEntry<K, V> {
+ WeakExpirableEvictableEntry(
+ ReferenceQueue<K> queue, K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ super(queue, key, hash, next);
+ }
+
+ // The code below is exactly the same for each expirable entry type.
+
+ volatile long time = Long.MAX_VALUE;
+
+ @Override
+ public long getExpirationTime() {
+ return time;
+ }
+
+ @Override
+ public void setExpirationTime(long time) {
+ this.time = time;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ return nextExpirable;
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ this.nextExpirable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousExpirable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ return previousExpirable;
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ this.previousExpirable = previous;
+ }
+
+ // The code below is exactly the same for each evictable entry type.
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> nextEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ return nextEvictable;
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ this.nextEvictable = next;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> previousEvictable = nullEntry();
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ return previousEvictable;
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ this.previousEvictable = previous;
+ }
+ }
+
+ /**
+ * References a weak value.
+ */
+ static final class WeakValueReference<K, V>
+ extends WeakReference<V> implements ValueReference<K, V> {
+ final ReferenceEntry<K, V> entry;
+
+ WeakValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry) {
+ super(referent, queue);
+ this.entry = entry;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return entry;
+ }
+
+ @Override
+ public void clear(ValueReference<K, V> newValue) {
+ clear();
+ }
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ return new WeakValueReference<K, V>(queue, value, entry);
+ }
+
+ @Override
+ public boolean isComputingReference() {
+ return false;
+ }
+
+ @Override
+ public V waitForValue() {
+ return get();
+ }
+ }
+
+ /**
+ * References a soft value.
+ */
+ static final class SoftValueReference<K, V>
+ extends SoftReference<V> implements ValueReference<K, V> {
+ final ReferenceEntry<K, V> entry;
+
+ SoftValueReference(ReferenceQueue<V> queue, V referent, ReferenceEntry<K, V> entry) {
+ super(referent, queue);
+ this.entry = entry;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return entry;
+ }
+
+ @Override
+ public void clear(ValueReference<K, V> newValue) {
+ clear();
+ }
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ return new SoftValueReference<K, V>(queue, value, entry);
+ }
+
+ @Override
+ public boolean isComputingReference() {
+ return false;
+ }
+
+ @Override
+ public V waitForValue() {
+ return get();
+ }
+ }
+
+ /**
+ * References a strong value.
+ */
+ static final class StrongValueReference<K, V> implements ValueReference<K, V> {
+ final V referent;
+
+ StrongValueReference(V referent) {
+ this.referent = referent;
+ }
+
+ @Override
+ public V get() {
+ return referent;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> getEntry() {
+ return null;
+ }
+
+ @Override
+ public ValueReference<K, V> copyFor(
+ ReferenceQueue<V> queue, V value, ReferenceEntry<K, V> entry) {
+ return this;
+ }
+
+ @Override
+ public boolean isComputingReference() {
+ return false;
+ }
+
+ @Override
+ public V waitForValue() {
+ return get();
+ }
+
+ @Override
+ public void clear(ValueReference<K, V> newValue) {}
+ }
+
+ /**
+ * Applies a supplemental hash function to a given hash code, which defends against poor quality
+ * hash functions. This is critical when the concurrent hash map uses power-of-two length hash
+ * tables, that otherwise encounter collisions for hash codes that do not differ in lower or
+ * upper bits.
+ *
+ * @param h hash code
+ */
+ static int rehash(int h) {
+ // Spread bits to regularize both segment and index locations,
+ // using variant of single-word Wang/Jenkins hash.
+ // TODO(kevinb): use Hashing/move this to Hashing?
+ h += (h << 15) ^ 0xffffcd7d;
+ h ^= (h >>> 10);
+ h += (h << 3);
+ h ^= (h >>> 6);
+ h += (h << 2) + (h << 14);
+ return h ^ (h >>> 16);
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link Segment#newEntry} directly.
+ */
+ @GuardedBy("Segment.this")
+ @VisibleForTesting
+ ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> next) {
+ return segmentFor(hash).newEntry(key, hash, next);
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link Segment#copyEntry} directly.
+ */
+ @GuardedBy("Segment.this")
+ @VisibleForTesting
+ ReferenceEntry<K, V> copyEntry(ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
+ int hash = original.getHash();
+ return segmentFor(hash).copyEntry(original, newNext);
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link Segment#setValue} instead.
+ */
+ @GuardedBy("Segment.this")
+ @VisibleForTesting
+ ValueReference<K, V> newValueReference(ReferenceEntry<K, V> entry, V value) {
+ int hash = entry.getHash();
+ return valueStrength.referenceValue(segmentFor(hash), entry, value);
+ }
+
+ int hash(Object key) {
+ int h = keyEquivalence.hash(key);
+ return rehash(h);
+ }
+
+ void reclaimValue(ValueReference<K, V> valueReference) {
+ ReferenceEntry<K, V> entry = valueReference.getEntry();
+ int hash = entry.getHash();
+ segmentFor(hash).reclaimValue(entry.getKey(), hash, valueReference);
+ }
+
+ void reclaimKey(ReferenceEntry<K, V> entry) {
+ int hash = entry.getHash();
+ segmentFor(hash).reclaimKey(entry, hash);
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link Segment#getLiveValue}
+ * instead.
+ */
+ @VisibleForTesting
+ boolean isLive(ReferenceEntry<K, V> entry) {
+ return segmentFor(entry.getHash()).getLiveValue(entry) != null;
+ }
+
+ /**
+ * Returns the segment that should be used for a key with the given hash.
+ *
+ * @param hash the hash code for the key
+ * @return the segment
+ */
+ Segment<K, V> segmentFor(int hash) {
+ // TODO(fry): Lazily create segments?
+ return segments[(hash >>> segmentShift) & segmentMask];
+ }
+
+ Segment<K, V> createSegment(int initialCapacity, int maxSegmentSize) {
+ return new Segment<K, V>(this, initialCapacity, maxSegmentSize);
+ }
+
+ /**
+ * Gets the value from an entry. Returns {@code null} if the entry is invalid,
+ * partially-collected, computing, or expired. Unlike {@link Segment#getLiveValue} this method
+ * does not attempt to clean up stale entries.
+ */
+ V getLiveValue(ReferenceEntry<K, V> entry) {
+ if (entry.getKey() == null) {
+ return null;
+ }
+ V value = entry.getValueReference().get();
+ if (value == null) {
+ return null;
+ }
+
+ if (expires() && isExpired(entry)) {
+ return null;
+ }
+ return value;
+ }
+
+ // expiration
+
+ /**
+ * Returns {@code true} if the entry has expired.
+ */
+ boolean isExpired(ReferenceEntry<K, V> entry) {
+ return isExpired(entry, ticker.read());
+ }
+
+ /**
+ * Returns {@code true} if the entry has expired.
+ */
+ boolean isExpired(ReferenceEntry<K, V> entry, long now) {
+ // if the expiration time had overflowed, this "undoes" the overflow
+ return now - entry.getExpirationTime() > 0;
+ }
+
+ @GuardedBy("Segment.this")
+ static <K, V> void connectExpirables(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
+ previous.setNextExpirable(next);
+ next.setPreviousExpirable(previous);
+ }
+
+ @GuardedBy("Segment.this")
+ static <K, V> void nullifyExpirable(ReferenceEntry<K, V> nulled) {
+ ReferenceEntry<K, V> nullEntry = nullEntry();
+ nulled.setNextExpirable(nullEntry);
+ nulled.setPreviousExpirable(nullEntry);
+ }
+
+ // eviction
+
+ /**
+ * Notifies listeners that an entry has been automatically removed due to expiration, eviction,
+ * or eligibility for garbage collection. This should be called every time expireEntries or
+ * evictEntry is called (once the lock is released).
+ */
+ void processPendingNotifications() {
+ RemovalNotification<K, V> notification;
+ while ((notification = removalNotificationQueue.poll()) != null) {
+ try {
+ removalListener.onRemoval(notification);
+ } catch (Exception e) {
+ logger.log(Level.WARNING, "Exception thrown by removal listener", e);
+ }
+ }
+ }
+
+ /** Links the evitables together. */
+ @GuardedBy("Segment.this")
+ static <K, V> void connectEvictables(ReferenceEntry<K, V> previous, ReferenceEntry<K, V> next) {
+ previous.setNextEvictable(next);
+ next.setPreviousEvictable(previous);
+ }
+
+ @GuardedBy("Segment.this")
+ static <K, V> void nullifyEvictable(ReferenceEntry<K, V> nulled) {
+ ReferenceEntry<K, V> nullEntry = nullEntry();
+ nulled.setNextEvictable(nullEntry);
+ nulled.setPreviousEvictable(nullEntry);
+ }
+
+ @SuppressWarnings("unchecked")
+ final Segment<K, V>[] newSegmentArray(int ssize) {
+ return new Segment[ssize];
+ }
+
+ // Inner Classes
+
+ /**
+ * Segments are specialized versions of hash tables. This subclass inherits from ReentrantLock
+ * opportunistically, just to simplify some locking and avoid separate construction.
+ */
+ @SuppressWarnings("serial") // This class is never serialized.
+ static class Segment<K, V> extends ReentrantLock {
+
+ /*
+ * TODO(fry): Consider copying variables (like evictsBySize) from outer class into this class.
+ * It will require more memory but will reduce indirection.
+ */
+
+ /*
+ * Segments maintain a table of entry lists that are ALWAYS kept in a consistent state, so can
+ * be read without locking. Next fields of nodes are immutable (final). All list additions are
+ * performed at the front of each bin. This makes it easy to check changes, and also fast to
+ * traverse. When nodes would otherwise be changed, new nodes are created to replace them. This
+ * works well for hash tables since the bin lists tend to be short. (The average length is less
+ * than two.)
+ *
+ * Read operations can thus proceed without locking, but rely on selected uses of volatiles to
+ * ensure that completed write operations performed by other threads are noticed. For most
+ * purposes, the "count" field, tracking the number of elements, serves as that volatile
+ * variable ensuring visibility. This is convenient because this field needs to be read in many
+ * read operations anyway:
+ *
+ * - All (unsynchronized) read operations must first read the "count" field, and should not
+ * look at table entries if it is 0.
+ *
+ * - All (synchronized) write operations should write to the "count" field after structurally
+ * changing any bin. The operations must not take any action that could even momentarily
+ * cause a concurrent read operation to see inconsistent data. This is made easier by the
+ * nature of the read operations in Map. For example, no operation can reveal that the table
+ * has grown but the threshold has not yet been updated, so there are no atomicity requirements
+ * for this with respect to reads.
+ *
+ * As a guide, all critical volatile reads and writes to the count field are marked in code
+ * comments.
+ */
+
+ final MapMakerInternalMap<K, V> map;
+
+ /**
+ * The number of live elements in this segment's region. This does not include unset elements
+ * which are awaiting cleanup.
+ */
+ volatile int count;
+
+ /**
+ * Number of updates that alter the size of the table. This is used during bulk-read methods to
+ * make sure they see a consistent snapshot: If modCounts change during a traversal of segments
+ * computing size or checking containsValue, then we might have an inconsistent view of state
+ * so (usually) must retry.
+ */
+ int modCount;
+
+ /**
+ * The table is expanded when its size exceeds this threshold. (The value of this field is
+ * always {@code (int)(capacity * 0.75)}.)
+ */
+ int threshold;
+
+ /**
+ * The per-segment table.
+ */
+ volatile AtomicReferenceArray<ReferenceEntry<K, V>> table;
+
+ /**
+ * The maximum size of this map. MapMaker.UNSET_INT if there is no maximum.
+ */
+ final int maxSegmentSize;
+
+ /**
+ * The key reference queue contains entries whose keys have been garbage collected, and which
+ * need to be cleaned up internally.
+ */
+ final ReferenceQueue<K> keyReferenceQueue;
+
+ /**
+ * The value reference queue contains value references whose values have been garbage collected,
+ * and which need to be cleaned up internally.
+ */
+ final ReferenceQueue<V> valueReferenceQueue;
+
+ /**
+ * The recency queue is used to record which entries were accessed for updating the eviction
+ * list's ordering. It is drained as a batch operation when either the DRAIN_THRESHOLD is
+ * crossed or a write occurs on the segment.
+ */
+ final Queue<ReferenceEntry<K, V>> recencyQueue;
+
+ /**
+ * A counter of the number of reads since the last write, used to drain queues on a small
+ * fraction of read operations.
+ */
+ final AtomicInteger readCount = new AtomicInteger();
+
+ /**
+ * A queue of elements currently in the map, ordered by access time. Elements are added to the
+ * tail of the queue on access/write.
+ */
+ @GuardedBy("Segment.this")
+ final Queue<ReferenceEntry<K, V>> evictionQueue;
+
+ /**
+ * A queue of elements currently in the map, ordered by expiration time (either access or write
+ * time). Elements are added to the tail of the queue on access/write.
+ */
+ @GuardedBy("Segment.this")
+ final Queue<ReferenceEntry<K, V>> expirationQueue;
+
+ Segment(MapMakerInternalMap<K, V> map, int initialCapacity, int maxSegmentSize) {
+ this.map = map;
+ this.maxSegmentSize = maxSegmentSize;
+ initTable(newEntryArray(initialCapacity));
+
+ keyReferenceQueue = map.usesKeyReferences()
+ ? new ReferenceQueue<K>() : null;
+
+ valueReferenceQueue = map.usesValueReferences()
+ ? new ReferenceQueue<V>() : null;
+
+ recencyQueue = (map.evictsBySize() || map.expiresAfterAccess())
+ ? new ConcurrentLinkedQueue<ReferenceEntry<K, V>>()
+ : MapMakerInternalMap.<ReferenceEntry<K, V>>discardingQueue();
+
+ evictionQueue = map.evictsBySize()
+ ? new EvictionQueue<K, V>()
+ : MapMakerInternalMap.<ReferenceEntry<K, V>>discardingQueue();
+
+ expirationQueue = map.expires()
+ ? new ExpirationQueue<K, V>()
+ : MapMakerInternalMap.<ReferenceEntry<K, V>>discardingQueue();
+ }
+
+ AtomicReferenceArray<ReferenceEntry<K, V>> newEntryArray(int size) {
+ return new AtomicReferenceArray<ReferenceEntry<K, V>>(size);
+ }
+
+ void initTable(AtomicReferenceArray<ReferenceEntry<K, V>> newTable) {
+ this.threshold = newTable.length() * 3 / 4; // 0.75
+ if (this.threshold == maxSegmentSize) {
+ // prevent spurious expansion before eviction
+ this.threshold++;
+ }
+ this.table = newTable;
+ }
+
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> newEntry(K key, int hash, @Nullable ReferenceEntry<K, V> 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.isComputingReference()) {
+ // value collected
+ return null;
+ }
+
+ ReferenceEntry<K, V> newEntry = map.entryFactory.copyEntry(this, original, newNext);
+ newEntry.setValueReference(valueReference.copyFor(this.valueReferenceQueue, value, newEntry));
+ return newEntry;
+ }
+
+ /**
+ * Sets a new value of an entry. Adds newly created entries at the end of the expiration queue.
+ */
+ @GuardedBy("Segment.this")
+ void setValue(ReferenceEntry<K, V> entry, V value) {
+ ValueReference<K, V> valueReference = map.valueStrength.referenceValue(this, entry, value);
+ entry.setValueReference(valueReference);
+ recordWrite(entry);
+ }
+
+ // reference queues, for garbage collection cleanup
+
+ /**
+ * Cleanup collected entries when the lock is available.
+ */
+ void tryDrainReferenceQueues() {
+ if (tryLock()) {
+ try {
+ drainReferenceQueues();
+ } finally {
+ unlock();
+ }
+ }
+ }
+
+ /**
+ * Drain the key and value reference queues, cleaning up internal entries containing garbage
+ * collected keys or values.
+ */
+ @GuardedBy("Segment.this")
+ void drainReferenceQueues() {
+ if (map.usesKeyReferences()) {
+ drainKeyReferenceQueue();
+ }
+ if (map.usesValueReferences()) {
+ drainValueReferenceQueue();
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ void drainKeyReferenceQueue() {
+ Reference<? extends K> ref;
+ int i = 0;
+ while ((ref = keyReferenceQueue.poll()) != null) {
+ @SuppressWarnings("unchecked")
+ ReferenceEntry<K, V> entry = (ReferenceEntry<K, V>) ref;
+ map.reclaimKey(entry);
+ if (++i == DRAIN_MAX) {
+ break;
+ }
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ void drainValueReferenceQueue() {
+ Reference<? extends V> ref;
+ int i = 0;
+ while ((ref = valueReferenceQueue.poll()) != null) {
+ @SuppressWarnings("unchecked")
+ ValueReference<K, V> valueReference = (ValueReference<K, V>) ref;
+ map.reclaimValue(valueReference);
+ if (++i == DRAIN_MAX) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Clears all entries from the key and value reference queues.
+ */
+ void clearReferenceQueues() {
+ if (map.usesKeyReferences()) {
+ clearKeyReferenceQueue();
+ }
+ if (map.usesValueReferences()) {
+ clearValueReferenceQueue();
+ }
+ }
+
+ void clearKeyReferenceQueue() {
+ while (keyReferenceQueue.poll() != null) {}
+ }
+
+ void clearValueReferenceQueue() {
+ while (valueReferenceQueue.poll() != null) {}
+ }
+
+ // recency queue, shared by expiration and eviction
+
+ /**
+ * Records the relative order in which this read was performed by adding {@code entry} to the
+ * recency queue. At write-time, or when the queue is full past the threshold, the queue will
+ * be drained and the entries therein processed.
+ *
+ * <p>Note: locked reads should use {@link #recordLockedRead}.
+ */
+ void recordRead(ReferenceEntry<K, V> entry) {
+ if (map.expiresAfterAccess()) {
+ recordExpirationTime(entry, map.expireAfterAccessNanos);
+ }
+ recencyQueue.add(entry);
+ }
+
+ /**
+ * Updates the eviction metadata that {@code entry} was just read. This currently amounts to
+ * adding {@code entry} to relevant eviction lists.
+ *
+ * <p>Note: this method should only be called under lock, as it directly manipulates the
+ * eviction queues. Unlocked reads should use {@link #recordRead}.
+ */
+ @GuardedBy("Segment.this")
+ void recordLockedRead(ReferenceEntry<K, V> entry) {
+ evictionQueue.add(entry);
+ if (map.expiresAfterAccess()) {
+ recordExpirationTime(entry, map.expireAfterAccessNanos);
+ expirationQueue.add(entry);
+ }
+ }
+
+ /**
+ * Updates eviction metadata that {@code entry} was just written. This currently amounts to
+ * adding {@code entry} to relevant eviction lists.
+ */
+ @GuardedBy("Segment.this")
+ void recordWrite(ReferenceEntry<K, V> entry) {
+ // we are already under lock, so drain the recency queue immediately
+ drainRecencyQueue();
+ evictionQueue.add(entry);
+ if (map.expires()) {
+ // currently MapMaker ensures that expireAfterWrite and
+ // expireAfterAccess are mutually exclusive
+ long expiration = map.expiresAfterAccess()
+ ? map.expireAfterAccessNanos
+ : map.expireAfterWriteNanos;
+ recordExpirationTime(entry, expiration);
+ expirationQueue.add(entry);
+ }
+ }
+
+ /**
+ * Drains the recency queue, updating eviction metadata that the entries therein were read in
+ * the specified relative order. This currently amounts to adding them to relevant eviction
+ * lists (accounting for the fact that they could have been removed from the map since being
+ * added to the recency queue).
+ */
+ @GuardedBy("Segment.this")
+ void drainRecencyQueue() {
+ ReferenceEntry<K, V> e;
+ while ((e = recencyQueue.poll()) != null) {
+ // An entry may be in the recency queue despite it being removed from
+ // the map . This can occur when the entry was concurrently read while a
+ // writer is removing it from the segment or after a clear has removed
+ // all of the segment's entries.
+ if (evictionQueue.contains(e)) {
+ evictionQueue.add(e);
+ }
+ if (map.expiresAfterAccess() && expirationQueue.contains(e)) {
+ expirationQueue.add(e);
+ }
+ }
+ }
+
+ // expiration
+
+ void recordExpirationTime(ReferenceEntry<K, V> entry, long expirationNanos) {
+ // might overflow, but that's okay (see isExpired())
+ entry.setExpirationTime(map.ticker.read() + expirationNanos);
+ }
+
+ /**
+ * Cleanup expired entries when the lock is available.
+ */
+ void tryExpireEntries() {
+ if (tryLock()) {
+ try {
+ expireEntries();
+ } finally {
+ unlock();
+ // don't call postWriteCleanup as we're in a read
+ }
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ void expireEntries() {
+ drainRecencyQueue();
+
+ if (expirationQueue.isEmpty()) {
+ // There's no point in calling nanoTime() if we have no entries to
+ // expire.
+ return;
+ }
+ long now = map.ticker.read();
+ ReferenceEntry<K, V> e;
+ while ((e = expirationQueue.peek()) != null && map.isExpired(e, now)) {
+ if (!removeEntry(e, e.getHash(), RemovalCause.EXPIRED)) {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ // eviction
+
+ void enqueueNotification(ReferenceEntry<K, V> entry, RemovalCause cause) {
+ enqueueNotification(entry.getKey(), entry.getHash(), entry.getValueReference().get(), cause);
+ }
+
+ void enqueueNotification(@Nullable K key, int hash, @Nullable V value, RemovalCause cause) {
+ if (map.removalNotificationQueue != DISCARDING_QUEUE) {
+ RemovalNotification<K, V> notification = new RemovalNotification<K, V>(key, value, cause);
+ map.removalNotificationQueue.offer(notification);
+ }
+ }
+
+ /**
+ * Performs eviction if the segment is full. This should only be called prior to adding a new
+ * entry and increasing {@code count}.
+ *
+ * @return {@code true} if eviction occurred
+ */
+ @GuardedBy("Segment.this")
+ boolean evictEntries() {
+ if (map.evictsBySize() && count >= maxSegmentSize) {
+ drainRecencyQueue();
+
+ ReferenceEntry<K, V> e = evictionQueue.remove();
+ if (!removeEntry(e, e.getHash(), RemovalCause.SIZE)) {
+ throw new AssertionError();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns first entry of bin for given hash.
+ */
+ ReferenceEntry<K, V> getFirst(int hash) {
+ // read this volatile field only once
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ return table.get(hash & (table.length() - 1));
+ }
+
+ // Specialized implementations of map methods
+
+ ReferenceEntry<K, V> getEntry(Object key, int hash) {
+ if (count != 0) { // read-volatile
+ for (ReferenceEntry<K, V> e = getFirst(hash); e != null; e = e.getNext()) {
+ if (e.getHash() != hash) {
+ continue;
+ }
+
+ K entryKey = e.getKey();
+ if (entryKey == null) {
+ tryDrainReferenceQueues();
+ continue;
+ }
+
+ if (map.keyEquivalence.equivalent(key, entryKey)) {
+ return e;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ ReferenceEntry<K, V> getLiveEntry(Object key, int hash) {
+ ReferenceEntry<K, V> e = getEntry(key, hash);
+ if (e == null) {
+ return null;
+ } else if (map.expires() && map.isExpired(e)) {
+ tryExpireEntries();
+ return null;
+ }
+ return e;
+ }
+
+ V get(Object key, int hash) {
+ try {
+ ReferenceEntry<K, V> e = getLiveEntry(key, hash);
+ if (e == null) {
+ return null;
+ }
+
+ V value = e.getValueReference().get();
+ if (value != null) {
+ recordRead(e);
+ } else {
+ tryDrainReferenceQueues();
+ }
+ return value;
+ } finally {
+ postReadCleanup();
+ }
+ }
+
+ boolean containsKey(Object key, int hash) {
+ try {
+ if (count != 0) { // read-volatile
+ ReferenceEntry<K, V> e = getLiveEntry(key, hash);
+ if (e == null) {
+ return false;
+ }
+ return e.getValueReference().get() != null;
+ }
+
+ return false;
+ } finally {
+ postReadCleanup();
+ }
+ }
+
+ /**
+ * This method is a convenience for testing. Code should call {@link
+ * MapMakerInternalMap#containsValue} directly.
+ */
+ @VisibleForTesting
+ boolean containsValue(Object value) {
+ try {
+ if (count != 0) { // read-volatile
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int length = table.length();
+ for (int i = 0; i < length; ++i) {
+ for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) {
+ V entryValue = getLiveValue(e);
+ if (entryValue == null) {
+ continue;
+ }
+ if (map.valueEquivalence.equivalent(value, entryValue)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ } finally {
+ postReadCleanup();
+ }
+ }
+
+ V put(K key, int hash, V value, boolean onlyIfAbsent) {
+ lock();
+ try {
+ preWriteCleanup();
+
+ 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);
+
+ // Look for an existing entry.
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ // We found an existing entry.
+
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+
+ if (entryValue == null) {
+ ++modCount;
+ setValue(e, value);
+ if (!valueReference.isComputingReference()) {
+ enqueueNotification(key, hash, entryValue, RemovalCause.COLLECTED);
+ newCount = this.count; // count remains unchanged
+ } else if (evictEntries()) { // evictEntries after setting new value
+ newCount = this.count + 1;
+ }
+ this.count = newCount; // write-volatile
+ return null;
+ } else if (onlyIfAbsent) {
+ // Mimic
+ // "if (!map.containsKey(key)) ...
+ // else return map.get(key);
+ recordLockedRead(e);
+ return entryValue;
+ } else {
+ // clobber existing entry, count remains unchanged
+ ++modCount;
+ enqueueNotification(key, hash, entryValue, RemovalCause.REPLACED);
+ setValue(e, value);
+ return entryValue;
+ }
+ }
+ }
+
+ // Create a new entry.
+ ++modCount;
+ ReferenceEntry<K, V> newEntry = newEntry(key, hash, first);
+ setValue(newEntry, value);
+ table.set(index, newEntry);
+ if (evictEntries()) { // evictEntries after setting new value
+ newCount = this.count + 1;
+ }
+ this.count = newCount; // write-volatile
+ return null;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ /**
+ * Expands the table if possible.
+ */
+ @GuardedBy("Segment.this")
+ void expand() {
+ AtomicReferenceArray<ReferenceEntry<K, V>> oldTable = table;
+ int oldCapacity = oldTable.length();
+ if (oldCapacity >= MAXIMUM_CAPACITY) {
+ return;
+ }
+
+ /*
+ * Reclassify nodes in each list to new Map. Because we are using power-of-two expansion, the
+ * elements from each bin must either stay at same index, or move with a power of two offset.
+ * We eliminate unnecessary node creation by catching cases where old nodes can be reused
+ * because their next fields won't change. Statistically, at the default threshold, only
+ * about one-sixth of them need cloning when a table doubles. The nodes they replace will be
+ * garbage collectable as soon as they are no longer referenced by any reader thread that may
+ * be in the midst of traversing table right now.
+ */
+
+ int newCount = count;
+ AtomicReferenceArray<ReferenceEntry<K, V>> newTable = newEntryArray(oldCapacity << 1);
+ threshold = newTable.length() * 3 / 4;
+ int newMask = newTable.length() - 1;
+ for (int oldIndex = 0; oldIndex < oldCapacity; ++oldIndex) {
+ // We need to guarantee that any existing reads of old Map can
+ // proceed. So we cannot yet null out each bin.
+ ReferenceEntry<K, V> head = oldTable.get(oldIndex);
+
+ if (head != null) {
+ ReferenceEntry<K, V> next = head.getNext();
+ int headIndex = head.getHash() & newMask;
+
+ // Single node on list
+ if (next == null) {
+ newTable.set(headIndex, head);
+ } else {
+ // Reuse the consecutive sequence of nodes with the same target
+ // index from the end of the list. tail points to the first
+ // entry in the reusable list.
+ ReferenceEntry<K, V> tail = head;
+ int tailIndex = headIndex;
+ for (ReferenceEntry<K, V> e = next; e != null; e = e.getNext()) {
+ int newIndex = e.getHash() & newMask;
+ if (newIndex != tailIndex) {
+ // The index changed. We'll need to copy the previous entry.
+ tailIndex = newIndex;
+ tail = e;
+ }
+ }
+ newTable.set(tailIndex, tail);
+
+ // 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 {
+ removeCollectedEntry(e);
+ newCount--;
+ }
+ }
+ }
+ }
+ }
+ table = newTable;
+ this.count = newCount;
+ }
+
+ boolean replace(K key, int hash, V oldValue, V newValue) {
+ lock();
+ try {
+ preWriteCleanup();
+
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ // If the value disappeared, this entry is partially collected,
+ // and we should pretend like it doesn't exist.
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+ if (entryValue == null) {
+ if (isCollected(valueReference)) {
+ int newCount = this.count - 1;
+ ++modCount;
+ enqueueNotification(entryKey, hash, entryValue, RemovalCause.COLLECTED);
+ ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ }
+ return false;
+ }
+
+ if (map.valueEquivalence.equivalent(oldValue, entryValue)) {
+ ++modCount;
+ enqueueNotification(key, hash, entryValue, RemovalCause.REPLACED);
+ setValue(e, newValue);
+ return true;
+ } else {
+ // Mimic
+ // "if (map.containsKey(key) && map.get(key).equals(oldValue))..."
+ recordLockedRead(e);
+ return false;
+ }
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ V replace(K key, int hash, V newValue) {
+ lock();
+ try {
+ preWriteCleanup();
+
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ // If the value disappeared, this entry is partially collected,
+ // and we should pretend like it doesn't exist.
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+ if (entryValue == null) {
+ if (isCollected(valueReference)) {
+ int newCount = this.count - 1;
+ ++modCount;
+ enqueueNotification(entryKey, hash, entryValue, RemovalCause.COLLECTED);
+ ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ }
+ return null;
+ }
+
+ ++modCount;
+ enqueueNotification(key, hash, entryValue, RemovalCause.REPLACED);
+ setValue(e, newValue);
+ return entryValue;
+ }
+ }
+
+ return null;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ V remove(Object key, int hash) {
+ lock();
+ try {
+ preWriteCleanup();
+
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+
+ RemovalCause cause;
+ if (entryValue != null) {
+ cause = RemovalCause.EXPLICIT;
+ } else if (isCollected(valueReference)) {
+ cause = RemovalCause.COLLECTED;
+ } else {
+ return null;
+ }
+
+ ++modCount;
+ enqueueNotification(entryKey, hash, entryValue, cause);
+ ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return entryValue;
+ }
+ }
+
+ return null;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ boolean remove(Object key, int hash, Object value) {
+ lock();
+ try {
+ preWriteCleanup();
+
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> valueReference = e.getValueReference();
+ V entryValue = valueReference.get();
+
+ RemovalCause cause;
+ if (map.valueEquivalence.equivalent(value, entryValue)) {
+ cause = RemovalCause.EXPLICIT;
+ } else if (isCollected(valueReference)) {
+ cause = RemovalCause.COLLECTED;
+ } else {
+ return false;
+ }
+
+ ++modCount;
+ enqueueNotification(entryKey, hash, entryValue, cause);
+ ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return (cause == RemovalCause.EXPLICIT);
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ void clear() {
+ if (count != 0) {
+ lock();
+ try {
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ if (map.removalNotificationQueue != DISCARDING_QUEUE) {
+ for (int i = 0; i < table.length(); ++i) {
+ for (ReferenceEntry<K, V> e = table.get(i); e != null; e = e.getNext()) {
+ // Computing references aren't actually in the map yet.
+ if (!e.getValueReference().isComputingReference()) {
+ enqueueNotification(e, RemovalCause.EXPLICIT);
+ }
+ }
+ }
+ }
+ for (int i = 0; i < table.length(); ++i) {
+ table.set(i, null);
+ }
+ clearReferenceQueues();
+ evictionQueue.clear();
+ expirationQueue.clear();
+ readCount.set(0);
+
+ ++modCount;
+ count = 0; // write-volatile
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+ }
+
+ /**
+ * Removes an entry from within a table. All entries following the removed node can stay, but
+ * all preceding ones need to be cloned.
+ *
+ * <p>This method does not decrement count for the removed entry, but does decrement count for
+ * all partially collected entries which are skipped. As such callers which are modifying count
+ * must re-read it after calling removeFromChain.
+ *
+ * @param first the first entry of the table
+ * @param entry the entry being removed from the table
+ * @return the new first entry for the table
+ */
+ @GuardedBy("Segment.this")
+ ReferenceEntry<K, V> removeFromChain(ReferenceEntry<K, V> first, ReferenceEntry<K, V> entry) {
+ evictionQueue.remove(entry);
+ expirationQueue.remove(entry);
+
+ 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 {
+ removeCollectedEntry(e);
+ newCount--;
+ }
+ }
+ this.count = newCount;
+ return newFirst;
+ }
+
+ void removeCollectedEntry(ReferenceEntry<K, V> entry) {
+ enqueueNotification(entry, RemovalCause.COLLECTED);
+ evictionQueue.remove(entry);
+ expirationQueue.remove(entry);
+ }
+
+ /**
+ * Removes an entry whose key has been garbage collected.
+ */
+ boolean reclaimKey(ReferenceEntry<K, V> entry, int hash) {
+ lock();
+ try {
+ int newCount = count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ if (e == entry) {
+ ++modCount;
+ enqueueNotification(
+ e.getKey(), hash, e.getValueReference().get(), RemovalCause.COLLECTED);
+ ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return true;
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ /**
+ * Removes an entry whose value has been garbage collected.
+ */
+ boolean reclaimValue(K key, int hash, ValueReference<K, V> valueReference) {
+ lock();
+ try {
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> v = e.getValueReference();
+ if (v == valueReference) {
+ ++modCount;
+ enqueueNotification(key, hash, valueReference.get(), RemovalCause.COLLECTED);
+ ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return true;
+ }
+ return false;
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ if (!isHeldByCurrentThread()) { // don't cleanup inside of put
+ postWriteCleanup();
+ }
+ }
+ }
+
+ /**
+ * Clears a value that has not yet been set, and thus does not require count to be modified.
+ */
+ boolean clearValue(K key, int hash, ValueReference<K, V> valueReference) {
+ lock();
+ try {
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ K entryKey = e.getKey();
+ if (e.getHash() == hash && entryKey != null
+ && map.keyEquivalence.equivalent(key, entryKey)) {
+ ValueReference<K, V> v = e.getValueReference();
+ if (v == valueReference) {
+ ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
+ table.set(index, newFirst);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ return false;
+ } finally {
+ unlock();
+ postWriteCleanup();
+ }
+ }
+
+ @GuardedBy("Segment.this")
+ boolean removeEntry(ReferenceEntry<K, V> entry, int hash, RemovalCause cause) {
+ int newCount = this.count - 1;
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
+ int index = hash & (table.length() - 1);
+ ReferenceEntry<K, V> first = table.get(index);
+
+ for (ReferenceEntry<K, V> e = first; e != null; e = e.getNext()) {
+ if (e == entry) {
+ ++modCount;
+ enqueueNotification(e.getKey(), hash, e.getValueReference().get(), cause);
+ ReferenceEntry<K, V> newFirst = removeFromChain(first, e);
+ newCount = this.count - 1;
+ table.set(index, newFirst);
+ this.count = newCount; // write-volatile
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * 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.
+ */
+ boolean isCollected(ValueReference<K, V> valueReference) {
+ if (valueReference.isComputingReference()) {
+ return false;
+ }
+ return (valueReference.get() == null);
+ }
+
+ /**
+ * Gets the value from an entry. Returns {@code null} if the entry is invalid,
+ * partially-collected, computing, or expired.
+ */
+ V getLiveValue(ReferenceEntry<K, V> entry) {
+ if (entry.getKey() == null) {
+ tryDrainReferenceQueues();
+ return null;
+ }
+ V value = entry.getValueReference().get();
+ if (value == null) {
+ tryDrainReferenceQueues();
+ return null;
+ }
+
+ if (map.expires() && map.isExpired(entry)) {
+ tryExpireEntries();
+ return null;
+ }
+ return value;
+ }
+
+ /**
+ * Performs routine cleanup following a read. Normally cleanup happens during writes, or from
+ * the cleanupExecutor. If cleanup is not observed after a sufficient number of reads, try
+ * cleaning up from the read thread.
+ */
+ void postReadCleanup() {
+ if ((readCount.incrementAndGet() & DRAIN_THRESHOLD) == 0) {
+ runCleanup();
+ }
+ }
+
+ /**
+ * Performs routine cleanup prior to executing a write. This should be called every time a
+ * write thread acquires the segment lock, immediately after acquiring the lock.
+ *
+ * <p>Post-condition: expireEntries has been run.
+ */
+ @GuardedBy("Segment.this")
+ void preWriteCleanup() {
+ runLockedCleanup();
+ }
+
+ /**
+ * Performs routine cleanup following a write.
+ */
+ void postWriteCleanup() {
+ runUnlockedCleanup();
+ }
+
+ void runCleanup() {
+ runLockedCleanup();
+ runUnlockedCleanup();
+ }
+
+ void runLockedCleanup() {
+ if (tryLock()) {
+ try {
+ drainReferenceQueues();
+ expireEntries(); // calls drainRecencyQueue
+ readCount.set(0);
+ } finally {
+ unlock();
+ }
+ }
+ }
+
+ void runUnlockedCleanup() {
+ // locked cleanup may generate notifications we can send unlocked
+ if (!isHeldByCurrentThread()) {
+ map.processPendingNotifications();
+ }
+ }
+
+ }
+
+ // Queues
+
+ /**
+ * A custom queue for managing eviction order. Note that this is tightly integrated with {@code
+ * ReferenceEntry}, upon which it relies to perform its linking.
+ *
+ * <p>Note that this entire implementation makes the assumption that all elements which are in
+ * the map are also in this queue, and that all elements not in the queue are not in the map.
+ *
+ * <p>The benefits of creating our own queue are that (1) we can replace elements in the middle
+ * of the queue as part of copyEvictableEntry, and (2) the contains method is highly optimized
+ * for the current model.
+ */
+ static final class EvictionQueue<K, V> extends AbstractQueue<ReferenceEntry<K, V>> {
+ final ReferenceEntry<K, V> head = new AbstractReferenceEntry<K, V>() {
+
+ ReferenceEntry<K, V> nextEvictable = this;
+
+ @Override
+ public ReferenceEntry<K, V> getNextEvictable() {
+ return nextEvictable;
+ }
+
+ @Override
+ public void setNextEvictable(ReferenceEntry<K, V> next) {
+ this.nextEvictable = next;
+ }
+
+ ReferenceEntry<K, V> previousEvictable = this;
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousEvictable() {
+ return previousEvictable;
+ }
+
+ @Override
+ public void setPreviousEvictable(ReferenceEntry<K, V> previous) {
+ this.previousEvictable = previous;
+ }
+ };
+
+ // implements Queue
+
+ @Override
+ public boolean offer(ReferenceEntry<K, V> entry) {
+ // unlink
+ connectEvictables(entry.getPreviousEvictable(), entry.getNextEvictable());
+
+ // add to tail
+ connectEvictables(head.getPreviousEvictable(), entry);
+ connectEvictables(entry, head);
+
+ return true;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> peek() {
+ ReferenceEntry<K, V> next = head.getNextEvictable();
+ return (next == head) ? null : next;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> poll() {
+ ReferenceEntry<K, V> next = head.getNextEvictable();
+ if (next == head) {
+ return null;
+ }
+
+ remove(next);
+ return next;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean remove(Object o) {
+ ReferenceEntry<K, V> e = (ReferenceEntry) o;
+ ReferenceEntry<K, V> previous = e.getPreviousEvictable();
+ ReferenceEntry<K, V> next = e.getNextEvictable();
+ connectEvictables(previous, next);
+ nullifyEvictable(e);
+
+ return next != NullEntry.INSTANCE;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean contains(Object o) {
+ ReferenceEntry<K, V> e = (ReferenceEntry) o;
+ return e.getNextEvictable() != NullEntry.INSTANCE;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return head.getNextEvictable() == head;
+ }
+
+ @Override
+ public int size() {
+ int size = 0;
+ for (ReferenceEntry<K, V> e = head.getNextEvictable(); e != head; e = e.getNextEvictable()) {
+ size++;
+ }
+ return size;
+ }
+
+ @Override
+ public void clear() {
+ ReferenceEntry<K, V> e = head.getNextEvictable();
+ while (e != head) {
+ ReferenceEntry<K, V> next = e.getNextEvictable();
+ nullifyEvictable(e);
+ e = next;
+ }
+
+ head.setNextEvictable(head);
+ head.setPreviousEvictable(head);
+ }
+
+ @Override
+ public Iterator<ReferenceEntry<K, V>> iterator() {
+ return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) {
+ @Override
+ protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) {
+ ReferenceEntry<K, V> next = previous.getNextEvictable();
+ return (next == head) ? null : next;
+ }
+ };
+ }
+ }
+
+ /**
+ * A custom queue for managing expiration order. Note that this is tightly integrated with
+ * {@code ReferenceEntry}, upon which it reliese to perform its linking.
+ *
+ * <p>Note that this entire implementation makes the assumption that all elements which are in
+ * the map are also in this queue, and that all elements not in the queue are not in the map.
+ *
+ * <p>The benefits of creating our own queue are that (1) we can replace elements in the middle
+ * of the queue as part of copyEvictableEntry, and (2) the contains method is highly optimized
+ * for the current model.
+ */
+ static final class ExpirationQueue<K, V> extends AbstractQueue<ReferenceEntry<K, V>> {
+ final ReferenceEntry<K, V> head = new AbstractReferenceEntry<K, V>() {
+
+ @Override
+ public long getExpirationTime() {
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public void setExpirationTime(long time) {}
+
+ ReferenceEntry<K, V> nextExpirable = this;
+
+ @Override
+ public ReferenceEntry<K, V> getNextExpirable() {
+ return nextExpirable;
+ }
+
+ @Override
+ public void setNextExpirable(ReferenceEntry<K, V> next) {
+ this.nextExpirable = next;
+ }
+
+ ReferenceEntry<K, V> previousExpirable = this;
+
+ @Override
+ public ReferenceEntry<K, V> getPreviousExpirable() {
+ return previousExpirable;
+ }
+
+ @Override
+ public void setPreviousExpirable(ReferenceEntry<K, V> previous) {
+ this.previousExpirable = previous;
+ }
+ };
+
+ // implements Queue
+
+ @Override
+ public boolean offer(ReferenceEntry<K, V> entry) {
+ // unlink
+ connectExpirables(entry.getPreviousExpirable(), entry.getNextExpirable());
+
+ // add to tail
+ connectExpirables(head.getPreviousExpirable(), entry);
+ connectExpirables(entry, head);
+
+ return true;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> peek() {
+ ReferenceEntry<K, V> next = head.getNextExpirable();
+ return (next == head) ? null : next;
+ }
+
+ @Override
+ public ReferenceEntry<K, V> poll() {
+ ReferenceEntry<K, V> next = head.getNextExpirable();
+ if (next == head) {
+ return null;
+ }
+
+ remove(next);
+ return next;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean remove(Object o) {
+ ReferenceEntry<K, V> e = (ReferenceEntry) o;
+ ReferenceEntry<K, V> previous = e.getPreviousExpirable();
+ ReferenceEntry<K, V> next = e.getNextExpirable();
+ connectExpirables(previous, next);
+ nullifyExpirable(e);
+
+ return next != NullEntry.INSTANCE;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean contains(Object o) {
+ ReferenceEntry<K, V> e = (ReferenceEntry) o;
+ return e.getNextExpirable() != NullEntry.INSTANCE;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return head.getNextExpirable() == head;
+ }
+
+ @Override
+ public int size() {
+ int size = 0;
+ for (ReferenceEntry<K, V> e = head.getNextExpirable(); e != head; e = e.getNextExpirable()) {
+ size++;
+ }
+ return size;
+ }
+
+ @Override
+ public void clear() {
+ ReferenceEntry<K, V> e = head.getNextExpirable();
+ while (e != head) {
+ ReferenceEntry<K, V> next = e.getNextExpirable();
+ nullifyExpirable(e);
+ e = next;
+ }
+
+ head.setNextExpirable(head);
+ head.setPreviousExpirable(head);
+ }
+
+ @Override
+ public Iterator<ReferenceEntry<K, V>> iterator() {
+ return new AbstractSequentialIterator<ReferenceEntry<K, V>>(peek()) {
+ @Override
+ protected ReferenceEntry<K, V> computeNext(ReferenceEntry<K, V> previous) {
+ ReferenceEntry<K, V> next = previous.getNextExpirable();
+ return (next == head) ? null : next;
+ }
+ };
+ }
+ }
+
+ static final class CleanupMapTask implements Runnable {
+ final WeakReference<MapMakerInternalMap<?, ?>> mapReference;
+
+ public CleanupMapTask(MapMakerInternalMap<?, ?> map) {
+ this.mapReference = new WeakReference<MapMakerInternalMap<?, ?>>(map);
+ }
+
+ @Override
+ public void run() {
+ MapMakerInternalMap<?, ?> map = mapReference.get();
+ if (map == null) {
+ throw new CancellationException();
+ }
+
+ for (Segment<?, ?> segment : map.segments) {
+ segment.runCleanup();
+ }
+ }
+ }
+
+ // ConcurrentMap methods
+
+ @Override
+ public boolean isEmpty() {
+ /*
+ * Sum per-segment modCounts to avoid mis-reporting when elements are concurrently added and
+ * removed in one segment while checking another, in which case the table was never actually
+ * empty at any point. (The sum ensures accuracy up through at least 1<<31 per-segment
+ * modifications before recheck.) Method containsValue() uses similar constructions for
+ * stability checks.
+ */
+ long sum = 0L;
+ Segment<K, V>[] segments = this.segments;
+ for (int i = 0; i < segments.length; ++i) {
+ if (segments[i].count != 0) {
+ return false;
+ }
+ sum += segments[i].modCount;
+ }
+
+ if (sum != 0L) { // recheck unless no modifications
+ for (int i = 0; i < segments.length; ++i) {
+ if (segments[i].count != 0) {
+ return false;
+ }
+ sum -= segments[i].modCount;
+ }
+ if (sum != 0L) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int size() {
+ Segment<K, V>[] segments = this.segments;
+ long sum = 0;
+ for (int i = 0; i < segments.length; ++i) {
+ sum += segments[i].count;
+ }
+ return Ints.saturatedCast(sum);
+ }
+
+ @Override
+ public V get(@Nullable Object key) {
+ if (key == null) {
+ return null;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).get(key, hash);
+ }
+
+ /**
+ * Returns the internal entry for the specified key. The entry may be computing, expired, or
+ * partially collected. Does not impact recency ordering.
+ */
+ ReferenceEntry<K, V> getEntry(@Nullable Object key) {
+ if (key == null) {
+ return null;
+ }
+ int hash = hash(key);
+ 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) {
+ return false;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).containsKey(key, hash);
+ }
+
+ @Override
+ public boolean containsValue(@Nullable Object value) {
+ if (value == null) {
+ return false;
+ }
+
+ // This implementation is patterned after ConcurrentHashMap, but without the locking. The only
+ // way for it to return a false negative would be for the target value to jump around in the map
+ // 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;
+ long last = -1L;
+ for (int i = 0; i < CONTAINS_VALUE_RETRIES; i++) {
+ long sum = 0L;
+ for (Segment<K, V> segment : segments) {
+ // ensure visibility of most recent completed write
+ @SuppressWarnings({"UnusedDeclaration", "unused"})
+ int c = segment.count; // read-volatile
+
+ AtomicReferenceArray<ReferenceEntry<K, V>> table = segment.table;
+ 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)) {
+ return true;
+ }
+ }
+ }
+ sum += segment.modCount;
+ }
+ if (sum == last) {
+ break;
+ }
+ last = sum;
+ }
+ return false;
+ }
+
+ @Override
+ public V put(K key, V value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ int hash = hash(key);
+ return segmentFor(hash).put(key, hash, value, false);
+ }
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ int hash = hash(key);
+ return segmentFor(hash).put(key, hash, value, true);
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ for (Entry<? extends K, ? extends V> e : m.entrySet()) {
+ put(e.getKey(), e.getValue());
+ }
+ }
+
+ @Override
+ public V remove(@Nullable Object key) {
+ if (key == null) {
+ return null;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).remove(key, hash);
+ }
+
+ @Override
+ public boolean remove(@Nullable Object key, @Nullable Object value) {
+ if (key == null || value == null) {
+ return false;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).remove(key, hash, value);
+ }
+
+ @Override
+ public boolean replace(K key, @Nullable V oldValue, V newValue) {
+ checkNotNull(key);
+ checkNotNull(newValue);
+ if (oldValue == null) {
+ return false;
+ }
+ int hash = hash(key);
+ return segmentFor(hash).replace(key, hash, oldValue, newValue);
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ int hash = hash(key);
+ return segmentFor(hash).replace(key, hash, value);
+ }
+
+ @Override
+ public void clear() {
+ for (Segment<K, V> segment : segments) {
+ segment.clear();
+ }
+ }
+
+ transient Set<K> keySet;
+
+ @Override
+ public Set<K> keySet() {
+ Set<K> ks = keySet;
+ return (ks != null) ? ks : (keySet = new KeySet());
+ }
+
+ transient Collection<V> values;
+
+ @Override
+ public Collection<V> values() {
+ Collection<V> vs = values;
+ return (vs != null) ? vs : (values = new Values());
+ }
+
+ transient Set<Entry<K, V>> entrySet;
+
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ Set<Entry<K, V>> es = entrySet;
+ return (es != null) ? es : (entrySet = new EntrySet());
+ }
+
+ // Iterator Support
+
+ abstract class HashIterator {
+
+ int nextSegmentIndex;
+ int nextTableIndex;
+ Segment<K, V> currentSegment;
+ AtomicReferenceArray<ReferenceEntry<K, V>> currentTable;
+ ReferenceEntry<K, V> nextEntry;
+ WriteThroughEntry nextExternal;
+ WriteThroughEntry lastReturned;
+
+ HashIterator() {
+ nextSegmentIndex = segments.length - 1;
+ nextTableIndex = -1;
+ advance();
+ }
+
+ final void advance() {
+ nextExternal = null;
+
+ if (nextInChain()) {
+ return;
+ }
+
+ if (nextInTable()) {
+ return;
+ }
+
+ while (nextSegmentIndex >= 0) {
+ currentSegment = segments[nextSegmentIndex--];
+ if (currentSegment.count != 0) {
+ currentTable = currentSegment.table;
+ nextTableIndex = currentTable.length() - 1;
+ if (nextInTable()) {
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Finds the next entry in the current chain. Returns {@code true} if an entry was found.
+ */
+ boolean nextInChain() {
+ if (nextEntry != null) {
+ for (nextEntry = nextEntry.getNext(); nextEntry != null; nextEntry = nextEntry.getNext()) {
+ if (advanceTo(nextEntry)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Finds the next entry in the current table. Returns {@code true} if an entry was found.
+ */
+ boolean nextInTable() {
+ while (nextTableIndex >= 0) {
+ if ((nextEntry = currentTable.get(nextTableIndex--)) != null) {
+ if (advanceTo(nextEntry) || nextInChain()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Advances to the given entry. Returns {@code true} if the entry was valid, {@code false} if it
+ * should be skipped.
+ */
+ boolean advanceTo(ReferenceEntry<K, V> entry) {
+ try {
+ K key = entry.getKey();
+ V value = getLiveValue(entry);
+ if (value != null) {
+ nextExternal = new WriteThroughEntry(key, value);
+ return true;
+ } else {
+ // Skip stale entry.
+ return false;
+ }
+ } finally {
+ currentSegment.postReadCleanup();
+ }
+ }
+
+ public boolean hasNext() {
+ return nextExternal != null;
+ }
+
+ WriteThroughEntry nextEntry() {
+ if (nextExternal == null) {
+ throw new NoSuchElementException();
+ }
+ lastReturned = nextExternal;
+ advance();
+ return lastReturned;
+ }
+
+ public void remove() {
+ checkState(lastReturned != null);
+ MapMakerInternalMap.this.remove(lastReturned.getKey());
+ lastReturned = null;
+ }
+ }
+
+ final class KeyIterator extends HashIterator implements Iterator<K> {
+
+ @Override
+ public K next() {
+ return nextEntry().getKey();
+ }
+ }
+
+ final class ValueIterator extends HashIterator implements Iterator<V> {
+
+ @Override
+ public V next() {
+ return nextEntry().getValue();
+ }
+ }
+
+ /**
+ * Custom Entry class used by EntryIterator.next(), that relays setValue changes to the
+ * underlying map.
+ */
+ final class WriteThroughEntry extends AbstractMapEntry<K, V> {
+ final K key; // non-null
+ V value; // non-null
+
+ WriteThroughEntry(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ @Override
+ public K getKey() {
+ return key;
+ }
+
+ @Override
+ public V getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ // Cannot use key and value equivalence
+ if (object instanceof Entry) {
+ Entry<?, ?> that = (Entry<?, ?>) object;
+ return key.equals(that.getKey()) && value.equals(that.getValue());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ // Cannot use key and value equivalence
+ return key.hashCode() ^ value.hashCode();
+ }
+
+ @Override
+ public V setValue(V newValue) {
+ V oldValue = put(key, newValue);
+ value = newValue; // only if put succeeds
+ return oldValue;
+ }
+ }
+
+ final class EntryIterator extends HashIterator implements Iterator<Entry<K, V>> {
+
+ @Override
+ public Entry<K, V> next() {
+ return nextEntry();
+ }
+ }
+
+ final class KeySet extends AbstractSet<K> {
+
+ @Override
+ public Iterator<K> iterator() {
+ return new KeyIterator();
+ }
+
+ @Override
+ public int size() {
+ return MapMakerInternalMap.this.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return MapMakerInternalMap.this.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return MapMakerInternalMap.this.containsKey(o);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return MapMakerInternalMap.this.remove(o) != null;
+ }
+
+ @Override
+ public void clear() {
+ MapMakerInternalMap.this.clear();
+ }
+ }
+
+ final class Values extends AbstractCollection<V> {
+
+ @Override
+ public Iterator<V> iterator() {
+ return new ValueIterator();
+ }
+
+ @Override
+ public int size() {
+ return MapMakerInternalMap.this.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return MapMakerInternalMap.this.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return MapMakerInternalMap.this.containsValue(o);
+ }
+
+ @Override
+ public void clear() {
+ MapMakerInternalMap.this.clear();
+ }
+ }
+
+ final class EntrySet extends AbstractSet<Entry<K, V>> {
+
+ @Override
+ public Iterator<Entry<K, V>> iterator() {
+ return new EntryIterator();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ Entry<?, ?> e = (Entry<?, ?>) o;
+ Object key = e.getKey();
+ if (key == null) {
+ return false;
+ }
+ V v = MapMakerInternalMap.this.get(key);
+
+ return v != null && valueEquivalence.equivalent(e.getValue(), v);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ Entry<?, ?> e = (Entry<?, ?>) o;
+ Object key = e.getKey();
+ return key != null && MapMakerInternalMap.this.remove(key, e.getValue());
+ }
+
+ @Override
+ public int size() {
+ return MapMakerInternalMap.this.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return MapMakerInternalMap.this.isEmpty();
+ }
+
+ @Override
+ public void clear() {
+ MapMakerInternalMap.this.clear();
+ }
+ }
+
+ // Serialization Support
+
+ private static final long serialVersionUID = 5;
+
+ Object writeReplace() {
+ return new SerializationProxy<K, V>(keyStrength, valueStrength, keyEquivalence,
+ valueEquivalence, expireAfterWriteNanos, expireAfterAccessNanos, maximumSize,
+ concurrencyLevel, removalListener, this);
+ }
+
+ /**
+ * The actual object that gets serialized. Unfortunately, readResolve() doesn't get called when a
+ * circular dependency is present, so the proxy must be able to behave as the map itself.
+ */
+ abstract static class AbstractSerializationProxy<K, V>
+ extends ForwardingConcurrentMap<K, V> implements Serializable {
+ private static final long serialVersionUID = 3;
+
+ final Strength keyStrength;
+ final Strength valueStrength;
+ final Equivalence<Object> keyEquivalence;
+ final Equivalence<Object> valueEquivalence;
+ final long expireAfterWriteNanos;
+ final long expireAfterAccessNanos;
+ final int maximumSize;
+ final int concurrencyLevel;
+ final RemovalListener<? super K, ? super V> removalListener;
+
+ transient ConcurrentMap<K, V> delegate;
+
+ AbstractSerializationProxy(Strength keyStrength, Strength valueStrength,
+ Equivalence<Object> keyEquivalence, Equivalence<Object> valueEquivalence,
+ long expireAfterWriteNanos, long expireAfterAccessNanos, int maximumSize,
+ int concurrencyLevel, RemovalListener<? super K, ? super V> removalListener,
+ ConcurrentMap<K, V> delegate) {
+ this.keyStrength = keyStrength;
+ this.valueStrength = valueStrength;
+ this.keyEquivalence = keyEquivalence;
+ this.valueEquivalence = valueEquivalence;
+ this.expireAfterWriteNanos = expireAfterWriteNanos;
+ this.expireAfterAccessNanos = expireAfterAccessNanos;
+ this.maximumSize = maximumSize;
+ this.concurrencyLevel = concurrencyLevel;
+ this.removalListener = removalListener;
+ this.delegate = delegate;
+ }
+
+ @Override
+ protected ConcurrentMap<K, V> delegate() {
+ return delegate;
+ }
+
+ void writeMapTo(ObjectOutputStream out) throws IOException {
+ out.writeInt(delegate.size());
+ for (Entry<K, V> entry : delegate.entrySet()) {
+ out.writeObject(entry.getKey());
+ out.writeObject(entry.getValue());
+ }
+ out.writeObject(null); // terminate entries
+ }
+
+ @SuppressWarnings("deprecation") // serialization of deprecated feature
+ MapMaker readMapMaker(ObjectInputStream in) throws IOException {
+ int size = in.readInt();
+ MapMaker mapMaker = new MapMaker()
+ .initialCapacity(size)
+ .setKeyStrength(keyStrength)
+ .setValueStrength(valueStrength)
+ .keyEquivalence(keyEquivalence)
+ .concurrencyLevel(concurrencyLevel);
+ mapMaker.removalListener(removalListener);
+ if (expireAfterWriteNanos > 0) {
+ mapMaker.expireAfterWrite(expireAfterWriteNanos, TimeUnit.NANOSECONDS);
+ }
+ if (expireAfterAccessNanos > 0) {
+ mapMaker.expireAfterAccess(expireAfterAccessNanos, TimeUnit.NANOSECONDS);
+ }
+ if (maximumSize != MapMaker.UNSET_INT) {
+ mapMaker.maximumSize(maximumSize);
+ }
+ return mapMaker;
+ }
+
+ @SuppressWarnings("unchecked")
+ void readEntries(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ while (true) {
+ K key = (K) in.readObject();
+ if (key == null) {
+ break; // terminator
+ }
+ V value = (V) in.readObject();
+ delegate.put(key, value);
+ }
+ }
+ }
+
+ /**
+ * The actual object that gets serialized. Unfortunately, readResolve() doesn't get called when a
+ * circular dependency is present, so the proxy must be able to behave as the map itself.
+ */
+ private static final class SerializationProxy<K, V> extends AbstractSerializationProxy<K, V> {
+ private static final long serialVersionUID = 3;
+
+ SerializationProxy(Strength keyStrength, Strength valueStrength,
+ Equivalence<Object> keyEquivalence, Equivalence<Object> valueEquivalence,
+ long expireAfterWriteNanos, long expireAfterAccessNanos, int maximumSize,
+ int concurrencyLevel, RemovalListener<? super K, ? super V> removalListener,
+ ConcurrentMap<K, V> delegate) {
+ super(keyStrength, valueStrength, keyEquivalence, valueEquivalence, expireAfterWriteNanos,
+ expireAfterAccessNanos, maximumSize, concurrencyLevel, removalListener, delegate);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.defaultWriteObject();
+ writeMapTo(out);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ MapMaker mapMaker = readMapMaker(in);
+ delegate = mapMaker.makeMap();
+ readEntries(in);
+ }
+
+ private Object readResolve() {
+ return delegate;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/Maps.java b/guava/src/com/google/common/collect/Maps.java
new file mode 100644
index 0000000..73978b7
--- /dev/null
+++ b/guava/src/com/google/common/collect/Maps.java
@@ -0,0 +1,3240 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner.MapJoiner;
+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.MapDifference.ValueDifference;
+import com.google.common.primitives.Ints;
+
+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.EnumMap;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+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>.
+ *
+ * @author Kevin Bourrillion
+ * @author Mike Bostock
+ * @author Isaac Shum
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(emulated = true)
+public final class Maps {
+ private Maps() {}
+
+ /**
+ * Creates a <i>mutable</i>, empty {@code HashMap} instance.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableMap#of()} instead.
+ *
+ * <p><b>Note:</b> if {@code K} is an {@code enum} type, use {@link
+ * #newEnumMap} instead.
+ *
+ * @return a new, empty {@code HashMap}
+ */
+ public static <K, V> HashMap<K, V> newHashMap() {
+ return new HashMap<K, V>();
+ }
+
+ /**
+ * Creates a {@code HashMap} instance, with a high enough "initial capacity"
+ * that it <i>should</i> hold {@code expectedSize} elements without growth.
+ * This behavior cannot be broadly guaranteed, but it is observed to be true
+ * for OpenJDK 1.6. It also can't be guaranteed that the method isn't
+ * inadvertently <i>oversizing</i> the returned map.
+ *
+ * @param expectedSize the number of elements you expect to add to the
+ * returned map
+ * @return a new, empty {@code HashMap} with enough capacity to hold {@code
+ * expectedSize} elements without resizing
+ * @throws IllegalArgumentException if {@code expectedSize} is negative
+ */
+ public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(
+ int expectedSize) {
+ return new HashMap<K, V>(capacity(expectedSize));
+ }
+
+ /**
+ * Returns a capacity that is sufficient to keep the map from being resized as
+ * long as it grows no larger than expectedSize and the load factor is >= its
+ * default (0.75).
+ */
+ static int capacity(int expectedSize) {
+ if (expectedSize < 3) {
+ checkArgument(expectedSize >= 0);
+ return expectedSize + 1;
+ }
+ if (expectedSize < Ints.MAX_POWER_OF_TWO) {
+ return expectedSize + expectedSize / 3;
+ }
+ return Integer.MAX_VALUE; // any large value
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code HashMap} instance with the same mappings as
+ * the specified map.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableMap#copyOf(Map)} instead.
+ *
+ * <p><b>Note:</b> if {@code K} is an {@link Enum} type, use {@link
+ * #newEnumMap} instead.
+ *
+ * @param map the mappings to be placed in the new map
+ * @return a new {@code HashMap} initialized with the mappings from {@code
+ * map}
+ */
+ public static <K, V> HashMap<K, V> newHashMap(
+ Map<? extends K, ? extends V> map) {
+ return new HashMap<K, V>(map);
+ }
+
+ /**
+ * Creates a <i>mutable</i>, empty, insertion-ordered {@code LinkedHashMap}
+ * instance.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableMap#of()} instead.
+ *
+ * @return a new, empty {@code LinkedHashMap}
+ */
+ public static <K, V> LinkedHashMap<K, V> newLinkedHashMap() {
+ return new LinkedHashMap<K, V>();
+ }
+
+ /**
+ * Creates a <i>mutable</i>, insertion-ordered {@code LinkedHashMap} instance
+ * with the same mappings as the specified map.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableMap#copyOf(Map)} instead.
+ *
+ * @param map the mappings to be placed in the new map
+ * @return a new, {@code LinkedHashMap} initialized with the mappings from
+ * {@code map}
+ */
+ public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(
+ Map<? extends K, ? extends V> map) {
+ return new LinkedHashMap<K, V>(map);
+ }
+
+ /**
+ * Returns a general-purpose instance of {@code ConcurrentMap}, which supports
+ * all optional operations of the ConcurrentMap interface. It does not permit
+ * null keys or values. It is serializable.
+ *
+ * <p>This is currently accomplished by calling {@link MapMaker#makeMap()}.
+ *
+ * <p>It is preferable to use {@code MapMaker} directly (rather than through
+ * this method), as it presents numerous useful configuration options,
+ * such as the concurrency level, load factor, key/value reference types,
+ * and value computation.
+ *
+ * @return a new, empty {@code ConcurrentMap}
+ * @since 3.0
+ */
+ public static <K, V> ConcurrentMap<K, V> newConcurrentMap() {
+ return new MapMaker().<K, V>makeMap();
+ }
+
+ /**
+ * Creates a <i>mutable</i>, empty {@code TreeMap} instance using the natural
+ * ordering of its elements.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableSortedMap#of()} instead.
+ *
+ * @return a new, empty {@code TreeMap}
+ */
+ public static <K extends Comparable, V> TreeMap<K, V> newTreeMap() {
+ return new TreeMap<K, V>();
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code TreeMap} instance with the same mappings as
+ * the specified map and using the same ordering as the specified map.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableSortedMap#copyOfSorted(SortedMap)} instead.
+ *
+ * @param map the sorted map whose mappings are to be placed in the new map
+ * and whose comparator is to be used to sort the new map
+ * @return a new {@code TreeMap} initialized with the mappings from {@code
+ * map} and using the comparator of {@code map}
+ */
+ public static <K, V> TreeMap<K, V> newTreeMap(SortedMap<K, ? extends V> map) {
+ return new TreeMap<K, V>(map);
+ }
+
+ /**
+ * Creates a <i>mutable</i>, empty {@code TreeMap} instance using the given
+ * comparator.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@code
+ * ImmutableSortedMap.orderedBy(comparator).build()} instead.
+ *
+ * @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
+ // work-around of a compiler type inference quirk that prevents the
+ // following code from being compiled:
+ // Comparator<Class<?>> comparator = null;
+ // Map<Class<? extends Throwable>, String> map = newTreeMap(comparator);
+ return new TreeMap<K, V>(comparator);
+ }
+
+ /**
+ * Creates an {@code EnumMap} instance.
+ *
+ * @param type the key type for this map
+ * @return a new, empty {@code EnumMap}
+ */
+ public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(Class<K> type) {
+ return new EnumMap<K, V>(checkNotNull(type));
+ }
+
+ /**
+ * Creates an {@code EnumMap} with the same mappings as the specified map.
+ *
+ * @param map the map from which to initialize this {@code EnumMap}
+ * @return a new {@code EnumMap} initialized with the mappings from {@code
+ * map}
+ * @throws IllegalArgumentException if {@code m} is not an {@code EnumMap}
+ * instance and contains no mappings
+ */
+ public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(
+ Map<K, ? extends V> map) {
+ return new EnumMap<K, V>(map);
+ }
+
+ /**
+ * Creates an {@code IdentityHashMap} instance.
+ *
+ * @return a new, empty {@code IdentityHashMap}
+ */
+ public static <K, V> IdentityHashMap<K, V> newIdentityHashMap() {
+ return new IdentityHashMap<K, V>();
+ }
+
+ /**
+ * 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.
+ *
+ * <p>Since this method uses {@code HashMap} instances internally, the keys of
+ * the supplied maps must be well-behaved with respect to
+ * {@link Object#equals} and {@link Object#hashCode}.
+ *
+ * <p><b>Note:</b>If you only need to know whether two 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
+ */
+ @SuppressWarnings("unchecked")
+ public static <K, V> MapDifference<K, V> difference(
+ Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right) {
+ if (left instanceof SortedMap) {
+ SortedMap<K, ? extends V> sortedLeft = (SortedMap<K, ? extends V>) left;
+ SortedMapDifference<K, V> result = difference(sortedLeft, right);
+ return result;
+ }
+ return difference(left, right, Equivalence.equals());
+ }
+
+ /**
+ * 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.
+ *
+ * <p>Values are compared using a provided equivalence, in the case of
+ * equality, the value on the 'left' is returned in the difference.
+ *
+ * <p>Since this method uses {@code HashMap} instances internally, the keys of
+ * the supplied maps must be well-behaved with respect to
+ * {@link Object#equals} and {@link Object#hashCode}.
+ *
+ * @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
+ * @param valueEquivalence the equivalence relationship to use to compare
+ * values
+ * @return the difference between the two maps
+ * @since 10.0
+ */
+ @Beta
+ public static <K, V> MapDifference<K, V> difference(
+ Map<? extends K, ? extends V> left, Map<? extends K, ? extends V> right,
+ Equivalence<? super V> valueEquivalence) {
+ Preconditions.checkNotNull(valueEquivalence);
+
+ Map<K, V> onlyOnLeft = newHashMap();
+ Map<K, V> onlyOnRight = new HashMap<K, V>(right); // will whittle it down
+ Map<K, V> onBoth = newHashMap();
+ Map<K, MapDifference.ValueDifference<V>> differences = newHashMap();
+ boolean eq = true;
+
+ for (Entry<? extends K, ? extends V> entry : left.entrySet()) {
+ K leftKey = entry.getKey();
+ V leftValue = entry.getValue();
+ if (right.containsKey(leftKey)) {
+ V rightValue = onlyOnRight.remove(leftKey);
+ if (valueEquivalence.equivalent(leftValue, rightValue)) {
+ onBoth.put(leftKey, leftValue);
+ } else {
+ eq = false;
+ differences.put(
+ leftKey, ValueDifferenceImpl.create(leftValue, rightValue));
+ }
+ } else {
+ eq = false;
+ onlyOnLeft.put(leftKey, leftValue);
+ }
+ }
+
+ boolean areEqual = eq && onlyOnRight.isEmpty();
+ return mapDifference(
+ areEqual, onlyOnLeft, onlyOnRight, onBoth, differences);
+ }
+
+ private static <K, V> MapDifference<K, V> mapDifference(boolean areEqual,
+ Map<K, V> onlyOnLeft, Map<K, V> onlyOnRight, Map<K, V> onBoth,
+ Map<K, ValueDifference<V>> differences) {
+ return new MapDifferenceImpl<K, V>(areEqual,
+ Collections.unmodifiableMap(onlyOnLeft),
+ Collections.unmodifiableMap(onlyOnRight),
+ Collections.unmodifiableMap(onBoth),
+ Collections.unmodifiableMap(differences));
+ }
+
+ static class MapDifferenceImpl<K, V> implements MapDifference<K, V> {
+ final boolean areEqual;
+ final Map<K, V> onlyOnLeft;
+ final Map<K, V> onlyOnRight;
+ final Map<K, V> onBoth;
+ final Map<K, ValueDifference<V>> differences;
+
+ MapDifferenceImpl(boolean areEqual, Map<K, V> onlyOnLeft,
+ Map<K, V> onlyOnRight, Map<K, V> onBoth,
+ Map<K, ValueDifference<V>> differences) {
+ this.areEqual = areEqual;
+ this.onlyOnLeft = onlyOnLeft;
+ this.onlyOnRight = onlyOnRight;
+ this.onBoth = onBoth;
+ this.differences = differences;
+ }
+
+ @Override
+ public boolean areEqual() {
+ return areEqual;
+ }
+
+ @Override
+ public Map<K, V> entriesOnlyOnLeft() {
+ return onlyOnLeft;
+ }
+
+ @Override
+ public Map<K, V> entriesOnlyOnRight() {
+ return onlyOnRight;
+ }
+
+ @Override
+ public Map<K, V> entriesInCommon() {
+ return onBoth;
+ }
+
+ @Override
+ public Map<K, ValueDifference<V>> entriesDiffering() {
+ return differences;
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof MapDifference) {
+ MapDifference<?, ?> other = (MapDifference<?, ?>) object;
+ return entriesOnlyOnLeft().equals(other.entriesOnlyOnLeft())
+ && entriesOnlyOnRight().equals(other.entriesOnlyOnRight())
+ && entriesInCommon().equals(other.entriesInCommon())
+ && entriesDiffering().equals(other.entriesDiffering());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(entriesOnlyOnLeft(), entriesOnlyOnRight(),
+ entriesInCommon(), entriesDiffering());
+ }
+
+ @Override public String toString() {
+ if (areEqual) {
+ return "equal";
+ }
+
+ StringBuilder result = new StringBuilder("not equal");
+ if (!onlyOnLeft.isEmpty()) {
+ result.append(": only on left=").append(onlyOnLeft);
+ }
+ if (!onlyOnRight.isEmpty()) {
+ result.append(": only on right=").append(onlyOnRight);
+ }
+ if (!differences.isEmpty()) {
+ result.append(": value differences=").append(differences);
+ }
+ return result.toString();
+ }
+ }
+
+ static class ValueDifferenceImpl<V>
+ implements MapDifference.ValueDifference<V> {
+ private final V left;
+ private final V right;
+
+ static <V> ValueDifference<V> create(@Nullable V left, @Nullable V right) {
+ return new ValueDifferenceImpl<V>(left, right);
+ }
+
+ private ValueDifferenceImpl(@Nullable V left, @Nullable V right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public V leftValue() {
+ return left;
+ }
+
+ @Override
+ public V rightValue() {
+ return right;
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof MapDifference.ValueDifference) {
+ MapDifference.ValueDifference<?> that =
+ (MapDifference.ValueDifference<?>) object;
+ return Objects.equal(this.left, that.leftValue())
+ && Objects.equal(this.right, that.rightValue());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(left, right);
+ }
+
+ @Override public String toString() {
+ return "(" + left + ", " + right + ")";
+ }
+ }
+
+ /**
+ * 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
+ * @since 11.0
+ */
+ public static <K, V> SortedMapDifference<K, V> difference(
+ SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) {
+ checkNotNull(left);
+ checkNotNull(right);
+ Comparator<? super K> comparator = orNaturalOrder(left.comparator());
+ SortedMap<K, V> onlyOnLeft = Maps.newTreeMap(comparator);
+ SortedMap<K, V> onlyOnRight = Maps.newTreeMap(comparator);
+ onlyOnRight.putAll(right); // will whittle it down
+ SortedMap<K, V> onBoth = Maps.newTreeMap(comparator);
+ SortedMap<K, MapDifference.ValueDifference<V>> differences =
+ Maps.newTreeMap(comparator);
+ boolean eq = true;
+
+ for (Entry<? extends K, ? extends V> entry : left.entrySet()) {
+ K leftKey = entry.getKey();
+ V leftValue = entry.getValue();
+ if (right.containsKey(leftKey)) {
+ V rightValue = onlyOnRight.remove(leftKey);
+ if (Objects.equal(leftValue, rightValue)) {
+ onBoth.put(leftKey, leftValue);
+ } else {
+ eq = false;
+ differences.put(
+ leftKey, ValueDifferenceImpl.create(leftValue, rightValue));
+ }
+ } else {
+ eq = false;
+ onlyOnLeft.put(leftKey, leftValue);
+ }
+ }
+
+ boolean areEqual = eq && onlyOnRight.isEmpty();
+ return sortedMapDifference(
+ areEqual, onlyOnLeft, onlyOnRight, onBoth, differences);
+ }
+
+ private static <K, V> SortedMapDifference<K, V> sortedMapDifference(
+ boolean areEqual, SortedMap<K, V> onlyOnLeft, SortedMap<K, V> onlyOnRight,
+ SortedMap<K, V> onBoth, SortedMap<K, ValueDifference<V>> differences) {
+ return new SortedMapDifferenceImpl<K, V>(areEqual,
+ Collections.unmodifiableSortedMap(onlyOnLeft),
+ Collections.unmodifiableSortedMap(onlyOnRight),
+ Collections.unmodifiableSortedMap(onBoth),
+ Collections.unmodifiableSortedMap(differences));
+ }
+
+ static class SortedMapDifferenceImpl<K, V> extends MapDifferenceImpl<K, V>
+ implements SortedMapDifference<K, V> {
+ SortedMapDifferenceImpl(boolean areEqual, SortedMap<K, V> onlyOnLeft,
+ SortedMap<K, V> onlyOnRight, SortedMap<K, V> onBoth,
+ SortedMap<K, ValueDifference<V>> differences) {
+ super(areEqual, onlyOnLeft, onlyOnRight, onBoth, differences);
+ }
+
+ @Override public SortedMap<K, ValueDifference<V>> entriesDiffering() {
+ return (SortedMap<K, ValueDifference<V>>) super.entriesDiffering();
+ }
+
+ @Override public SortedMap<K, V> entriesInCommon() {
+ return (SortedMap<K, V>) super.entriesInCommon();
+ }
+
+ @Override public SortedMap<K, V> entriesOnlyOnLeft() {
+ return (SortedMap<K, V>) super.entriesOnlyOnLeft();
+ }
+
+ @Override public SortedMap<K, V> entriesOnlyOnRight() {
+ return (SortedMap<K, V>) super.entriesOnlyOnRight();
+ }
+ }
+
+ /**
+ * 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 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.
+ */
+ @Beta
+ 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.
+ */
+ @Beta
+ static <K, V> SortedMap<K, V> asMap(
+ SortedSet<K> set, Function<? super K, V> function) {
+ // TODO: NavigableSet overloads
+ return new SortedAsMapView<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 new ForwardingSet<K>() {
+ @Override
+ protected Set<K> delegate() {
+ return set;
+ }
+
+ @Override
+ public boolean add(K element) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends K> collection) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public Collection<V> values() {
+ // probably not worth caching
+ return Collections2.transform(set, function);
+ }
+
+ @Override
+ public int size() {
+ return set.size();
+ }
+
+ @Override
+ public boolean containsKey(@Nullable Object key) {
+ return set.contains(key);
+ }
+
+ @Override
+ 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 V remove(@Nullable Object key) {
+ if (set.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() {
+ set.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() {
+ final Iterator<K> backingIterator = set.iterator();
+ return new Iterator<Entry<K, V>>() {
+ @Override
+ public boolean hasNext() {
+ return backingIterator.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ K k = backingIterator.next();
+ return Maps.immutableEntry(k, function.apply(k));
+ }
+
+ @Override
+ public void remove() {
+ backingIterator.remove();
+ }
+ };
+ }
+ };
+ }
+ }
+
+ private static final 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
+ public Comparator<? super K> comparator() {
+ return backingSet().comparator();
+ }
+
+ @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();
+ }
+
+ @Override
+ SortedSet<K> backingSet() {
+ return (SortedSet<K>) super.backingSet();
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @param values the values to use when constructing the {@code Map}
+ * @param keyFunction the function used to produce the key for each value
+ * @return a map mapping the result of evaluating the function {@code
+ * keyFunction} on each value in the input collection to that value
+ * @throws IllegalArgumentException if {@code keyFunction} produces the same
+ * key for more than one value in the input collection
+ * @throws NullPointerException if any elements of {@code values} is null, or
+ * if {@code keyFunction} produces {@code null} for any value
+ */
+ public static <K, V> ImmutableMap<K, V> uniqueIndex(
+ Iterable<V> values, Function<? super V, K> keyFunction) {
+ return uniqueIndex(values.iterator(), 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.
+ *
+ * @param values the values to use when constructing the {@code Map}
+ * @param keyFunction the function used to produce the key for each value
+ * @return a map mapping the result of evaluating the function {@code
+ * keyFunction} on each value in the input collection to that value
+ * @throws IllegalArgumentException if {@code keyFunction} produces the same
+ * key for more than one value in the input collection
+ * @throws NullPointerException if any elements of {@code values} is null, or
+ * if {@code keyFunction} produces {@code null} for any value
+ * @since 10.0
+ */
+ public static <K, V> ImmutableMap<K, V> uniqueIndex(
+ Iterator<V> values, Function<? super V, K> keyFunction) {
+ checkNotNull(keyFunction);
+ ImmutableMap.Builder<K, V> builder = ImmutableMap.builder();
+ while (values.hasNext()) {
+ V value = values.next();
+ builder.put(keyFunction.apply(value), value);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Creates an {@code ImmutableMap<String, String>} from a {@code Properties}
+ * instance. Properties normally derive from {@code Map<Object, Object>}, but
+ * they typically contain strings, which is awkward. This method lets you get
+ * a plain-old-{@code Map} out of a {@code Properties}.
+ *
+ * @param properties a {@code Properties} object to be converted
+ * @return an immutable map containing all the entries in {@code properties}
+ * @throws ClassCastException if any key in {@code Properties} is not a {@code
+ * String}
+ * @throws NullPointerException if any key or value in {@code Properties} is
+ * null
+ */
+ @GwtIncompatible("java.util.Properties")
+ public static ImmutableMap<String, String> fromProperties(
+ Properties properties) {
+ ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+
+ for (Enumeration<?> e = properties.propertyNames(); e.hasMoreElements();) {
+ String key = (String) e.nextElement();
+ builder.put(key, properties.getProperty(key));
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Returns an immutable map entry with the specified key and value. The {@link
+ * Entry#setValue} operation throws an {@link UnsupportedOperationException}.
+ *
+ * <p>The returned entry is serializable.
+ *
+ * @param key the key to be associated with the returned entry
+ * @param value the value to be associated with the returned entry
+ */
+ @GwtCompatible(serializable = true)
+ public static <K, V> Entry<K, V> immutableEntry(
+ @Nullable K key, @Nullable V value) {
+ return new ImmutableEntry<K, V>(key, value);
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified set of entries. The {@link
+ * Entry#setValue} operation throws an {@link UnsupportedOperationException},
+ * as do any operations that would modify the returned set.
+ *
+ * @param entrySet the entries for which to return an unmodifiable view
+ * @return an unmodifiable view of the entries
+ */
+ static <K, V> Set<Entry<K, V>> unmodifiableEntrySet(
+ Set<Entry<K, V>> entrySet) {
+ return new UnmodifiableEntrySet<K, V>(
+ Collections.unmodifiableSet(entrySet));
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified map entry. The {@link
+ * Entry#setValue} operation throws an {@link UnsupportedOperationException}.
+ * This also has the side-effect of redefining {@code equals} to comply with
+ * the Entry contract, to avoid a possible nefarious implementation of equals.
+ *
+ * @param entry the entry for which to return an unmodifiable view
+ * @return an unmodifiable view of the entry
+ */
+ static <K, V> Entry<K, V> unmodifiableEntry(final Entry<K, V> entry) {
+ checkNotNull(entry);
+ return new AbstractMapEntry<K, V>() {
+ @Override public K getKey() {
+ return entry.getKey();
+ }
+
+ @Override public V getValue() {
+ return entry.getValue();
+ }
+ };
+ }
+
+ /** @see Multimaps#unmodifiableEntries */
+ static class UnmodifiableEntries<K, V>
+ extends ForwardingCollection<Entry<K, V>> {
+ private final Collection<Entry<K, V>> entries;
+
+ UnmodifiableEntries(Collection<Entry<K, V>> entries) {
+ this.entries = entries;
+ }
+
+ @Override protected Collection<Entry<K, V>> delegate() {
+ return entries;
+ }
+
+ @Override public Iterator<Entry<K, V>> iterator() {
+ final Iterator<Entry<K, V>> delegate = super.iterator();
+ return new ForwardingIterator<Entry<K, V>>() {
+ @Override public Entry<K, V> next() {
+ return unmodifiableEntry(super.next());
+ }
+
+ @Override public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override protected Iterator<Entry<K, V>> delegate() {
+ return delegate;
+ }
+ };
+ }
+
+ // See java.util.Collections.UnmodifiableEntrySet for details on attacks.
+
+ @Override public boolean add(Entry<K, V> element) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean addAll(
+ Collection<? extends Entry<K, V>> collection) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean remove(Object object) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean removeAll(Collection<?> collection) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean retainAll(Collection<?> collection) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Object[] toArray() {
+ return standardToArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return standardToArray(array);
+ }
+ }
+
+ /** @see Maps#unmodifiableEntrySet(Set) */
+ static class UnmodifiableEntrySet<K, V>
+ extends UnmodifiableEntries<K, V> implements Set<Entry<K, V>> {
+ UnmodifiableEntrySet(Set<Entry<K, V>> entries) {
+ super(entries);
+ }
+
+ // See java.util.Collections.UnmodifiableEntrySet for details on attacks.
+
+ @Override public boolean equals(@Nullable Object object) {
+ return Sets.equalsImpl(this, object);
+ }
+
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+ }
+
+ /**
+ * 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
+ * attempts to modify the returned map, whether direct or via its collection
+ * views, result in an {@code UnsupportedOperationException}.
+ *
+ * <p>The returned bimap will be serializable if the specified bimap is
+ * serializable.
+ *
+ * @param bimap the bimap for which an unmodifiable view is to be returned
+ * @return an unmodifiable view of the specified bimap
+ */
+ public static <K, V> BiMap<K, V> unmodifiableBiMap(
+ BiMap<? extends K, ? extends V> bimap) {
+ return new UnmodifiableBiMap<K, V>(bimap, null);
+ }
+
+ /** @see Maps#unmodifiableBiMap(BiMap) */
+ private static class UnmodifiableBiMap<K, V>
+ 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 Set<V> values;
+
+ UnmodifiableBiMap(BiMap<? extends K, ? extends V> delegate,
+ @Nullable BiMap<V, K> inverse) {
+ unmodifiableMap = Collections.unmodifiableMap(delegate);
+ this.delegate = delegate;
+ this.inverse = inverse;
+ }
+
+ @Override protected Map<K, V> delegate() {
+ return unmodifiableMap;
+ }
+
+ @Override
+ public V forcePut(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public BiMap<V, K> inverse() {
+ BiMap<V, K> result = inverse;
+ return (result == null)
+ ? inverse = new UnmodifiableBiMap<V, K>(delegate.inverse(), this)
+ : result;
+ }
+
+ @Override public Set<V> values() {
+ Set<V> result = values;
+ return (result == null)
+ ? values = Collections.unmodifiableSet(delegate.values())
+ : result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a view of a 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
+ *
+ * Map<String, Integer> map = ImmutableMap.of("a", 4, "b", 9);
+ * Function<Integer, Double> sqrt =
+ * new Function<Integer, Double>() {
+ * public Double apply(Integer in) {
+ * return Math.sqrt((int) in);
+ * }
+ * };
+ * Map<String, Double> transformed = Maps.transformValues(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.
+ */
+ public static <K, V1, V2> Map<K, V2> transformValues(
+ Map<K, V1> fromMap, Function<? super V1, V2> function) {
+ return transformEntries(fromMap, asEntryTransformer(function));
+ }
+
+ /**
+ * 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.
+ *
+ * @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
+ */
+ @Beta
+ @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) {
+ checkNotNull(function);
+ return new EntryTransformer<K, V1, V2>() {
+ @Override
+ public V2 transformEntry(K key, V1 value) {
+ return function.apply(value);
+ }
+ };
+ }
+
+ /**
+ * Returns a view of a map whose values are derived from the original 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 =
+ * ImmutableMap.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 : "no" + key;
+ * }
+ * };
+ * Map<String, String> transformed =
+ * Maps.transformEntries(options, flagPrefixer);
+ * System.out.println(transformed);}</pre>
+ *
+ * ... prints {@code {verbose=verbose, sort=nosort}}.
+ *
+ * <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 7.0
+ */
+ public static <K, V1, V2> Map<K, V2> transformEntries(
+ Map<K, V1> fromMap,
+ EntryTransformer<? super K, ? super V1, V2> transformer) {
+ if (fromMap instanceof SortedMap) {
+ return transformEntries((SortedMap<K, V1>) fromMap, transformer);
+ }
+ return new TransformedEntriesMap<K, V1, V2>(fromMap, transformer);
+ }
+
+ /**
+ * 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.
+ *
+ * @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
+ */
+ @Beta
+ @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,
+ EntryTransformer<? super K, ? super V1, V2> transformer) {
+ return new TransformedEntriesSortedMap<K, V1, V2>(fromMap, transformer);
+ }
+
+ /**
+ * A transformation of the value of a key-value pair, using both key and value
+ * as inputs. To apply the transformation to a map, use
+ * {@link Maps#transformEntries(Map, EntryTransformer)}.
+ *
+ * @param <K> the key type of the input and output entries
+ * @param <V1> the value type of the input entry
+ * @param <V2> the value type of the output entry
+ * @since 7.0
+ */
+ public interface EntryTransformer<K, V1, V2> {
+ /**
+ * Determines an output value based on a key-value pair. This method is
+ * <i>generally expected</i>, but not absolutely required, to have the
+ * following properties:
+ *
+ * <ul>
+ * <li>Its execution does not cause any observable side effects.
+ * <li>The computation is <i>consistent with equals</i>; that is,
+ * {@link Objects#equal Objects.equal}{@code (k1, k2) &&}
+ * {@link Objects#equal}{@code (v1, v2)} implies that {@code
+ * Objects.equal(transformer.transform(k1, v1),
+ * transformer.transform(k2, v2))}.
+ * </ul>
+ *
+ * @throws NullPointerException if the key or value is null and this
+ * transformer does not accept null arguments
+ */
+ V2 transformEntry(@Nullable K key, @Nullable V1 value);
+ }
+
+ static class TransformedEntriesMap<K, V1, V2>
+ extends AbstractMap<K, V2> {
+ final Map<K, V1> fromMap;
+ final EntryTransformer<? super K, ? super V1, V2> transformer;
+
+ TransformedEntriesMap(
+ Map<K, V1> fromMap,
+ EntryTransformer<? super K, ? super V1, V2> transformer) {
+ this.fromMap = checkNotNull(fromMap);
+ this.transformer = checkNotNull(transformer);
+ }
+
+ @Override public int size() {
+ return fromMap.size();
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return fromMap.containsKey(key);
+ }
+
+ // safe as long as the user followed the <b>Warning</b> in the javadoc
+ @SuppressWarnings("unchecked")
+ @Override public V2 get(Object key) {
+ V1 value = fromMap.get(key);
+ return (value != null || fromMap.containsKey(key))
+ ? transformer.transformEntry((K) key, value)
+ : null;
+ }
+
+ // safe as long as the user followed the <b>Warning</b> in the javadoc
+ @SuppressWarnings("unchecked")
+ @Override public V2 remove(Object key) {
+ return fromMap.containsKey(key)
+ ? transformer.transformEntry((K) key, fromMap.remove(key))
+ : null;
+ }
+
+ @Override public void clear() {
+ fromMap.clear();
+ }
+
+ @Override public Set<K> keySet() {
+ return fromMap.keySet();
+ }
+
+ Set<Entry<K, V2>> entrySet;
+
+ @Override public Set<Entry<K, V2>> entrySet() {
+ Set<Entry<K, V2>> result = entrySet;
+ if (result == null) {
+ entrySet = result = new EntrySet<K, V2>() {
+ @Override Map<K, V2> map() {
+ return TransformedEntriesMap.this;
+ }
+
+ @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();
+ }
+
+ @Override
+ public V2 getValue() {
+ return transformer.transformEntry(entry.getKey(), entry.getValue());
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+ return result;
+ }
+
+ Collection<V2> values;
+
+ @Override public Collection<V2> values() {
+ Collection<V2> result = values;
+ if (result == null) {
+ return values = new Values<K, V2>() {
+ @Override Map<K, V2> map() {
+ return TransformedEntriesMap.this;
+ }
+ };
+ }
+ return result;
+ }
+ }
+
+ static class TransformedEntriesSortedMap<K, V1, V2>
+ extends TransformedEntriesMap<K, V1, V2> implements SortedMap<K, V2> {
+
+ protected SortedMap<K, V1> fromMap() {
+ return (SortedMap<K, V1>) fromMap;
+ }
+
+ TransformedEntriesSortedMap(SortedMap<K, V1> fromMap,
+ EntryTransformer<? super K, ? super V1, V2> transformer) {
+ super(fromMap, transformer);
+ }
+
+ @Override public Comparator<? super K> comparator() {
+ return fromMap().comparator();
+ }
+
+ @Override public K firstKey() {
+ return fromMap().firstKey();
+ }
+
+ @Override public SortedMap<K, V2> headMap(K toKey) {
+ return transformEntries(fromMap().headMap(toKey), transformer);
+ }
+
+ @Override public K lastKey() {
+ return fromMap().lastKey();
+ }
+
+ @Override public SortedMap<K, V2> subMap(K fromKey, K toKey) {
+ return transformEntries(
+ fromMap().subMap(fromKey, toKey), transformer);
+ }
+
+ @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();
+ }
+ }
+
+ /**
+ * Returns a 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.
+ */
+ public static <K, V> Map<K, V> filterKeys(
+ Map<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
+ if (unfiltered instanceof SortedMap) {
+ return filterKeys((SortedMap<K, V>) unfiltered, 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 (unfiltered instanceof AbstractFilteredMap)
+ ? filterFiltered((AbstractFilteredMap<K, V>) unfiltered, entryPredicate)
+ : new FilteredKeyMap<K, V>(
+ checkNotNull(unfiltered), keyPredicate, entryPredicate);
+ }
+
+ /**
+ * 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.
+ *
+ * @since 11.0
+ */
+ 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 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.
+ */
+ public static <K, V> Map<K, V> filterValues(
+ Map<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
+ if (unfiltered instanceof SortedMap) {
+ return filterValues((SortedMap<K, V>) unfiltered, 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} 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 11.0
+ */
+ 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 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}.
+ */
+ public static <K, V> Map<K, V> filterEntries(
+ Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
+ if (unfiltered instanceof SortedMap) {
+ return filterEntries((SortedMap<K, V>) unfiltered, entryPredicate);
+ }
+ checkNotNull(entryPredicate);
+ return (unfiltered instanceof AbstractFilteredMap)
+ ? filterFiltered((AbstractFilteredMap<K, V>) unfiltered, entryPredicate)
+ : new FilteredEntryMap<K, V>(checkNotNull(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}.
+ *
+ * @since 11.0
+ */
+ public static <K, V> SortedMap<K, V> filterEntries(
+ SortedMap<K, V> unfiltered,
+ Predicate<? super Entry<K, V>> entryPredicate) {
+ checkNotNull(entryPredicate);
+ return (unfiltered instanceof FilteredEntrySortedMap)
+ ? filterFiltered((FilteredEntrySortedMap<K, V>) unfiltered, entryPredicate)
+ : new FilteredEntrySortedMap<K, V>(checkNotNull(unfiltered), entryPredicate);
+ }
+
+ /**
+ * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
+ * filtering a filtered map.
+ */
+ private static <K, V> Map<K, V> filterFiltered(AbstractFilteredMap<K, V> map,
+ Predicate<? super Entry<K, V>> entryPredicate) {
+ Predicate<Entry<K, V>> predicate =
+ Predicates.and(map.predicate, entryPredicate);
+ return new FilteredEntryMap<K, V>(map.unfiltered, predicate);
+ }
+
+ private abstract static class AbstractFilteredMap<K, V>
+ extends AbstractMap<K, V> {
+ final Map<K, V> unfiltered;
+ final Predicate<? super Entry<K, V>> predicate;
+
+ AbstractFilteredMap(
+ Map<K, V> unfiltered, Predicate<? super Entry<K, V>> predicate) {
+ this.unfiltered = unfiltered;
+ this.predicate = predicate;
+ }
+
+ boolean apply(Object key, V value) {
+ // This method is called only when the key is in the map, implying that
+ // key is a K.
+ @SuppressWarnings("unchecked")
+ K k = (K) key;
+ return predicate.apply(Maps.immutableEntry(k, value));
+ }
+
+ @Override public V put(K key, V value) {
+ checkArgument(apply(key, value));
+ return unfiltered.put(key, value);
+ }
+
+ @Override public void putAll(Map<? extends K, ? extends V> map) {
+ for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ checkArgument(apply(entry.getKey(), entry.getValue()));
+ }
+ unfiltered.putAll(map);
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return unfiltered.containsKey(key) && apply(key, unfiltered.get(key));
+ }
+
+ @Override public V get(Object key) {
+ V value = unfiltered.get(key);
+ return ((value != null) && apply(key, value)) ? value : null;
+ }
+
+ @Override public boolean isEmpty() {
+ return entrySet().isEmpty();
+ }
+
+ @Override public V remove(Object key) {
+ return containsKey(key) ? unfiltered.remove(key) : null;
+ }
+
+ Collection<V> values;
+
+ @Override public Collection<V> values() {
+ Collection<V> result = values;
+ return (result == null) ? values = new Values() : result;
+ }
+
+ class Values extends AbstractCollection<V> {
+ @Override public Iterator<V> iterator() {
+ final Iterator<Entry<K, V>> entryIterator = entrySet().iterator();
+ return new UnmodifiableIterator<V>() {
+ @Override
+ public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+
+ @Override
+ public V next() {
+ return entryIterator.next().getValue();
+ }
+ };
+ }
+
+ @Override public int size() {
+ return entrySet().size();
+ }
+
+ @Override public void clear() {
+ entrySet().clear();
+ }
+
+ @Override public boolean isEmpty() {
+ return entrySet().isEmpty();
+ }
+
+ @Override public boolean remove(Object o) {
+ Iterator<Entry<K, V>> iterator = unfiltered.entrySet().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<?> collection) {
+ checkNotNull(collection);
+ boolean changed = false;
+ Iterator<Entry<K, V>> iterator = unfiltered.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry<K, V> entry = iterator.next();
+ if (collection.contains(entry.getValue()) && predicate.apply(entry)) {
+ iterator.remove();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ @Override public boolean retainAll(Collection<?> collection) {
+ checkNotNull(collection);
+ boolean changed = false;
+ Iterator<Entry<K, V>> iterator = unfiltered.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry<K, V> entry = iterator.next();
+ if (!collection.contains(entry.getValue())
+ && predicate.apply(entry)) {
+ iterator.remove();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ @Override public Object[] toArray() {
+ // creating an ArrayList so filtering happens once
+ return Lists.newArrayList(iterator()).toArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return Lists.newArrayList(iterator()).toArray(array);
+ }
+ }
+ }
+ /**
+ * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
+ * filtering a filtered sorted map.
+ */
+ private static <K, V> SortedMap<K, V> filterFiltered(
+ FilteredEntrySortedMap<K, V> map,
+ Predicate<? super Entry<K, V>> entryPredicate) {
+ Predicate<Entry<K, V>> predicate
+ = Predicates.and(map.predicate, entryPredicate);
+ return new FilteredEntrySortedMap<K, V>(map.sortedMap(), predicate);
+ }
+
+ private static class FilteredEntrySortedMap<K, V>
+ extends FilteredEntryMap<K, V> implements SortedMap<K, V> {
+
+ FilteredEntrySortedMap(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 FilteredEntrySortedMap<K, V>(sortedMap().headMap(toKey), predicate);
+ }
+
+ @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
+ return new FilteredEntrySortedMap<K, V>(
+ sortedMap().subMap(fromKey, toKey), predicate);
+ }
+
+ @Override public SortedMap<K, V> tailMap(K fromKey) {
+ return new FilteredEntrySortedMap<K, V>(
+ sortedMap().tailMap(fromKey), predicate);
+ }
+ }
+
+ private static class FilteredKeyMap<K, V> extends AbstractFilteredMap<K, V> {
+ Predicate<? super K> keyPredicate;
+
+ FilteredKeyMap(Map<K, V> unfiltered, Predicate<? super K> keyPredicate,
+ Predicate<Entry<K, V>> entryPredicate) {
+ super(unfiltered, entryPredicate);
+ this.keyPredicate = keyPredicate;
+ }
+
+ Set<Entry<K, V>> entrySet;
+
+ @Override public Set<Entry<K, V>> entrySet() {
+ Set<Entry<K, V>> result = entrySet;
+ return (result == null)
+ ? entrySet = Sets.filter(unfiltered.entrySet(), predicate)
+ : result;
+ }
+
+ Set<K> keySet;
+
+ @Override public Set<K> keySet() {
+ Set<K> result = keySet;
+ return (result == null)
+ ? keySet = Sets.filter(unfiltered.keySet(), keyPredicate)
+ : result;
+ }
+
+ // The cast is called only when the key is in the unfiltered map, implying
+ // that key is a K.
+ @Override
+ @SuppressWarnings("unchecked")
+ public boolean containsKey(Object key) {
+ return unfiltered.containsKey(key) && keyPredicate.apply((K) key);
+ }
+ }
+
+ static class FilteredEntryMap<K, V> extends AbstractFilteredMap<K, V> {
+ /**
+ * Entries in this set satisfy the predicate, but they don't validate the
+ * input to {@code Entry.setValue()}.
+ */
+ final Set<Entry<K, V>> filteredEntrySet;
+
+ FilteredEntryMap(
+ Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
+ super(unfiltered, entryPredicate);
+ filteredEntrySet = Sets.filter(unfiltered.entrySet(), predicate);
+ }
+
+ Set<Entry<K, V>> entrySet;
+
+ @Override public Set<Entry<K, V>> entrySet() {
+ Set<Entry<K, V>> result = entrySet;
+ return (result == null) ? entrySet = new EntrySet() : result;
+ }
+
+ private class EntrySet extends ForwardingSet<Entry<K, V>> {
+ @Override protected Set<Entry<K, V>> delegate() {
+ return filteredEntrySet;
+ }
+
+ @Override public Iterator<Entry<K, V>> iterator() {
+ final Iterator<Entry<K, V>> iterator = filteredEntrySet.iterator();
+ return new UnmodifiableIterator<Entry<K, V>>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ final Entry<K, V> entry = iterator.next();
+ return new ForwardingMapEntry<K, V>() {
+ @Override protected Entry<K, V> delegate() {
+ return entry;
+ }
+
+ @Override public V setValue(V value) {
+ checkArgument(apply(entry.getKey(), value));
+ return super.setValue(value);
+ }
+ };
+ }
+ };
+ }
+ }
+
+ Set<K> keySet;
+
+ @Override public Set<K> keySet() {
+ Set<K> result = keySet;
+ return (result == null) ? keySet = new KeySet() : result;
+ }
+
+ private class KeySet extends Sets.ImprovedAbstractSet<K> {
+ @Override public Iterator<K> iterator() {
+ final Iterator<Entry<K, V>> iterator = filteredEntrySet.iterator();
+ return new UnmodifiableIterator<K>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public K next() {
+ return iterator.next().getKey();
+ }
+ };
+ }
+
+ @Override public int size() {
+ return filteredEntrySet.size();
+ }
+
+ @Override public void clear() {
+ filteredEntrySet.clear();
+ }
+
+ @Override public boolean contains(Object o) {
+ return containsKey(o);
+ }
+
+ @Override public boolean remove(Object o) {
+ if (containsKey(o)) {
+ unfiltered.remove(o);
+ return true;
+ }
+ return false;
+ }
+
+ @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())) {
+ iterator.remove();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ @Override public Object[] toArray() {
+ // creating an ArrayList so filtering happens once
+ return Lists.newArrayList(iterator()).toArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return Lists.newArrayList(iterator()).toArray(array);
+ }
+ }
+ }
+
+ /**
+ * 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
+ */
+ @Beta
+ @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
+ * isEmpty()} methods of its key set and value collection to this
+ * implementation.
+ */
+ @GwtCompatible
+ abstract static 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}
+ * is first called.
+ */
+ protected abstract Set<Entry<K, V>> createEntrySet();
+
+ private Set<Entry<K, V>> entrySet;
+
+ @Override public Set<Entry<K, V>> entrySet() {
+ Set<Entry<K, V>> result = entrySet;
+ if (result == null) {
+ entrySet = result = createEntrySet();
+ }
+ return result;
+ }
+
+ private Set<K> keySet;
+
+ @Override public Set<K> keySet() {
+ Set<K> result = keySet;
+ if (result == null) {
+ return keySet = new KeySet<K, V>() {
+ @Override Map<K, V> map() {
+ return ImprovedAbstractMap.this;
+ }
+ };
+ }
+ return result;
+ }
+
+ private Collection<V> values;
+
+ @Override public Collection<V> values() {
+ Collection<V> result = values;
+ if (result == null) {
+ return values = new Values<K, V>() {
+ @Override Map<K, V> map() {
+ return ImprovedAbstractMap.this;
+ }
+ };
+ }
+ return result;
+ }
+ }
+
+ static final MapJoiner STANDARD_JOINER =
+ Collections2.STANDARD_JOINER.withKeyValueSeparator("=");
+
+ /**
+ * Delegates to {@link Map#get}. Returns {@code null} on {@code
+ * ClassCastException}.
+ */
+ static <V> V safeGet(Map<?, V> map, Object key) {
+ try {
+ return map.get(key);
+ } catch (ClassCastException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Delegates to {@link Map#containsKey}. Returns {@code false} on {@code
+ * ClassCastException}
+ */
+ static boolean safeContainsKey(Map<?, ?> map, Object key) {
+ try {
+ return map.containsKey(key);
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Implements {@code Collection.contains} safely for forwarding collections of
+ * map entries. If {@code o} is an instance of {@code Map.Entry}, it is
+ * wrapped using {@link #unmodifiableEntry} to protect against a possible
+ * nefarious equals method.
+ *
+ * <p>Note that {@code c} is the backing (delegate) collection, rather than
+ * the forwarding collection.
+ *
+ * @param c the delegate (unwrapped) collection of map entries
+ * @param o the object that might be contained in {@code c}
+ * @return {@code true} if {@code c} contains {@code o}
+ */
+ static <K, V> boolean containsEntryImpl(Collection<Entry<K, V>> c, Object o) {
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ return c.contains(unmodifiableEntry((Entry<?, ?>) o));
+ }
+
+ /**
+ * Implements {@code Collection.remove} safely for forwarding collections of
+ * map entries. If {@code o} is an instance of {@code Map.Entry}, it is
+ * wrapped using {@link #unmodifiableEntry} to protect against a possible
+ * nefarious equals method.
+ *
+ * <p>Note that {@code c} is backing (delegate) collection, rather than the
+ * forwarding collection.
+ *
+ * @param c the delegate (unwrapped) collection of map entries
+ * @param o the object to remove from {@code c}
+ * @return {@code true} if {@code c} was changed
+ */
+ static <K, V> boolean removeEntryImpl(Collection<Entry<K, V>> c, Object o) {
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ return c.remove(unmodifiableEntry((Entry<?, ?>) o));
+ }
+
+ /**
+ * An implementation of {@link Map#equals}.
+ */
+ static boolean equalsImpl(Map<?, ?> map, Object object) {
+ if (map == object) {
+ return true;
+ }
+ if (object instanceof Map) {
+ Map<?, ?> o = (Map<?, ?>) object;
+ return map.entrySet().equals(o.entrySet());
+ }
+ return false;
+ }
+
+ /**
+ * 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) {
+ StringBuilder sb
+ = Collections2.newStringBuilderForCollection(map.size()).append('{');
+ STANDARD_JOINER.appendTo(sb, map);
+ return sb.append('}').toString();
+ }
+
+ /**
+ * An implementation of {@link Map#putAll}.
+ */
+ static <K, V> void putAllImpl(
+ Map<K, V> self, Map<? extends K, ? extends V> map) {
+ for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ self.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * An admittedly inefficient implementation of {@link Map#containsKey}.
+ */
+ static boolean containsKeyImpl(Map<?, ?> map, @Nullable Object 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) {
+ for (Entry<?, ?> entry : map.entrySet()) {
+ if (Objects.equal(entry.getValue(), value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ 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();
+ }
+ };
+ }
+
+ abstract static class KeySet<K, V> extends Sets.ImprovedAbstractSet<K> {
+ abstract Map<K, V> map();
+
+ @Override public Iterator<K> iterator() {
+ return keyIterator(map().entrySet().iterator());
+ }
+
+ @Override public int size() {
+ return map().size();
+ }
+
+ @Override public boolean isEmpty() {
+ return map().isEmpty();
+ }
+
+ @Override public boolean contains(Object o) {
+ return map().containsKey(o);
+ }
+
+ @Override public boolean remove(Object o) {
+ if (contains(o)) {
+ map().remove(o);
+ return true;
+ }
+ return false;
+ }
+
+ @Override public void clear() {
+ map().clear();
+ }
+ }
+
+ @Nullable
+ static <K> K keyOrNull(@Nullable Entry<K, ?> entry) {
+ return (entry == null) ? null : entry.getKey();
+ }
+
+ @GwtIncompatible("NavigableMap")
+ abstract static class NavigableKeySet<K, V> extends KeySet<K, V> implements NavigableSet<K> {
+ @Override
+ abstract NavigableMap<K, V> 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);
+ }
+
+ @Override
+ public SortedSet<K> tailSet(K fromElement) {
+ return tailSet(fromElement, true);
+ }
+ }
+
+ 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());
+ }
+
+ @Override public boolean remove(Object o) {
+ try {
+ return super.remove(o);
+ } catch (UnsupportedOperationException e) {
+ for (Entry<K, V> entry : map().entrySet()) {
+ if (Objects.equal(o, entry.getValue())) {
+ map().remove(entry.getKey());
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ try {
+ return super.removeAll(checkNotNull(c));
+ } catch (UnsupportedOperationException e) {
+ Set<K> toRemove = Sets.newHashSet();
+ for (Entry<K, V> entry : map().entrySet()) {
+ if (c.contains(entry.getValue())) {
+ toRemove.add(entry.getKey());
+ }
+ }
+ return map().keySet().removeAll(toRemove);
+ }
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ try {
+ return super.retainAll(checkNotNull(c));
+ } catch (UnsupportedOperationException e) {
+ Set<K> toRetain = Sets.newHashSet();
+ for (Entry<K, V> entry : map().entrySet()) {
+ if (c.contains(entry.getValue())) {
+ toRetain.add(entry.getKey());
+ }
+ }
+ return map().keySet().retainAll(toRetain);
+ }
+ }
+
+ @Override public int size() {
+ return map().size();
+ }
+
+ @Override public boolean isEmpty() {
+ return map().isEmpty();
+ }
+
+ @Override public boolean contains(@Nullable Object o) {
+ return map().containsValue(o);
+ }
+
+ @Override public void clear() {
+ map().clear();
+ }
+ }
+
+ abstract static class EntrySet<K, V>
+ extends Sets.ImprovedAbstractSet<Entry<K, V>> {
+ abstract Map<K, V> map();
+
+ @Override public int size() {
+ return map().size();
+ }
+
+ @Override public void clear() {
+ map().clear();
+ }
+
+ @Override public boolean contains(Object o) {
+ if (o instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ Object key = entry.getKey();
+ V value = map().get(key);
+ return Objects.equal(value, entry.getValue())
+ && (value != null || map().containsKey(key));
+ }
+ return false;
+ }
+
+ @Override public boolean isEmpty() {
+ return map().isEmpty();
+ }
+
+ @Override public boolean remove(Object o) {
+ if (contains(o)) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ return map().keySet().remove(entry.getKey());
+ }
+ return false;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ try {
+ return super.removeAll(checkNotNull(c));
+ } catch (UnsupportedOperationException e) {
+ // if the iterators don't support remove
+ boolean changed = true;
+ for (Object o : c) {
+ changed |= remove(o);
+ }
+ return changed;
+ }
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ try {
+ return super.retainAll(checkNotNull(c));
+ } catch (UnsupportedOperationException e) {
+ // if the iterators don't support remove
+ Set<Object> keys = Sets.newHashSetWithExpectedSize(c.size());
+ for (Object o : c) {
+ if (contains(o)) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ keys.add(entry.getKey());
+ }
+ }
+ return map().keySet().retainAll(keys);
+ }
+ }
+ }
+
+ @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;
+ if (result == null) {
+ result = navigableKeySet = new NavigableKeySet<K, V>() {
+ @Override
+ NavigableMap<K, V> map() {
+ return DescendingMap.this;
+ }
+ };
+ }
+ return 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
new file mode 100644
index 0000000..f9c2d92
--- /dev/null
+++ b/guava/src/com/google/common/collect/MinMaxPriorityQueue.java
@@ -0,0 +1,939 @@
+/*
+ * 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.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkPositionIndex;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.Beta;
+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.List;
+import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
+import java.util.Queue;
+
+/**
+ * A double-ended priority queue, which provides constant-time access to both
+ * its least element and its greatest element, as determined by the queue's
+ * specified comparator. If no comparator is given at construction time, the
+ * natural order of elements is used.
+ *
+ * <p>As a {@link Queue} it functions exactly as a {@link PriorityQueue}: its
+ * head element -- the implicit target of the methods {@link #peek()}, {@link
+ * #poll()} and {@link #remove()} -- is defined as the <i>least</i> element in
+ * the queue according to the queue's comparator. But unlike a regular priority
+ * queue, the methods {@link #peekLast}, {@link #pollLast} and
+ * {@link #removeLast} are also provided, to act on the <i>greatest</i> element
+ * in the queue instead.
+ *
+ * <p>A min-max priority queue can be configured with a maximum size. If so,
+ * each time the size of the queue exceeds that value, the queue automatically
+ * removes its greatest element according to its comparator (which might be the
+ * element that was just added). This is different from conventional bounded
+ * queues, which either block or reject new elements when full.
+ *
+ * <p>This implementation is based on the
+ * <a href="http://portal.acm.org/citation.cfm?id=6621">min-max heap</a>
+ * developed by Atkinson, et al. Unlike many other double-ended priority queues,
+ * it stores elements in a single array, as compact as the traditional heap data
+ * structure used in {@link PriorityQueue}.
+ *
+ * <p>This class is not thread-safe, and does not accept null elements.
+ *
+ * <p><i>Performance notes:</i>
+ *
+ * <ul>
+ * <li>The retrieval operations {@link #peek}, {@link #peekFirst}, {@link
+ * #peekLast}, {@link #element}, and {@link #size} are constant-time
+ * <li>The enqueing and dequeing operations ({@link #offer}, {@link #add}, and
+ * all the forms of {@link #poll} and {@link #remove()}) run in {@code
+ * O(log n) time}
+ * <li>The {@link #remove(Object)} and {@link #contains} operations require
+ * linear ({@code O(n)}) time
+ * <li>If you only access one end of the queue, and don't use a maximum size,
+ * this class is functionally equivalent to {@link PriorityQueue}, but
+ * significantly slower.
+ * </ul>
+ *
+ * @author Sverre Sundsdal
+ * @author Torbjorn Gannholm
+ * @since 8.0
+ */
+// TODO(kevinb): GWT compatibility
+@Beta
+public final class MinMaxPriorityQueue<E> extends AbstractQueue<E> {
+
+ /**
+ * Creates a new min-max priority queue with default settings: natural order,
+ * no maximum size, no initial contents, and an initial expected size of 11.
+ */
+ public static <E extends Comparable<E>> MinMaxPriorityQueue<E> create() {
+ return new Builder<Comparable>(Ordering.natural()).create();
+ }
+
+ /**
+ * Creates a new min-max priority queue using natural order, no maximum size,
+ * and initially containing the given elements.
+ */
+ public static <E extends Comparable<E>> MinMaxPriorityQueue<E> create(
+ Iterable<? extends E> initialContents) {
+ return new Builder<E>(Ordering.<E>natural()).create(initialContents);
+ }
+
+ /**
+ * Creates and returns a new builder, configured to build {@code
+ * MinMaxPriorityQueue} instances that use {@code comparator} to determine the
+ * least and greatest elements.
+ */
+ public static <B> Builder<B> orderedBy(Comparator<B> comparator) {
+ return new Builder<B>(comparator);
+ }
+
+ /**
+ * Creates and returns a new builder, configured to build {@code
+ * MinMaxPriorityQueue} instances sized appropriately to hold {@code
+ * expectedSize} elements.
+ */
+ public static Builder<Comparable> expectedSize(int expectedSize) {
+ return new Builder<Comparable>(Ordering.natural())
+ .expectedSize(expectedSize);
+ }
+
+ /**
+ * Creates and returns a new builder, configured to build {@code
+ * MinMaxPriorityQueue} instances that are limited to {@code maximumSize}
+ * elements. Each time a queue grows beyond this bound, it immediately
+ * removes its greatest element (according to its comparator), which might be
+ * the element that was just added.
+ */
+ public static Builder<Comparable> maximumSize(int maximumSize) {
+ return new Builder<Comparable>(Ordering.natural())
+ .maximumSize(maximumSize);
+ }
+
+ /**
+ * The builder class used in creation of min-max priority queues. Instead of
+ * constructing one directly, use {@link
+ * MinMaxPriorityQueue#orderedBy(Comparator)}, {@link
+ * MinMaxPriorityQueue#expectedSize(int)} or {@link
+ * MinMaxPriorityQueue#maximumSize(int)}.
+ *
+ * @param <B> the upper bound on the eventual type that can be produced by
+ * this builder (for example, a {@code Builder<Number>} can produce a
+ * {@code Queue<Number>} or {@code Queue<Integer>} but not a {@code
+ * Queue<Object>}).
+ * @since 8.0
+ */
+ @Beta
+ public static final class Builder<B> {
+ /*
+ * TODO(kevinb): when the dust settles, see if we still need this or can
+ * just default to DEFAULT_CAPACITY.
+ */
+ private static final int UNSET_EXPECTED_SIZE = -1;
+
+ private final Comparator<B> comparator;
+ private int expectedSize = UNSET_EXPECTED_SIZE;
+ private int maximumSize = Integer.MAX_VALUE;
+
+ private Builder(Comparator<B> comparator) {
+ this.comparator = checkNotNull(comparator);
+ }
+
+ /**
+ * Configures this builder to build min-max priority queues with an initial
+ * expected size of {@code expectedSize}.
+ */
+ public Builder<B> expectedSize(int expectedSize) {
+ checkArgument(expectedSize >= 0);
+ this.expectedSize = expectedSize;
+ return this;
+ }
+
+ /**
+ * Configures this builder to build {@code MinMaxPriorityQueue} instances
+ * that are limited to {@code maximumSize} elements. Each time a queue grows
+ * beyond this bound, it immediately removes its greatest element (according
+ * to its comparator), which might be the element that was just added.
+ */
+ public Builder<B> maximumSize(int maximumSize) {
+ checkArgument(maximumSize > 0);
+ this.maximumSize = maximumSize;
+ return this;
+ }
+
+ /**
+ * Builds a new min-max priority queue using the previously specified
+ * options, and having no initial contents.
+ */
+ public <T extends B> MinMaxPriorityQueue<T> create() {
+ return create(Collections.<T>emptySet());
+ }
+
+ /**
+ * Builds a new min-max priority queue using the previously specified
+ * options, and having the given initial elements.
+ */
+ public <T extends B> MinMaxPriorityQueue<T> create(
+ Iterable<? extends T> initialContents) {
+ MinMaxPriorityQueue<T> queue = new MinMaxPriorityQueue<T>(
+ this, initialQueueSize(expectedSize, maximumSize, initialContents));
+ for (T element : initialContents) {
+ queue.offer(element);
+ }
+ return queue;
+ }
+
+ @SuppressWarnings("unchecked") // safe "contravariant cast"
+ private <T extends B> Ordering<T> ordering() {
+ return Ordering.from((Comparator<T>) comparator);
+ }
+ }
+
+ private final Heap minHeap;
+ private final Heap maxHeap;
+ @VisibleForTesting final int maximumSize;
+ private Object[] queue;
+ private int size;
+ private int modCount;
+
+ private MinMaxPriorityQueue(Builder<? super E> builder, int queueSize) {
+ Ordering<E> ordering = builder.ordering();
+ this.minHeap = new Heap(ordering);
+ this.maxHeap = new Heap(ordering.reverse());
+ minHeap.otherHeap = maxHeap;
+ maxHeap.otherHeap = minHeap;
+
+ this.maximumSize = builder.maximumSize;
+ // TODO(kevinb): pad?
+ this.queue = new Object[queueSize];
+ }
+
+ @Override public int size() {
+ return size;
+ }
+
+ /**
+ * Adds the given element to this queue. If this queue has a maximum size,
+ * after adding {@code element} the queue will automatically evict its
+ * greatest element (according to its comparator), which may be {@code
+ * element} itself.
+ *
+ * @return {@code true} always
+ */
+ @Override public boolean add(E element) {
+ offer(element);
+ return true;
+ }
+
+ @Override public boolean addAll(Collection<? extends E> newElements) {
+ boolean modified = false;
+ for (E element : newElements) {
+ offer(element);
+ modified = true;
+ }
+ return modified;
+ }
+
+ /**
+ * Adds the given element to this queue. If this queue has a maximum size,
+ * after adding {@code element} the queue will automatically evict its
+ * greatest element (according to its comparator), which may be {@code
+ * element} itself.
+ */
+ @Override public boolean offer(E element) {
+ checkNotNull(element);
+ modCount++;
+ int insertIndex = size++;
+
+ growIfNeeded();
+
+ // Adds the element to the end of the heap and bubbles it up to the correct
+ // position.
+ heapForIndex(insertIndex).bubbleUp(insertIndex, element);
+ return size <= maximumSize || pollLast() != element;
+ }
+
+ @Override public E poll() {
+ return isEmpty() ? null : removeAndGet(0);
+ }
+
+ @SuppressWarnings("unchecked") // we must carefully only allow Es to get in
+ E elementData(int index) {
+ return (E) queue[index];
+ }
+
+ @Override public E peek() {
+ return isEmpty() ? null : elementData(0);
+ }
+
+ /**
+ * Returns the index of the max element.
+ */
+ private int getMaxElementIndex() {
+ switch (size) {
+ case 1:
+ return 0; // The lone element in the queue is the maximum.
+ case 2:
+ return 1; // The lone element in the maxHeap is the maximum.
+ default:
+ // The max element must sit on the first level of the maxHeap. It is
+ // actually the *lesser* of the two from the maxHeap's perspective.
+ return (maxHeap.compareElements(1, 2) <= 0) ? 1 : 2;
+ }
+ }
+
+ /**
+ * Removes and returns the least element of this queue, or returns {@code
+ * null} if the queue is empty.
+ */
+ public E pollFirst() {
+ return poll();
+ }
+
+ /**
+ * Removes and returns the least element of this queue.
+ *
+ * @throws NoSuchElementException if the queue is empty
+ */
+ public E removeFirst() {
+ return remove();
+ }
+
+ /**
+ * Retrieves, but does not remove, the least element of this queue, or returns
+ * {@code null} if the queue is empty.
+ */
+ public E peekFirst() {
+ return peek();
+ }
+
+ /**
+ * Removes and returns the greatest element of this queue, or returns {@code
+ * null} if the queue is empty.
+ */
+ public E pollLast() {
+ return isEmpty() ? null : removeAndGet(getMaxElementIndex());
+ }
+
+ /**
+ * Removes and returns the greatest element of this queue.
+ *
+ * @throws NoSuchElementException if the queue is empty
+ */
+ public E removeLast() {
+ if (isEmpty()) {
+ throw new NoSuchElementException();
+ }
+ return removeAndGet(getMaxElementIndex());
+ }
+
+ /**
+ * Retrieves, but does not remove, the greatest element of this queue, or
+ * returns {@code null} if the queue is empty.
+ */
+ public E peekLast() {
+ return isEmpty() ? null : elementData(getMaxElementIndex());
+ }
+
+ /**
+ * Removes the element at position {@code index}.
+ *
+ * <p>Normally this method leaves the elements at up to {@code index - 1},
+ * inclusive, untouched. Under these circumstances, it returns {@code null}.
+ *
+ * <p>Occasionally, in order to maintain the heap invariant, it must swap a
+ * later element of the list with one before {@code index}. Under these
+ * circumstances it returns a pair of elements as a {@link MoveDesc}. The
+ * first one is the element that was previously at the end of the heap and is
+ * now at some position before {@code index}. The second element is the one
+ * that was swapped down to replace the element at {@code index}. This fact is
+ * used by iterator.remove so as to visit elements during a traversal once and
+ * only once.
+ */
+ @VisibleForTesting MoveDesc<E> removeAt(int index) {
+ checkPositionIndex(index, size);
+ modCount++;
+ size--;
+ if (size == index) {
+ queue[size] = null;
+ return null;
+ }
+ E actualLastElement = elementData(size);
+ int lastElementAt = heapForIndex(size)
+ .getCorrectLastElement(actualLastElement);
+ E toTrickle = elementData(size);
+ queue[size] = null;
+ MoveDesc<E> changes = fillHole(index, toTrickle);
+ if (lastElementAt < index) {
+ // Last element is moved to before index, swapped with trickled element.
+ if (changes == null) {
+ // The trickled element is still after index.
+ return new MoveDesc<E>(actualLastElement, toTrickle);
+ } else {
+ // The trickled element is back before index, but the replaced element
+ // has now been moved after index.
+ return new MoveDesc<E>(actualLastElement, changes.replaced);
+ }
+ }
+ // Trickled element was after index to begin with, no adjustment needed.
+ return changes;
+ }
+
+ private MoveDesc<E> fillHole(int index, E toTrickle) {
+ Heap heap = heapForIndex(index);
+ // We consider elementData(index) a "hole", and we want to fill it
+ // with the last element of the heap, toTrickle.
+ // Since the last element of the heap is from the bottom level, we
+ // optimistically fill index position with elements from lower levels,
+ // moving the hole down. In most cases this reduces the number of
+ // comparisons with toTrickle, but in some cases we will need to bubble it
+ // all the way up again.
+ int vacated = heap.fillHoleAt(index);
+ // Try to see if toTrickle can be bubbled up min levels.
+ int bubbledTo = heap.bubbleUpAlternatingLevels(vacated, toTrickle);
+ if (bubbledTo == vacated) {
+ // Could not bubble toTrickle up min levels, try moving
+ // it from min level to max level (or max to min level) and bubble up
+ // there.
+ return heap.tryCrossOverAndBubbleUp(index, vacated, toTrickle);
+ } else {
+ return (bubbledTo < index)
+ ? new MoveDesc<E>(toTrickle, elementData(index))
+ : null;
+ }
+ }
+
+ // Returned from removeAt() to iterator.remove()
+ static class MoveDesc<E> {
+ final E toTrickle;
+ final E replaced;
+
+ MoveDesc(E toTrickle, E replaced) {
+ this.toTrickle = toTrickle;
+ this.replaced = replaced;
+ }
+ }
+
+ /**
+ * Removes and returns the value at {@code index}.
+ */
+ private E removeAndGet(int index) {
+ E value = elementData(index);
+ removeAt(index);
+ return value;
+ }
+
+ private Heap heapForIndex(int i) {
+ return isEvenLevel(i) ? minHeap : maxHeap;
+ }
+
+ private static final int EVEN_POWERS_OF_TWO = 0x55555555;
+ private static final int ODD_POWERS_OF_TWO = 0xaaaaaaaa;
+
+ @VisibleForTesting static boolean isEvenLevel(int index) {
+ int oneBased = index + 1;
+ checkState(oneBased > 0, "negative index");
+ return (oneBased & EVEN_POWERS_OF_TWO) > (oneBased & ODD_POWERS_OF_TWO);
+ }
+
+ /**
+ * Returns {@code true} if the MinMax heap structure holds. This is only used
+ * in testing.
+ *
+ * TODO(kevinb): move to the test class?
+ */
+ @VisibleForTesting boolean isIntact() {
+ for (int i = 1; i < size; i++) {
+ if (!heapForIndex(i).verifyIndex(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Each instance of MinMaxPriortyQueue encapsulates two instances of Heap:
+ * a min-heap and a max-heap. Conceptually, these might each have their own
+ * array for storage, but for efficiency's sake they are stored interleaved on
+ * alternate heap levels in the same array (MMPQ.queue).
+ */
+ private class Heap {
+ final Ordering<E> ordering;
+ Heap otherHeap;
+
+ Heap(Ordering<E> ordering) {
+ this.ordering = ordering;
+ }
+
+ int compareElements(int a, int b) {
+ return ordering.compare(elementData(a), elementData(b));
+ }
+
+ /**
+ * Tries to move {@code toTrickle} from a min to a max level and
+ * bubble up there. If it moved before {@code removeIndex} this method
+ * returns a pair as described in {@link #removeAt}.
+ */
+ MoveDesc<E> tryCrossOverAndBubbleUp(
+ int removeIndex, int vacated, E toTrickle) {
+ int crossOver = crossOver(vacated, toTrickle);
+ if (crossOver == vacated) {
+ return null;
+ }
+ // Successfully crossed over from min to max.
+ // Bubble up max levels.
+ E parent;
+ // If toTrickle is moved up to a parent of removeIndex, the parent is
+ // placed in removeIndex position. We must return that to the iterator so
+ // that it knows to skip it.
+ if (crossOver < removeIndex) {
+ // We crossed over to the parent level in crossOver, so the parent
+ // has already been moved.
+ parent = elementData(removeIndex);
+ } else {
+ parent = elementData(getParentIndex(removeIndex));
+ }
+ // bubble it up the opposite heap
+ if (otherHeap.bubbleUpAlternatingLevels(crossOver, toTrickle)
+ < removeIndex) {
+ return new MoveDesc<E>(toTrickle, parent);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Bubbles a value from {@code index} up the appropriate heap if required.
+ */
+ void bubbleUp(int index, E x) {
+ int crossOver = crossOverUp(index, x);
+
+ Heap heap;
+ if (crossOver == index) {
+ heap = this;
+ } else {
+ index = crossOver;
+ heap = otherHeap;
+ }
+ heap.bubbleUpAlternatingLevels(index, x);
+ }
+
+ /**
+ * Bubbles a value from {@code index} up the levels of this heap, and
+ * returns the index the element ended up at.
+ */
+ int bubbleUpAlternatingLevels(int index, E x) {
+ while (index > 2) {
+ int grandParentIndex = getGrandparentIndex(index);
+ E e = elementData(grandParentIndex);
+ if (ordering.compare(e, x) <= 0) {
+ break;
+ }
+ queue[index] = e;
+ index = grandParentIndex;
+ }
+ queue[index] = x;
+ return index;
+ }
+
+ /**
+ * Returns the index of minimum value between {@code index} and
+ * {@code index + len}, or {@code -1} if {@code index} is greater than
+ * {@code size}.
+ */
+ int findMin(int index, int len) {
+ if (index >= size) {
+ return -1;
+ }
+ checkState(index > 0);
+ int limit = Math.min(index, size - len) + len;
+ int minIndex = index;
+ for (int i = index + 1; i < limit; i++) {
+ if (compareElements(i, minIndex) < 0) {
+ minIndex = i;
+ }
+ }
+ return minIndex;
+ }
+
+ /**
+ * Returns the minimum child or {@code -1} if no child exists.
+ */
+ int findMinChild(int index) {
+ return findMin(getLeftChildIndex(index), 2);
+ }
+
+ /**
+ * Returns the minimum grand child or -1 if no grand child exists.
+ */
+ int findMinGrandChild(int index) {
+ int leftChildIndex = getLeftChildIndex(index);
+ if (leftChildIndex < 0) {
+ return -1;
+ }
+ return findMin(getLeftChildIndex(leftChildIndex), 4);
+ }
+
+ /**
+ * Moves an element one level up from a min level to a max level
+ * (or vice versa).
+ * Returns the new position of the element.
+ */
+ int crossOverUp(int index, E x) {
+ if (index == 0) {
+ queue[0] = x;
+ return 0;
+ }
+ int parentIndex = getParentIndex(index);
+ E parentElement = elementData(parentIndex);
+ if (parentIndex != 0) {
+ // This is a guard for the case of the childless uncle.
+ // Since the end of the array is actually the middle of the heap,
+ // a smaller childless uncle can become a child of x when we
+ // bubble up alternate levels, violating the invariant.
+ int grandparentIndex = getParentIndex(parentIndex);
+ int uncleIndex = getRightChildIndex(grandparentIndex);
+ if (uncleIndex != parentIndex
+ && getLeftChildIndex(uncleIndex) >= size) {
+ E uncleElement = elementData(uncleIndex);
+ if (ordering.compare(uncleElement, parentElement) < 0) {
+ parentIndex = uncleIndex;
+ parentElement = uncleElement;
+ }
+ }
+ }
+ if (ordering.compare(parentElement, x) < 0) {
+ queue[index] = parentElement;
+ queue[parentIndex] = x;
+ return parentIndex;
+ }
+ queue[index] = x;
+ return index;
+ }
+
+ /**
+ * Returns the conceptually correct last element of the heap.
+ *
+ * <p>Since the last element of the array is actually in the
+ * middle of the sorted structure, a childless uncle node could be
+ * smaller, which would corrupt the invariant if this element
+ * becomes the new parent of the uncle. In that case, we first
+ * switch the last element with its uncle, before returning.
+ */
+ int getCorrectLastElement(E actualLastElement) {
+ int parentIndex = getParentIndex(size);
+ if (parentIndex != 0) {
+ int grandparentIndex = getParentIndex(parentIndex);
+ int uncleIndex = getRightChildIndex(grandparentIndex);
+ if (uncleIndex != parentIndex
+ && getLeftChildIndex(uncleIndex) >= size) {
+ E uncleElement = elementData(uncleIndex);
+ if (ordering.compare(uncleElement, actualLastElement) < 0) {
+ queue[uncleIndex] = actualLastElement;
+ queue[size] = uncleElement;
+ return uncleIndex;
+ }
+ }
+ }
+ return size;
+ }
+
+ /**
+ * Crosses an element over to the opposite heap by moving it one level down
+ * (or up if there are no elements below it).
+ *
+ * Returns the new position of the element.
+ */
+ int crossOver(int index, E x) {
+ int minChildIndex = findMinChild(index);
+ // TODO(kevinb): split the && into two if's and move crossOverUp so it's
+ // only called when there's no child.
+ if ((minChildIndex > 0)
+ && (ordering.compare(elementData(minChildIndex), x) < 0)) {
+ queue[index] = elementData(minChildIndex);
+ queue[minChildIndex] = x;
+ return minChildIndex;
+ }
+ return crossOverUp(index, x);
+ }
+
+ /**
+ * Fills the hole at {@code index} by moving in the least of its
+ * grandchildren to this position, then recursively filling the new hole
+ * created.
+ *
+ * @return the position of the new hole (where the lowest grandchild moved
+ * from, that had no grandchild to replace it)
+ */
+ int fillHoleAt(int index) {
+ int minGrandchildIndex;
+ while ((minGrandchildIndex = findMinGrandChild(index)) > 0) {
+ queue[index] = elementData(minGrandchildIndex);
+ index = minGrandchildIndex;
+ }
+ return index;
+ }
+
+ private boolean verifyIndex(int i) {
+ if ((getLeftChildIndex(i) < size)
+ && (compareElements(i, getLeftChildIndex(i)) > 0)) {
+ return false;
+ }
+ if ((getRightChildIndex(i) < size)
+ && (compareElements(i, getRightChildIndex(i)) > 0)) {
+ return false;
+ }
+ if ((i > 0) && (compareElements(i, getParentIndex(i)) > 0)) {
+ return false;
+ }
+ if ((i > 2) && (compareElements(getGrandparentIndex(i), i) > 0)) {
+ return false;
+ }
+ return true;
+ }
+
+ // These would be static if inner classes could have static members.
+
+ private int getLeftChildIndex(int i) {
+ return i * 2 + 1;
+ }
+
+ private int getRightChildIndex(int i) {
+ return i * 2 + 2;
+ }
+
+ private int getParentIndex(int i) {
+ return (i - 1) / 2;
+ }
+
+ private int getGrandparentIndex(int i) {
+ return getParentIndex(getParentIndex(i)); // (i - 3) / 4
+ }
+ }
+
+ /**
+ * Iterates the elements of the queue in no particular order.
+ *
+ * If the underlying queue is modified during iteration an exception will be
+ * thrown.
+ */
+ private class QueueIterator implements Iterator<E> {
+ private int cursor = -1;
+ private int expectedModCount = modCount;
+ private Queue<E> forgetMeNot;
+ private List<E> skipMe;
+ private E lastFromForgetMeNot;
+ private boolean canRemove;
+
+ @Override public boolean hasNext() {
+ checkModCount();
+ return (nextNotInSkipMe(cursor + 1) < size())
+ || ((forgetMeNot != null) && !forgetMeNot.isEmpty());
+ }
+
+ @Override public E next() {
+ checkModCount();
+ int tempCursor = nextNotInSkipMe(cursor + 1);
+ if (tempCursor < size()) {
+ cursor = tempCursor;
+ canRemove = true;
+ return elementData(cursor);
+ } else if (forgetMeNot != null) {
+ cursor = size();
+ lastFromForgetMeNot = forgetMeNot.poll();
+ if (lastFromForgetMeNot != null) {
+ canRemove = true;
+ return lastFromForgetMeNot;
+ }
+ }
+ throw new NoSuchElementException(
+ "iterator moved past last element in queue.");
+ }
+
+ @Override public void remove() {
+ checkState(canRemove,
+ "no calls to remove() since the last call to next()");
+ checkModCount();
+ canRemove = false;
+ expectedModCount++;
+ if (cursor < size()) {
+ MoveDesc<E> moved = removeAt(cursor);
+ if (moved != null) {
+ if (forgetMeNot == null) {
+ forgetMeNot = new ArrayDeque<E>();
+ skipMe = new ArrayList<E>(3);
+ }
+ forgetMeNot.add(moved.toTrickle);
+ skipMe.add(moved.replaced);
+ }
+ cursor--;
+ } else { // we must have set lastFromForgetMeNot in next()
+ checkState(removeExact(lastFromForgetMeNot));
+ lastFromForgetMeNot = null;
+ }
+ }
+
+ // Finds only this exact instance, not others that are equals()
+ private boolean containsExact(Iterable<E> elements, E target) {
+ for (E element : elements) {
+ if (element == target) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Removes only this exact instance, not others that are equals()
+ boolean removeExact(Object target) {
+ for (int i = 0; i < size; i++) {
+ if (queue[i] == target) {
+ removeAt(i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void checkModCount() {
+ if (modCount != expectedModCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ /**
+ * Returns the index of the first element after {@code c} that is not in
+ * {@code skipMe} and returns {@code size()} if there is no such element.
+ */
+ private int nextNotInSkipMe(int c) {
+ if (skipMe != null) {
+ while (c < size() && containsExact(skipMe, elementData(c))) {
+ c++;
+ }
+ }
+ return c;
+ }
+ }
+
+ /**
+ * Returns an iterator over the elements contained in this collection,
+ * <i>in no particular order</i>.
+ *
+ * <p>The iterator is <i>fail-fast</i>: If the MinMaxPriorityQueue is modified
+ * at any time after the iterator is created, in any way except through the
+ * iterator's own remove method, the iterator will generally throw a
+ * {@link ConcurrentModificationException}. Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the
+ * future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification. Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * @return an iterator over the elements contained in this collection
+ */
+ @Override public Iterator<E> iterator() {
+ return new QueueIterator();
+ }
+
+ @Override public void clear() {
+ for (int i = 0; i < size; i++) {
+ queue[i] = null;
+ }
+ size = 0;
+ }
+
+ @Override public Object[] toArray() {
+ Object[] copyTo = new Object[size];
+ System.arraycopy(queue, 0, copyTo, 0, size);
+ return copyTo;
+ }
+
+ /**
+ * Returns the comparator used to order the elements in this queue. Obeys the
+ * general contract of {@link PriorityQueue#comparator}, but returns {@link
+ * Ordering#natural} instead of {@code null} to indicate natural ordering.
+ */
+ public Comparator<? super E> comparator() {
+ return minHeap.ordering;
+ }
+
+ @VisibleForTesting int capacity() {
+ return queue.length;
+ }
+
+ // Size/capacity-related methods
+
+ private static final int DEFAULT_CAPACITY = 11;
+
+ @VisibleForTesting static int initialQueueSize(int configuredExpectedSize,
+ int maximumSize, Iterable<?> initialContents) {
+ // Start with what they said, if they said it, otherwise DEFAULT_CAPACITY
+ int result = (configuredExpectedSize == Builder.UNSET_EXPECTED_SIZE)
+ ? DEFAULT_CAPACITY
+ : configuredExpectedSize;
+
+ // Enlarge to contain initial contents
+ if (initialContents instanceof Collection) {
+ int initialSize = ((Collection<?>) initialContents).size();
+ result = Math.max(result, initialSize);
+ }
+
+ // Now cap it at maxSize + 1
+ return capAtMaximumSize(result, maximumSize);
+ }
+
+ private void growIfNeeded() {
+ if (size > queue.length) {
+ int newCapacity = calculateNewCapacity();
+ Object[] newQueue = new Object[newCapacity];
+ System.arraycopy(queue, 0, newQueue, 0, queue.length);
+ queue = newQueue;
+ }
+ }
+
+ /** Returns ~2x the old capacity if small; ~1.5x otherwise. */
+ private int calculateNewCapacity() {
+ int oldCapacity = queue.length;
+ int newCapacity = (oldCapacity < 64)
+ ? (oldCapacity + 1) * 2
+ : IntMath.checkedMultiply(oldCapacity / 2, 3);
+ return capAtMaximumSize(newCapacity, maximumSize);
+ }
+
+ /** There's no reason for the queueSize to ever be more than maxSize + 1 */
+ private static int capAtMaximumSize(int queueSize, int maximumSize) {
+ return Math.min(queueSize - 1, maximumSize) + 1; // don't overflow
+ }
+}
diff --git a/guava/src/com/google/common/collect/Multimap.java b/guava/src/com/google/common/collect/Multimap.java
new file mode 100644
index 0000000..7310842
--- /dev/null
+++ b/guava/src/com/google/common/collect/Multimap.java
@@ -0,0 +1,360 @@
+/*
+ * 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 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 collections of values:
+ *
+ * <ul>
+ * <li>a → 1, 2
+ * <li>b → 3
+ * </ul>
+ *
+ * ... or as a single "flattened" collection of key-value pairs:
+ *
+ * <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.
+ *
+ * <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.
+ *
+ * <h3>Uses</h3>
+ *
+ * <p>Multimaps are commonly used anywhere a {@code Map<K, Collection<V>>} would
+ * otherwise have appeared. The advantages 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>It will not retain empty collections after the last value for a key is
+ * removed. As a result, {@link #containsKey} behaves logically, and the
+ * multimap won't leak memory.
+ * <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>.
+ *
+ * @author Jared Levy
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public interface Multimap<K, V> {
+ // Query Operations
+
+ /** Returns the number of key-value pairs in the multimap. */
+ int size();
+
+ /** Returns {@code true} if the multimap contains no key-value pairs. */
+ boolean isEmpty();
+
+ /**
+ * Returns {@code true} if the multimap contains any values for the specified
+ * key.
+ *
+ * @param key key to search for in multimap
+ */
+ boolean containsKey(@Nullable Object key);
+
+ /**
+ * Returns {@code true} if the multimap contains the specified value for any
+ * key.
+ *
+ * @param value value to search for in multimap
+ */
+ boolean containsValue(@Nullable Object value);
+
+ /**
+ * Returns {@code true} if the multimap contains the specified key-value pair.
+ *
+ * @param key key to search for in multimap
+ * @param value value to search for in multimap
+ */
+ boolean containsEntry(@Nullable Object key, @Nullable Object value);
+
+ // Modification Operations
+
+ /**
+ * Stores a key-value pair in the multimap.
+ *
+ * <p>Some multimap implementations allow duplicate key-value pairs, in which
+ * case {@code put} always adds a new key-value pair and increases the
+ * multimap size by 1. Other implementations prohibit duplicates, and storing
+ * a key-value pair that's already in the multimap has no effect.
+ *
+ * @param key key to store in the multimap
+ * @param value value to store in the multimap
+ * @return {@code true} if the method increased the size of the multimap, or
+ * {@code false} if the multimap already contained the key-value pair and
+ * doesn't allow duplicates
+ */
+ boolean put(@Nullable K key, @Nullable V value);
+
+ /**
+ * Removes a single 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
+ * @return {@code true} if the multimap changed
+ */
+ boolean remove(@Nullable Object key, @Nullable Object value);
+
+ // Bulk Operations
+
+ /**
+ * Stores a collection of values with the same key.
+ *
+ * @param key key to store in the multimap
+ * @param values values to store in the multimap
+ * @return {@code true} if the multimap changed
+ */
+ boolean putAll(@Nullable K key, Iterable<? extends V> values);
+
+ /**
+ * Copies all of another multimap's key-value pairs into this multimap. The
+ * order in which the mappings are added is determined by
+ * {@code multimap.entries()}.
+ *
+ * @param multimap mappings to store in this multimap
+ * @return {@code true} if the multimap changed
+ */
+ boolean putAll(Multimap<? extends K, ? extends V> multimap);
+
+ /**
+ * Stores a collection of values with the same key, replacing any existing
+ * values for that key.
+ *
+ * @param key key to store in the multimap
+ * @param values values to store in the multimap
+ * @return the collection of replaced values, or an empty collection if no
+ * values were previously associated with the key. The collection
+ * <i>may</i> be modifiable, but updating it will have no effect on the
+ * multimap.
+ */
+ Collection<V> replaceValues(@Nullable K key, Iterable<? extends V> values);
+
+ /**
+ * Removes all values associated with a given key.
+ *
+ * @param key key of entries to remove from the multimap
+ * @return the collection of removed values, or an empty collection if no
+ * values were associated with the provided key. The collection
+ * <i>may</i> be modifiable, but updating it will have no effect on the
+ * multimap.
+ */
+ Collection<V> removeAll(@Nullable Object key);
+
+ /**
+ * Removes all key-value pairs from the multimap.
+ */
+ void clear();
+
+ // Views
+
+ /**
+ * 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 the collection of values that the key maps to
+ */
+ Collection<V> get(@Nullable K key);
+
+ /**
+ * Returns the set of all keys, each appearing once in the returned set.
+ * Changes to the returned set will update the underlying multimap, and vice
+ * versa.
+ *
+ * @return the collection of distinct keys
+ */
+ Set<K> keySet();
+
+ /**
+ * Returns a collection, which may contain duplicates, of all keys. The number
+ * of times of key appears in the returned multiset equals the number of
+ * mappings the key has in the multimap. Changes to the returned multiset will
+ * update the underlying multimap, and vice versa.
+ *
+ * @return a multiset with keys corresponding to the distinct keys of the
+ * multimap and frequencies corresponding to the number of values that
+ * each key maps to
+ */
+ Multiset<K> keys();
+
+ /**
+ * Returns a collection of all values in the multimap. Changes to the returned
+ * collection will update the underlying multimap, and vice versa.
+ *
+ * @return collection of values, which may include the same value multiple
+ * times if it occurs in multiple mappings
+ */
+ Collection<V> values();
+
+ /**
+ * Returns a collection of all key-value pairs. Changes to the returned
+ * collection will update the underlying multimap, and vice versa. The entries
+ * collection does not support the {@code add} or {@code addAll} operations.
+ *
+ * @return collection of map entries consisting of key-value pairs
+ */
+ Collection<Map.Entry<K, V>> entries();
+
+ /**
+ * Returns a map view that associates each key with the corresponding values
+ * in the multimap. Changes to the returned map, such as element removal, will
+ * update the underlying multimap. The map does not support {@code setValue()}
+ * on its entries, {@code put}, or {@code putAll}.
+ *
+ * <p>When passed a key that is present in the map, {@code
+ * asMap().get(Object)} has the same behavior as {@link #get}, returning a
+ * live collection. When passed a key that is not present, however, {@code
+ * asMap().get(Object)} returns {@code null} instead of an empty collection.
+ *
+ * @return a map view from a key to its collection of values
+ */
+ Map<K, Collection<V>> asMap();
+
+ // Comparison and hashing
+
+ /**
+ * Compares the specified object with this multimap for equality. Two
+ * multimaps are equal when their map views, as returned by {@link #asMap},
+ * are also equal.
+ *
+ * <p>In general, two multimaps with identical key-value mappings may or may
+ * not be equal, depending on the implementation. For example, two
+ * {@link SetMultimap} instances with the same key-value mappings are equal,
+ * but equality of two {@link ListMultimap} instances depends on the ordering
+ * of the values for each key.
+ *
+ * <p>A non-empty {@link SetMultimap} cannot be equal to a non-empty
+ * {@link ListMultimap}, since their {@link #asMap} views contain unequal
+ * collections as values. However, any two empty multimaps are equal, because
+ * they both have empty {@link #asMap} views.
+ */
+ @Override
+ boolean equals(@Nullable Object obj);
+
+ /**
+ * Returns the hash code for this multimap.
+ *
+ * <p>The hash code of a multimap is defined as the hash code of the map view,
+ * as returned by {@link Multimap#asMap}.
+ */
+ @Override
+ int hashCode();
+}
diff --git a/guava/src/com/google/common/collect/Multimaps.java b/guava/src/com/google/common/collect/Multimaps.java
new file mode 100644
index 0000000..1eb7fa8
--- /dev/null
+++ b/guava/src/com/google/common/collect/Multimaps.java
@@ -0,0 +1,2695 @@
+/*
+ * 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 static com.google.common.base.Preconditions.checkState;
+
+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;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.AbstractCollection;
+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.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedSet;
+
+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
+ * @author Louis Wasserman
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(emulated = true)
+public final class Multimaps {
+ private Multimaps() {}
+
+ /**
+ * 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
+ * {@code equals}, {@code hashCode}, and {@code toString} methods for the
+ * multimap and its returned views. However, the multimap's {@code get}
+ * method returns instances of a different class than {@code factory.get()}
+ * does.
+ *
+ * <p>The multimap is serializable if {@code map}, {@code factory}, the
+ * collections generated by {@code factory}, and the multimap contents are all
+ * serializable.
+ *
+ * <p>The multimap is not threadsafe when any concurrent operations update the
+ * multimap, even if {@code map} and the instances generated by
+ * {@code factory} are. Concurrent read operations will work correctly. To
+ * allow concurrent update operations, wrap the multimap with a call to
+ * {@link #synchronizedMultimap}.
+ *
+ * <p>Call this method only when the simpler methods
+ * {@link ArrayListMultimap#create()}, {@link HashMultimap#create()},
+ * {@link LinkedHashMultimap#create()}, {@link LinkedListMultimap#create()},
+ * {@link TreeMultimap#create()}, and
+ * {@link TreeMultimap#create(Comparator, Comparator)} won't suffice.
+ *
+ * <p>Note: the multimap assumes complete ownership over of {@code map} and
+ * the collections returned by {@code factory}. Those objects should not be
+ * manually updated and they should not use soft, weak, or phantom references.
+ *
+ * @param map place to store the mapping from each key to its corresponding
+ * values
+ * @param factory supplier of new, empty collections that will each hold all
+ * values for a given key
+ * @throws IllegalArgumentException if {@code map} is not empty
+ */
+ public static <K, V> Multimap<K, V> newMultimap(Map<K, Collection<V>> map,
+ final Supplier<? extends Collection<V>> factory) {
+ return new CustomMultimap<K, V>(map, factory);
+ }
+
+ private static class CustomMultimap<K, V> extends AbstractMultimap<K, V> {
+ transient Supplier<? extends Collection<V>> factory;
+
+ CustomMultimap(Map<K, Collection<V>> map,
+ Supplier<? extends Collection<V>> factory) {
+ super(map);
+ this.factory = checkNotNull(factory);
+ }
+
+ @Override protected Collection<V> createCollection() {
+ return factory.get();
+ }
+
+ // can't use Serialization writeMultimap and populateMultimap methods since
+ // there's no way to generate the empty backing map.
+
+ /** @serialData the factory and the backing map */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(factory);
+ stream.writeObject(backingMap());
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ factory = (Supplier<? extends Collection<V>>) stream.readObject();
+ Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject();
+ setMap(map);
+ }
+
+ @GwtIncompatible("java serialization not supported")
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Creates a new {@code ListMultimap} that uses the provided map and factory.
+ * It can generate a multimap based on arbitrary {@link Map} and {@link List}
+ * classes.
+ *
+ * <p>The {@code factory}-generated and {@code map} classes determine the
+ * multimap iteration order. They also specify the behavior of the
+ * {@code equals}, {@code hashCode}, and {@code toString} methods for the
+ * multimap and its returned views. The multimap's {@code get}, {@code
+ * removeAll}, and {@code replaceValues} methods return {@code RandomAccess}
+ * lists if the factory does. However, the multimap's {@code get} method
+ * returns instances of a different class than does {@code factory.get()}.
+ *
+ * <p>The multimap is serializable if {@code map}, {@code factory}, the
+ * lists generated by {@code factory}, and the multimap contents are all
+ * serializable.
+ *
+ * <p>The multimap is not threadsafe when any concurrent operations update the
+ * multimap, even if {@code map} and the instances generated by
+ * {@code factory} are. Concurrent read operations will work correctly. To
+ * allow concurrent update operations, wrap the multimap with a call to
+ * {@link #synchronizedListMultimap}.
+ *
+ * <p>Call this method only when the simpler methods
+ * {@link ArrayListMultimap#create()} and {@link LinkedListMultimap#create()}
+ * won't suffice.
+ *
+ * <p>Note: the multimap assumes complete ownership over of {@code map} and
+ * the lists returned by {@code factory}. Those objects should not be manually
+ * updated, they should be empty when provided, and they should not use soft,
+ * weak, or phantom references.
+ *
+ * @param map place to store the mapping from each key to its corresponding
+ * values
+ * @param factory supplier of new, empty lists that will each hold all values
+ * for a given key
+ * @throws IllegalArgumentException if {@code map} is not empty
+ */
+ public static <K, V> ListMultimap<K, V> newListMultimap(
+ Map<K, Collection<V>> map, final Supplier<? extends List<V>> factory) {
+ return new CustomListMultimap<K, V>(map, factory);
+ }
+
+ private static class CustomListMultimap<K, V>
+ extends AbstractListMultimap<K, V> {
+ transient Supplier<? extends List<V>> factory;
+
+ CustomListMultimap(Map<K, Collection<V>> map,
+ Supplier<? extends List<V>> factory) {
+ super(map);
+ this.factory = checkNotNull(factory);
+ }
+
+ @Override protected List<V> createCollection() {
+ return factory.get();
+ }
+
+ /** @serialData the factory and the backing map */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(factory);
+ stream.writeObject(backingMap());
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ factory = (Supplier<? extends List<V>>) stream.readObject();
+ Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject();
+ setMap(map);
+ }
+
+ @GwtIncompatible("java serialization not supported")
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Creates a new {@code SetMultimap} that uses the provided map and factory.
+ * It can generate a multimap based on arbitrary {@link Map} and {@link Set}
+ * classes.
+ *
+ * <p>The {@code factory}-generated and {@code map} classes determine the
+ * multimap iteration order. They also specify the behavior of the
+ * {@code equals}, {@code hashCode}, and {@code toString} methods for the
+ * multimap and its returned views. However, the multimap's {@code get}
+ * method returns instances of a different class than {@code factory.get()}
+ * does.
+ *
+ * <p>The multimap is serializable if {@code map}, {@code factory}, the
+ * sets generated by {@code factory}, and the multimap contents are all
+ * serializable.
+ *
+ * <p>The multimap is not threadsafe when any concurrent operations update the
+ * multimap, even if {@code map} and the instances generated by
+ * {@code factory} are. Concurrent read operations will work correctly. To
+ * allow concurrent update operations, wrap the multimap with a call to
+ * {@link #synchronizedSetMultimap}.
+ *
+ * <p>Call this method only when the simpler methods
+ * {@link HashMultimap#create()}, {@link LinkedHashMultimap#create()},
+ * {@link TreeMultimap#create()}, and
+ * {@link TreeMultimap#create(Comparator, Comparator)} won't suffice.
+ *
+ * <p>Note: the multimap assumes complete ownership over of {@code map} and
+ * the sets returned by {@code factory}. Those objects should not be manually
+ * updated and they should not use soft, weak, or phantom references.
+ *
+ * @param map place to store the mapping from each key to its corresponding
+ * values
+ * @param factory supplier of new, empty sets that will each hold all values
+ * for a given key
+ * @throws IllegalArgumentException if {@code map} is not empty
+ */
+ public static <K, V> SetMultimap<K, V> newSetMultimap(
+ Map<K, Collection<V>> map, final Supplier<? extends Set<V>> factory) {
+ return new CustomSetMultimap<K, V>(map, factory);
+ }
+
+ private static class CustomSetMultimap<K, V>
+ extends AbstractSetMultimap<K, V> {
+ transient Supplier<? extends Set<V>> factory;
+
+ CustomSetMultimap(Map<K, Collection<V>> map,
+ Supplier<? extends Set<V>> factory) {
+ super(map);
+ this.factory = checkNotNull(factory);
+ }
+
+ @Override protected Set<V> createCollection() {
+ return factory.get();
+ }
+
+ /** @serialData the factory and the backing map */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(factory);
+ stream.writeObject(backingMap());
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ factory = (Supplier<? extends Set<V>>) stream.readObject();
+ Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject();
+ setMap(map);
+ }
+
+ @GwtIncompatible("not needed in emulated source")
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Creates a new {@code SortedSetMultimap} that uses the provided map and
+ * factory. It can generate a multimap based on arbitrary {@link Map} and
+ * {@link SortedSet} classes.
+ *
+ * <p>The {@code factory}-generated and {@code map} classes determine the
+ * multimap iteration order. They also specify the behavior of the
+ * {@code equals}, {@code hashCode}, and {@code toString} methods for the
+ * multimap and its returned views. However, the multimap's {@code get}
+ * method returns instances of a different class than {@code factory.get()}
+ * does.
+ *
+ * <p>The multimap is serializable if {@code map}, {@code factory}, the
+ * sets generated by {@code factory}, and the multimap contents are all
+ * serializable.
+ *
+ * <p>The multimap is not threadsafe when any concurrent operations update the
+ * multimap, even if {@code map} and the instances generated by
+ * {@code factory} are. Concurrent read operations will work correctly. To
+ * allow concurrent update operations, wrap the multimap with a call to
+ * {@link #synchronizedSortedSetMultimap}.
+ *
+ * <p>Call this method only when the simpler methods
+ * {@link TreeMultimap#create()} and
+ * {@link TreeMultimap#create(Comparator, Comparator)} won't suffice.
+ *
+ * <p>Note: the multimap assumes complete ownership over of {@code map} and
+ * the sets returned by {@code factory}. Those objects should not be manually
+ * updated and they should not use soft, weak, or phantom references.
+ *
+ * @param map place to store the mapping from each key to its corresponding
+ * values
+ * @param factory supplier of new, empty sorted sets that will each hold
+ * all values for a given key
+ * @throws IllegalArgumentException if {@code map} is not empty
+ */
+ public static <K, V> SortedSetMultimap<K, V> newSortedSetMultimap(
+ Map<K, Collection<V>> map,
+ final Supplier<? extends SortedSet<V>> factory) {
+ return new CustomSortedSetMultimap<K, V>(map, factory);
+ }
+
+ private static class CustomSortedSetMultimap<K, V>
+ extends AbstractSortedSetMultimap<K, V> {
+ transient Supplier<? extends SortedSet<V>> factory;
+ transient Comparator<? super V> valueComparator;
+
+ CustomSortedSetMultimap(Map<K, Collection<V>> map,
+ Supplier<? extends SortedSet<V>> factory) {
+ super(map);
+ this.factory = checkNotNull(factory);
+ valueComparator = factory.get().comparator();
+ }
+
+ @Override protected SortedSet<V> createCollection() {
+ return factory.get();
+ }
+
+ @Override public Comparator<? super V> valueComparator() {
+ return valueComparator;
+ }
+
+ /** @serialData the factory and the backing map */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(factory);
+ stream.writeObject(backingMap());
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ factory = (Supplier<? extends SortedSet<V>>) stream.readObject();
+ valueComparator = factory.get().comparator();
+ Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject();
+ setMap(map);
+ }
+
+ @GwtIncompatible("not needed in emulated source")
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Copies each key-value mapping in {@code source} into {@code dest}, with
+ * its key and value reversed.
+ *
+ * <p>If {@code source} is an {@link ImmutableMultimap}, consider using
+ * {@link ImmutableMultimap#inverse} instead.
+ *
+ * @param source any multimap
+ * @param dest the multimap to copy into; usually empty
+ * @return {@code dest}
+ */
+ public static <K, V, M extends Multimap<K, V>> M invertFrom(
+ Multimap<? extends V, ? extends K> source, M dest) {
+ checkNotNull(dest);
+ for (Map.Entry<? extends V, ? extends K> entry : source.entries()) {
+ dest.put(entry.getValue(), entry.getKey());
+ }
+ return dest;
+ }
+
+ /**
+ * Returns a synchronized (thread-safe) multimap backed by the specified
+ * multimap. In order to guarantee serial access, it is critical that
+ * <b>all</b> access to the backing multimap is accomplished through the
+ * returned multimap.
+ *
+ * <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(
+ * HashMultimap.<K, V>create());
+ * ...
+ * Collection<V> values = multimap.get(key); // Needn't be in synchronized block
+ * ...
+ * synchronized (multimap) { // Synchronizing on multimap, not values!
+ * Iterator<V> i = values.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>Note that the generated multimap's {@link Multimap#removeAll} and
+ * {@link Multimap#replaceValues} methods return collections that aren't
+ * synchronized.
+ *
+ * <p>The returned multimap will be serializable if the specified multimap is
+ * serializable.
+ *
+ * @param multimap the multimap to be wrapped in a synchronized view
+ * @return a synchronized view of the specified multimap
+ */
+ public static <K, V> Multimap<K, V> synchronizedMultimap(
+ Multimap<K, V> multimap) {
+ return Synchronized.multimap(multimap, null);
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified multimap. Query operations on
+ * the returned multimap "read through" to the specified multimap, and
+ * attempts to modify the returned multimap, either directly or through the
+ * multimap's views, result in an {@code UnsupportedOperationException}.
+ *
+ * <p>Note that the generated multimap's {@link Multimap#removeAll} and
+ * {@link Multimap#replaceValues} methods return collections that are
+ * modifiable.
+ *
+ * <p>The returned multimap will be serializable if the specified multimap is
+ * serializable.
+ *
+ * @param delegate the multimap for which an unmodifiable view is to be
+ * returned
+ * @return an unmodifiable view of the specified multimap
+ */
+ public static <K, V> Multimap<K, V> unmodifiableMultimap(
+ Multimap<K, V> delegate) {
+ if (delegate instanceof UnmodifiableMultimap ||
+ delegate instanceof ImmutableMultimap) {
+ return delegate;
+ }
+ return new UnmodifiableMultimap<K, V>(delegate);
+ }
+
+ /**
+ * Simply returns its argument.
+ *
+ * @deprecated no need to use this
+ * @since 10.0
+ */
+ @Deprecated public static <K, V> Multimap<K, V> unmodifiableMultimap(
+ ImmutableMultimap<K, V> delegate) {
+ return checkNotNull(delegate);
+ }
+
+ private static class UnmodifiableMultimap<K, V>
+ extends ForwardingMultimap<K, V> implements Serializable {
+ final Multimap<K, V> delegate;
+ transient Collection<Entry<K, V>> entries;
+ transient Multiset<K> keys;
+ transient Set<K> keySet;
+ transient Collection<V> values;
+ transient Map<K, Collection<V>> map;
+
+ UnmodifiableMultimap(final Multimap<K, V> delegate) {
+ this.delegate = checkNotNull(delegate);
+ }
+
+ @Override protected Multimap<K, V> delegate() {
+ return delegate;
+ }
+
+ @Override public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Map<K, Collection<V>> asMap() {
+ Map<K, Collection<V>> result = map;
+ if (result == null) {
+ final Map<K, Collection<V>> unmodifiableMap
+ = Collections.unmodifiableMap(delegate.asMap());
+ map = result = new ForwardingMap<K, Collection<V>>() {
+ @Override protected Map<K, Collection<V>> delegate() {
+ return unmodifiableMap;
+ }
+
+ Set<Entry<K, Collection<V>>> entrySet;
+
+ @Override public Set<Map.Entry<K, Collection<V>>> entrySet() {
+ Set<Entry<K, Collection<V>>> result = entrySet;
+ return (result == null)
+ ? entrySet
+ = unmodifiableAsMapEntries(unmodifiableMap.entrySet())
+ : result;
+ }
+
+ @Override public Collection<V> get(Object key) {
+ Collection<V> collection = unmodifiableMap.get(key);
+ return (collection == null)
+ ? null : unmodifiableValueCollection(collection);
+ }
+
+ Collection<Collection<V>> asMapValues;
+
+ @Override public Collection<Collection<V>> values() {
+ Collection<Collection<V>> result = asMapValues;
+ return (result == null)
+ ? asMapValues
+ = new UnmodifiableAsMapValues<V>(unmodifiableMap.values())
+ : result;
+ }
+
+ @Override public boolean containsValue(Object o) {
+ return values().contains(o);
+ }
+ };
+ }
+ return result;
+ }
+
+ @Override public Collection<Entry<K, V>> entries() {
+ Collection<Entry<K, V>> result = entries;
+ if (result == null) {
+ entries = result = unmodifiableEntries(delegate.entries());
+ }
+ return result;
+ }
+
+ @Override public Collection<V> get(K key) {
+ return unmodifiableValueCollection(delegate.get(key));
+ }
+
+ @Override public Multiset<K> keys() {
+ Multiset<K> result = keys;
+ if (result == null) {
+ keys = result = Multisets.unmodifiableMultiset(delegate.keys());
+ }
+ return result;
+ }
+
+ @Override public Set<K> keySet() {
+ Set<K> result = keySet;
+ if (result == null) {
+ keySet = result = Collections.unmodifiableSet(delegate.keySet());
+ }
+ return result;
+ }
+
+ @Override public boolean put(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean putAll(K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean remove(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Collection<V> removeAll(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Collection<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Collection<V> values() {
+ Collection<V> result = values;
+ if (result == null) {
+ values = result = Collections.unmodifiableCollection(delegate.values());
+ }
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static class UnmodifiableAsMapValues<V>
+ extends ForwardingCollection<Collection<V>> {
+ final Collection<Collection<V>> delegate;
+ UnmodifiableAsMapValues(Collection<Collection<V>> delegate) {
+ this.delegate = Collections.unmodifiableCollection(delegate);
+ }
+ @Override protected Collection<Collection<V>> delegate() {
+ return delegate;
+ }
+ @Override public Iterator<Collection<V>> iterator() {
+ final Iterator<Collection<V>> iterator = delegate.iterator();
+ return new UnmodifiableIterator<Collection<V>>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ @Override
+ public Collection<V> next() {
+ return unmodifiableValueCollection(iterator.next());
+ }
+ };
+ }
+ @Override public Object[] toArray() {
+ return standardToArray();
+ }
+ @Override public <T> T[] toArray(T[] array) {
+ return standardToArray(array);
+ }
+ @Override public boolean contains(Object o) {
+ return standardContains(o);
+ }
+ @Override public boolean containsAll(Collection<?> c) {
+ return standardContainsAll(c);
+ }
+ }
+
+ private static class UnmodifiableListMultimap<K, V>
+ extends UnmodifiableMultimap<K, V> implements ListMultimap<K, V> {
+ UnmodifiableListMultimap(ListMultimap<K, V> delegate) {
+ super(delegate);
+ }
+ @Override public ListMultimap<K, V> delegate() {
+ return (ListMultimap<K, V>) super.delegate();
+ }
+ @Override public List<V> get(K key) {
+ return Collections.unmodifiableList(delegate().get(key));
+ }
+ @Override public List<V> removeAll(Object key) {
+ throw new UnsupportedOperationException();
+ }
+ @Override public List<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ private static class UnmodifiableSetMultimap<K, V>
+ extends UnmodifiableMultimap<K, V> implements SetMultimap<K, V> {
+ UnmodifiableSetMultimap(SetMultimap<K, V> delegate) {
+ super(delegate);
+ }
+ @Override public SetMultimap<K, V> delegate() {
+ return (SetMultimap<K, V>) super.delegate();
+ }
+ @Override public Set<V> get(K key) {
+ /*
+ * Note that this doesn't return a SortedSet when delegate is a
+ * SortedSetMultiset, unlike (SortedSet<V>) super.get().
+ */
+ return Collections.unmodifiableSet(delegate().get(key));
+ }
+ @Override public Set<Map.Entry<K, V>> entries() {
+ return Maps.unmodifiableEntrySet(delegate().entries());
+ }
+ @Override public Set<V> removeAll(Object key) {
+ throw new UnsupportedOperationException();
+ }
+ @Override public Set<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ private static class UnmodifiableSortedSetMultimap<K, V>
+ extends UnmodifiableSetMultimap<K, V> implements SortedSetMultimap<K, V> {
+ UnmodifiableSortedSetMultimap(SortedSetMultimap<K, V> delegate) {
+ super(delegate);
+ }
+ @Override public SortedSetMultimap<K, V> delegate() {
+ return (SortedSetMultimap<K, V>) super.delegate();
+ }
+ @Override public SortedSet<V> get(K key) {
+ return Collections.unmodifiableSortedSet(delegate().get(key));
+ }
+ @Override public SortedSet<V> removeAll(Object key) {
+ throw new UnsupportedOperationException();
+ }
+ @Override public SortedSet<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ public Comparator<? super V> valueComparator() {
+ return delegate().valueComparator();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a synchronized (thread-safe) {@code SetMultimap} backed by the
+ * specified multimap.
+ *
+ * <p>You must follow the warnings described in {@link #synchronizedMultimap}.
+ *
+ * <p>The returned multimap will be serializable if the specified multimap is
+ * serializable.
+ *
+ * @param multimap the multimap to be wrapped
+ * @return a synchronized view of the specified multimap
+ */
+ public static <K, V> SetMultimap<K, V> synchronizedSetMultimap(
+ SetMultimap<K, V> multimap) {
+ return Synchronized.setMultimap(multimap, null);
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified {@code SetMultimap}. Query
+ * operations on the returned multimap "read through" to the specified
+ * multimap, and attempts to modify the returned multimap, either directly or
+ * through the multimap's views, result in an
+ * {@code UnsupportedOperationException}.
+ *
+ * <p>Note that the generated multimap's {@link Multimap#removeAll} and
+ * {@link Multimap#replaceValues} methods return collections that are
+ * modifiable.
+ *
+ * <p>The returned multimap will be serializable if the specified multimap is
+ * serializable.
+ *
+ * @param delegate the multimap for which an unmodifiable view is to be
+ * returned
+ * @return an unmodifiable view of the specified multimap
+ */
+ public static <K, V> SetMultimap<K, V> unmodifiableSetMultimap(
+ SetMultimap<K, V> delegate) {
+ if (delegate instanceof UnmodifiableSetMultimap ||
+ delegate instanceof ImmutableSetMultimap) {
+ return delegate;
+ }
+ return new UnmodifiableSetMultimap<K, V>(delegate);
+ }
+
+ /**
+ * Simply returns its argument.
+ *
+ * @deprecated no need to use this
+ * @since 10.0
+ */
+ @Deprecated public static <K, V> SetMultimap<K, V> unmodifiableSetMultimap(
+ ImmutableSetMultimap<K, V> delegate) {
+ return checkNotNull(delegate);
+ }
+
+ /**
+ * Returns a synchronized (thread-safe) {@code SortedSetMultimap} backed by
+ * the specified multimap.
+ *
+ * <p>You must follow the warnings described in {@link #synchronizedMultimap}.
+ *
+ * <p>The returned multimap will be serializable if the specified multimap is
+ * serializable.
+ *
+ * @param multimap the multimap to be wrapped
+ * @return a synchronized view of the specified multimap
+ */
+ public static <K, V> SortedSetMultimap<K, V>
+ synchronizedSortedSetMultimap(SortedSetMultimap<K, V> multimap) {
+ return Synchronized.sortedSetMultimap(multimap, null);
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified {@code SortedSetMultimap}.
+ * Query operations on the returned multimap "read through" to the specified
+ * multimap, and attempts to modify the returned multimap, either directly or
+ * through the multimap's views, result in an
+ * {@code UnsupportedOperationException}.
+ *
+ * <p>Note that the generated multimap's {@link Multimap#removeAll} and
+ * {@link Multimap#replaceValues} methods return collections that are
+ * modifiable.
+ *
+ * <p>The returned multimap will be serializable if the specified multimap is
+ * serializable.
+ *
+ * @param delegate the multimap for which an unmodifiable view is to be
+ * returned
+ * @return an unmodifiable view of the specified multimap
+ */
+ public static <K, V> SortedSetMultimap<K, V> unmodifiableSortedSetMultimap(
+ SortedSetMultimap<K, V> delegate) {
+ if (delegate instanceof UnmodifiableSortedSetMultimap) {
+ return delegate;
+ }
+ return new UnmodifiableSortedSetMultimap<K, V>(delegate);
+ }
+
+ /**
+ * Returns a synchronized (thread-safe) {@code ListMultimap} backed by the
+ * specified multimap.
+ *
+ * <p>You must follow the warnings described in {@link #synchronizedMultimap}.
+ *
+ * @param multimap the multimap to be wrapped
+ * @return a synchronized view of the specified multimap
+ */
+ public static <K, V> ListMultimap<K, V> synchronizedListMultimap(
+ ListMultimap<K, V> multimap) {
+ return Synchronized.listMultimap(multimap, null);
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified {@code ListMultimap}. Query
+ * operations on the returned multimap "read through" to the specified
+ * multimap, and attempts to modify the returned multimap, either directly or
+ * through the multimap's views, result in an
+ * {@code UnsupportedOperationException}.
+ *
+ * <p>Note that the generated multimap's {@link Multimap#removeAll} and
+ * {@link Multimap#replaceValues} methods return collections that are
+ * modifiable.
+ *
+ * <p>The returned multimap will be serializable if the specified multimap is
+ * serializable.
+ *
+ * @param delegate the multimap for which an unmodifiable view is to be
+ * returned
+ * @return an unmodifiable view of the specified multimap
+ */
+ public static <K, V> ListMultimap<K, V> unmodifiableListMultimap(
+ ListMultimap<K, V> delegate) {
+ if (delegate instanceof UnmodifiableListMultimap ||
+ delegate instanceof ImmutableListMultimap) {
+ return delegate;
+ }
+ return new UnmodifiableListMultimap<K, V>(delegate);
+ }
+
+ /**
+ * Simply returns its argument.
+ *
+ * @deprecated no need to use this
+ * @since 10.0
+ */
+ @Deprecated public static <K, V> ListMultimap<K, V> unmodifiableListMultimap(
+ ImmutableListMultimap<K, V> delegate) {
+ return checkNotNull(delegate);
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified collection, preserving the
+ * interface for instances of {@code SortedSet}, {@code Set}, {@code List} and
+ * {@code Collection}, in that order of preference.
+ *
+ * @param collection the collection for which to return an unmodifiable view
+ * @return an unmodifiable view of the collection
+ */
+ private static <V> Collection<V> unmodifiableValueCollection(
+ 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);
+ }
+ return Collections.unmodifiableCollection(collection);
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified multimap {@code asMap} entry.
+ * The {@link Entry#setValue} operation throws an {@link
+ * UnsupportedOperationException}, and the collection returned by {@code
+ * getValue} is also an unmodifiable (type-preserving) view. This also has the
+ * side-effect of redefining equals to comply with the Map.Entry contract, and
+ * to avoid a possible nefarious implementation of equals.
+ *
+ * @param entry the entry for which to return an unmodifiable view
+ * @return an unmodifiable view of the entry
+ */
+ private static <K, V> Map.Entry<K, Collection<V>> unmodifiableAsMapEntry(
+ final Map.Entry<K, Collection<V>> entry) {
+ checkNotNull(entry);
+ return new AbstractMapEntry<K, Collection<V>>() {
+ @Override public K getKey() {
+ return entry.getKey();
+ }
+
+ @Override public Collection<V> getValue() {
+ return unmodifiableValueCollection(entry.getValue());
+ }
+ };
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified collection of entries. The
+ * {@link Entry#setValue} operation throws an {@link
+ * UnsupportedOperationException}. If the specified collection is a {@code
+ * Set}, the returned collection is also a {@code Set}.
+ *
+ * @param entries the entries for which to return an unmodifiable view
+ * @return an unmodifiable view of the entries
+ */
+ private static <K, V> Collection<Entry<K, V>> unmodifiableEntries(
+ Collection<Entry<K, V>> entries) {
+ if (entries instanceof Set) {
+ return Maps.unmodifiableEntrySet((Set<Entry<K, V>>) entries);
+ }
+ return new Maps.UnmodifiableEntries<K, V>(
+ Collections.unmodifiableCollection(entries));
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified set of {@code asMap} entries.
+ * The {@link Entry#setValue} operation throws an {@link
+ * UnsupportedOperationException}, as do any operations that attempt to modify
+ * the returned collection.
+ *
+ * @param asMapEntries the {@code asMap} entries for which to return an
+ * unmodifiable view
+ * @return an unmodifiable view of the collection entries
+ */
+ private static <K, V> Set<Entry<K, Collection<V>>> unmodifiableAsMapEntries(
+ Set<Entry<K, Collection<V>>> asMapEntries) {
+ return new UnmodifiableAsMapEntries<K, V>(
+ Collections.unmodifiableSet(asMapEntries));
+ }
+
+ /** @see Multimaps#unmodifiableAsMapEntries */
+ static class UnmodifiableAsMapEntries<K, V>
+ extends ForwardingSet<Entry<K, Collection<V>>> {
+ private final Set<Entry<K, Collection<V>>> delegate;
+ UnmodifiableAsMapEntries(Set<Entry<K, Collection<V>>> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override protected Set<Entry<K, Collection<V>>> delegate() {
+ return delegate;
+ }
+
+ @Override public Iterator<Entry<K, Collection<V>>> iterator() {
+ final Iterator<Entry<K, Collection<V>>> iterator = delegate.iterator();
+ return new ForwardingIterator<Entry<K, Collection<V>>>() {
+ @Override protected Iterator<Entry<K, Collection<V>>> delegate() {
+ return iterator;
+ }
+ @Override public Entry<K, Collection<V>> next() {
+ return unmodifiableAsMapEntry(iterator.next());
+ }
+ };
+ }
+
+ @Override public Object[] toArray() {
+ return standardToArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return standardToArray(array);
+ }
+
+ @Override public boolean contains(Object o) {
+ return Maps.containsEntryImpl(delegate(), o);
+ }
+
+ @Override public boolean containsAll(Collection<?> c) {
+ return standardContainsAll(c);
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return standardEquals(object);
+ }
+ }
+
+ /**
+ * Returns a multimap view of the specified map. The multimap is backed by the
+ * map, so changes to the map are reflected in the multimap, and vice versa.
+ * If the map is modified while an iteration over one of the multimap's
+ * collection views is in progress (except through the iterator's own {@code
+ * remove} operation, or through the {@code setValue} operation on a map entry
+ * returned by the iterator), the results of the iteration are undefined.
+ *
+ * <p>The multimap supports mapping removal, which removes the corresponding
+ * mapping from the map. It does not support any operations which might add
+ * mappings, such as {@code put}, {@code putAll} or {@code replaceValues}.
+ *
+ * <p>The returned multimap will be serializable if the specified map is
+ * serializable.
+ *
+ * @param map the backing map for the returned multimap view
+ */
+ public static <K, V> SetMultimap<K, V> forMap(Map<K, V> map) {
+ return new MapMultimap<K, V>(map);
+ }
+
+ /** @see Multimaps#forMap */
+ private static class MapMultimap<K, V>
+ implements SetMultimap<K, V>, Serializable {
+ final Map<K, V> map;
+ transient Map<K, Collection<V>> asMap;
+
+ MapMultimap(Map<K, V> map) {
+ this.map = checkNotNull(map);
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return map.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return map.containsValue(value);
+ }
+
+ @Override
+ public boolean containsEntry(Object key, Object value) {
+ return map.entrySet().contains(Maps.immutableEntry(key, value));
+ }
+
+ @Override
+ public Set<V> get(final K key) {
+ return new Sets.ImprovedAbstractSet<V>() {
+ @Override public Iterator<V> iterator() {
+ return new Iterator<V>() {
+ int i;
+
+ @Override
+ public boolean hasNext() {
+ return (i == 0) && map.containsKey(key);
+ }
+
+ @Override
+ public V next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ i++;
+ return map.get(key);
+ }
+
+ @Override
+ public void remove() {
+ checkState(i == 1);
+ i = -1;
+ map.remove(key);
+ }
+ };
+ }
+
+ @Override public int size() {
+ return map.containsKey(key) ? 1 : 0;
+ }
+ };
+ }
+
+ @Override
+ public boolean put(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean putAll(K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<V> replaceValues(K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ return map.entrySet().remove(Maps.immutableEntry(key, value));
+ }
+
+ @Override
+ public Set<V> removeAll(Object key) {
+ Set<V> values = new HashSet<V>(2);
+ if (!map.containsKey(key)) {
+ return values;
+ }
+ values.add(map.remove(key));
+ return values;
+ }
+
+ @Override
+ public void clear() {
+ map.clear();
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return map.keySet();
+ }
+
+ @Override
+ public Multiset<K> keys() {
+ return Multisets.forSet(map.keySet());
+ }
+
+ @Override
+ public Collection<V> values() {
+ return map.values();
+ }
+
+ @Override
+ public Set<Entry<K, V>> entries() {
+ return map.entrySet();
+ }
+
+ @Override
+ public Map<K, Collection<V>> asMap() {
+ Map<K, Collection<V>> result = asMap;
+ if (result == null) {
+ asMap = result = new AsMap();
+ }
+ return result;
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Multimap) {
+ Multimap<?, ?> that = (Multimap<?, ?>) object;
+ return this.size() == that.size() && asMap().equals(that.asMap());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return map.hashCode();
+ }
+
+ private static final MapJoiner JOINER
+ = Joiner.on("], ").withKeyValueSeparator("=[").useForNull("null");
+
+ @Override public String toString() {
+ if (map.isEmpty()) {
+ return "{}";
+ }
+ StringBuilder builder
+ = Collections2.newStringBuilderForCollection(map.size()).append('{');
+ JOINER.appendTo(builder, map);
+ return builder.append("]}").toString();
+ }
+
+ /** @see MapMultimap#asMap */
+ class AsMapEntries extends Sets.ImprovedAbstractSet<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()) {
+ @Override
+ Entry<K, Collection<V>> transform(final K key) {
+ return new AbstractMapEntry<K, Collection<V>>() {
+ @Override
+ public K getKey() {
+ return key;
+ }
+
+ @Override
+ public Collection<V> getValue() {
+ return get(key);
+ }
+ };
+ }
+ };
+ }
+
+ @Override public boolean contains(Object o) {
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ if (!(entry.getValue() instanceof Set)) {
+ return false;
+ }
+ Set<?> set = (Set<?>) entry.getValue();
+ return (set.size() == 1)
+ && containsEntry(entry.getKey(), set.iterator().next());
+ }
+
+ @Override public boolean remove(Object o) {
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ if (!(entry.getValue() instanceof Set)) {
+ return false;
+ }
+ Set<?> set = (Set<?>) entry.getValue();
+ return (set.size() == 1)
+ && map.entrySet().remove(
+ Maps.immutableEntry(entry.getKey(), set.iterator().next()));
+ }
+ }
+
+ /** @see MapMultimap#asMap */
+ class AsMap extends Maps.ImprovedAbstractMap<K, Collection<V>> {
+ @Override protected Set<Entry<K, Collection<V>>> createEntrySet() {
+ return new AsMapEntries();
+ }
+
+ // The following methods are included for performance.
+
+ @Override public boolean containsKey(Object key) {
+ return map.containsKey(key);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public Collection<V> get(Object key) {
+ Collection<V> collection = MapMultimap.this.get((K) key);
+ return collection.isEmpty() ? null : collection;
+ }
+
+ @Override public Collection<V> remove(Object key) {
+ Collection<V> collection = removeAll(key);
+ return collection.isEmpty() ? null : collection;
+ }
+ }
+ private static final long serialVersionUID = 7845222491160860175L;
+ }
+
+ /**
+ * Returns a view of a multimap where each value is transformed by a function.
+ * All other properties of the multimap, such as iteration order, are left
+ * intact. For example, the code: <pre> {@code
+ *
+ * Multimap<String, Integer> multimap =
+ * ImmutableSetMultimap.of("a", 2, "b", -3, "b", -3, "a", 4, "c", 6);
+ * Function<Integer, String> square = new Function<Integer, String>() {
+ * public String apply(Integer in) {
+ * return Integer.toString(in * in);
+ * }
+ * };
+ * Multimap<String, String> transformed =
+ * Multimaps.transformValues(multimap, square);
+ * System.out.println(transformed);}</pre>
+ *
+ * ... prints {@code {a=[4, 16], b=[9, 9], c=[6]}}.
+ *
+ * <p>Changes in the underlying multimap are reflected in this view.
+ * Conversely, this view supports removal operations, and these are reflected
+ * in the underlying multimap.
+ *
+ * <p>It's acceptable for the underlying multimap to contain null keys, and
+ * even null values provided that the function is capable of accepting null
+ * input. The transformed multimap might contain null values, if the function
+ * sometimes gives a null result.
+ *
+ * <p>The returned multimap is not thread-safe or serializable, even if the
+ * underlying multimap is. The {@code equals} and {@code hashCode} methods
+ * of the returned multimap are meaningless, since there is not a definition
+ * of {@code equals} or {@code hashCode} for general collections, and
+ * {@code get()} will return a general {@code Collection} as opposed to a
+ * {@code List} or a {@code Set}.
+ *
+ * <p>The function is applied lazily, invoked when needed. This is necessary
+ * for the returned multimap to be a view, but it means that the function will
+ * be applied many times for bulk operations like
+ * {@link Multimap#containsValue} and {@code Multimap.toString()}. For this to
+ * perform well, {@code function} should be fast. To avoid lazy evaluation
+ * when the returned multimap doesn't need to be a view, copy the returned
+ * multimap into a new multimap of your choosing.
+ *
+ * @since 7.0
+ */
+ public static <K, V1, V2> Multimap<K, V2> transformValues(
+ Multimap<K, V1> fromMultimap, 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(fromMultimap, transformer);
+ }
+
+ /**
+ * Returns a view of a multimap whose values are derived from the original
+ * multimap'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 multimap, such as iteration
+ * order, are left intact. For example, the code: <pre> {@code
+ *
+ * SetMultimap<String, Integer> multimap =
+ * ImmutableSetMultimap.of("a", 1, "a", 4, "b", -6);
+ * EntryTransformer<String, Integer, String> transformer =
+ * new EntryTransformer<String, Integer, String>() {
+ * public String transformEntry(String key, Integer value) {
+ * return (value >= 0) ? key : "no" + key;
+ * }
+ * };
+ * Multimap<String, String> transformed =
+ * Multimaps.transformEntries(multimap, transformer);
+ * System.out.println(transformed);}</pre>
+ *
+ * ... prints {@code {a=[a, a], b=[nob]}}.
+ *
+ * <p>Changes in the underlying multimap are reflected in this view.
+ * Conversely, this view supports removal operations, and these are reflected
+ * in the underlying multimap.
+ *
+ * <p>It's acceptable for the underlying multimap to contain null keys and
+ * null values provided that the transformer is capable of accepting null
+ * inputs. The transformed multimap might contain null values if the
+ * transformer sometimes gives a null result.
+ *
+ * <p>The returned multimap is not thread-safe or serializable, even if the
+ * underlying multimap is. The {@code equals} and {@code hashCode} methods
+ * of the returned multimap are meaningless, since there is not a definition
+ * of {@code equals} or {@code hashCode} for general collections, and
+ * {@code get()} will return a general {@code Collection} as opposed to a
+ * {@code List} or a {@code Set}.
+ *
+ * <p>The transformer is applied lazily, invoked when needed. This is
+ * necessary for the returned multimap to be a view, but it means that the
+ * transformer will be applied many times for bulk operations like {@link
+ * Multimap#containsValue} and {@link Object#toString}. For this to perform
+ * well, {@code transformer} should be fast. To avoid lazy evaluation when the
+ * returned multimap doesn't need to be a view, copy the returned multimap
+ * into a new multimap 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 multimap.
+ *
+ * @since 7.0
+ */
+ 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);
+ }
+
+ private static class TransformedEntriesMultimap<K, V1, V2>
+ implements Multimap<K, V2> {
+ final Multimap<K, V1> fromMultimap;
+ final EntryTransformer<? super K, ? super V1, V2> transformer;
+
+ TransformedEntriesMultimap(Multimap<K, V1> fromMultimap,
+ final EntryTransformer<? super K, ? super V1, V2> transformer) {
+ this.fromMultimap = checkNotNull(fromMultimap);
+ this.transformer = checkNotNull(transformer);
+ }
+
+ 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);
+ }
+ });
+ }
+
+ private transient Map<K, Collection<V2>> asMap;
+
+ @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() {
+ fromMultimap.clear();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public boolean containsEntry(Object key, Object value) {
+ Collection<V2> values = get((K) key);
+ return values.contains(value);
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return fromMultimap.containsKey(key);
+ }
+
+ @Override public boolean containsValue(Object value) {
+ return values().contains(value);
+ }
+
+ 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 Collection<V2> get(final K key) {
+ return transform(key, fromMultimap.get(key));
+ }
+
+ @Override public boolean isEmpty() {
+ return fromMultimap.isEmpty();
+ }
+
+ @Override public Set<K> keySet() {
+ return fromMultimap.keySet();
+ }
+
+ @Override public Multiset<K> keys() {
+ return fromMultimap.keys();
+ }
+
+ @Override public boolean put(K key, V2 value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean putAll(K key, Iterable<? extends V2> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean putAll(
+ Multimap<? extends K, ? extends V2> multimap) {
+ throw new UnsupportedOperationException();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public boolean remove(Object key, Object value) {
+ return get((K) key).remove(value);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public Collection<V2> removeAll(Object key) {
+ return transform((K) key, fromMultimap.removeAll(key));
+ }
+
+ @Override public Collection<V2> replaceValues(
+ K key, Iterable<? extends V2> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public int size() {
+ return fromMultimap.size();
+ }
+
+ 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();
+ }
+ }
+
+ /**
+ * Returns a view of a {@code ListMultimap} where each value is transformed by
+ * a function. All other properties of the multimap, such as iteration order,
+ * are left intact. For example, the code: <pre> {@code
+ *
+ * ListMultimap<String, Integer> multimap
+ * = ImmutableListMultimap.of("a", 4, "a", 16, "b", 9);
+ * Function<Integer, Double> sqrt =
+ * new Function<Integer, Double>() {
+ * public Double apply(Integer in) {
+ * return Math.sqrt((int) in);
+ * }
+ * };
+ * ListMultimap<String, Double> transformed = Multimaps.transformValues(map,
+ * sqrt);
+ * System.out.println(transformed);}</pre>
+ *
+ * ... prints {@code {a=[2.0, 4.0], b=[3.0]}}.
+ *
+ * <p>Changes in the underlying multimap are reflected in this view.
+ * Conversely, this view supports removal operations, and these are reflected
+ * in the underlying multimap.
+ *
+ * <p>It's acceptable for the underlying multimap to contain null keys, and
+ * even null values provided that the function is capable of accepting null
+ * input. The transformed multimap might contain null values, if the function
+ * sometimes gives a null result.
+ *
+ * <p>The returned multimap is not thread-safe or serializable, even if the
+ * underlying multimap is.
+ *
+ * <p>The function is applied lazily, invoked when needed. This is necessary
+ * for the returned multimap to be a view, but it means that the function will
+ * be applied many times for bulk operations like
+ * {@link Multimap#containsValue} and {@code Multimap.toString()}. For this to
+ * perform well, {@code function} should be fast. To avoid lazy evaluation
+ * when the returned multimap doesn't need to be a view, copy the returned
+ * multimap into a new multimap of your choosing.
+ *
+ * @since 7.0
+ */
+ public static <K, V1, V2> ListMultimap<K, V2> transformValues(
+ ListMultimap<K, V1> fromMultimap,
+ 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(fromMultimap, transformer);
+ }
+
+ /**
+ * Returns a view of a {@code ListMultimap} whose values are derived from the
+ * original multimap's entries. In contrast to
+ * {@link #transformValues(ListMultimap, Function)}, this method's
+ * entry-transformation logic may depend on the key as well as the value.
+ *
+ * <p>All other properties of the transformed multimap, such as iteration
+ * order, are left intact. For example, the code: <pre> {@code
+ *
+ * Multimap<String, Integer> multimap =
+ * ImmutableMultimap.of("a", 1, "a", 4, "b", 6);
+ * EntryTransformer<String, Integer, String> transformer =
+ * new EntryTransformer<String, Integer, String>() {
+ * public String transformEntry(String key, Integer value) {
+ * return key + value;
+ * }
+ * };
+ * Multimap<String, String> transformed =
+ * Multimaps.transformEntries(multimap, transformer);
+ * System.out.println(transformed);}</pre>
+ *
+ * ... prints {@code {"a"=["a1", "a4"], "b"=["b6"]}}.
+ *
+ * <p>Changes in the underlying multimap are reflected in this view.
+ * Conversely, this view supports removal operations, and these are reflected
+ * in the underlying multimap.
+ *
+ * <p>It's acceptable for the underlying multimap to contain null keys and
+ * null values provided that the transformer is capable of accepting null
+ * inputs. The transformed multimap might contain null values if the
+ * transformer sometimes gives a null result.
+ *
+ * <p>The returned multimap is not thread-safe or serializable, even if the
+ * underlying multimap is.
+ *
+ * <p>The transformer is applied lazily, invoked when needed. This is
+ * necessary for the returned multimap to be a view, but it means that the
+ * transformer will be applied many times for bulk operations like {@link
+ * Multimap#containsValue} and {@link Object#toString}. For this to perform
+ * well, {@code transformer} should be fast. To avoid lazy evaluation when the
+ * returned multimap doesn't need to be a view, copy the returned multimap
+ * into a new multimap 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 multimap.
+ *
+ * @since 7.0
+ */
+ public static <K, V1, V2> ListMultimap<K, V2> transformEntries(
+ ListMultimap<K, V1> fromMap,
+ EntryTransformer<? super K, ? super V1, V2> transformer) {
+ return new TransformedEntriesListMultimap<K, V1, V2>(fromMap, transformer);
+ }
+
+ private static final class TransformedEntriesListMultimap<K, V1, V2>
+ extends TransformedEntriesMultimap<K, V1, V2>
+ implements ListMultimap<K, V2> {
+
+ TransformedEntriesListMultimap(ListMultimap<K, V1> fromMultimap,
+ EntryTransformer<? super K, ? super V1, V2> transformer) {
+ super(fromMultimap, transformer);
+ }
+
+ @Override List<V2> transform(final K key, Collection<V1> values) {
+ return Lists.transform((List<V1>) values, new Function<V1, V2>() {
+ @Override public V2 apply(V1 value) {
+ return transformer.transformEntry(key, value);
+ }
+ });
+ }
+
+ @Override public List<V2> get(K key) {
+ return transform(key, fromMultimap.get(key));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public List<V2> removeAll(Object key) {
+ return transform((K) key, fromMultimap.removeAll(key));
+ }
+
+ @Override public List<V2> replaceValues(
+ K key, Iterable<? extends V2> values) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Creates an index {@code ImmutableListMultimap} that contains the results of
+ * applying a specified function to each item in an {@code Iterable} of
+ * values. Each value will be stored as a value in the resulting multimap,
+ * yielding a multimap with the same size as the input 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.
+ *
+ * <p>For example, <pre> {@code
+ *
+ * List<String> badGuys =
+ * Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
+ * Function<String, Integer> stringLengthFunction = ...;
+ * Multimap<Integer, String> index =
+ * Multimaps.index(badGuys, stringLengthFunction);
+ * System.out.println(index);}</pre>
+ *
+ * prints <pre> {@code
+ *
+ * {4=[Inky], 6=[Blinky], 5=[Pinky, Pinky, Clyde]}}</pre>
+ *
+ * The returned multimap is serializable if its keys and values are all
+ * serializable.
+ *
+ * @param values the values to use when constructing the {@code
+ * ImmutableListMultimap}
+ * @param keyFunction the function used to produce the key for each value
+ * @return {@code ImmutableListMultimap} mapping the result of evaluating the
+ * function {@code keyFunction} on each value in the input collection to
+ * that value
+ * @throws NullPointerException if any of the following cases is true:
+ * <ul>
+ * <li>{@code values} is null
+ * <li>{@code keyFunction} is null
+ * <li>An element in {@code values} is null
+ * <li>{@code keyFunction} returns {@code null} for any element of {@code
+ * values}
+ * </ul>
+ */
+ public static <K, V> ImmutableListMultimap<K, V> index(
+ Iterable<V> values, Function<? super V, K> keyFunction) {
+ return index(values.iterator(), 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,
+ * yielding a multimap with the same size as the input iterator. 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.
+ *
+ * <p>For example, <pre> {@code
+ *
+ * List<String> badGuys =
+ * Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
+ * Function<String, Integer> stringLengthFunction = ...;
+ * Multimap<Integer, String> index =
+ * Multimaps.index(badGuys.iterator(), stringLengthFunction);
+ * System.out.println(index);}</pre>
+ *
+ * prints <pre> {@code
+ *
+ * {4=[Inky], 6=[Blinky], 5=[Pinky, Pinky, Clyde]}}</pre>
+ *
+ * The returned multimap is serializable if its keys and values are all
+ * serializable.
+ *
+ * @param values the values to use when constructing the {@code
+ * ImmutableListMultimap}
+ * @param keyFunction the function used to produce the key for each value
+ * @return {@code ImmutableListMultimap} mapping the result of evaluating the
+ * function {@code keyFunction} on each value in the input collection to
+ * that value
+ * @throws NullPointerException if any of the following cases is true:
+ * <ul>
+ * <li>{@code values} is null
+ * <li>{@code keyFunction} is null
+ * <li>An element in {@code values} is null
+ * <li>{@code keyFunction} returns {@code null} for any element of {@code
+ * values}
+ * </ul>
+ * @since 10.0
+ */
+ public static <K, V> ImmutableListMultimap<K, V> index(
+ Iterator<V> values, Function<? super V, K> keyFunction) {
+ checkNotNull(keyFunction);
+ ImmutableListMultimap.Builder<K, V> builder
+ = ImmutableListMultimap.builder();
+ while (values.hasNext()) {
+ V value = values.next();
+ checkNotNull(value, values);
+ builder.put(keyFunction.apply(value), value);
+ }
+ return builder.build();
+ }
+
+ 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) {
+ return new Multisets.AbstractEntry<K>() {
+ @Override
+ public K getElement() {
+ return backingEntry.getKey();
+ }
+
+ @Override
+ public int getCount() {
+ return backingEntry.getValue().size();
+ }
+ };
+ }
+ };
+ }
+
+ @Override int distinctElements() {
+ return multimap().asMap().size();
+ }
+
+ @Override Set<Multiset.Entry<K>> createEntrySet() {
+ return new KeysEntrySet();
+ }
+
+ class KeysEntrySet extends Multisets.EntrySet<K> {
+ @Override Multiset<K> multiset() {
+ return Keys.this;
+ }
+
+ @Override public Iterator<Multiset.Entry<K>> iterator() {
+ return entryIterator();
+ }
+
+ @Override public int size() {
+ return distinctElements();
+ }
+
+ @Override public boolean isEmpty() {
+ return multimap().isEmpty();
+ }
+
+ @Override public boolean contains(@Nullable Object o) {
+ if (o instanceof Multiset.Entry) {
+ Multiset.Entry<?> entry = (Multiset.Entry<?>) o;
+ 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) {
+ Multiset.Entry<?> entry = (Multiset.Entry<?>) o;
+ Collection<V> collection = multimap().asMap().get(entry.getElement());
+ if (collection != null && collection.size() == entry.getCount()) {
+ collection.clear();
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ @Override public boolean contains(@Nullable Object element) {
+ return multimap().containsKey(element);
+ }
+
+ @Override public Iterator<K> iterator() {
+ return Maps.keyIterator(multimap().entries().iterator());
+ }
+
+ @Override public int count(@Nullable Object element) {
+ 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) {
+ checkArgument(occurrences >= 0);
+ if (occurrences == 0) {
+ return count(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;
+ }
+
+ int oldCount = values.size();
+ if (occurrences >= oldCount) {
+ values.clear();
+ } else {
+ Iterator<V> iterator = values.iterator();
+ for (int i = 0; i < occurrences; i++) {
+ iterator.next();
+ iterator.remove();
+ }
+ }
+ return oldCount;
+ }
+
+ @Override public void clear() {
+ multimap().clear();
+ }
+
+ @Override public Set<K> elementSet() {
+ return multimap().keySet();
+ }
+ }
+
+ 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());
+ }
+
+ @Override public int size() {
+ return multimap().size();
+ }
+
+ @Override public boolean contains(@Nullable Object o) {
+ return multimap().containsValue(o);
+ }
+
+ @Override public void clear() {
+ multimap().clear();
+ }
+ }
+
+ /**
+ * A skeleton implementation of {@link Multimap#entries()}.
+ */
+ static abstract class Entries<K, V> extends
+ AbstractCollection<Map.Entry<K, V>> {
+ abstract Multimap<K, V> multimap();
+
+ @Override public int size() {
+ return multimap().size();
+ }
+
+ @Override public boolean contains(@Nullable Object o) {
+ if (o instanceof Map.Entry) {
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
+ return multimap().containsEntry(entry.getKey(), entry.getValue());
+ }
+ return false;
+ }
+
+ @Override public boolean remove(@Nullable Object o) {
+ if (o instanceof Map.Entry) {
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
+ return multimap().remove(entry.getKey(), entry.getValue());
+ }
+ return false;
+ }
+
+ @Override public void clear() {
+ multimap().clear();
+ }
+ }
+
+ /**
+ * A skeleton implementation of {@link SetMultimap#entries()}.
+ */
+ static abstract class EntrySet<K, V> extends Entries<K, V> implements
+ Set<Map.Entry<K, V>> {
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ return Sets.equalsImpl(this, obj);
+ }
+ }
+
+ /**
+ * A skeleton implementation of {@link Multimap#asMap()}.
+ */
+ static abstract class AsMap<K, V> extends
+ Maps.ImprovedAbstractMap<K, Collection<V>> {
+ abstract Multimap<K, V> multimap();
+
+ @Override public abstract int size();
+
+ abstract Iterator<Entry<K, Collection<V>>> entryIterator();
+
+ @Override protected Set<Entry<K, Collection<V>>> createEntrySet() {
+ return new EntrySet();
+ }
+
+ void removeValuesForKey(Object key){
+ multimap().removeAll(key);
+ }
+
+ class EntrySet extends Maps.EntrySet<K, Collection<V>> {
+ @Override Map<K, Collection<V>> map() {
+ return AsMap.this;
+ }
+
+ @Override public Iterator<Entry<K, Collection<V>>> iterator() {
+ return entryIterator();
+ }
+
+ @Override public boolean remove(Object o) {
+ if (!contains(o)) {
+ return false;
+ }
+ Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
+ removeValuesForKey(entry.getKey());
+ return true;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public Collection<V> get(Object key) {
+ return containsKey(key) ? multimap().get((K) key) : null;
+ }
+
+ @Override public Collection<V> remove(Object key) {
+ return containsKey(key) ? multimap().removeAll(key) : null;
+ }
+
+ @Override public Set<K> keySet() {
+ return multimap().keySet();
+ }
+
+ @Override public boolean isEmpty() {
+ return multimap().isEmpty();
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return multimap().containsKey(key);
+ }
+
+ @Override public void clear() {
+ multimap().clear();
+ }
+ }
+
+ /**
+ * Returns a multimap containing the mappings in {@code unfiltered} whose keys
+ * satisfy a predicate. The returned multimap is a live view of
+ * {@code unfiltered}; changes to one affect the other.
+ *
+ * <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}.
+ *
+ * <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
+ * filter will be removed from the underlying multimap.
+ *
+ * <p>The returned multimap isn't threadsafe or serializable, even if
+ * {@code unfiltered} is.
+ *
+ * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate
+ * across every key/value mapping in the underlying multimap and determine
+ * which satisfy the filter. When a live view is <i>not</i> needed, it may be
+ * faster to copy the filtered multimap 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 11.0
+ */
+ @GwtIncompatible(value = "untested")
+ public static <K, V> Multimap<K, V> filterKeys(
+ 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);
+ }
+
+ /**
+ * Returns a multimap containing the mappings in {@code unfiltered} whose values
+ * satisfy a predicate. The returned multimap is a live view of
+ * {@code unfiltered}; changes to one affect the other.
+ *
+ * <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}.
+ *
+ * <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
+ * filter will be removed from the underlying multimap.
+ *
+ * <p>The returned multimap isn't threadsafe or serializable, even if
+ * {@code unfiltered} is.
+ *
+ * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate
+ * across every key/value mapping in the underlying multimap and determine
+ * which satisfy the filter. When a live view is <i>not</i> needed, it may be
+ * faster to copy the filtered multimap 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 11.0
+ */
+ @GwtIncompatible(value = "untested")
+ public static <K, V> Multimap<K, V> filterValues(
+ 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);
+ }
+
+ /**
+ * Returns a multimap containing the mappings in {@code unfiltered} that
+ * satisfy a predicate. The returned multimap is a live view of
+ * {@code unfiltered}; changes to one affect the other.
+ *
+ * <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}.
+ *
+ * <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
+ * filter will be removed from the underlying multimap.
+ *
+ * <p>The returned multimap isn't threadsafe or serializable, even if
+ * {@code unfiltered} is.
+ *
+ * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate
+ * across every key/value mapping in the underlying multimap and determine
+ * which satisfy the filter. When a live view is <i>not</i> needed, it may be
+ * faster to copy the filtered multimap and use the copy.
+ *
+ * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with
+ * equals</i>, as documented at {@link Predicate#apply}.
+ *
+ * @since 11.0
+ */
+ @GwtIncompatible(value = "untested")
+ public static <K, V> Multimap<K, V> filterEntries(
+ Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
+ checkNotNull(entryPredicate);
+ return (unfiltered instanceof FilteredMultimap)
+ ? filterFiltered((FilteredMultimap<K, V>) 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 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> map,
+ Predicate<? super Entry<K, V>> entryPredicate) {
+ Predicate<Entry<K, V>> 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.iterator());
+ }
+
+ @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(final Collection<?> c) {
+ return Sets.removeAllImpl(this, c.iterator());
+ }
+
+ @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
new file mode 100644
index 0000000..bb254c9
--- /dev/null
+++ b/guava/src/com/google/common/collect/Multiset.java
@@ -0,0 +1,440 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A collection that supports order-independent equality, like {@link Set}, but
+ * 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>{@code Multiset} refines the specifications of several methods from
+ * {@code Collection}. It also defines an additional query operation, {@link
+ * #count}, which returns the count of an element. There are five new
+ * bulk-modification operations, for example {@link #add(Object, int)}, to add
+ * or remove multiple occurrences of an element at once, or to set the count of
+ * an element to a specific value. These modification operations are optional,
+ * but implementations which support the standard collection operations {@link
+ * #add(Object)} or {@link #remove(Object)} are encouraged to implement the
+ * related methods as well. Finally, two collection views are provided: {@link
+ * #elementSet} contains the distinct elements of the multiset "with duplicates
+ * collapsed", and {@link #entrySet} is similar but contains {@link Entry
+ * Multiset.Entry} instances, each providing both a distinct element and the
+ * count of that element.
+ *
+ * <p>In addition to these required methods, implementations of {@code
+ * Multiset} are expected to provide two {@code static} creation methods:
+ * {@code create()}, returning an empty multiset, and {@code
+ * create(Iterable<? extends E>)}, returning a multiset containing the
+ * given initial elements. This is simply a refinement of {@code Collection}'s
+ * constructor recommendations, reflecting the new developments of Java 5.
+ *
+ * <p>As with other collection types, the modification operations are optional,
+ * and should throw {@link UnsupportedOperationException} when they are not
+ * implemented. Most implementations should support either all add operations
+ * or none of them, all removal operations or none of them, and if and only if
+ * all of these are supported, the {@code setCount} methods as well.
+ *
+ * <p>A multiset uses {@link Object#equals} to determine whether two instances
+ * should be considered "the same," <i>unless specified otherwise</i> by the
+ * implementation.
+ *
+ * <p>Common implementations include {@link ImmutableMultiset}, {@link
+ * HashMultiset}, and {@link ConcurrentHashMultiset}.
+ *
+ * <p>If your values may be zero, negative, or outside the range of an int, you
+ * 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)
+ */
+@GwtCompatible
+public interface Multiset<E> extends Collection<E> {
+ // Query Operations
+
+ /**
+ * Returns the number of occurrences of an element in this multiset (the
+ * <i>count</i> of the element). Note that for an {@link Object#equals}-based
+ * multiset, this gives the same result as {@link Collections#frequency}
+ * (which would presumably perform more poorly).
+ *
+ * <p><b>Note:</b> the utility method {@link Iterables#frequency} generalizes
+ * this operation; it correctly delegates to this method when dealing with a
+ * multiset, but it can also accept any other iterable type.
+ *
+ * @param element the element to count occurrences of
+ * @return the number of occurrences of the element in this multiset; possibly
+ * zero but never negative
+ */
+ int count(@Nullable Object element);
+
+ // Bulk Operations
+
+ /**
+ * Adds a number of occurrences of an element to this multiset. Note that if
+ * {@code occurrences == 1}, this method has the identical effect to {@link
+ * #add(Object)}. This method is functionally equivalent (except in the case
+ * of overflow) to the call {@code addAll(Collections.nCopies(element,
+ * occurrences))}, which would presumably perform much more poorly.
+ *
+ * @param element the element to add occurrences of; may be null only if
+ * explicitly allowed by the implementation
+ * @param occurrences the number of occurrences of the element to add. May be
+ * zero, in which case no change will be made.
+ * @return the count of the element before the operation; possibly zero
+ * @throws IllegalArgumentException if {@code occurrences} is negative, or if
+ * this operation would result in more than {@link Integer#MAX_VALUE}
+ * occurrences of the element
+ * @throws NullPointerException if {@code element} is null and this
+ * implementation does not permit null elements. Note that if {@code
+ * occurrences} is zero, the implementation may opt to return normally.
+ */
+ int add(@Nullable E element, int occurrences);
+
+ /**
+ * Removes a number of occurrences of the specified element from this
+ * multiset. If the multiset contains fewer than this number of occurrences to
+ * begin with, all occurrences will be removed. Note that if
+ * {@code occurrences == 1}, this is functionally equivalent to the call
+ * {@code remove(element)}.
+ *
+ * @param element the element to conditionally remove occurrences of
+ * @param occurrences the number of occurrences of the element to remove. May
+ * be zero, in which case no change will be made.
+ * @return the count of the element before the operation; possibly zero
+ * @throws IllegalArgumentException if {@code occurrences} is negative
+ */
+ int remove(@Nullable Object element, int occurrences);
+
+ /**
+ * Adds or removes the necessary occurrences of an element such that the
+ * element attains the desired count.
+ *
+ * @param element the element to add or remove occurrences of; may be null
+ * only if explicitly allowed by the implementation
+ * @param count the desired count of the element in this multiset
+ * @return the count of the element before the operation; possibly zero
+ * @throws IllegalArgumentException if {@code count} is negative
+ * @throws NullPointerException if {@code element} is null and this
+ * implementation does not permit null elements. Note that if {@code
+ * count} is zero, the implementor may optionally return zero instead.
+ */
+ int setCount(E element, int count);
+
+ /**
+ * Conditionally sets the count of an element to a new value, as described in
+ * {@link #setCount(Object, int)}, provided that the element has the expected
+ * current count. If the current count is not {@code oldCount}, no change is
+ * made.
+ *
+ * @param element the element to conditionally set the count of; may be null
+ * only if explicitly allowed by the implementation
+ * @param oldCount the expected present count of the element in this multiset
+ * @param newCount the desired count of the element in this multiset
+ * @return {@code true} if the condition for modification was met. This
+ * implies that the multiset was indeed modified, unless
+ * {@code oldCount == newCount}.
+ * @throws IllegalArgumentException if {@code oldCount} or {@code newCount} is
+ * negative
+ * @throws NullPointerException if {@code element} is null and the
+ * implementation does not permit null elements. Note that if {@code
+ * oldCount} and {@code newCount} are both zero, the implementor may
+ * optionally return {@code true} instead.
+ */
+ boolean setCount(E element, int oldCount, int newCount);
+
+ // Views
+
+ /**
+ * Returns the set of distinct elements contained in this multiset. The
+ * element set is backed by the same data as the multiset, so any change to
+ * either is immediately reflected in the other. The order of the elements in
+ * the element set is unspecified.
+ *
+ * <p>If the element set supports any removal operations, these necessarily
+ * cause <b>all</b> occurrences of the removed element(s) to be removed from
+ * the multiset. Implementations are not expected to support the add
+ * operations, although this is possible.
+ *
+ * <p>A common use for the element set is to find the number of distinct
+ * elements in the multiset: {@code elementSet().size()}.
+ *
+ * @return a view of the set of distinct elements in this multiset
+ */
+ Set<E> elementSet();
+
+ /**
+ * Returns a view of the contents of this multiset, grouped into {@code
+ * Multiset.Entry} instances, each providing an element of the multiset and
+ * the count of that element. This set contains exactly one entry for each
+ * distinct element in the multiset (thus it always has the same size as the
+ * {@link #elementSet}). The order of the elements in the element set is
+ * unspecified.
+ *
+ * <p>The entry set is backed by the same data as the multiset, so any change
+ * to either is immediately reflected in the other. However, multiset changes
+ * may or may not be reflected in any {@code Entry} instances already
+ * retrieved from the entry set (this is implementation-dependent).
+ * Furthermore, implementations are not required to support modifications to
+ * the entry set at all, and the {@code Entry} instances themselves don't
+ * even have methods for modification. See the specific implementation class
+ * for more details on how its entry set handles modifications.
+ *
+ * @return a set of entries representing the data of this multiset
+ */
+ Set<Entry<E>> entrySet();
+
+ /**
+ * An unmodifiable element-count pair for a multiset. The {@link
+ * Multiset#entrySet} method returns a view of the multiset whose elements
+ * are of this class. A multiset implementation may return Entry instances
+ * that are either live "read-through" views to the Multiset, or immutable
+ * snapshots. Note that this type is unrelated to the similarly-named type
+ * {@code Map.Entry}.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ interface Entry<E> {
+
+ /**
+ * Returns the multiset element corresponding to this entry. Multiple calls
+ * to this method always return the same instance.
+ *
+ * @return the element corresponding to this entry
+ */
+ E getElement();
+
+ /**
+ * Returns the count of the associated element in the underlying multiset.
+ * This count may either be an unchanging snapshot of the count at the time
+ * the entry was retrieved, or a live view of the current count of the
+ * element in the multiset, depending on the implementation. Note that in
+ * the former case, this method can never return zero, while in the latter,
+ * it will return zero if all occurrences of the element were since removed
+ * from the multiset.
+ *
+ * @return the count of the element; never negative
+ */
+ int getCount();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Returns {@code true} if the given object is also a multiset entry and
+ * the two entries represent the same element and count. That is, two
+ * entries {@code a} and {@code b} are equal if: <pre> {@code
+ *
+ * Objects.equal(a.getElement(), b.getElement())
+ * && a.getCount() == b.getCount()}</pre>
+ */
+ @Override
+ // TODO(kevinb): check this wrt TreeMultiset?
+ boolean equals(Object o);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The hash code of a multiset entry for element {@code element} and
+ * count {@code count} is defined as: <pre> {@code
+ *
+ * ((element == null) ? 0 : element.hashCode()) ^ count}</pre>
+ */
+ @Override
+ int hashCode();
+
+ /**
+ * Returns the canonical string representation of this entry, defined as
+ * follows. If the count for this entry is one, this is simply the string
+ * representation of the corresponding element. Otherwise, it is the string
+ * representation of the element, followed by the three characters {@code
+ * " x "} (space, letter x, space), followed by the count.
+ */
+ @Override
+ String toString();
+ }
+
+ // Comparison and hashing
+
+ /**
+ * Compares the specified object with this multiset for equality. Returns
+ * {@code true} if the given object is also a multiset and contains equal
+ * elements with equal counts, regardless of order.
+ */
+ @Override
+ // TODO(kevinb): caveats about equivalence-relation?
+ boolean equals(@Nullable Object object);
+
+ /**
+ * Returns the hash code for this multiset. This is defined as the sum of
+ * <pre> {@code
+ *
+ * ((element == null) ? 0 : element.hashCode()) ^ count(element)}</pre>
+ *
+ * over all distinct elements in the multiset. It follows that a multiset and
+ * its entry set always have the same hash code.
+ */
+ @Override
+ int hashCode();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>It is recommended, though not mandatory, that this method return the
+ * result of invoking {@link #toString} on the {@link #entrySet}, yielding a
+ * result such as {@code [a x 3, c, d x 2, e]}.
+ */
+ @Override
+ String toString();
+
+ // Refined Collection Methods
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Elements that occur multiple times in the multiset will appear
+ * multiple times in this iterator, though not necessarily sequentially.
+ */
+ @Override
+ Iterator<E> iterator();
+
+ /**
+ * Determines whether this multiset contains the specified element.
+ *
+ * <p>This method refines {@link Collection#contains} to further specify that
+ * it <b>may not</b> throw an exception in response to {@code element} being
+ * null or of the wrong type.
+ *
+ * @param element the element to check for
+ * @return {@code true} if this multiset contains at least one occurrence of
+ * the element
+ */
+ @Override
+ boolean contains(@Nullable Object element);
+
+ /**
+ * Returns {@code true} if this multiset contains at least one occurrence of
+ * each element in the specified collection.
+ *
+ * <p>This method refines {@link Collection#containsAll} to further specify
+ * that it <b>may not</b> throw an exception in response to any of {@code
+ * elements} being null or of the wrong type.
+ *
+ * <p><b>Note:</b> this method does not take into account the occurrence
+ * count of an element in the two collections; it may still return {@code
+ * true} even if {@code elements} contains several occurrences of an element
+ * and this multiset contains only one. This is no different than any other
+ * collection type like {@link List}, but it may be unexpected to the user of
+ * a multiset.
+ *
+ * @param elements the collection of elements to be checked for containment in
+ * this multiset
+ * @return {@code true} if this multiset contains at least one occurrence of
+ * each element contained in {@code elements}
+ * @throws NullPointerException if {@code elements} is null
+ */
+ @Override
+ boolean containsAll(Collection<?> elements);
+
+ /**
+ * Adds a single occurrence of the specified element to this multiset.
+ *
+ * <p>This method refines {@link Collection#add}, which only <i>ensures</i>
+ * the presence of the element, to further specify that a successful call must
+ * always increment the count of the element, and the overall size of the
+ * collection, by one.
+ *
+ * @param element the element to add one occurrence of; may be null only if
+ * explicitly allowed by the implementation
+ * @return {@code true} always, since this call is required to modify the
+ * multiset, unlike other {@link Collection} types
+ * @throws NullPointerException if {@code element} is null and this
+ * implementation does not permit null elements
+ * @throws IllegalArgumentException if {@link Integer#MAX_VALUE} occurrences
+ * of {@code element} are already contained in this multiset
+ */
+ @Override
+ boolean add(E element);
+
+ /**
+ * Removes a <i>single</i> occurrence of the specified element from this
+ * multiset, if present.
+ *
+ * <p>This method refines {@link Collection#remove} to further specify that it
+ * <b>may not</b> throw an exception in response to {@code element} being null
+ * or of the wrong type.
+ *
+ * @param element the element to remove one occurrence of
+ * @return {@code true} if an occurrence was found and removed
+ */
+ @Override
+ boolean remove(@Nullable Object element);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p><b>Note:</b> This method ignores how often any element might appear in
+ * {@code c}, and only cares whether or not an element appears at all.
+ * If you wish to remove one occurrence in this multiset for every occurrence
+ * in {@code c}, see {@link Multisets#removeOccurrences(Multiset, Multiset)}.
+ *
+ * <p>This method refines {@link Collection#removeAll} to further specify that
+ * it <b>may not</b> throw an exception in response to any of {@code elements}
+ * being null or of the wrong type.
+ */
+ @Override
+ boolean removeAll(Collection<?> c);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p><b>Note:</b> This method ignores how often any element might appear in
+ * {@code c}, and only cares whether or not an element appears at all.
+ * If you wish to remove one occurrence in this multiset for every occurrence
+ * in {@code c}, see {@link Multisets#retainOccurrences(Multiset, Multiset)}.
+ *
+ * <p>This method refines {@link Collection#retainAll} to further specify that
+ * it <b>may not</b> throw an exception in response to any of {@code elements}
+ * being null or of the wrong type.
+ *
+ * @see Multisets#retainOccurrences(Multiset, Multiset)
+ */
+ @Override
+ boolean retainAll(Collection<?> c);
+}
diff --git a/guava/src/com/google/common/collect/Multisets.java b/guava/src/com/google/common/collect/Multisets.java
new file mode 100644
index 0000000..60e1d26
--- /dev/null
+++ b/guava/src/com/google/common/collect/Multisets.java
@@ -0,0 +1,972 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Objects;
+import com.google.common.collect.Multiset.Entry;
+import com.google.common.primitives.Ints;
+
+import java.io.Serializable;
+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;
+
+/**
+ * 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
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+public final class Multisets {
+ private Multisets() {}
+
+ /**
+ * Returns an unmodifiable view of the specified multiset. Query operations on
+ * the returned multiset "read through" to the specified multiset, and
+ * attempts to modify the returned multiset result in an
+ * {@link UnsupportedOperationException}.
+ *
+ * <p>The returned multiset will be serializable if the specified multiset is
+ * serializable.
+ *
+ * @param multiset the multiset for which an unmodifiable view is to be
+ * generated
+ * @return an unmodifiable view of the multiset
+ */
+ public static <E> Multiset<E> unmodifiableMultiset(
+ Multiset<? extends E> multiset) {
+ if (multiset instanceof UnmodifiableMultiset ||
+ multiset instanceof ImmutableMultiset) {
+ // Since it's unmodifiable, the covariant cast is safe
+ @SuppressWarnings("unchecked")
+ Multiset<E> result = (Multiset<E>) multiset;
+ return result;
+ }
+ return new UnmodifiableMultiset<E>(checkNotNull(multiset));
+ }
+
+ /**
+ * Simply returns its argument.
+ *
+ * @deprecated no need to use this
+ * @since 10.0
+ */
+ @Deprecated public static <E> Multiset<E> unmodifiableMultiset(
+ ImmutableMultiset<E> multiset) {
+ return checkNotNull(multiset);
+ }
+
+ static class UnmodifiableMultiset<E>
+ extends ForwardingMultiset<E> implements Serializable {
+ final Multiset<? extends E> delegate;
+
+ UnmodifiableMultiset(Multiset<? extends E> delegate) {
+ this.delegate = delegate;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override protected Multiset<E> delegate() {
+ // This is safe because all non-covariant methods are overriden
+ return (Multiset<E>) delegate;
+ }
+
+ transient Set<E> elementSet;
+
+ Set<E> createElementSet() {
+ return Collections.<E>unmodifiableSet(delegate.elementSet());
+ }
+
+ @Override
+ public Set<E> elementSet() {
+ Set<E> es = elementSet;
+ return (es == null) ? elementSet = createElementSet() : es;
+ }
+
+ transient Set<Multiset.Entry<E>> entrySet;
+
+ @SuppressWarnings("unchecked")
+ @Override public Set<Multiset.Entry<E>> entrySet() {
+ Set<Multiset.Entry<E>> es = entrySet;
+ return (es == null)
+ // Safe because the returned set is made unmodifiable and Entry
+ // itself is readonly
+ ? entrySet = (Set) Collections.unmodifiableSet(delegate.entrySet())
+ : es;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public Iterator<E> iterator() {
+ // Safe because the returned Iterator is made unmodifiable
+ return (Iterator<E>) Iterators.unmodifiableIterator(delegate.iterator());
+ }
+
+ @Override public boolean add(E element) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public int add(E element, int occurences) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean addAll(Collection<? extends E> elementsToAdd) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean remove(Object element) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public int remove(Object element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean removeAll(Collection<?> elementsToRemove) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean retainAll(Collection<?> elementsToRetain) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public int setCount(E element, int count) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean setCount(E element, int oldCount, int newCount) {
+ throw new UnsupportedOperationException();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified sorted multiset. Query
+ * operations on the returned multiset "read through" to the specified
+ * multiset, and attempts to modify the returned multiset result in an {@link
+ * UnsupportedOperationException}.
+ *
+ * <p>The returned multiset will be serializable if the specified multiset is
+ * serializable.
+ *
+ * @param sortedMultiset the sorted multiset for which an unmodifiable view is
+ * to be generated
+ * @return an unmodifiable view of the multiset
+ * @since 11.0
+ */
+ @Beta
+ public static <E> SortedMultiset<E> unmodifiableSortedMultiset(
+ SortedMultiset<E> sortedMultiset) {
+ 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.
+ *
+ * @param e the element to be associated with the returned entry
+ * @param n the count to be associated with the returned entry
+ * @throws IllegalArgumentException if {@code n} is negative
+ */
+ public static <E> Multiset.Entry<E> immutableEntry(@Nullable E e, int n) {
+ return new ImmutableEntry<E>(e, n);
+ }
+
+ static final class ImmutableEntry<E> extends AbstractEntry<E> implements
+ Serializable {
+ @Nullable final E element;
+ final int count;
+
+ ImmutableEntry(@Nullable E element, int count) {
+ this.element = element;
+ this.count = count;
+ checkArgument(count >= 0);
+ }
+
+ @Override
+ @Nullable public E getElement() {
+ return element;
+ }
+
+ @Override
+ public int getCount() {
+ return count;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * 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 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>The returned multiset will be serializable if the specified set is
+ * serializable. The multiset is threadsafe if the set is threadsafe.
+ *
+ * @param set the backing set for the returned multiset view
+ */
+ static <E> Multiset<E> forSet(Set<E> set) {
+ return new SetMultiset<E>(set);
+ }
+
+ /** @see Multisets#forSet */
+ private static class SetMultiset<E> extends ForwardingCollection<E>
+ implements Multiset<E>, Serializable {
+ final Set<E> delegate;
+
+ SetMultiset(Set<E> set) {
+ delegate = checkNotNull(set);
+ }
+
+ @Override protected Set<E> delegate() {
+ return delegate;
+ }
+
+ @Override
+ public int count(Object element) {
+ return delegate.contains(element) ? 1 : 0;
+ }
+
+ @Override
+ public int add(E element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ 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 Set<E> elementSet() {
+ Set<E> es = elementSet;
+ return (es == null) ? elementSet = new ElementSet() : es;
+ }
+
+ 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 new TransformedIterator<E, Entry<E>>(delegate.iterator()) {
+ @Override
+ Entry<E> transform(E e) {
+ return Multisets.immutableEntry(e, 1);
+ }
+ };
+ }
+
+ @Override public int size() {
+ return delegate.size();
+ }
+ };
+ }
+ return es;
+ }
+
+ @Override public boolean add(E o) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean addAll(Collection<? extends E> c) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ 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 {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public boolean setCount(E element, int oldCount, int newCount) {
+ return setCountImpl(this, element, oldCount, newCount);
+ }
+
+ @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 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;
+ }
+
+ /**
+ * Returns the expected number of distinct elements given the specified
+ * elements. The number of distinct elements is only computed if {@code
+ * elements} is an instance of {@code Multiset}; otherwise the default value
+ * of 11 is returned.
+ */
+ static int inferDistinctElements(Iterable<?> elements) {
+ if (elements instanceof Multiset) {
+ return ((Multiset<?>) elements).elementSet().size();
+ }
+ return 11; // initial capacity will be rounded up to 16
+ }
+
+ /**
+ * 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 2.0
+ */
+ public static <E> Multiset<E> intersection(
+ final Multiset<E> multiset1, final Multiset<?> multiset2) {
+ checkNotNull(multiset1);
+ checkNotNull(multiset2);
+
+ return new AbstractMultiset<E>() {
+ @Override
+ public int count(Object element) {
+ int count1 = multiset1.count(element);
+ return (count1 == 0) ? 0 : Math.min(count1, multiset2.count(element));
+ }
+
+ @Override
+ Set<E> createElementSet() {
+ return Sets.intersection(
+ multiset1.elementSet(), multiset2.elementSet());
+ }
+
+ @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 = Math.min(entry1.getCount(), multiset2.count(element));
+ if (count > 0) {
+ return Multisets.immutableEntry(element, count);
+ }
+ }
+ return endOfData();
+ }
+ };
+ }
+
+ @Override
+ int distinctElements() {
+ return elementSet().size();
+ }
+ };
+ }
+
+ /**
+ * Returns {@code true} if {@code subMultiset.count(o) <=
+ * superMultiset.count(o)} for all {@code o}.
+ *
+ * @since 10.0
+ */
+ public static boolean containsOccurrences(
+ Multiset<?> superMultiset, Multiset<?> subMultiset) {
+ checkNotNull(superMultiset);
+ checkNotNull(subMultiset);
+ for (Entry<?> entry : subMultiset.entrySet()) {
+ int superCount = superMultiset.count(entry.getElement());
+ if (superCount < entry.getCount()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Modifies {@code multisetToModify} so that its count for an element
+ * {@code e} is at most {@code multisetToRetain.count(e)}.
+ *
+ * <p>To be precise, {@code multisetToModify.count(e)} is set to
+ * {@code Math.min(multisetToModify.count(e),
+ * multisetToRetain.count(e))}. This is similar to
+ * {@link #intersection(Multiset, Multiset) intersection}
+ * {@code (multisetToModify, multisetToRetain)}, but mutates
+ * {@code multisetToModify} instead of returning a view.
+ *
+ * <p>In contrast, {@code multisetToModify.retainAll(multisetToRetain)} keeps
+ * all occurrences of elements that appear at all in {@code
+ * multisetToRetain}, and deletes all occurrences of all other elements.
+ *
+ * @return {@code true} if {@code multisetToModify} was changed as a result
+ * of this operation
+ * @since 10.0
+ */
+ public static boolean retainOccurrences(Multiset<?> multisetToModify,
+ Multiset<?> multisetToRetain) {
+ return retainOccurrencesImpl(multisetToModify, multisetToRetain);
+ }
+
+ /**
+ * Delegate implementation which cares about the element type.
+ */
+ private static <E> boolean retainOccurrencesImpl(
+ Multiset<E> multisetToModify, Multiset<?> occurrencesToRetain) {
+ checkNotNull(multisetToModify);
+ checkNotNull(occurrencesToRetain);
+ // Avoiding ConcurrentModificationExceptions is tricky.
+ Iterator<Entry<E>> entryIterator = multisetToModify.entrySet().iterator();
+ boolean changed = false;
+ while (entryIterator.hasNext()) {
+ Entry<E> entry = entryIterator.next();
+ int retainCount = occurrencesToRetain.count(entry.getElement());
+ if (retainCount == 0) {
+ entryIterator.remove();
+ changed = true;
+ } else if (retainCount < entry.getCount()) {
+ multisetToModify.setCount(entry.getElement(), retainCount);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ /**
+ * For each occurrence of an element {@code e} in {@code occurrencesToRemove},
+ * removes one occurrence of {@code e} in {@code multisetToModify}.
+ *
+ * <p>Equivalently, this method modifies {@code multisetToModify} so that
+ * {@code multisetToModify.count(e)} is set to
+ * {@code Math.max(0, multisetToModify.count(e) -
+ * occurrencesToRemove.count(e))}.
+ *
+ * <p>This is <i>not</i> the same as {@code multisetToModify.}
+ * {@link Multiset#removeAll removeAll}{@code (occurrencesToRemove)}, which
+ * removes all occurrences of elements that appear in
+ * {@code occurrencesToRemove}. However, this operation <i>is</i> equivalent
+ * to, albeit more efficient than, the following: <pre> {@code
+ *
+ * for (E e : occurrencesToRemove) {
+ * multisetToModify.remove(e);
+ * }}</pre>
+ *
+ * @return {@code true} if {@code multisetToModify} was changed as a result of
+ * this operation
+ * @since 10.0
+ */
+ public static boolean removeOccurrences(
+ Multiset<?> multisetToModify, Multiset<?> occurrencesToRemove) {
+ return removeOccurrencesImpl(multisetToModify, occurrencesToRemove);
+ }
+
+ /**
+ * Delegate that cares about the element types in occurrencesToRemove.
+ */
+ private static <E> boolean removeOccurrencesImpl(
+ Multiset<E> multisetToModify, Multiset<?> occurrencesToRemove) {
+ // TODO(user): generalize to removing an Iterable, perhaps
+ checkNotNull(multisetToModify);
+ checkNotNull(occurrencesToRemove);
+
+ boolean changed = false;
+ Iterator<Entry<E>> entryIterator = multisetToModify.entrySet().iterator();
+ while (entryIterator.hasNext()) {
+ Entry<E> entry = entryIterator.next();
+ int removeCount = occurrencesToRemove.count(entry.getElement());
+ if (removeCount >= entry.getCount()) {
+ entryIterator.remove();
+ changed = true;
+ } else if (removeCount > 0) {
+ multisetToModify.remove(entry.getElement(), removeCount);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ /**
+ * Implementation of the {@code equals}, {@code hashCode}, and
+ * {@code toString} methods of {@link Multiset.Entry}.
+ */
+ abstract static class AbstractEntry<E> implements Multiset.Entry<E> {
+ /**
+ * Indicates whether an object equals this entry, following the behavior
+ * specified in {@link Multiset.Entry#equals}.
+ */
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Multiset.Entry) {
+ Multiset.Entry<?> that = (Multiset.Entry<?>) object;
+ return this.getCount() == that.getCount()
+ && Objects.equal(this.getElement(), that.getElement());
+ }
+ return false;
+ }
+
+ /**
+ * Return this entry's hash code, following the behavior specified in
+ * {@link Multiset.Entry#hashCode}.
+ */
+ @Override public int hashCode() {
+ E e = getElement();
+ return ((e == null) ? 0 : e.hashCode()) ^ getCount();
+ }
+
+ /**
+ * Returns a string representation of this multiset entry. The string
+ * representation consists of the associated element if the associated count
+ * is one, and otherwise the associated element followed by the characters
+ * " x " (space, x and space) followed by the count. Elements and counts are
+ * converted to strings as by {@code String.valueOf}.
+ */
+ @Override public String toString() {
+ String text = String.valueOf(getElement());
+ int n = getCount();
+ return (n == 1) ? text : (text + " x " + n);
+ }
+ }
+
+ /**
+ * An implementation of {@link Multiset#equals}.
+ */
+ static boolean equalsImpl(Multiset<?> multiset, @Nullable Object object) {
+ if (object == multiset) {
+ return true;
+ }
+ if (object instanceof Multiset) {
+ Multiset<?> that = (Multiset<?>) object;
+ /*
+ * We can't simply check whether the entry sets are equal, since that
+ * approach fails when a TreeMultiset has a comparator that returns 0
+ * when passed unequal elements.
+ */
+
+ if (multiset.size() != that.size()
+ || multiset.entrySet().size() != that.entrySet().size()) {
+ return false;
+ }
+ for (Entry<?> entry : that.entrySet()) {
+ if (multiset.count(entry.getElement()) != entry.getCount()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * An implementation of {@link Multiset#addAll}.
+ */
+ static <E> boolean addAllImpl(
+ Multiset<E> self, Collection<? extends E> elements) {
+ if (elements.isEmpty()) {
+ return false;
+ }
+ if (elements instanceof Multiset) {
+ Multiset<? extends E> that = cast(elements);
+ for (Entry<? extends E> entry : that.entrySet()) {
+ self.add(entry.getElement(), entry.getCount());
+ }
+ } else {
+ Iterators.addAll(self, elements.iterator());
+ }
+ return true;
+ }
+
+ /**
+ * An implementation of {@link Multiset#removeAll}.
+ */
+ static boolean removeAllImpl(
+ Multiset<?> self, Collection<?> elementsToRemove) {
+ Collection<?> collection = (elementsToRemove instanceof Multiset)
+ ? ((Multiset<?>) elementsToRemove).elementSet() : elementsToRemove;
+
+ return self.elementSet().removeAll(collection);
+ }
+
+ /**
+ * An implementation of {@link Multiset#retainAll}.
+ */
+ static boolean retainAllImpl(
+ Multiset<?> self, Collection<?> elementsToRetain) {
+ checkNotNull(elementsToRetain);
+ Collection<?> collection = (elementsToRetain instanceof Multiset)
+ ? ((Multiset<?>) elementsToRetain).elementSet() : elementsToRetain;
+
+ return self.elementSet().retainAll(collection);
+ }
+
+ /**
+ * An implementation of {@link Multiset#setCount(Object, int)}.
+ */
+ static <E> int setCountImpl(Multiset<E> self, E element, int count) {
+ checkNonnegative(count, "count");
+
+ int oldCount = self.count(element);
+
+ int delta = count - oldCount;
+ if (delta > 0) {
+ self.add(element, delta);
+ } else if (delta < 0) {
+ self.remove(element, -delta);
+ }
+
+ return oldCount;
+ }
+
+ /**
+ * An implementation of {@link Multiset#setCount(Object, int, int)}.
+ */
+ static <E> boolean setCountImpl(
+ Multiset<E> self, E element, int oldCount, int newCount) {
+ checkNonnegative(oldCount, "oldCount");
+ checkNonnegative(newCount, "newCount");
+
+ if (self.count(element) == oldCount) {
+ self.setCount(element, newCount);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ abstract static class ElementSet<E> extends Sets.ImprovedAbstractSet<E> {
+ abstract Multiset<E> multiset();
+
+ @Override public void clear() {
+ multiset().clear();
+ }
+
+ @Override public boolean contains(Object o) {
+ return multiset().contains(o);
+ }
+
+ @Override public boolean containsAll(Collection<?> c) {
+ return multiset().containsAll(c);
+ }
+
+ @Override public boolean isEmpty() {
+ return multiset().isEmpty();
+ }
+
+ @Override public Iterator<E> iterator() {
+ return new TransformedIterator<Entry<E>, E>(multiset().entrySet().iterator()) {
+ @Override
+ E transform(Entry<E> entry) {
+ return entry.getElement();
+ }
+ };
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ int count = multiset().count(o);
+ if (count > 0) {
+ multiset().remove(o, count);
+ return true;
+ }
+ return false;
+ }
+
+ @Override public int size() {
+ return multiset().entrySet().size();
+ }
+ }
+
+ abstract static class EntrySet<E> extends Sets.ImprovedAbstractSet<Entry<E>> {
+ abstract Multiset<E> multiset();
+
+ @Override public boolean contains(@Nullable Object o) {
+ if (o instanceof Entry) {
+ @SuppressWarnings("cast")
+ Entry<?> entry = (Entry<?>) o;
+ if (entry.getCount() <= 0) {
+ return false;
+ }
+ int count = multiset().count(entry.getElement());
+ return count == entry.getCount();
+
+ }
+ return false;
+ }
+
+ @SuppressWarnings("cast")
+ @Override public boolean remove(Object o) {
+ return contains(o)
+ && multiset().elementSet().remove(((Entry<?>) o).getElement());
+ }
+
+ @Override public void clear() {
+ multiset().clear();
+ }
+ }
+
+ /**
+ * An implementation of {@link Multiset#iterator}.
+ */
+ static <E> Iterator<E> iteratorImpl(Multiset<E> multiset) {
+ return new MultisetIteratorImpl<E>(
+ multiset, multiset.entrySet().iterator());
+ }
+
+ static final class MultisetIteratorImpl<E> implements Iterator<E> {
+ private final Multiset<E> multiset;
+ private final Iterator<Entry<E>> entryIterator;
+ private Entry<E> currentEntry;
+ /** Count of subsequent elements equal to current element */
+ private int laterCount;
+ /** Count of all elements equal to current element */
+ private int totalCount;
+ private boolean canRemove;
+
+ MultisetIteratorImpl(
+ Multiset<E> multiset, Iterator<Entry<E>> entryIterator) {
+ this.multiset = multiset;
+ this.entryIterator = entryIterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return laterCount > 0 || entryIterator.hasNext();
+ }
+
+ @Override
+ public E next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ if (laterCount == 0) {
+ currentEntry = entryIterator.next();
+ totalCount = laterCount = currentEntry.getCount();
+ }
+ laterCount--;
+ canRemove = true;
+ return currentEntry.getElement();
+ }
+
+ @Override
+ public void remove() {
+ Iterators.checkRemove(canRemove);
+ if (totalCount == 1) {
+ entryIterator.remove();
+ } else {
+ multiset.remove(currentEntry.getElement());
+ }
+ totalCount--;
+ canRemove = false;
+ }
+ }
+
+ /**
+ * An implementation of {@link Multiset#size}.
+ */
+ static int sizeImpl(Multiset<?> multiset) {
+ long size = 0;
+ for (Entry<?> entry : multiset.entrySet()) {
+ size += entry.getCount();
+ }
+ return Ints.saturatedCast(size);
+ }
+
+ static void checkNonnegative(int count, String name) {
+ checkArgument(count >= 0, "%s cannot be negative: %s", name, count);
+ }
+
+ /**
+ * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
+ */
+ static <T> Multiset<T> cast(Iterable<T> iterable) {
+ return (Multiset<T>) iterable;
+ }
+
+ private static final Ordering<Entry<?>> DECREASING_COUNT_ORDERING = new Ordering<Entry<?>>() {
+ @Override
+ public int compare(Entry<?> entry1, Entry<?> entry2) {
+ return Ints.compare(entry2.getCount(), entry1.getCount());
+ }
+ };
+
+ /**
+ * Returns a copy of {@code multiset} as an {@link ImmutableMultiset} whose iteration order is
+ * highest count first, with ties broken by the iteration order of the original multiset.
+ *
+ * @since 11.0
+ */
+ @Beta
+ public static <E> ImmutableMultiset<E> copyHighestCountFirst(Multiset<E> multiset) {
+ List<Entry<E>> sortedEntries =
+ Multisets.DECREASING_COUNT_ORDERING.sortedCopy(multiset.entrySet());
+ return ImmutableMultiset.copyFromEntries(sortedEntries);
+ }
+}
diff --git a/guava/src/com/google/common/collect/MutableClassToInstanceMap.java b/guava/src/com/google/common/collect/MutableClassToInstanceMap.java
new file mode 100644
index 0000000..c723cea
--- /dev/null
+++ b/guava/src/com/google/common/collect/MutableClassToInstanceMap.java
@@ -0,0 +1,86 @@
+/*
+ * 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 com.google.common.collect.MapConstraints.ConstrainedMap;
+import com.google.common.primitives.Primitives;
+
+import java.util.HashMap;
+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)
+ */
+public final class MutableClassToInstanceMap<B>
+ extends ConstrainedMap<Class<? extends B>, B>
+ implements ClassToInstanceMap<B> {
+
+ /**
+ * Returns a new {@code MutableClassToInstanceMap} instance backed by a {@link
+ * HashMap} using the default initial capacity and load factor.
+ */
+ public static <B> MutableClassToInstanceMap<B> create() {
+ return new MutableClassToInstanceMap<B>(
+ new HashMap<Class<? extends B>, B>());
+ }
+
+ /**
+ * Returns a new {@code MutableClassToInstanceMap} instance backed by a given
+ * empty {@code backingMap}. The caller surrenders control of the backing map,
+ * and thus should not allow any direct references to it to remain accessible.
+ */
+ public static <B> MutableClassToInstanceMap<B> create(
+ Map<Class<? extends B>, B> backingMap) {
+ return new MutableClassToInstanceMap<B>(backingMap);
+ }
+
+ private MutableClassToInstanceMap(Map<Class<? extends B>, B> delegate) {
+ super(delegate, VALUE_CAN_BE_CAST_TO_KEY);
+ }
+
+ private static final MapConstraint<Class<?>, Object> VALUE_CAN_BE_CAST_TO_KEY
+ = new MapConstraint<Class<?>, Object>() {
+ @Override
+ public void checkKeyValue(Class<?> key, Object value) {
+ cast(key, value);
+ }
+ };
+
+ @Override
+ public <T extends B> T putInstance(Class<T> type, T value) {
+ return cast(type, put(type, value));
+ }
+
+ @Override
+ public <T extends B> T getInstance(Class<T> type) {
+ return cast(type, get(type));
+ }
+
+ private static <B, T extends B> T cast(Class<T> type, B value) {
+ return Primitives.wrap(type).cast(value);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/NaturalOrdering.java b/guava/src/com/google/common/collect/NaturalOrdering.java
new file mode 100644
index 0000000..8fbe0d0
--- /dev/null
+++ b/guava/src/com/google/common/collect/NaturalOrdering.java
@@ -0,0 +1,74 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+
+/** An ordering that uses the natural order of the values. */
+@GwtCompatible(serializable = true)
+@SuppressWarnings("unchecked") // TODO(kevinb): the right way to explain this??
+final class NaturalOrdering
+ extends Ordering<Comparable> implements Serializable {
+ static final NaturalOrdering INSTANCE = new NaturalOrdering();
+
+ @Override public int compare(Comparable left, Comparable right) {
+ checkNotNull(left); // for GWT
+ checkNotNull(right);
+ if (left == right) {
+ return 0;
+ }
+
+ return left.compareTo(right);
+ }
+
+ @Override public <S extends Comparable> Ordering<S> reverse() {
+ return (Ordering<S>) ReverseNaturalOrdering.INSTANCE;
+ }
+
+ // Override to remove a level of indirection from inner loop
+ @Override public int binarySearch(
+ List<? extends Comparable> sortedList, Comparable key) {
+ return Collections.binarySearch((List) sortedList, key);
+ }
+
+ // Override to remove a level of indirection from inner loop
+ @Override public <E extends Comparable> List<E> sortedCopy(
+ Iterable<E> iterable) {
+ List<E> list = Lists.newArrayList(iterable);
+ Collections.sort(list);
+ return list;
+ }
+
+ // preserving singleton-ness gives equals()/hashCode() for free
+ private Object readResolve() {
+ return INSTANCE;
+ }
+
+ @Override public String toString() {
+ return "Ordering.natural()";
+ }
+
+ private NaturalOrdering() {}
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/NullsFirstOrdering.java b/guava/src/com/google/common/collect/NullsFirstOrdering.java
new file mode 100644
index 0000000..2e8a3ac
--- /dev/null
+++ b/guava/src/com/google/common/collect/NullsFirstOrdering.java
@@ -0,0 +1,81 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+
+import javax.annotation.Nullable;
+
+/** An ordering that treats {@code null} as less than all other values. */
+@GwtCompatible(serializable = true)
+final class NullsFirstOrdering<T> extends Ordering<T> implements Serializable {
+ final Ordering<? super T> ordering;
+
+ NullsFirstOrdering(Ordering<? super T> ordering) {
+ this.ordering = ordering;
+ }
+
+ @Override public int compare(@Nullable T left, @Nullable T right) {
+ if (left == right) {
+ return 0;
+ }
+ if (left == null) {
+ return RIGHT_IS_GREATER;
+ }
+ if (right == null) {
+ return LEFT_IS_GREATER;
+ }
+ return ordering.compare(left, right);
+ }
+
+ @Override public <S extends T> Ordering<S> reverse() {
+ // ordering.reverse() might be optimized, so let it do its thing
+ return ordering.reverse().nullsLast();
+ }
+
+ @SuppressWarnings("unchecked") // still need the right way to explain this
+ @Override public <S extends T> Ordering<S> nullsFirst() {
+ return (Ordering<S>) this;
+ }
+
+ @Override public <S extends T> Ordering<S> nullsLast() {
+ return ordering.nullsLast();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof NullsFirstOrdering) {
+ NullsFirstOrdering<?> that = (NullsFirstOrdering<?>) object;
+ return this.ordering.equals(that.ordering);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return ordering.hashCode() ^ 957692532; // meaningless
+ }
+
+ @Override public String toString() {
+ return ordering + ".nullsFirst()";
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/NullsLastOrdering.java b/guava/src/com/google/common/collect/NullsLastOrdering.java
new file mode 100644
index 0000000..9de17bd
--- /dev/null
+++ b/guava/src/com/google/common/collect/NullsLastOrdering.java
@@ -0,0 +1,81 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+
+import javax.annotation.Nullable;
+
+/** An ordering that treats {@code null} as greater than all other values. */
+@GwtCompatible(serializable = true)
+final class NullsLastOrdering<T> extends Ordering<T> implements Serializable {
+ final Ordering<? super T> ordering;
+
+ NullsLastOrdering(Ordering<? super T> ordering) {
+ this.ordering = ordering;
+ }
+
+ @Override public int compare(@Nullable T left, @Nullable T right) {
+ if (left == right) {
+ return 0;
+ }
+ if (left == null) {
+ return LEFT_IS_GREATER;
+ }
+ if (right == null) {
+ return RIGHT_IS_GREATER;
+ }
+ return ordering.compare(left, right);
+ }
+
+ @Override public <S extends T> Ordering<S> reverse() {
+ // ordering.reverse() might be optimized, so let it do its thing
+ return ordering.reverse().nullsFirst();
+ }
+
+ @Override public <S extends T> Ordering<S> nullsFirst() {
+ return ordering.nullsFirst();
+ }
+
+ @SuppressWarnings("unchecked") // still need the right way to explain this
+ @Override public <S extends T> Ordering<S> nullsLast() {
+ return (Ordering<S>) this;
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof NullsLastOrdering) {
+ NullsLastOrdering<?> that = (NullsLastOrdering<?>) object;
+ return this.ordering.equals(that.ordering);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return ordering.hashCode() ^ -921210296; // meaningless
+ }
+
+ @Override public String toString() {
+ return ordering + ".nullsLast()";
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ObjectArrays.java b/guava/src/com/google/common/collect/ObjectArrays.java
new file mode 100644
index 0000000..dfd1fe9
--- /dev/null
+++ b/guava/src/com/google/common/collect/ObjectArrays.java
@@ -0,0 +1,195 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+
+import javax.annotation.Nullable;
+
+/**
+ * Static utility methods pertaining to object arrays.
+ *
+ * @author Kevin Bourrillion
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(emulated = true)
+public final class ObjectArrays {
+ static final Object[] EMPTY_ARRAY = new Object[0];
+
+ private ObjectArrays() {}
+
+ /**
+ * 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")
+ public 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.
+ *
+ * @param reference any array of the desired type
+ * @param length the length of the new array
+ */
+ public static <T> T[] newArray(T[] reference, int length) {
+ return Platform.newArray(reference, length);
+ }
+
+ /**
+ * Returns a new array that contains the concatenated contents of two arrays.
+ *
+ * @param first the first array of elements to concatenate
+ * @param second the second array of elements to concatenate
+ * @param type the component type of the returned array
+ */
+ @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);
+ return result;
+ }
+
+ /**
+ * Returns a new array that prepends {@code element} to {@code array}.
+ *
+ * @param element the element to prepend to the front of {@code array}
+ * @param array the array of elements to append
+ * @return an array whose size is one larger than {@code array}, with
+ * {@code element} occupying the first position, and the
+ * elements of {@code array} occupying the remaining elements.
+ */
+ 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);
+ return result;
+ }
+
+ /**
+ * Returns a new array that appends {@code element} to {@code array}.
+ *
+ * @param array the array of elements to prepend
+ * @param element the element to append to the end
+ * @return an array whose size is one larger than {@code array}, with
+ * the same contents as {@code array}, plus {@code element} occupying the
+ * last position.
+ */
+ public static <T> T[] concat(T[] array, @Nullable T element) {
+ T[] result = arraysCopyOf(array, array.length + 1);
+ result[array.length] = element;
+ return result;
+ }
+
+ /** GWT safe version of Arrays.copyOf. */
+ static <T> T[] arraysCopyOf(T[] original, int newLength) {
+ T[] copy = newArray(original, newLength);
+ System.arraycopy(
+ original, 0, copy, 0, Math.min(original.length, newLength));
+ return copy;
+ }
+
+ /**
+ * Returns an array containing all of the elements in the specified
+ * collection; the runtime type of the returned array is that of the specified
+ * array. If the collection fits in the specified array, it is returned
+ * therein. Otherwise, a new array is allocated with the runtime type of the
+ * specified array and the size of the specified collection.
+ *
+ * <p>If the collection fits in the specified array with room to spare (i.e.,
+ * the array has more elements than the collection), the element in the array
+ * immediately following the end of the collection is set to {@code null}.
+ * This is useful in determining the length of the collection <i>only</i> if
+ * the caller knows that the collection does not contain any null elements.
+ *
+ * <p>This method returns the elements in the order they are returned by the
+ * collection's iterator.
+ *
+ * <p>TODO(kevinb): support concurrently modified collections?
+ *
+ * @param c the collection for which to return an array of elements
+ * @param array the array in which to place the collection elements
+ * @throws ArrayStoreException if the runtime type of the specified array is
+ * not a supertype of the runtime type of every element in the specified
+ * collection
+ */
+ static <T> T[] toArrayImpl(Collection<?> c, T[] array) {
+ int size = c.size();
+ if (array.length < size) {
+ array = newArray(array, size);
+ }
+ fillArray(c, array);
+ if (array.length > size) {
+ array[size] = null;
+ }
+ return array;
+ }
+
+ /**
+ * Returns an array containing all of the elements in the specified
+ * collection. This method returns the elements in the order they are returned
+ * by the collection's iterator. The returned array is "safe" in that no
+ * references to it are maintained by the collection. The caller is thus free
+ * to modify the returned array.
+ *
+ * <p>This method assumes that the collection size doesn't change while the
+ * method is running.
+ *
+ * <p>TODO(kevinb): support concurrently modified collections?
+ *
+ * @param c the collection for which to return an array of elements
+ */
+ static Object[] toArrayImpl(Collection<?> c) {
+ return fillArray(c, new Object[c.size()]);
+ }
+
+ private static Object[] fillArray(Iterable<?> elements, Object[] array) {
+ int i = 0;
+ for (Object element : elements) {
+ array[i++] = element;
+ }
+ return array;
+ }
+
+ /**
+ * Swaps {@code array[i]} with {@code array[j]}.
+ */
+ static void swap(Object[] array, int i, int j) {
+ Object temp = array[i];
+ 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
new file mode 100644
index 0000000..3530765
--- /dev/null
+++ b/guava/src/com/google/common/collect/Ordering.java
@@ -0,0 +1,791 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+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
+ *
+ * if (Ordering.from(comparator).reverse().isOrdered(list)) { ... }}</pre>
+ *
+ * The {@link #from(Comparator)} method returns the equivalent {@code Ordering}
+ * instance for a pre-existing comparator. You can also skip the comparator step
+ * and extend {@code Ordering} directly: <pre> {@code
+ *
+ * Ordering<String> byLengthOrdering = new Ordering<String>() {
+ * public int compare(String left, String right) {
+ * return Ints.compare(left.length(), right.length());
+ * }
+ * };}</pre>
+ *
+ * Except as noted, the orderings returned by the factory methods of this
+ * class are serializable if and only if the provided instances that back them
+ * 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
+
+ /**
+ * Returns a serializable ordering that uses the natural order of the values.
+ * The ordering throws a {@link NullPointerException} when passed a null
+ * parameter.
+ *
+ * <p>The type specification is {@code <C extends Comparable>}, instead of
+ * the technically correct {@code <C extends Comparable<? super C>>}, to
+ * support legacy types from before Java 5.
+ */
+ @GwtCompatible(serializable = true)
+ @SuppressWarnings("unchecked") // TODO(kevinb): right way to explain this??
+ public static <C extends Comparable> Ordering<C> natural() {
+ 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.
+ *
+ * @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) {
+ return (comparator instanceof Ordering)
+ ? (Ordering<T>) comparator
+ : new ComparatorOrdering<T>(comparator);
+ }
+
+ /**
+ * Simply returns its argument.
+ *
+ * @deprecated no need to use this
+ */
+ @GwtCompatible(serializable = true)
+ @Deprecated public static <T> Ordering<T> from(Ordering<T> ordering) {
+ return checkNotNull(ordering);
+ }
+
+ /**
+ * Returns an ordering that compares objects according to the order in
+ * which they appear in the given list. Only objects present in the list
+ * (according to {@link Object#equals}) may be compared. This comparator
+ * imposes a "partial ordering" over the type {@code T}. Subsequent changes
+ * to the {@code valuesInOrder} list will have no effect on the returned
+ * comparator. Null values in the list are not supported.
+ *
+ * <p>The returned comparator throws an {@link ClassCastException} when it
+ * receives an input parameter that isn't among the provided values.
+ *
+ * <p>The generated comparator is serializable if all the provided values are
+ * serializable.
+ *
+ * @param valuesInOrder the values that the returned comparator will be able
+ * to compare, in the order the comparator should induce
+ * @return the comparator described above
+ * @throws NullPointerException if any of the provided values is null
+ * @throws IllegalArgumentException if {@code valuesInOrder} contains any
+ * duplicate values (according to {@link Object#equals})
+ */
+ @GwtCompatible(serializable = true)
+ public static <T> Ordering<T> explicit(List<T> valuesInOrder) {
+ return new ExplicitOrdering<T>(valuesInOrder);
+ }
+
+ /**
+ * Returns an ordering that compares objects according to the order in
+ * which they are given to this method. Only objects present in the argument
+ * list (according to {@link Object#equals}) may be compared. This comparator
+ * imposes a "partial ordering" over the type {@code T}. Null values in the
+ * argument list are not supported.
+ *
+ * <p>The returned comparator throws a {@link ClassCastException} when it
+ * receives an input parameter that isn't among the provided values.
+ *
+ * <p>The generated comparator is serializable if all the provided values are
+ * serializable.
+ *
+ * @param leastValue the value which the returned comparator should consider
+ * the "least" of all values
+ * @param remainingValuesInOrder the rest of the values that the returned
+ * comparator will be able to compare, in the order the comparator should
+ * follow
+ * @return the comparator described above
+ * @throws NullPointerException if any of the provided values is null
+ * @throws IllegalArgumentException if any duplicate values (according to
+ * {@link Object#equals(Object)}) are present among the method arguments
+ */
+ @GwtCompatible(serializable = true)
+ public static <T> Ordering<T> explicit(
+ T leastValue, T... remainingValuesInOrder) {
+ 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.
+ */
+ @GwtCompatible(serializable = true)
+ @SuppressWarnings("unchecked")
+ public static Ordering<Object> allEqual() {
+ return AllEqualOrdering.INSTANCE;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Returns an arbitrary ordering over all objects, for which {@code compare(a,
+ * b) == 0} implies {@code a == b} (identity equality). There is no meaning
+ * whatsoever to the order imposed, but it is constant for the life of the VM.
+ *
+ * <p>Because the ordering is identity-based, it is not "consistent with
+ * {@link Object#equals(Object)}" as defined by {@link Comparator}. Use
+ * caution when building a {@link SortedSet} or {@link SortedMap} from it, as
+ * the resulting collection will not behave exactly according to spec.
+ *
+ * <p>This ordering is not serializable, as its implementation relies on
+ * {@link System#identityHashCode(Object)}, so its behavior cannot be
+ * preserved across serialization.
+ *
+ * @since 2.0
+ */
+ public static Ordering<Object> arbitrary() {
+ return ArbitraryOrderingHolder.ARBITRARY_ORDERING;
+ }
+
+ private static class ArbitraryOrderingHolder {
+ static final Ordering<Object> ARBITRARY_ORDERING = new ArbitraryOrdering();
+ }
+
+ @VisibleForTesting static class ArbitraryOrdering extends Ordering<Object> {
+ @SuppressWarnings("deprecation") // TODO(kevinb): ?
+ private Map<Object, Integer> uids =
+ Platform.tryWeakKeys(new MapMaker()).makeComputingMap(
+ new Function<Object, Integer>() {
+ final AtomicInteger counter = new AtomicInteger(0);
+ @Override
+ public Integer apply(Object from) {
+ return counter.getAndIncrement();
+ }
+ });
+
+ @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);
+ if (leftCode != rightCode) {
+ return leftCode < rightCode ? -1 : 1;
+ }
+
+ // identityHashCode collision (rare, but not as rare as you'd think)
+ int result = uids.get(left).compareTo(uids.get(right));
+ if (result == 0) {
+ throw new AssertionError(); // extremely, extremely unlikely.
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ return "Ordering.arbitrary()";
+ }
+
+ /*
+ * We need to be able to mock identityHashCode() calls for tests, because it
+ * can take 1-10 seconds to find colliding objects. Mocking frameworks that
+ * can do magic to mock static method calls still can't do so for a system
+ * class, so we need the indirection. In production, Hotspot should still
+ * recognize that the call is 1-morphic and should still be willing to
+ * inline it if necessary.
+ */
+ int identityHashCode(Object object) {
+ return System.identityHashCode(object);
+ }
+ }
+
+ // 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)}.
+ */
+ // 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 an ordering that treats {@code null} as less than all other values
+ * and uses {@code this} to compare non-null values.
+ */
+ // 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 an ordering that treats {@code null} as greater than all other
+ * values and uses this ordering to compare non-null values.
+ */
+ // 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 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);
+ }
+
+ /**
+ * Returns an ordering which first uses the ordering {@code this}, but which
+ * in the event of a "tie", then delegates to {@code secondaryComparator}.
+ * For example, to sort a bug list first by status and second by priority, you
+ * might use {@code byStatus.compound(byPriority)}. For a compound ordering
+ * with three or more components, simply chain multiple calls to this method.
+ *
+ * <p>An ordering produced by this method, or a chain of calls to this method,
+ * is equivalent to one created using {@link Ordering#compound(Iterable)} on
+ * the same component comparators.
+ */
+ @GwtCompatible(serializable = true)
+ public <U extends T> Ordering<U> compound(
+ Comparator<? super U> secondaryComparator) {
+ return new CompoundOrdering<U>(this, checkNotNull(secondaryComparator));
+ }
+
+ /**
+ * 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
+ */
+ @GwtCompatible(serializable = true)
+ public static <T> Ordering<T> compound(
+ Iterable<? extends Comparator<? super T>> comparators) {
+ return new CompoundOrdering<T>(comparators);
+ }
+
+ /**
+ * Returns a new ordering which sorts iterables by comparing corresponding
+ * elements pairwise until a nonzero result is found; imposes "dictionary
+ * order". If the end of one iterable is reached, but not the other, the
+ * shorter iterable is considered to be less than the longer one. For example,
+ * a lexicographical natural ordering over integers considers {@code
+ * [] < [1] < [1, 1] < [1, 2] < [2]}.
+ *
+ * <p>Note that {@code ordering.lexicographical().reverse()} is not
+ * equivalent to {@code ordering.reverse().lexicographical()} (consider how
+ * each would order {@code [1]} and {@code [1, 1]}).
+ *
+ * @since 2.0
+ */
+ @GwtCompatible(serializable = true)
+ // type parameter <S> lets us avoid the extra <String> in statements like:
+ // Ordering<Iterable<String>> o =
+ // Ordering.<String>natural().lexicographical();
+ public <S extends T> Ordering<Iterable<S>> lexicographical() {
+ /*
+ * Note that technically the returned ordering should be capable of
+ * handling not just {@code Iterable<S>} instances, but also any {@code
+ * Iterable<? extends S>}. However, the need for this comes up so rarely
+ * that it doesn't justify making everyone else deal with the very ugly
+ * wildcard.
+ */
+ 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
+ */
+ @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 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
+ */
+ @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;
+ }
+
+ /**
+ * 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.
+ */
+ public <E extends T> E max(Iterable<E> iterable) {
+ return max(iterable.iterator());
+ }
+
+ /**
+ * 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 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);
+ }
+
+ return maxSoFar;
+ }
+
+ /**
+ * Returns the {@code k} least elements of the given iterable according to
+ * this ordering, in order from least to greatest. 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
+ * @throws IllegalArgumentException if {@code k} is negative
+ * @since 8.0
+ */
+ @Beta
+ public <E extends T> List<E> leastOf(Iterable<E> iterable, int k) {
+ 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 Collections.unmodifiableList(Arrays.asList(resultArray));
+ }
+
+ /**
+ * 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
+ */
+ @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);
+ }
+
+ 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);
+ }
+ }
+ }
+
+ private <E extends T> int partition(
+ E[] values, int left, int right, int pivotIndex) {
+ E pivotValue = values[pivotIndex];
+
+ values[pivotIndex] = values[right];
+ values[right] = pivotValue;
+
+ int storeIndex = left;
+ for (int i = left; i < right; i++) {
+ if (compare(values[i], pivotValue) < 0) {
+ ObjectArrays.swap(values, storeIndex, i);
+ storeIndex++;
+ }
+ }
+ ObjectArrays.swap(values, right, storeIndex);
+ return storeIndex;
+ }
+
+ /**
+ * Returns a copy of the given iterable sorted by this ordering. The input is
+ * not modified. The returned list is modifiable, serializable, and has random
+ * access.
+ *
+ * <p>Unlike {@link Sets#newTreeSet(Iterable)}, this method does not discard
+ * elements that are duplicates according to the comparator. The sort
+ * performed is <i>stable</i>, meaning that such elements will appear in the
+ * resulting list in the same order they appeared in the input.
+ *
+ * @param iterable the elements to be copied and sorted
+ * @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));
+ }
+
+ /**
+ * Returns an <i>immutable</i> copy of the given iterable sorted by this
+ * ordering. The input is not modified.
+ *
+ * <p>Unlike {@link Sets#newTreeSet(Iterable)}, this method does not discard
+ * elements that are duplicates according to the comparator. The sort
+ * performed is <i>stable</i>, meaning that such elements will appear in the
+ * resulting list in the same order they appeared in the input.
+ *
+ * @param iterable the elements to be copied and sorted
+ * @return a new immutable list containing the given elements in sorted order
+ * @throws NullPointerException if {@code iterable} or any of its elements is
+ * null
+ * @since 3.0
+ */
+ 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);
+ }
+
+ /**
+ * Returns {@code true} if each element in {@code iterable} after the first is
+ * greater than or equal to the element that preceded it, according to this
+ * ordering. Note that this is always true when the iterable has fewer than
+ * two elements.
+ */
+ public boolean isOrdered(Iterable<? extends T> iterable) {
+ Iterator<? extends T> it = iterable.iterator();
+ if (it.hasNext()) {
+ T prev = it.next();
+ while (it.hasNext()) {
+ T next = it.next();
+ if (compare(prev, next) > 0) {
+ return false;
+ }
+ prev = next;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns {@code true} if each element in {@code iterable} after the first is
+ * <i>strictly</i> greater than the element that preceded it, according to
+ * this ordering. Note that this is always true when the iterable has fewer
+ * than two elements.
+ */
+ public boolean isStrictlyOrdered(Iterable<? extends T> iterable) {
+ Iterator<? extends T> it = iterable.iterator();
+ if (it.hasNext()) {
+ T prev = it.next();
+ while (it.hasNext()) {
+ T next = it.next();
+ if (compare(prev, next) >= 0) {
+ return false;
+ }
+ prev = next;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * {@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.
+ *
+ * @param sortedList the list to be searched
+ * @param key the key to be searched for
+ */
+ public int binarySearch(List<? extends T> sortedList, @Nullable T key) {
+ return Collections.binarySearch(sortedList, key, this);
+ }
+
+ /**
+ * 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.
+ */
+ // TODO(kevinb): make this public, document it right
+ @VisibleForTesting
+ static class IncomparableValueException extends ClassCastException {
+ final Object value;
+
+ IncomparableValueException(Object value) {
+ super("Cannot compare value: " + value);
+ this.value = value;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ // Never make these public
+ static final int LEFT_IS_GREATER = 1;
+ static final int RIGHT_IS_GREATER = -1;
+}
diff --git a/guava/src/com/google/common/collect/PeekingIterator.java b/guava/src/com/google/common/collect/PeekingIterator.java
new file mode 100644
index 0000000..294b2e6
--- /dev/null
+++ b/guava/src/com/google/common/collect/PeekingIterator.java
@@ -0,0 +1,69 @@
+/*
+ * 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.Iterator;
+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)
+ */
+@GwtCompatible
+public interface PeekingIterator<E> extends Iterator<E> {
+ /**
+ * Returns the next element in the iteration, without advancing the iteration.
+ *
+ * <p>Calls to {@code peek()} should not change the state of the iteration,
+ * except that it <i>may</i> prevent removal of the most recent element via
+ * {@link #remove()}.
+ *
+ * @throws NoSuchElementException if the iteration has no more elements
+ * according to {@link #hasNext()}
+ */
+ E peek();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The objects returned by consecutive calls to {@link #peek()} then {@link
+ * #next()} are guaranteed to be equal to each other.
+ */
+ @Override
+ E next();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Implementations may or may not support removal when a call to {@link
+ * #peek()} has occurred since the most recent call to {@link #next()}.
+ *
+ * @throws IllegalStateException if there has been a call to {@link #peek()}
+ * since the most recent call to {@link #next()} and this implementation
+ * does not support this sequence of calls (optional)
+ */
+ @Override
+ void remove();
+}
diff --git a/guava/src/com/google/common/collect/Platform.java b/guava/src/com/google/common/collect/Platform.java
new file mode 100644
index 0000000..4baa666
--- /dev/null
+++ b/guava/src/com/google/common/collect/Platform.java
@@ -0,0 +1,77 @@
+/*
+ * 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.collect.Maps.EntryTransformer;
+
+import java.lang.reflect.Array;
+import java.util.NavigableMap;
+import java.util.SortedMap;
+
+/**
+ * Methods factored out so that they can be emulated differently in GWT.
+ *
+ * @author Hayward Chan
+ */
+@GwtCompatible(emulated = true)
+class Platform {
+ /**
+ * Clone the given array using {@link Object#clone()}. It is factored out so
+ * that it can be emulated in GWT.
+ */
+ static <T> T[] clone(T[] array) {
+ return array.clone();
+ }
+
+ /**
+ * Returns a new array of the given length with the same type as a reference
+ * array.
+ *
+ * @param reference any array of the desired type
+ * @param length the length of the new array
+ */
+ static <T> T[] newArray(T[] reference, int length) {
+ Class<?> type = reference.getClass().getComponentType();
+
+ // the cast is safe because
+ // result.getClass() == reference.getClass().getComponentType()
+ @SuppressWarnings("unchecked")
+ T[] result = (T[]) Array.newInstance(type, length);
+ return result;
+ }
+
+ /**
+ * Configures the given map maker to use weak keys, if possible; does nothing
+ * otherwise (i.e., in GWT). This is sometimes acceptable, when only
+ * server-side code could generate enough volume that reclamation becomes
+ * important.
+ */
+ static MapMaker tryWeakKeys(MapMaker mapMaker) {
+ 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);
+ }
+
+ private Platform() {}
+}
diff --git a/guava/src/com/google/common/collect/Queues.java b/guava/src/com/google/common/collect/Queues.java
new file mode 100644
index 0000000..bf1daf2
--- /dev/null
+++ b/guava/src/com/google/common/collect/Queues.java
@@ -0,0 +1,341 @@
+/*
+ * 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 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;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+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}.
+ *
+ * @author Kurt Alfred Kluever
+ * @since 11.0
+ */
+@Beta
+public final class Queues {
+ private Queues() {}
+
+ // ArrayBlockingQueue
+
+ /**
+ * Creates an empty {@code ArrayBlockingQueue} instance.
+ *
+ * @return a new, empty {@code ArrayBlockingQueue}
+ */
+ public static <E> ArrayBlockingQueue<E> newArrayBlockingQueue(int capacity) {
+ return new ArrayBlockingQueue<E>(capacity);
+ }
+
+ // 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
+
+ /**
+ * Creates an empty {@code ConcurrentLinkedQueue} instance.
+ *
+ * @return a new, empty {@code ConcurrentLinkedQueue}
+ */
+ public static <E> ConcurrentLinkedQueue<E> newConcurrentLinkedQueue() {
+ return new ConcurrentLinkedQueue<E>();
+ }
+
+ /**
+ * Creates an {@code ConcurrentLinkedQueue} instance containing the given elements.
+ *
+ * @param elements the elements that the queue should contain, in order
+ * @return a new {@code ConcurrentLinkedQueue} containing those elements
+ */
+ public static <E> ConcurrentLinkedQueue<E> newConcurrentLinkedQueue(
+ Iterable<? extends E> elements) {
+ if (elements instanceof Collection) {
+ return new ConcurrentLinkedQueue<E>(Collections2.cast(elements));
+ }
+ ConcurrentLinkedQueue<E> queue = new ConcurrentLinkedQueue<E>();
+ Iterables.addAll(queue, elements);
+ return queue;
+ }
+
+ // 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
+
+ /**
+ * Creates an empty {@code LinkedBlockingQueue} instance.
+ *
+ * @return a new, empty {@code LinkedBlockingQueue}
+ */
+ public static <E> LinkedBlockingQueue<E> newLinkedBlockingQueue() {
+ return new LinkedBlockingQueue<E>();
+ }
+
+ /**
+ * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
+ *
+ * @param capacity the capacity of this queue
+ * @return a new, empty {@code LinkedBlockingQueue}
+ * @throws IllegalArgumentException if {@code capacity} is less than 1
+ */
+ public static <E> LinkedBlockingQueue<E> newLinkedBlockingQueue(int capacity) {
+ return new LinkedBlockingQueue<E>(capacity);
+ }
+
+ /**
+ * Creates an {@code LinkedBlockingQueue} instance containing the given elements.
+ *
+ * @param elements the elements that the queue should contain, in order
+ * @return a new {@code LinkedBlockingQueue} containing those elements
+ */
+ public static <E> LinkedBlockingQueue<E> newLinkedBlockingQueue(Iterable<? extends E> elements) {
+ if (elements instanceof Collection) {
+ return new LinkedBlockingQueue<E>(Collections2.cast(elements));
+ }
+ LinkedBlockingQueue<E> queue = new LinkedBlockingQueue<E>();
+ Iterables.addAll(queue, elements);
+ return queue;
+ }
+
+ // LinkedList: see {@link com.google.common.collect.Lists}
+
+ // PriorityBlockingQueue
+
+ /**
+ * Creates an empty {@code PriorityBlockingQueue} instance.
+ *
+ * @return a new, empty {@code PriorityBlockingQueue}
+ */
+ public static <E> PriorityBlockingQueue<E> newPriorityBlockingQueue() {
+ return new PriorityBlockingQueue<E>();
+ }
+
+ /**
+ * Creates an {@code PriorityBlockingQueue} instance containing the given elements.
+ *
+ * @param elements the elements that the queue should contain, in order
+ * @return a new {@code PriorityBlockingQueue} containing those elements
+ */
+ public static <E> PriorityBlockingQueue<E> newPriorityBlockingQueue(
+ Iterable<? extends E> elements) {
+ if (elements instanceof Collection) {
+ return new PriorityBlockingQueue<E>(Collections2.cast(elements));
+ }
+ PriorityBlockingQueue<E> queue = new PriorityBlockingQueue<E>();
+ Iterables.addAll(queue, elements);
+ return queue;
+ }
+
+ // PriorityQueue
+
+ /**
+ * Creates an empty {@code PriorityQueue} instance.
+ *
+ * @return a new, empty {@code PriorityQueue}
+ */
+ public static <E> PriorityQueue<E> newPriorityQueue() {
+ return new PriorityQueue<E>();
+ }
+
+ /**
+ * Creates an {@code PriorityQueue} instance containing the given elements.
+ *
+ * @param elements the elements that the queue should contain, in order
+ * @return a new {@code PriorityQueue} containing those elements
+ */
+ public static <E> PriorityQueue<E> newPriorityQueue(Iterable<? extends E> elements) {
+ if (elements instanceof Collection) {
+ return new PriorityQueue<E>(Collections2.cast(elements));
+ }
+ PriorityQueue<E> queue = new PriorityQueue<E>();
+ Iterables.addAll(queue, elements);
+ return queue;
+ }
+
+ // SynchronousQueue
+
+ /**
+ * Creates an empty {@code SynchronousQueue} instance.
+ *
+ * @return a new, empty {@code SynchronousQueue}
+ */
+ public static <E> SynchronousQueue<E> newSynchronousQueue() {
+ return new SynchronousQueue<E>();
+ }
+
+ /**
+ * 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
+ * @param timeout how long to wait before giving up, in units of {@code unit}
+ * @param unit a {@code TimeUnit} determining how to interpret the timeout parameter
+ * @return the number of elements transferred
+ * @throws InterruptedException if interrupted while waiting
+ */
+ public static <E> int drain(BlockingQueue<E> q, Collection<? super E> buffer, int numElements,
+ long timeout, TimeUnit unit) throws InterruptedException {
+ Preconditions.checkNotNull(buffer);
+ /*
+ * This code performs one System.nanoTime() more than necessary, and in return, the time to
+ * execute Queue#drainTo is not added *on top* of waiting for the timeout (which could make
+ * the timeout arbitrarily inaccurate, given a queue that is slow to drain).
+ */
+ long deadline = System.nanoTime() + unit.toNanos(timeout);
+ int added = 0;
+ while (added < numElements) {
+ // 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
+ E e = q.poll(deadline - System.nanoTime(), TimeUnit.NANOSECONDS);
+ if (e == null) {
+ break; // we already waited enough, and there are no more elements in sight
+ }
+ buffer.add(e);
+ added++;
+ }
+ }
+ 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).
+ *
+ * @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
+ * @param timeout how long to wait before giving up, in units of {@code unit}
+ * @param unit a {@code TimeUnit} determining how to interpret the timeout parameter
+ * @return the number of elements transferred
+ */
+ 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);
+ int added = 0;
+ boolean interrupted = false;
+ try {
+ while (added < numElements) {
+ // 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
+ E e; // written exactly once, by a successful (uninterrupted) invocation of #poll
+ while (true) {
+ try {
+ e = q.poll(deadline - System.nanoTime(), TimeUnit.NANOSECONDS);
+ break;
+ } catch (InterruptedException ex) {
+ interrupted = true; // note interruption and retry
+ }
+ }
+ if (e == null) {
+ break; // we already waited enough, and there are no more elements in sight
+ }
+ buffer.add(e);
+ added++;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ return added;
+ }
+}
diff --git a/guava/src/com/google/common/collect/Range.java b/guava/src/com/google/common/collect/Range.java
new file mode 100644
index 0000000..332e4f7
--- /dev/null
+++ b/guava/src/com/google/common/collect/Range.java
@@ -0,0 +1,438 @@
+/*
+ * 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 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.Predicate;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Set;
+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 unless an appropriate {@link
+ * DiscreteDomain} can be provided to the {@link #asSet asSet} method.
+ *
+ * <h3>Types of ranges</h3>
+ *
+ * <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>.")
+ *
+ * <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 Ranges#open open}
+ * <tr><td>{@code [a..b]} <td>{@code {x | a <= x <= b}}<td>{@link Ranges#closed closed}
+ * <tr><td>{@code (a..b]} <td>{@code {x | a < x <= b}} <td>{@link Ranges#openClosed openClosed}
+ * <tr><td>{@code [a..b)} <td>{@code {x | a <= x < b}} <td>{@link Ranges#closedOpen closedOpen}
+ * <tr><td>{@code (a..+∞)} <td>{@code {x | x > a}} <td>{@link Ranges#greaterThan greaterThan}
+ * <tr><td>{@code [a..+∞)} <td>{@code {x | x >= a}} <td>{@link Ranges#atLeast atLeast}
+ * <tr><td>{@code (-∞..b)} <td>{@code {x | x < b}} <td>{@link Ranges#lessThan lessThan}
+ * <tr><td>{@code (-∞..b]} <td>{@code {x | x <= b}} <td>{@link Ranges#atMost atMost}
+ * <tr><td>{@code (-∞..+∞)}<td>{@code {x}} <td>{@link Ranges#all all}
+ * </table></blockquote>
+ *
+ * <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:
+ *
+ * <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
+ * </ul>
+ *
+ * <h3>Warnings</h3>
+ *
+ * <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>
+ *
+ * <h3>Other notes</h3>
+ *
+ * <ul>
+ * <li>Instances of this type are obtained using the static factory methods in the {@link Ranges}
+ * 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>
+ *
+ * <h3>Further reading</h3>
+ *
+ * <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
+ */
+@Beta
+@GwtCompatible
+@SuppressWarnings("rawtypes")
+public final class Range<C extends Comparable> implements Predicate<C>, Serializable {
+ final Cut<C> lowerBound;
+ final Cut<C> upperBound;
+
+ Range(Cut<C> lowerBound, Cut<C> upperBound) {
+ if (lowerBound.compareTo(upperBound) > 0) {
+ throw new IllegalArgumentException("Invalid range: " + toString(lowerBound, upperBound));
+ }
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ }
+
+ /**
+ * Returns {@code true} if this range has a lower endpoint.
+ */
+ public boolean hasLowerBound() {
+ return lowerBound != Cut.belowAll();
+ }
+
+ /**
+ * Returns the lower endpoint of this range.
+ *
+ * @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.
+ *
+ * @throws IllegalStateException if this range is unbounded below (that is, {@link
+ * #hasLowerBound()} returns {@code false})
+ */
+ public BoundType lowerBoundType() {
+ return lowerBound.typeAsLowerBound();
+ }
+
+ /**
+ * Returns {@code true} if this range has an upper endpoint.
+ */
+ public boolean hasUpperBound() {
+ return upperBound != Cut.aboveAll();
+ }
+
+ /**
+ * Returns the upper endpoint of this range.
+ *
+ * @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.
+ *
+ * @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.)
+ *
+ * <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}.
+ */
+ public boolean contains(C value) {
+ checkNotNull(value);
+ // let this throw CCE if there is some trickery going on
+ return lowerBound.isLessThan(value) && !upperBound.isLessThan(value);
+ }
+
+ /**
+ * 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.
+ */
+ public boolean containsAll(Iterable<? extends C> values) {
+ if (Iterables.isEmpty(values)) {
+ return true;
+ }
+
+ // this optimizes testing equality of two range-backed sets
+ if (values instanceof SortedSet) {
+ SortedSet<? extends C> set = cast(values);
+ Comparator<?> comparator = set.comparator();
+ if (Ordering.natural().equals(comparator) || comparator == null) {
+ return contains(set.first()) && contains(set.last());
+ }
+ }
+
+ for (C value : values) {
+ if (!contains(value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 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]} 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)
+ * </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.
+ *
+ * <p>Being reflexive, antisymmetric and transitive, the {@code encloses} relation defines a
+ * <i>partial order</i> over ranges. There exists a unique {@linkplain Ranges#all maximal} range
+ * according to this relation, and also numerous {@linkplain #isEmpty minimal} ranges. Enclosure
+ * also implies {@linkplain #isConnected connectedness}.
+ */
+ public boolean encloses(Range<C> other) {
+ return lowerBound.compareTo(other.lowerBound) <= 0
+ && upperBound.compareTo(other.upperBound) >= 0;
+ }
+
+ /**
+ * 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 is both reflexive and symmetric, but does not form an {@linkplain
+ * Equivalence equivalence relation} as it is not transitive.
+ */
+ public boolean isConnected(Range<C> other) {
+ return lowerBound.compareTo(other.upperBound) <= 0
+ && other.lowerBound.compareTo(upperBound) <= 0;
+ }
+
+ /**
+ * 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 Ranges#all}).
+ *
+ * @throws IllegalArgumentException if {@code isConnected(connectedRange)} is {@code false}
+ */
+ public Range<C> intersection(Range<C> connectedRange) {
+ Cut<C> newLower = Ordering.natural().max(lowerBound, connectedRange.lowerBound);
+ Cut<C> newUpper = Ordering.natural().min(upperBound, connectedRange.upperBound);
+ return create(newLower, newUpper);
+ }
+
+ /**
+ * 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)}.
+ *
+ * <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>Like {@link #intersection(Range) intersection}, this operation is commutative, associative
+ * and idempotent. Unlike it, it is always well-defined for any two input ranges.
+ */
+ public Range<C> span(Range<C> other) {
+ 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.
+ *
+ * <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 (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]}"}.
+ *
+ * @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?
+ @GwtCompatible(serializable = false)
+ public ContiguousSet<C> asSet(DiscreteDomain<C> domain) {
+ return ContiguousSet.create(this, domain);
+ }
+
+ /**
+ * 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 a.canonical(domain).asSet(domain).equals(a.asSet(domain))}
+ * <li>uniqueness: unless {@code a.isEmpty()}, {@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))}
+ * </ul>
+ *
+ * Furthermore, this method guarantees that the range returned will be one of the following
+ * canonical forms:
+ *
+ * <ul>
+ * <li>[start..end)
+ * <li>[start..+∞)
+ * <li>(-∞..end) (only if type {@code C} is unbounded below)
+ * <li>(-∞..+∞) (only if type {@code C} is unbounded below)
+ * </ul>
+ */
+ public Range<C> canonical(DiscreteDomain<C> domain) {
+ checkNotNull(domain);
+ Cut<C> lower = lowerBound.canonical(domain);
+ Cut<C> upper = upperBound.canonical(domain);
+ 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.
+ */
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Range) {
+ Range<?> other = (Range<?>) object;
+ return lowerBound.equals(other.lowerBound)
+ && upperBound.equals(other.upperBound);
+ }
+ return false;
+ }
+
+ /** Returns a hash code for this range. */
+ @Override public int hashCode() {
+ return lowerBound.hashCode() * 31 + upperBound.hashCode();
+ }
+
+ /**
+ * 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);
+ }
+
+ private static String toString(Cut<?> lowerBound, Cut<?> upperBound) {
+ StringBuilder sb = new StringBuilder(16);
+ lowerBound.describeAsLowerBound(sb);
+ sb.append('\u2025');
+ upperBound.describeAsUpperBound(sb);
+ return sb.toString();
+ }
+
+ /**
+ * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
+ */
+ private static <T> SortedSet<T> cast(Iterable<T> iterable) {
+ return (SortedSet<T>) iterable;
+ }
+
+ @SuppressWarnings("unchecked") // this method may throw CCE
+ static int compareOrThrow(Comparable left, Comparable right) {
+ return left.compareTo(right);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/RangeMap.java b/guava/src/com/google/common/collect/RangeMap.java
new file mode 100644
index 0000000..0174401
--- /dev/null
+++ b/guava/src/com/google/common/collect/RangeMap.java
@@ -0,0 +1,223 @@
+/*
+ * 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.GwtIncompatible;
+import com.google.common.base.Function;
+
+import java.io.Serializable;
+import java.util.AbstractMap;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+import java.util.TreeMap;
+
+import javax.annotation.Nullable;
+
+/**
+ * A mapping from keys to values that efficiently supports mapping entire ranges at once. This
+ * implementation does not support null values.
+ *
+ * @author Louis Wasserman
+ */
+@GwtIncompatible("NavigableMap") final class RangeMap<K extends Comparable, V>
+ implements Function<K, V>, Serializable {
+ private final NavigableMap<Cut<K>, RangeValue<K, V>> map;
+
+ /**
+ * Creates a new, empty {@code RangeMap}.
+ */
+ public static <K extends Comparable, V> RangeMap<K, V> create() {
+ return new RangeMap<K, V>(new TreeMap<Cut<K>, RangeValue<K, V>>());
+ }
+
+ private RangeMap(NavigableMap<Cut<K>, RangeValue<K, V>> map) {
+ this.map = map;
+ }
+
+ /**
+ * Equivalent to {@link #get(Comparable) get(K)}, provided only to satisfy the {@link Function}
+ * interface. When using a reference of type {@code RangeMap}, always invoke
+ * {@link #get(Comparable) get(K)} directly instead.
+ */
+ @Override
+ public V apply(K input) {
+ return get(input);
+ }
+
+ /**
+ * Returns the value associated with {@code key}, or {@code null} if there is no such value.
+ */
+ @Nullable
+ public V get(K key) {
+ Entry<Cut<K>, RangeValue<K, V>> lowerEntry = map.lowerEntry(Cut.aboveValue(key));
+ if (lowerEntry != null && lowerEntry.getValue().getKey().contains(key)) {
+ return lowerEntry.getValue().getValue();
+ }
+ return null;
+ }
+
+ /**
+ * Associates {@code value} with every key {@linkplain Range#contains contained} in {@code
+ * keyRange}.
+ *
+ * <p>This method takes amortized <i>O(log n)</i> time.
+ */
+ public void put(Range<K> keyRange, V value) {
+ checkNotNull(keyRange);
+ checkNotNull(value);
+ if (keyRange.isEmpty()) {
+ return;
+ }
+ clear(keyRange);
+ putRange(new RangeValue<K, V>(keyRange, value));
+ }
+
+ /**
+ * Puts all the associations from the specified {@code RangeMap} into this {@code RangeMap}.
+ */
+ public void putAll(RangeMap<K, V> rangeMap) {
+ checkNotNull(rangeMap);
+ for (RangeValue<K, V> rangeValue : rangeMap.map.values()) {
+ put(rangeValue.getKey(), rangeValue.getValue());
+ }
+ }
+
+ /**
+ * Clears all associations from this {@code RangeMap}.
+ */
+ public void clear() {
+ map.clear();
+ }
+
+ /**
+ * Removes all associations to keys {@linkplain Range#contains contained} in {@code
+ * rangeToClear}.
+ */
+ public void clear(Range<K> rangeToClear) {
+ checkNotNull(rangeToClear);
+ if (rangeToClear.isEmpty()) {
+ return;
+ }
+
+ Entry<Cut<K>, RangeValue<K, V>> lowerThanLB = map.lowerEntry(rangeToClear.lowerBound);
+ // We will use { } to denote the ends of rangeToClear, and < > to denote the ends of
+ // other ranges currently in the map. For example, < { > indicates that we know that
+ // rangeToClear.lowerBound is between the bounds of some range already in the map.
+
+ if (lowerThanLB != null) {
+ RangeValue<K, V> lowerRangeValue = lowerThanLB.getValue();
+ Cut<K> upperCut = lowerRangeValue.getUpperBound();
+ if (upperCut.compareTo(rangeToClear.lowerBound) >= 0) { // < { >
+ RangeValue<K, V> replacement = lowerRangeValue.withUpperBound(rangeToClear.lowerBound);
+ if (replacement == null) {
+ removeRange(lowerRangeValue);
+ } else {
+ putRange(replacement); // overwrites old range
+ }
+ if (upperCut.compareTo(rangeToClear.upperBound) >= 0) { // < { } >
+ putRange(lowerRangeValue.withLowerBound(rangeToClear.upperBound));
+ return; // we must be done
+ }
+ }
+ }
+
+ Entry<Cut<K>, RangeValue<K, V>> lowerThanUB = map.lowerEntry(rangeToClear.upperBound);
+ if (lowerThanUB != null) {
+ RangeValue<K, V> lowerRangeValue = lowerThanUB.getValue();
+ Cut<K> upperCut = lowerRangeValue.getUpperBound();
+ if (upperCut.compareTo(rangeToClear.upperBound) >= 0) { // < } >
+ // we can't have < { } >, we already dealt with that
+ removeRange(lowerRangeValue);
+ putRange(lowerRangeValue.withLowerBound(rangeToClear.upperBound));
+ }
+ }
+
+ // everything left with { < } is a { < > }, so we clear it indiscriminately
+ map.subMap(rangeToClear.lowerBound, rangeToClear.upperBound).clear();
+ }
+
+ private void removeRange(RangeValue<K, V> rangeValue) {
+ RangeValue<K, V> removed = map.remove(rangeValue.getLowerBound());
+ assert removed == rangeValue;
+ }
+
+ private void putRange(@Nullable RangeValue<K, V> rangeValue) {
+ if (rangeValue != null && !rangeValue.getKey().isEmpty()) {
+ map.put(rangeValue.getLowerBound(), rangeValue);
+ }
+ }
+
+ private static final class RangeValue<K extends Comparable, V> extends AbstractMap.SimpleEntry<
+ Range<K>, V> {
+
+ RangeValue(Range<K> key, V value) {
+ super(checkNotNull(key), checkNotNull(value));
+ assert !key.isEmpty();
+ }
+
+ Cut<K> getLowerBound() {
+ return getKey().lowerBound;
+ }
+
+ Cut<K> getUpperBound() {
+ return getKey().upperBound;
+ }
+
+ @Nullable
+ RangeValue<K, V> withLowerBound(Cut<K> newLowerBound) {
+ Range<K> newRange = new Range<K>(newLowerBound, getUpperBound());
+ return newRange.isEmpty() ? null : new RangeValue<K, V>(newRange, getValue());
+ }
+
+ @Nullable
+ RangeValue<K, V> withUpperBound(Cut<K> newUpperBound) {
+ Range<K> newRange = new Range<K>(getLowerBound(), newUpperBound);
+ return newRange.isEmpty() ? null : new RangeValue<K, V>(newRange, getValue());
+ }
+
+ private static final long serialVersionUID = 0L;
+ }
+
+ /**
+ * Compares the specified object with this {@code RangeMap} for equality. It is guaranteed that:
+ * <ul>
+ * <li>The relation defined by this method is reflexive, symmetric, and transitive, as required
+ * by the contract of {@link Object#equals(Object)}.
+ * <li>Two empty range maps are always equal.
+ * <li>If two range maps are equal, and the same operation is performed on each, the resulting
+ * range maps are also equal.
+ * <li>If {@code rangeMap1.equals(rangeMap2)}, it is guaranteed that {@code rangeMap1.get(k)}
+ * is equal to {@code rangeMap2.get(k)}.
+ * </ul>
+ */
+ @Override
+ public boolean equals(@Nullable Object o) {
+ return o instanceof RangeMap && map.equals(((RangeMap) o).map);
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return map.toString();
+ }
+
+ private static final long serialVersionUID = 0L;
+}
diff --git a/guava/src/com/google/common/collect/RangeSet.java b/guava/src/com/google/common/collect/RangeSet.java
new file mode 100644
index 0000000..d393991
--- /dev/null
+++ b/guava/src/com/google/common/collect/RangeSet.java
@@ -0,0 +1,289 @@
+/*
+ * 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 java.util.AbstractSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A set of values of type {@code C} made up of zero or more <i>disjoint</i> {@linkplain Range
+ * ranges}.
+ *
+ * <p>It is guaranteed that {@linkplain Range#isConnected connected} ranges will be
+ * {@linkplain Range#span coalesced} together, and that {@linkplain Range#isEmpty empty} ranges
+ * will never be held in a {@code RangeSet}.
+ *
+ * <p>For a {@link Set} whose contents are specified by a {@link Range}, see {@link ContiguousSet}.
+ *
+ * @author Kevin Bourrillion
+ * @author Louis Wasserman
+ */ abstract class RangeSet<C extends Comparable> {
+ RangeSet() {}
+
+ /**
+ * Determines whether any of this range set's member ranges contains {@code value}.
+ */
+ public boolean contains(C value) {
+ return rangeContaining(value) != null;
+ }
+
+ /**
+ * 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}.
+ */
+ public Range<C> rangeContaining(C value) {
+ checkNotNull(value);
+ for (Range<C> range : asRanges()) {
+ if (range.contains(value)) {
+ return range;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 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).
+ */
+ public abstract Set<Range<C>> asRanges();
+
+ /**
+ * Returns {@code true} if this range set contains no ranges.
+ */
+ public boolean isEmpty() {
+ return asRanges().isEmpty();
+ }
+
+ /**
+ * 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.
+ */
+ public abstract RangeSet<C> complement();
+
+ /**
+ * A basic, simple implementation of {@link #complement}. This is not efficient on all methods;
+ * for example, {@link #rangeContaining} and {@link #encloses} are linear-time.
+ */
+ static class StandardComplement<C extends Comparable> extends RangeSet<C> {
+ final RangeSet<C> positive;
+
+ public StandardComplement(RangeSet<C> positive) {
+ this.positive = positive;
+ }
+
+ @Override
+ public boolean contains(C value) {
+ return !positive.contains(value);
+ }
+
+ @Override
+ public void add(Range<C> range) {
+ positive.remove(range);
+ }
+
+ @Override
+ public void remove(Range<C> range) {
+ positive.add(range);
+ }
+
+ private transient Set<Range<C>> asRanges;
+
+ @Override
+ public final Set<Range<C>> asRanges() {
+ Set<Range<C>> result = asRanges;
+ return (result == null) ? asRanges = createAsRanges() : result;
+ }
+
+ Set<Range<C>> createAsRanges() {
+ return new AbstractSet<Range<C>>() {
+
+ @Override
+ public Iterator<Range<C>> iterator() {
+ final Iterator<Range<C>> positiveIterator = positive.asRanges().iterator();
+ return new AbstractIterator<Range<C>>() {
+ Cut<C> prevCut = Cut.belowAll();
+
+ @Override
+ protected Range<C> computeNext() {
+ while (positiveIterator.hasNext()) {
+ Cut<C> oldCut = prevCut;
+ Range<C> positiveRange = positiveIterator.next();
+ prevCut = positiveRange.upperBound;
+ if (oldCut.compareTo(positiveRange.lowerBound) < 0) {
+ return new Range<C>(oldCut, positiveRange.lowerBound);
+ }
+ }
+ Cut<C> posInfinity = Cut.aboveAll();
+ if (prevCut.compareTo(posInfinity) < 0) {
+ Range<C> result = new Range<C>(prevCut, posInfinity);
+ prevCut = posInfinity;
+ return result;
+ }
+ return endOfData();
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return Iterators.size(iterator());
+ }
+ };
+ }
+
+ @Override
+ public RangeSet<C> complement() {
+ return positive;
+ }
+ }
+
+ /**
+ * 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
+ */
+ public void add(Range<C> range) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * 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
+ */
+ public void remove(Range<C> range) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns {@code true} if there exists a member range in this range set which
+ * {@linkplain Range#encloses encloses} the specified range.
+ */
+ public boolean encloses(Range<C> otherRange) {
+ for (Range<C> range : asRanges()) {
+ if (range.encloses(otherRange)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 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}.
+ */
+ public boolean enclosesAll(RangeSet<C> other) {
+ for (Range<C> range : other.asRanges()) {
+ if (!encloses(range)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 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
+ */
+ public void addAll(RangeSet<C> other) {
+ for (Range<C> range : other.asRanges()) {
+ this.add(range);
+ }
+ }
+
+ /**
+ * 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
+ */
+ public void removeAll(RangeSet<C> other) {
+ for (Range<C> range : other.asRanges()) {
+ this.remove(range);
+ }
+ }
+
+ /**
+ * Returns {@code true} if {@code obj} is another {@code RangeSet} that contains the same ranges
+ * according to {@link Range#equals(Object)}.
+ */
+ @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();
+ }
+
+ /**
+ * 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
+ 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/Ranges.java b/guava/src/com/google/common/collect/Ranges.java
new file mode 100644
index 0000000..4062146
--- /dev/null
+++ b/guava/src/com/google/common/collect/Ranges.java
@@ -0,0 +1,255 @@
+/*
+ * 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;
+
+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;
+
+/**
+ * Static methods pertaining to {@link Range} instances. Each of the
+ * {@link Range nine types of ranges} can be constructed with a corresponding
+ * factory method:
+ *
+ * <dl>
+ * <dt>{@code (a..b)}
+ * <dd>{@link #open}
+ * <dt>{@code [a..b]}
+ * <dd>{@link #closed}
+ * <dt>{@code [a..b)}
+ * <dd>{@link #closedOpen}
+ * <dt>{@code (a..b]}
+ * <dd>{@link #openClosed}
+ * <dt>{@code (a..+∞)}
+ * <dd>{@link #greaterThan}
+ * <dt>{@code [a..+∞)}
+ * <dd>{@link #atLeast}
+ * <dt>{@code (-∞..b)}
+ * <dd>{@link #lessThan}
+ * <dt>{@code (-∞..b]}
+ * <dd>{@link #atMost}
+ * <dt>{@code (-∞..+∞)}
+ * <dd>{@link #all}
+ * </dl>
+ *
+ * <p>Additionally, {@link Range} instances can be constructed by passing the
+ * {@link BoundType bound types} explicitly.
+ *
+ * <dl>
+ * <dt>Bounded on both ends
+ * <dd>{@link #range}
+ * <dt>Unbounded on top ({@code (a..+∞)} or {@code (a..+∞)})
+ * <dd>{@link #downTo}
+ * <dt>Unbounded on bottom ({@code (-∞..b)} or {@code (-∞..b]})
+ * <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
+ */
+@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}.
+ *
+ * @throws IllegalArgumentException if {@code lower} is greater than <i>or
+ * equal to</i> {@code upper}
+ */
+ 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}
+ */
+ 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}
+ */
+ 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}
+ */
+ 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}
+ */
+ 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}.
+ */
+ 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}.
+ */
+ 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).
+ */
+ 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}.
+ */
+ 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}.
+ */
+ 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.
+ */
+ 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();
+ }
+ }
+
+ /** Returns a range that contains every value of type {@code C}. */
+ public static <C extends Comparable<?>> Range<C> all() {
+ return create(Cut.<C>belowAll(), Cut.<C>aboveAll());
+ }
+
+ /**
+ * Returns a range that {@linkplain Range#contains(Comparable) contains} only
+ * the given value. The returned range is {@linkplain BoundType#CLOSED closed}
+ * on both ends.
+ */
+ 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
+ */
+ 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);
+ }
+}
diff --git a/guava/src/com/google/common/collect/RegularContiguousSet.java b/guava/src/com/google/common/collect/RegularContiguousSet.java
new file mode 100644
index 0000000..65d35c1
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularContiguousSet.java
@@ -0,0 +1,276 @@
+/*
+ * 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 static com.google.common.collect.BoundType.CLOSED;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+import javax.annotation.Nullable;
+
+/**
+ * An implementation of {@link ContiguousSet} that contains one or more elements.
+ *
+ * @author Gregory Kick
+ */
+@GwtCompatible(emulated = true)
+@SuppressWarnings("unchecked") // allow ungenerified Comparable types
+final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C> {
+ private final Range<C> range;
+
+ RegularContiguousSet(Range<C> range, DiscreteDomain<C> domain) {
+ super(domain);
+ this.range = range;
+ }
+
+ private ContiguousSet<C> intersectionInCurrentDomain(Range<C> other) {
+ return (range.isConnected(other))
+ ? range.intersection(other).asSet(domain)
+ : new EmptyContiguousSet<C>(domain);
+ }
+
+ @Override ContiguousSet<C> headSetImpl(C toElement, boolean inclusive) {
+ return intersectionInCurrentDomain(Ranges.upTo(toElement, BoundType.forBoolean(inclusive)));
+ }
+
+ @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(Ranges.range(
+ fromElement, BoundType.forBoolean(fromInclusive),
+ toElement, BoundType.forBoolean(toInclusive)));
+ }
+
+ @Override ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive) {
+ return intersectionInCurrentDomain(Ranges.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;
+ }
+
+ @Override public UnmodifiableIterator<C> iterator() {
+ return new AbstractSequentialIterator<C>(first()) {
+ final C last = last();
+
+ @Override
+ protected C computeNext(C previous) {
+ return equalsOrThrow(previous, last) ? null : domain.next(previous);
+ }
+ };
+ }
+
+ private static boolean equalsOrThrow(Comparable<?> left, @Nullable Comparable<?> right) {
+ return right != null && Range.compareOrThrow(left, right) == 0;
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public C first() {
+ return range.lowerBound.leastValueAbove(domain);
+ }
+
+ @Override public C last() {
+ return range.upperBound.greatestValueBelow(domain);
+ }
+
+ @Override public int size() {
+ long distance = domain.distance(first(), last());
+ return (distance >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) distance + 1;
+ }
+
+ @Override public boolean contains(Object object) {
+ if (object == null) {
+ return false;
+ }
+ try {
+ return range.contains((C) object);
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ return Collections2.containsAllImpl(this, targets);
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ // copied to make sure not to use the GWT-emulated version
+ @Override public Object[] toArray() {
+ return ObjectArrays.toArrayImpl(this);
+ }
+
+ // copied to make sure not to use the GWT-emulated version
+ @Override public <T> T[] toArray(T[] other) {
+ return ObjectArrays.toArrayImpl(this, other);
+ }
+
+ @Override public ContiguousSet<C> intersection(ContiguousSet<C> other) {
+ checkNotNull(other);
+ checkArgument(this.domain.equals(other.domain));
+ if (other.isEmpty()) {
+ return other;
+ } else {
+ C lowerEndpoint = Ordering.natural().max(this.first(), other.first());
+ C upperEndpoint = Ordering.natural().min(this.last(), other.last());
+ return (lowerEndpoint.compareTo(upperEndpoint) < 0)
+ ? Ranges.closed(lowerEndpoint, upperEndpoint).asSet(domain)
+ : new EmptyContiguousSet<C>(domain);
+ }
+ }
+
+ @Override public Range<C> range() {
+ return range(CLOSED, CLOSED);
+ }
+
+ @Override public Range<C> range(BoundType lowerBoundType, BoundType upperBoundType) {
+ return Ranges.create(range.lowerBound.withLowerBoundType(lowerBoundType, domain),
+ range.upperBound.withUpperBoundType(upperBoundType, domain));
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ } else if (object instanceof RegularContiguousSet) {
+ RegularContiguousSet<?> that = (RegularContiguousSet<?>) object;
+ if (this.domain.equals(that.domain)) {
+ return this.first().equals(that.first())
+ && this.last().equals(that.last());
+ }
+ }
+ return super.equals(object);
+ }
+
+ // copied to make sure not to use the GWT-emulated version
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+
+ @GwtIncompatible("serialization")
+ private static final class SerializedForm<C extends Comparable> implements Serializable {
+ final Range<C> range;
+ final DiscreteDomain<C> domain;
+
+ private SerializedForm(Range<C> range, DiscreteDomain<C> domain) {
+ this.range = range;
+ this.domain = domain;
+ }
+
+ private Object readResolve() {
+ return new RegularContiguousSet<C>(range, domain);
+ }
+ }
+
+ @GwtIncompatible("serialization")
+ @Override Object writeReplace() {
+ return new SerializedForm<C>(range, domain);
+ }
+
+ private static final long serialVersionUID = 0;
+
+ @GwtIncompatible("NavigableSet")
+ @Override
+ ImmutableSortedSet<C> createDescendingSet() {
+ return new DescendingContiguousSet();
+ }
+
+ @GwtIncompatible("NavigableSet")
+ private final class DescendingContiguousSet extends ImmutableSortedSet<C> {
+
+ private DescendingContiguousSet() {
+ super(Ordering.natural().reverse());
+ }
+
+ @Override
+ public C first() {
+ return RegularContiguousSet.this.last();
+ }
+
+ @Override
+ public C last() {
+ return RegularContiguousSet.this.first();
+ }
+
+ @Override
+ public int size() {
+ return RegularContiguousSet.this.size();
+ }
+
+ @Override
+ public UnmodifiableIterator<C> iterator() {
+ return new AbstractSequentialIterator<C>(first()) {
+ final C last = last();
+
+ @Override
+ protected C computeNext(C previous) {
+ return equalsOrThrow(previous, last) ? null : domain.previous(previous);
+ }
+ };
+ }
+
+ @Override
+ ImmutableSortedSet<C> headSetImpl(C toElement, boolean inclusive) {
+ return RegularContiguousSet.this.tailSetImpl(toElement, inclusive).descendingSet();
+ }
+
+ @Override
+ ImmutableSortedSet<C> subSetImpl(
+ C fromElement,
+ boolean fromInclusive,
+ C toElement,
+ boolean toInclusive) {
+ return RegularContiguousSet.this.subSetImpl(
+ toElement,
+ toInclusive,
+ fromElement,
+ fromInclusive).descendingSet();
+ }
+
+ @Override
+ ImmutableSortedSet<C> tailSetImpl(C fromElement, boolean inclusive) {
+ return RegularContiguousSet.this.headSetImpl(fromElement, inclusive).descendingSet();
+ }
+
+ @Override
+ ImmutableSortedSet<C> createDescendingSet() {
+ return RegularContiguousSet.this;
+ }
+
+ @Override
+ int indexOf(Object target) {
+ return contains(target) ? (int) domain.distance(last(), (C) target) : -1;
+ }
+
+ @Override
+ boolean isPartialView() {
+ return false;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/RegularImmutableAsList.java b/guava/src/com/google/common/collect/RegularImmutableAsList.java
new file mode 100644
index 0000000..c137d6b
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableAsList.java
@@ -0,0 +1,91 @@
+/*
+ * 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
new file mode 100644
index 0000000..dca1f05
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableBiMap.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+/**
+ * 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> {
+ final transient ImmutableMap<K, V> delegate;
+ final transient ImmutableBiMap<V, K> inverse;
+
+ RegularImmutableBiMap(ImmutableMap<K, V> delegate) {
+ this.delegate = delegate;
+
+ ImmutableMap.Builder<V, K> builder = ImmutableMap.builder();
+ for (Entry<K, V> entry : delegate.entrySet()) {
+ builder.put(entry.getValue(), entry.getKey());
+ }
+ ImmutableMap<V, K> backwardMap = builder.build();
+ this.inverse = new RegularImmutableBiMap<V, K>(backwardMap, this);
+ }
+
+ RegularImmutableBiMap(ImmutableMap<K, V> delegate,
+ ImmutableBiMap<V, K> inverse) {
+ this.delegate = delegate;
+ this.inverse = inverse;
+ }
+
+ @Override ImmutableMap<K, V> delegate() {
+ return delegate;
+ }
+
+ @Override public ImmutableBiMap<V, K> inverse() {
+ return inverse;
+ }
+
+ @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
new file mode 100644
index 0000000..4314b6e
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableList.java
@@ -0,0 +1,139 @@
+/*
+ * 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;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Preconditions;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * Implementation of {@link ImmutableList} with one or more elements.
+ *
+ * @author Kevin Bourrillion
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // uses writeReplace(), not default serialization
+class RegularImmutableList<E> extends ImmutableList<E> {
+ private final transient int offset;
+ private final transient int size;
+ private final transient Object[] array;
+
+ RegularImmutableList(Object[] array, int offset, int size) {
+ this.offset = offset;
+ this.size = size;
+ this.array = array;
+ }
+
+ RegularImmutableList(Object[] array) {
+ this(array, 0, array.length);
+ }
+
+ @Override
+ public int size() {
+ return size;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override boolean isPartialView() {
+ return offset != 0 || size != array.length;
+ }
+
+ @Override public Object[] toArray() {
+ Object[] newArray = new Object[size()];
+ System.arraycopy(array, offset, newArray, 0, size);
+ return newArray;
+ }
+
+ @Override public <T> T[] toArray(T[] other) {
+ if (other.length < size) {
+ other = ObjectArrays.newArray(other, size);
+ } else if (other.length > size) {
+ other[size] = null;
+ }
+ System.arraycopy(array, offset, other, 0, size);
+ return other;
+ }
+
+ // The fake cast to E is safe because the creation methods only allow E's
+ @Override
+ @SuppressWarnings("unchecked")
+ public E get(int index) {
+ Preconditions.checkElementIndex(index, size);
+ return (E) array[index + offset];
+ }
+
+ @Override
+ ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
+ return new RegularImmutableList<E>(
+ array, offset + fromIndex, toIndex - fromIndex);
+ }
+
+ @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 boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (!(object instanceof List)) {
+ return false;
+ }
+
+ List<?> that = (List<?>) object;
+ if (this.size() != that.size()) {
+ return false;
+ }
+
+ int index = offset;
+ if (object instanceof RegularImmutableList) {
+ RegularImmutableList<?> other = (RegularImmutableList<?>) object;
+ for (int i = other.offset; i < other.offset + other.size; i++) {
+ if (!array[index++].equals(other.array[i])) {
+ return false;
+ }
+ }
+ } else {
+ for (Object element : that) {
+ if (!array[index++].equals(element)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override public String toString() {
+ StringBuilder sb = Collections2.newStringBuilderForCollection(size())
+ .append('[').append(array[offset]);
+ for (int i = offset + 1; i < offset + size; i++) {
+ sb.append(", ").append(array[i]);
+ }
+ return sb.append(']').toString();
+ }
+}
diff --git a/guava/src/com/google/common/collect/RegularImmutableMap.java b/guava/src/com/google/common/collect/RegularImmutableMap.java
new file mode 100644
index 0000000..7a2e859
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableMap.java
@@ -0,0 +1,246 @@
+/*
+ * 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.checkArgument;
+
+import com.google.common.annotations.GwtCompatible;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Implementation of {@link ImmutableMap} with two or more entries.
+ *
+ * @author Jesse Wilson
+ * @author Kevin Bourrillion
+ * @author Gregory Kick
+ */
+@GwtCompatible(serializable = true, emulated = true)
+final class RegularImmutableMap<K, V> extends ImmutableMap<K, V> {
+
+ // entries in insertion order
+ private final transient LinkedEntry<K, V>[] entries;
+ // array of linked lists of entries
+ 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.
+ RegularImmutableMap(Entry<?, ?>... immutableEntries) {
+ int size = immutableEntries.length;
+ entries = createEntryArray(size);
+
+ 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
+ LinkedEntry<K, V> linkedEntry =
+ newLinkedEntry(key, entry.getValue(), existing);
+ table[tableIndex] = linkedEntry;
+ entries[entryIndex] = linkedEntry;
+ while (existing != null) {
+ checkArgument(!key.equals(existing.getKey()), "duplicate key: %s", key);
+ 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;
+
+ /**
+ * Give a good hash table size for the given number of keys.
+ *
+ * @param size The number of keys to be inserted. Must be greater than or equal to 2.
+ */
+ private static int chooseTableSize(int size) {
+ // Get the recommended table size.
+ // Round down to the nearest power of 2.
+ int tableSize = Integer.highestOneBit(size);
+ // Check to make sure that we will not exceed the maximum load factor.
+ if ((double) size / tableSize > MAX_LOAD_FACTOR) {
+ tableSize <<= 1;
+ checkArgument(tableSize > 0, "table too large: %s", size);
+ }
+ return tableSize;
+ }
+
+ /**
+ * Creates a {@link LinkedEntry} array to hold parameterized entries. The
+ * result must never be upcast back to LinkedEntry[] (or Object[], etc.), or
+ * allowed to escape the class.
+ */
+ @SuppressWarnings("unchecked") // Safe as long as the javadocs are followed
+ private LinkedEntry<K, V>[] createEntryArray(int size) {
+ return new LinkedEntry[size];
+ }
+
+ private static <K, V> LinkedEntry<K, V> newLinkedEntry(K key, V value,
+ @Nullable LinkedEntry<K, V> next) {
+ return (next == null)
+ ? new TerminalEntry<K, V>(key, value)
+ : new NonTerminalEntry<K, V>(key, value, next);
+ }
+
+ private interface LinkedEntry<K, V> extends Entry<K, V> {
+ /** Returns the next entry in the list or {@code null} if none exists. */
+ @Nullable LinkedEntry<K, V> next();
+ }
+
+ /** {@code LinkedEntry} implementation that has a next value. */
+ @Immutable
+ @SuppressWarnings("serial") // this class is never serialized
+ private static final class NonTerminalEntry<K, V>
+ extends ImmutableEntry<K, V> implements LinkedEntry<K, V> {
+ final LinkedEntry<K, V> next;
+
+ NonTerminalEntry(K key, V value, LinkedEntry<K, V> next) {
+ super(key, value);
+ this.next = next;
+ }
+
+ @Override public LinkedEntry<K, V> next() {
+ return next;
+ }
+ }
+
+ /**
+ * {@code LinkedEntry} implementation that serves as the last entry in the
+ * list. I.e. no next entry
+ */
+ @Immutable
+ @SuppressWarnings("serial") // this class is never serialized
+ private static final class TerminalEntry<K, V> extends ImmutableEntry<K, V>
+ implements LinkedEntry<K, V> {
+ TerminalEntry(K key, V value) {
+ super(key, value);
+ }
+
+ @Nullable @Override public LinkedEntry<K, V> next() {
+ return null;
+ }
+ }
+
+ @Override public V get(@Nullable Object key) {
+ if (key == null) {
+ return null;
+ }
+ int index = Hashing.smear(key.hashCode()) & mask;
+ for (LinkedEntry<K, V> entry = table[index];
+ entry != null;
+ entry = entry.next()) {
+ K candidateKey = entry.getKey();
+
+ /*
+ * Assume that equals uses the == optimization when appropriate, and that
+ * it would check hash codes as an optimization when appropriate. If we
+ * did these things, it would just make things worse for the most
+ * performance-conscious users.
+ */
+ if (key.equals(candidateKey)) {
+ return entry.getValue();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ 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();
+ }
+
+ @SuppressWarnings("serial") // uses writeReplace(), not default serialization
+ private class EntrySet extends ImmutableMapEntrySet<K, V> {
+ @Override ImmutableMap<K, V> map() {
+ return RegularImmutableMap.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
+ ImmutableSet<K> createKeySet() {
+ return new ImmutableMapKeySet<K, V>(entrySet(), keySetHashCode) {
+ @Override ImmutableMap<K, V> map() {
+ return RegularImmutableMap.this;
+ }
+ };
+ }
+
+ @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
+ // warning go away (and suppressing would suppress for all nested classes too)
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/RegularImmutableMultiset.java b/guava/src/com/google/common/collect/RegularImmutableMultiset.java
new file mode 100644
index 0000000..e46f424
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableMultiset.java
@@ -0,0 +1,110 @@
+/*
+ * 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 java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * Implementation of {@link ImmutableMultiset} with one or more elements.
+ *
+ * @author Jared Levy
+ * @author Louis Wasserman
+ */
+@GwtCompatible(serializable = true)
+@SuppressWarnings("serial")
+// uses writeReplace(), not default serialization
+class RegularImmutableMultiset<E> extends ImmutableMultiset<E> {
+ private final transient ImmutableMap<E, Integer> map;
+ private final transient int size;
+
+ RegularImmutableMultiset(ImmutableMap<E, Integer> map, int size) {
+ this.map = map;
+ this.size = size;
+ }
+
+ @Override
+ boolean isPartialView() {
+ return map.isPartialView();
+ }
+
+ @Override
+ public int count(@Nullable Object element) {
+ Integer value = map.get(element);
+ return (value == null) ? 0 : value;
+ }
+
+ @Override
+ public int size() {
+ return size;
+ }
+
+ @Override
+ public boolean contains(@Nullable Object element) {
+ return map.containsKey(element);
+ }
+
+ @Override
+ public ImmutableSet<E> elementSet() {
+ 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;
+ }
+ };
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+}
diff --git a/guava/src/com/google/common/collect/RegularImmutableSet.java b/guava/src/com/google/common/collect/RegularImmutableSet.java
new file mode 100644
index 0000000..75a49c1
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableSet.java
@@ -0,0 +1,67 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableSet.ArrayImmutableSet;
+
+/**
+ * Implementation of {@link ImmutableSet} with two or more elements.
+ *
+ * @author Kevin Bourrillion
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // uses writeReplace(), not default serialization
+final class RegularImmutableSet<E> extends ArrayImmutableSet<E> {
+ // the same elements in hashed positions (plus nulls)
+ @VisibleForTesting final transient Object[] table;
+ // 'and' with an int to get a valid table index.
+ private final transient int mask;
+ private final transient int hashCode;
+
+ RegularImmutableSet(
+ Object[] elements, int hashCode, Object[] table, int mask) {
+ super(elements);
+ this.table = table;
+ this.mask = mask;
+ this.hashCode = hashCode;
+ }
+
+ @Override public boolean contains(Object target) {
+ if (target == null) {
+ return false;
+ }
+ for (int i = Hashing.smear(target.hashCode()); true; i++) {
+ Object candidate = table[i & mask];
+ if (candidate == null) {
+ return false;
+ }
+ if (candidate.equals(target)) {
+ return true;
+ }
+ }
+ }
+
+ @Override public int hashCode() {
+ return hashCode;
+ }
+
+ @Override boolean isHashCodeFast() {
+ return true;
+ }
+}
diff --git a/guava/src/com/google/common/collect/RegularImmutableSortedMap.java b/guava/src/com/google/common/collect/RegularImmutableSortedMap.java
new file mode 100644
index 0000000..ef04429
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableSortedMap.java
@@ -0,0 +1,128 @@
+/*
+ * 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 javax.annotation.Nullable;
+
+/**
+ * An implementation of an immutable sorted map with one or more entries.
+ *
+ * @author Louis Wasserman
+ */
+@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();
+ private final ImmutableList<V> valueList = values().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
new file mode 100644
index 0000000..3db3405
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableSortedMultiset.java
@@ -0,0 +1,145 @@
+/*
+ * 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.checkPositionIndexes;
+import static com.google.common.collect.BoundType.CLOSED;
+
+import com.google.common.primitives.Ints;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable sorted multiset with one or more distinct elements.
+ *
+ * @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;
+
+ 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;
+ }
+
+ private Entry<E> getEntry(int index) {
+ return Multisets.immutableEntry(
+ elementSet.asList().get(index),
+ counts[offset + index]);
+ }
+
+ @Override
+ public Entry<E> firstEntry() {
+ return getEntry(0);
+ }
+
+ @Override
+ public Entry<E> lastEntry() {
+ return getEntry(length - 1);
+ }
+
+ @Override
+ public int count(@Nullable Object element) {
+ int index = elementSet.indexOf(element);
+ return (index == -1) ? 0 : counts[index + offset];
+ }
+
+ @Override
+ public int size() {
+ long size = cumulativeCounts[offset + length] - cumulativeCounts[offset];
+ return Ints.saturatedCast(size);
+ }
+
+ @Override
+ public ImmutableSortedSet<E> elementSet() {
+ return elementSet;
+ }
+
+ @Override
+ public ImmutableSortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
+ return getSubMultiset(0, elementSet.headIndex(upperBound, checkNotNull(boundType) == CLOSED));
+ }
+
+ @Override
+ public ImmutableSortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
+ return getSubMultiset(elementSet.tailIndex(lowerBound, checkNotNull(boundType) == CLOSED),
+ length);
+ }
+
+ 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
+ ImmutableSet<Entry<E>> createEntrySet() {
+ return new EntrySet();
+ }
+
+ private final class EntrySet extends ImmutableMultiset<E>.EntrySet {
+ @Override
+ public int size() {
+ return length;
+ }
+
+ @Override
+ public UnmodifiableIterator<Entry<E>> iterator() {
+ return asList().iterator();
+ }
+
+ @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
+ boolean isPartialView() {
+ return offset > 0 || length < counts.length;
+ }
+}
diff --git a/guava/src/com/google/common/collect/RegularImmutableSortedSet.java b/guava/src/com/google/common/collect/RegularImmutableSortedSet.java
new file mode 100644
index 0000000..eef64ed
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableSortedSet.java
@@ -0,0 +1,262 @@
+/*
+ * 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;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+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.KeyPresentBehavior.ANY_PRESENT;
+import static com.google.common.collect.SortedLists.KeyPresentBehavior.FIRST_AFTER;
+import static com.google.common.collect.SortedLists.KeyPresentBehavior.FIRST_PRESENT;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable sorted set with one or more elements. TODO(jlevy): Consider
+ * separate class for a single-element sorted set.
+ *
+ * @author Jared Levy
+ * @author Louis Wasserman
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial")
+final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
+
+ private transient final ImmutableList<E> elements;
+
+ RegularImmutableSortedSet(
+ ImmutableList<E> elements, Comparator<? super E> comparator) {
+ super(comparator);
+ this.elements = elements;
+ checkArgument(!elements.isEmpty());
+ }
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ return elements.iterator();
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public int size() {
+ return elements.size();
+ }
+
+ @Override public boolean contains(Object o) {
+ if (o == null) {
+ return false;
+ }
+ try {
+ return unsafeBinarySearch(o) >= 0;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ // TODO(jlevy): For optimal performance, use a binary search when
+ // 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)
+ || (targets.size() <= 1)) {
+ return super.containsAll(targets);
+ }
+
+ /*
+ * If targets is a sorted set with the same comparator, containsAll can run
+ * in O(n) time stepping through the two collections.
+ */
+ Iterator<E> thisIterator = iterator();
+ Iterator<?> thatIterator = targets.iterator();
+ Object target = thatIterator.next();
+
+ try {
+
+ while (thisIterator.hasNext()) {
+
+ int cmp = unsafeCompare(thisIterator.next(), target);
+
+ if (cmp == 0) {
+
+ if (!thatIterator.hasNext()) {
+
+ return true;
+ }
+
+ target = thatIterator.next();
+
+ } else if (cmp > 0) {
+ return false;
+ }
+ }
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+
+ return false;
+ }
+
+ private int unsafeBinarySearch(Object key) throws ClassCastException {
+ return Collections.binarySearch(elements, key, unsafeComparator());
+ }
+
+ @Override boolean isPartialView() {
+ return elements.isPartialView();
+ }
+
+ @Override public Object[] toArray() {
+ return elements.toArray();
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return elements.toArray(array);
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (!(object instanceof Set)) {
+ return false;
+ }
+
+ Set<?> that = (Set<?>) object;
+ if (size() != that.size()) {
+ return false;
+ }
+
+ if (SortedIterables.hasSameComparator(comparator, that)) {
+ Iterator<?> otherIterator = that.iterator();
+ try {
+ Iterator<E> iterator = iterator();
+ while (iterator.hasNext()) {
+ Object element = iterator.next();
+ Object otherElement = otherIterator.next();
+ if (otherElement == null
+ || unsafeCompare(element, otherElement) != 0) {
+ return false;
+ }
+ }
+ return true;
+ } catch (ClassCastException e) {
+ return false;
+ } catch (NoSuchElementException e) {
+ return false; // concurrent change to other set
+ }
+ }
+ return this.containsAll(that);
+ }
+
+ @Override
+ public E first() {
+ return elements.get(0);
+ }
+
+ @Override
+ public E last() {
+ return elements.get(size() - 1);
+ }
+
+ @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);
+ }
+
+ @Override
+ ImmutableSortedSet<E> subSetImpl(
+ E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+ return tailSetImpl(fromElement, fromInclusive)
+ .headSetImpl(toElement, toInclusive);
+ }
+
+ @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);
+ }
+
+ // 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;
+ }
+
+ ImmutableSortedSet<E> getSubSet(int newFromIndex, int newToIndex) {
+ if (newFromIndex == 0 && newToIndex == size()) {
+ return this;
+ } else if (newFromIndex < newToIndex) {
+ return new RegularImmutableSortedSet<E>(
+ elements.subList(newFromIndex, newToIndex), comparator);
+ } else {
+ return emptySet(comparator);
+ }
+ }
+
+ @Override int indexOf(@Nullable Object target) {
+ if (target == null) {
+ return -1;
+ }
+ int position;
+ try {
+ position = SortedLists.binarySearch(elements, target, unsafeComparator(),
+ ANY_PRESENT, INVERTED_INSERTION_INDEX);
+ } catch (ClassCastException e) {
+ return -1;
+ }
+ return (position >= 0) ? 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
new file mode 100644
index 0000000..7245c9a
--- /dev/null
+++ b/guava/src/com/google/common/collect/RegularImmutableTable.java
@@ -0,0 +1,559 @@
+/*
+ * 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;
+
+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.base.Function;
+import com.google.common.base.Objects;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * An implementation of {@link ImmutableTable} holding an arbitrary number of
+ * cells.
+ *
+ * @author Gregory Kick
+ */
+@GwtCompatible
+abstract class RegularImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
+ // TODO(user): split DenseImmutableTable, SparseImmutableTable into their own classes
+ private final ImmutableSet<Cell<R, C, V>> cellSet;
+
+ private RegularImmutableTable(ImmutableSet<Cell<R, C, V>> cellSet) {
+ this.cellSet = cellSet;
+ }
+
+ 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;
+ }
+
+ @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;
+ }
+
+ @Override public final int size() {
+ return cellSet().size();
+ }
+
+ @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,
+ @Nullable final Comparator<? super C> columnComparator) {
+ checkNotNull(cells);
+ if (rowComparator != null || columnComparator != null) {
+ /*
+ * This sorting logic leads to a cellSet() ordering that may not be
+ * expected and that isn't documented in the Javadoc. If a row Comparator
+ * is provided, cellSet() iterates across the columns in the first row,
+ * the columns in the second row, etc. If a column Comparator is provided
+ * but a row Comparator isn't, cellSet() iterates across the rows in the
+ * first column, the rows in the second column, etc.
+ */
+ Comparator<Cell<R, C, V>> comparator = new Comparator<Cell<R, C, V>>() {
+ @Override public int compare(Cell<R, C, V> cell1, Cell<R, C, V> cell2) {
+ int rowCompare = (rowComparator == null) ? 0
+ : rowComparator.compare(cell1.getRowKey(), cell2.getRowKey());
+ if (rowCompare != 0) {
+ return rowCompare;
+ }
+ return (columnComparator == null) ? 0
+ : columnComparator.compare(
+ cell1.getColumnKey(), cell2.getColumnKey());
+ }
+ };
+ Collections.sort(cells, comparator);
+ }
+ return forCellsInternal(cells, rowComparator, columnComparator);
+ }
+
+ static final <R, C, V> RegularImmutableTable<R, C, V> forCells(
+ Iterable<Cell<R, C, V>> cells) {
+ return forCellsInternal(cells, null, null);
+ }
+
+ /**
+ * A factory that chooses the most space-efficient representation of the
+ * table.
+ */
+ private static final <R, C, V> RegularImmutableTable<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();
+ 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) {
+ List<R> rowList = Lists.newArrayList(rowSpace);
+ Collections.sort(rowList, rowComparator);
+ rowSpace = ImmutableSet.copyOf(rowList);
+ }
+ ImmutableSet<C> columnSpace = columnSpaceBuilder.build();
+ if (columnComparator != null) {
+ List<C> columnList = Lists.newArrayList(columnSpace);
+ Collections.sort(columnList, columnComparator);
+ columnSpace = ImmutableSet.copyOf(columnList);
+ }
+
+ // use a dense table if more than half of the cells have values
+ // TODO(gak): tune this condition based on empirical evidence
+ return (cellSet.size() > ((rowSpace.size() * columnSpace.size()) / 2 )) ?
+ new DenseImmutableTable<R, C, V>(cellSet, rowSpace, columnSpace) :
+ new SparseImmutableTable<R, C, V>(cellSet, rowSpace, columnSpace);
+ }
+
+ /**
+ * A {@code RegularImmutableTable} optimized for sparse data.
+ */
+ @Immutable
+ @VisibleForTesting
+ static final class SparseImmutableTable<R, C, V>
+ extends RegularImmutableTable<R, C, V> {
+
+ private final ImmutableMap<R, Map<C, V>> rowMap;
+ private final ImmutableMap<C, Map<R, V>> columnMap;
+
+ /**
+ * 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());
+ }
+ 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();
+ rowIndexBuilder.get(rowKey).put(columnKey, value);
+ columnIndexBuilder.get(columnKey).put(rowKey, value);
+ }
+ this.rowMap = buildIndex(rowIndexBuilder);
+ this.columnMap = buildIndex(columnIndexBuilder);
+ }
+
+ @Override public ImmutableMap<R, V> column(C columnKey) {
+ checkNotNull(columnKey);
+ // value maps are guaranteed to be immutable maps
+ return Objects.firstNonNull((ImmutableMap<R, V>) columnMap.get(columnKey),
+ ImmutableMap.<R, V>of());
+ }
+
+ @Override public ImmutableSet<C> columnKeySet() {
+ return columnMap.keySet();
+ }
+
+ @Override public ImmutableMap<C, Map<R, V>> columnMap() {
+ return columnMap;
+ }
+
+ @Override public ImmutableMap<C, V> row(R rowKey) {
+ checkNotNull(rowKey);
+ // value maps are guaranteed to be immutable maps
+ return Objects.firstNonNull((ImmutableMap<C, V>) rowMap.get(rowKey),
+ ImmutableMap.<C, V>of());
+ }
+
+ @Override public ImmutableSet<R> rowKeySet() {
+ return rowMap.keySet();
+ }
+
+ @Override public ImmutableMap<R, Map<C, V>> rowMap() {
+ return rowMap;
+ }
+
+ @Override public boolean contains(@Nullable Object rowKey,
+ @Nullable Object columnKey) {
+ Map<C, V> row = rowMap.get(rowKey);
+ return (row != null) && row.containsKey(columnKey);
+ }
+
+ @Override public boolean containsColumn(@Nullable Object columnKey) {
+ return columnMap.containsKey(columnKey);
+ }
+
+ @Override public boolean containsRow(@Nullable Object rowKey) {
+ return rowMap.containsKey(rowKey);
+ }
+
+ @Override public V get(@Nullable Object rowKey,
+ @Nullable Object columnKey) {
+ Map<C, V> row = rowMap.get(rowKey);
+ return (row == null) ? null : row.get(columnKey);
+ }
+ }
+
+ /**
+ * 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();
+ }
+ };
+ }
+ };
+ }
+ }
+ }
+
+ /**
+ * A {@code RegularImmutableTable} optimized for dense data.
+ */
+ @Immutable @VisibleForTesting
+ 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 V[][] values;
+
+ private static <E> ImmutableMap<E, Integer> makeIndex(
+ ImmutableSet<E> set) {
+ ImmutableMap.Builder<E, Integer> indexBuilder =
+ ImmutableMap.builder();
+ int i = 0;
+ for (E key : set) {
+ indexBuilder.put(key, i);
+ i++;
+ }
+ return indexBuilder.build();
+ }
+
+ 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()];
+ for (Cell<R, C, V> cell : cellSet) {
+ R rowKey = cell.getRowKey();
+ C columnKey = cell.getColumnKey();
+ int rowIndex = rowKeyToIndex.get(rowKey);
+ int columnIndex = columnKeyToIndex.get(columnKey);
+ V existingValue = values[rowIndex][columnIndex];
+ checkArgument(existingValue == null, "duplicate key: (%s, %s)", rowKey,
+ columnKey);
+ values[rowIndex][columnIndex] = cell.getValue();
+ rowCounts[rowIndex]++;
+ columnCounts[columnIndex]++;
+ }
+
+ 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) {
+ return ImmutableMap.of();
+ } else {
+ return new Column(columnIndex);
+ }
+ }
+
+ @Override public ImmutableSet<C> columnKeySet() {
+ return columnKeyToIndex.keySet();
+ }
+
+ @Override public ImmutableMap<C, Map<R, V>> columnMap() {
+ return columnMap;
+ }
+
+ @Override public boolean contains(@Nullable Object rowKey,
+ @Nullable Object columnKey) {
+ return (get(rowKey, columnKey) != null);
+ }
+
+ @Override public boolean containsColumn(@Nullable Object columnKey) {
+ return columnKeyToIndex.containsKey(columnKey);
+ }
+
+ @Override public boolean containsRow(@Nullable Object rowKey) {
+ return rowKeyToIndex.containsKey(rowKey);
+ }
+
+ @Override public V get(@Nullable Object rowKey,
+ @Nullable Object columnKey) {
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ Integer columnIndex = columnKeyToIndex.get(columnKey);
+ return ((rowIndex == null) || (columnIndex == null)) ? null
+ : values[rowIndex][columnIndex];
+ }
+
+ @Override public ImmutableMap<C, V> row(R rowKey) {
+ checkNotNull(rowKey);
+ Integer rowIndex = rowKeyToIndex.get(rowKey);
+ if (rowIndex == null) {
+ return ImmutableMap.of();
+ } else {
+ return new Row(rowIndex);
+ }
+ }
+
+ @Override public ImmutableSet<R> rowKeySet() {
+ return rowKeyToIndex.keySet();
+ }
+
+ @Override
+ public ImmutableMap<R, Map<C, V>> rowMap() {
+ return rowMap;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/ReverseNaturalOrdering.java b/guava/src/com/google/common/collect/ReverseNaturalOrdering.java
new file mode 100644
index 0000000..9a73613
--- /dev/null
+++ b/guava/src/com/google/common/collect/ReverseNaturalOrdering.java
@@ -0,0 +1,92 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+/** An ordering that uses the reverse of the natural order of the values. */
+@GwtCompatible(serializable = true)
+@SuppressWarnings("unchecked") // TODO(kevinb): the right way to explain this??
+final class ReverseNaturalOrdering
+ extends Ordering<Comparable> implements Serializable {
+ static final ReverseNaturalOrdering INSTANCE = new ReverseNaturalOrdering();
+
+ @Override public int compare(Comparable left, Comparable right) {
+ checkNotNull(left); // right null is caught later
+ if (left == right) {
+ return 0;
+ }
+
+ return right.compareTo(left);
+ }
+
+ @Override public <S extends Comparable> Ordering<S> reverse() {
+ return Ordering.natural();
+ }
+
+ // Override the min/max methods to "hoist" delegation outside loops
+
+ @Override public <E extends Comparable> E min(E a, E b) {
+ return NaturalOrdering.INSTANCE.max(a, b);
+ }
+
+ @Override public <E extends Comparable> E min(E a, E b, E c, E... rest) {
+ return NaturalOrdering.INSTANCE.max(a, b, c, rest);
+ }
+
+ @Override public <E extends Comparable> E min(Iterator<E> iterator) {
+ return NaturalOrdering.INSTANCE.max(iterator);
+ }
+
+ @Override public <E extends Comparable> E min(Iterable<E> iterable) {
+ return NaturalOrdering.INSTANCE.max(iterable);
+ }
+
+ @Override public <E extends Comparable> E max(E a, E b) {
+ return NaturalOrdering.INSTANCE.min(a, b);
+ }
+
+ @Override public <E extends Comparable> E max(E a, E b, E c, E... rest) {
+ return NaturalOrdering.INSTANCE.min(a, b, c, rest);
+ }
+
+ @Override public <E extends Comparable> E max(Iterator<E> iterator) {
+ return NaturalOrdering.INSTANCE.min(iterator);
+ }
+
+ @Override public <E extends Comparable> E max(Iterable<E> iterable) {
+ return NaturalOrdering.INSTANCE.min(iterable);
+ }
+
+ // preserving singleton-ness gives equals()/hashCode() for free
+ private Object readResolve() {
+ return INSTANCE;
+ }
+
+ @Override public String toString() {
+ return "Ordering.natural().reverse()";
+ }
+
+ private ReverseNaturalOrdering() {}
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/ReverseOrdering.java b/guava/src/com/google/common/collect/ReverseOrdering.java
new file mode 100644
index 0000000..36ae02c
--- /dev/null
+++ b/guava/src/com/google/common/collect/ReverseOrdering.java
@@ -0,0 +1,100 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import javax.annotation.Nullable;
+
+/** An ordering that uses the reverse of a given order. */
+@GwtCompatible(serializable = true)
+final class ReverseOrdering<T> extends Ordering<T> implements Serializable {
+ final Ordering<? super T> forwardOrder;
+
+ ReverseOrdering(Ordering<? super T> forwardOrder) {
+ this.forwardOrder = checkNotNull(forwardOrder);
+ }
+
+ @Override public int compare(T a, T b) {
+ return forwardOrder.compare(b, a);
+ }
+
+ @SuppressWarnings("unchecked") // how to explain?
+ @Override public <S extends T> Ordering<S> reverse() {
+ return (Ordering<S>) forwardOrder;
+ }
+
+ // Override the min/max methods to "hoist" delegation outside loops
+
+ @Override public <E extends T> E min(E a, E b) {
+ return forwardOrder.max(a, b);
+ }
+
+ @Override public <E extends T> E min(E a, E b, E c, E... rest) {
+ return forwardOrder.max(a, b, c, rest);
+ }
+
+ @Override public <E extends T> E min(Iterator<E> iterator) {
+ return forwardOrder.max(iterator);
+ }
+
+ @Override public <E extends T> E min(Iterable<E> iterable) {
+ return forwardOrder.max(iterable);
+ }
+
+ @Override public <E extends T> E max(E a, E b) {
+ return forwardOrder.min(a, b);
+ }
+
+ @Override public <E extends T> E max(E a, E b, E c, E... rest) {
+ return forwardOrder.min(a, b, c, rest);
+ }
+
+ @Override public <E extends T> E max(Iterator<E> iterator) {
+ return forwardOrder.min(iterator);
+ }
+
+ @Override public <E extends T> E max(Iterable<E> iterable) {
+ return forwardOrder.min(iterable);
+ }
+
+ @Override public int hashCode() {
+ return -forwardOrder.hashCode();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof ReverseOrdering) {
+ ReverseOrdering<?> that = (ReverseOrdering<?>) object;
+ return this.forwardOrder.equals(that.forwardOrder);
+ }
+ return false;
+ }
+
+ @Override public String toString() {
+ return forwardOrder + ".reverse()";
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/RowSortedTable.java b/guava/src/com/google/common/collect/RowSortedTable.java
new file mode 100644
index 0000000..4b597b7
--- /dev/null
+++ b/guava/src/com/google/common/collect/RowSortedTable.java
@@ -0,0 +1,55 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+
+/**
+ * Interface that extends {@code Table} and whose rows are sorted.
+ *
+ * <p>The {@link #rowKeySet} method returns a {@link SortedSet} and the {@link
+ * #rowMap} method returns a {@link SortedMap}, instead of the {@link Set} and
+ * {@link Map} specified by the {@link Table} interface.
+ *
+ * @author Warren Dukes
+ * @since 8.0
+ */
+@GwtCompatible
+@Beta
+public interface RowSortedTable<R, C, V> extends Table<R, C, V> {
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method returns a {@link SortedSet}, instead of the {@code Set}
+ * specified in the {@link Table} interface.
+ */
+ @Override SortedSet<R> rowKeySet();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method returns a {@link SortedMap}, instead of the {@code Map}
+ * specified in the {@link Table} interface.
+ */
+ @Override SortedMap<R, Map<C, V>> rowMap();
+}
diff --git a/guava/src/com/google/common/collect/Serialization.java b/guava/src/com/google/common/collect/Serialization.java
new file mode 100644
index 0000000..2541548
--- /dev/null
+++ b/guava/src/com/google/common/collect/Serialization.java
@@ -0,0 +1,231 @@
+/*
+ * 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 java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Provides static methods for serializing collection classes.
+ *
+ * <p>This class assists the implementation of collection classes. Do not use
+ * this class to serialize collections that are defined elsewhere.
+ *
+ * @author Jared Levy
+ */
+final class Serialization {
+ private Serialization() {}
+
+ /**
+ * Reads a count corresponding to a serialized map, multiset, or multimap. It
+ * returns the size of a map serialized by {@link
+ * #writeMap(Map, ObjectOutputStream)}, the number of distinct elements in a
+ * multiset serialized by {@link
+ * #writeMultiset(Multiset, ObjectOutputStream)}, or the number of distinct
+ * keys in a multimap serialized by {@link
+ * #writeMultimap(Multimap, ObjectOutputStream)}.
+ *
+ * <p>The returned count may be used to construct an empty collection of the
+ * appropriate capacity before calling any of the {@code populate} methods.
+ */
+ static int readCount(ObjectInputStream stream) throws IOException {
+ return stream.readInt();
+ }
+
+ /**
+ * Stores the contents of a map in an output stream, as part of serialization.
+ * It does not support concurrent maps whose content may change while the
+ * method is running.
+ *
+ * <p>The serialized output consists of the number of entries, first key,
+ * first value, second key, second value, and so on.
+ */
+ static <K, V> void writeMap(Map<K, V> map, ObjectOutputStream stream)
+ throws IOException {
+ stream.writeInt(map.size());
+ for (Map.Entry<K, V> entry : map.entrySet()) {
+ stream.writeObject(entry.getKey());
+ stream.writeObject(entry.getValue());
+ }
+ }
+
+ /**
+ * Populates a map by reading an input stream, as part of deserialization.
+ * See {@link #writeMap} for the data format.
+ */
+ static <K, V> void populateMap(Map<K, V> map, ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ int size = stream.readInt();
+ populateMap(map, stream, size);
+ }
+
+ /**
+ * Populates a map by reading an input stream, as part of deserialization.
+ * See {@link #writeMap} for the data format. The size is determined by a
+ * prior call to {@link #readCount}.
+ */
+ static <K, V> void populateMap(Map<K, V> map, ObjectInputStream stream,
+ int size) throws IOException, ClassNotFoundException {
+ for (int i = 0; i < size; i++) {
+ @SuppressWarnings("unchecked") // reading data stored by writeMap
+ K key = (K) stream.readObject();
+ @SuppressWarnings("unchecked") // reading data stored by writeMap
+ V value = (V) stream.readObject();
+ map.put(key, value);
+ }
+ }
+
+ /**
+ * Stores the contents of a multiset in an output stream, as part of
+ * serialization. It does not support concurrent multisets whose content may
+ * change while the method is running.
+ *
+ * <p>The serialized output consists of the number of distinct elements, the
+ * first element, its count, the second element, its count, and so on.
+ */
+ static <E> void writeMultiset(
+ Multiset<E> multiset, ObjectOutputStream stream) throws IOException {
+ int entryCount = multiset.entrySet().size();
+ stream.writeInt(entryCount);
+ for (Multiset.Entry<E> entry : multiset.entrySet()) {
+ stream.writeObject(entry.getElement());
+ stream.writeInt(entry.getCount());
+ }
+ }
+
+ /**
+ * Populates a multiset by reading an input stream, as part of
+ * deserialization. See {@link #writeMultiset} for the data format.
+ */
+ static <E> void populateMultiset(
+ Multiset<E> multiset, ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ int distinctElements = stream.readInt();
+ populateMultiset(multiset, stream, distinctElements);
+ }
+
+ /**
+ * Populates a multiset by reading an input stream, as part of
+ * deserialization. See {@link #writeMultiset} for the data format. The number
+ * of distinct elements is determined by a prior call to {@link #readCount}.
+ */
+ static <E> void populateMultiset(
+ Multiset<E> multiset, ObjectInputStream stream, int distinctElements)
+ throws IOException, ClassNotFoundException {
+ for (int i = 0; i < distinctElements; i++) {
+ @SuppressWarnings("unchecked") // reading data stored by writeMultiset
+ E element = (E) stream.readObject();
+ int count = stream.readInt();
+ multiset.add(element, count);
+ }
+ }
+
+ /**
+ * Stores the contents of a multimap in an output stream, as part of
+ * serialization. It does not support concurrent multimaps whose content may
+ * change while the method is running. The {@link Multimap#asMap} view
+ * determines the ordering in which data is written to the stream.
+ *
+ * <p>The serialized output consists of the number of distinct keys, and then
+ * for each distinct key: the key, the number of values for that key, and the
+ * key's values.
+ */
+ static <K, V> void writeMultimap(
+ Multimap<K, V> multimap, ObjectOutputStream stream) throws IOException {
+ stream.writeInt(multimap.asMap().size());
+ for (Map.Entry<K, Collection<V>> entry : multimap.asMap().entrySet()) {
+ stream.writeObject(entry.getKey());
+ stream.writeInt(entry.getValue().size());
+ for (V value : entry.getValue()) {
+ stream.writeObject(value);
+ }
+ }
+ }
+
+ /**
+ * Populates a multimap by reading an input stream, as part of
+ * deserialization. See {@link #writeMultimap} for the data format.
+ */
+ static <K, V> void populateMultimap(
+ Multimap<K, V> multimap, ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ int distinctKeys = stream.readInt();
+ populateMultimap(multimap, stream, distinctKeys);
+ }
+
+ /**
+ * Populates a multimap by reading an input stream, as part of
+ * deserialization. See {@link #writeMultimap} for the data format. The number
+ * of distinct keys is determined by a prior call to {@link #readCount}.
+ */
+ static <K, V> void populateMultimap(
+ Multimap<K, V> multimap, ObjectInputStream stream, int distinctKeys)
+ throws IOException, ClassNotFoundException {
+ for (int i = 0; i < distinctKeys; i++) {
+ @SuppressWarnings("unchecked") // reading data stored by writeMultimap
+ K key = (K) stream.readObject();
+ Collection<V> values = multimap.get(key);
+ int valueCount = stream.readInt();
+ for (int j = 0; j < valueCount; j++) {
+ @SuppressWarnings("unchecked") // reading data stored by writeMultimap
+ V value = (V) stream.readObject();
+ values.add(value);
+ }
+ }
+ }
+
+ // Secret sauce for setting final fields; don't make it public.
+ static <T> FieldSetter<T> getFieldSetter(
+ final Class<T> clazz, String fieldName) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ return new FieldSetter<T>(field);
+ } catch (NoSuchFieldException e) {
+ throw new AssertionError(e); // programmer error
+ }
+ }
+
+ // Secret sauce for setting final fields; don't make it public.
+ static final class FieldSetter<T> {
+ private final Field field;
+
+ private FieldSetter(Field field) {
+ this.field = field;
+ field.setAccessible(true);
+ }
+
+ void set(T instance, Object value) {
+ try {
+ field.set(instance, value);
+ } catch (IllegalAccessException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ void set(T instance, int value) {
+ try {
+ field.set(instance, value);
+ } catch (IllegalAccessException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/SetMultimap.java b/guava/src/com/google/common/collect/SetMultimap.java
new file mode 100644
index 0000000..18f4a18
--- /dev/null
+++ b/guava/src/com/google/common/collect/SetMultimap.java
@@ -0,0 +1,113 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+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.
+ *
+ * <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)
+ */
+@GwtCompatible
+public interface SetMultimap<K, V> extends Multimap<K, V> {
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code SetMultimap} has unique values for a given key, this
+ * method returns a {@link Set}, instead of the {@link java.util.Collection}
+ * specified in the {@link Multimap} interface.
+ */
+ @Override
+ Set<V> get(@Nullable K key);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code SetMultimap} has unique values for a given key, this
+ * method returns a {@link Set}, instead of the {@link java.util.Collection}
+ * specified in the {@link Multimap} interface.
+ */
+ @Override
+ Set<V> removeAll(@Nullable Object key);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code SetMultimap} has unique values for a given key, this
+ * method returns a {@link Set}, instead of the {@link java.util.Collection}
+ * specified in the {@link Multimap} interface.
+ *
+ * <p>Any duplicates in {@code values} will be stored in the multimap once.
+ */
+ @Override
+ Set<V> replaceValues(K key, Iterable<? extends V> values);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code SetMultimap} has unique values for a given key, this
+ * method returns a {@link Set}, instead of the {@link java.util.Collection}
+ * specified in the {@link Multimap} interface.
+ */
+ @Override
+ Set<Map.Entry<K, V>> entries();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Though the method signature doesn't say so explicitly, the returned map
+ * has {@link Set} values.
+ */
+ @Override
+ Map<K, Collection<V>> asMap();
+
+ /**
+ * Compares the specified object to this multimap for equality.
+ *
+ * <p>Two {@code SetMultimap} instances are equal if, for each key, they
+ * contain the same values. Equality does not depend on the ordering of keys
+ * or values.
+ *
+ * <p>An empty {@code SetMultimap} is equal to any other empty {@code
+ * Multimap}, including an empty {@code ListMultimap}.
+ */
+ @Override
+ boolean equals(@Nullable Object obj);
+}
diff --git a/guava/src/com/google/common/collect/Sets.java b/guava/src/com/google/common/collect/Sets.java
new file mode 100644
index 0000000..016b3eb
--- /dev/null
+++ b/guava/src/com/google/common/collect/Sets.java
@@ -0,0 +1,1666 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+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;
+import java.io.Serializable;
+import java.util.AbstractSet;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashSet;
+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} and {@link Maps}.
+ *
+ * <p>See the Guava User Guide article on <a href=
+ * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Sets">
+ * {@code Sets}</a>.
+ *
+ * @author Kevin Bourrillion
+ * @author Jared Levy
+ * @author Chris Povirk
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(emulated = true)
+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}.
+ *
+ * <p>The iteration order of the returned set follows the enum's iteration
+ * order, not the order in which the elements are provided to the method.
+ *
+ * @param anElement one of the elements the set should contain
+ * @param otherElements the rest of the elements the set should contain
+ * @return an immutable set containing those elements, minus duplicates
+ */
+ // http://code.google.com/p/google-web-toolkit/issues/detail?id=3028
+ @GwtCompatible(serializable = true)
+ public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(
+ E anElement, E... otherElements) {
+ return new ImmutableEnumSet<E>(EnumSet.of(anElement, otherElements));
+ }
+
+ /**
+ * Returns an immutable set instance containing the given enum elements.
+ * Internally, the returned set will be backed by an {@link EnumSet}.
+ *
+ * <p>The iteration order of the returned set follows the enum's iteration
+ * order, not the order in which the elements appear in the given collection.
+ *
+ * @param elements the elements, all of the same {@code enum} type, that the
+ * set should contain
+ * @return an immutable set containing those elements, minus duplicates
+ */
+ // http://code.google.com/p/google-web-toolkit/issues/detail?id=3028
+ @GwtCompatible(serializable = true)
+ public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(
+ Iterable<E> elements) {
+ 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);
+ }
+
+ /**
+ * Returns a new {@code EnumSet} instance containing the given elements.
+ * Unlike {@link EnumSet#copyOf(Collection)}, this method does not produce an
+ * exception on an empty collection, and it may be called on any iterable, not
+ * just a {@code Collection}.
+ */
+ 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;
+ }
+
+ // HashSet
+
+ /**
+ * Creates a <i>mutable</i>, empty {@code HashSet} instance.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableSet#of()} instead.
+ *
+ * <p><b>Note:</b> if {@code E} is an {@link Enum} type, use {@link
+ * EnumSet#noneOf} instead.
+ *
+ * @return a new, empty {@code HashSet}
+ */
+ public static <E> HashSet<E> newHashSet() {
+ return new HashSet<E>();
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code HashSet} instance containing the given
+ * elements in unspecified order.
+ *
+ * <p><b>Note:</b> if mutability is not required and the elements are
+ * non-null, use an overload of {@link ImmutableSet#of()} (for varargs) or
+ * {@link ImmutableSet#copyOf(Object[])} (for an array) instead.
+ *
+ * <p><b>Note:</b> if {@code E} is an {@link Enum} type, use {@link
+ * EnumSet#of(Enum, Enum[])} instead.
+ *
+ * @param elements the elements that the set should contain
+ * @return a new {@code HashSet} containing those elements (minus duplicates)
+ */
+ public static <E> HashSet<E> newHashSet(E... elements) {
+ HashSet<E> set = newHashSetWithExpectedSize(elements.length);
+ Collections.addAll(set, elements);
+ return set;
+ }
+
+ /**
+ * Creates a {@code HashSet} instance, with a high enough "initial capacity"
+ * that it <i>should</i> hold {@code expectedSize} elements without growth.
+ * This behavior cannot be broadly guaranteed, but it is observed to be true
+ * for OpenJDK 1.6. It also can't be guaranteed that the method isn't
+ * inadvertently <i>oversizing</i> the returned set.
+ *
+ * @param expectedSize the number of elements you expect to add to the
+ * returned set
+ * @return a new, empty {@code HashSet} with enough capacity to hold {@code
+ * expectedSize} elements without resizing
+ * @throws IllegalArgumentException if {@code expectedSize} is negative
+ */
+ public static <E> HashSet<E> newHashSetWithExpectedSize(int expectedSize) {
+ return new HashSet<E>(Maps.capacity(expectedSize));
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code HashSet} instance containing the given
+ * elements in unspecified order.
+ *
+ * <p><b>Note:</b> if mutability is not required and the elements are
+ * non-null, use {@link ImmutableSet#copyOf(Iterable)} instead.
+ *
+ * <p><b>Note:</b> if {@code E} is an {@link Enum} type, use
+ * {@link #newEnumSet(Iterable, Class)} instead.
+ *
+ * @param elements the elements that the set should contain
+ * @return a new {@code HashSet} containing those elements (minus duplicates)
+ */
+ public static <E> HashSet<E> newHashSet(Iterable<? extends E> elements) {
+ return (elements instanceof Collection)
+ ? new HashSet<E>(Collections2.cast(elements))
+ : newHashSet(elements.iterator());
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code HashSet} instance containing the given
+ * elements in unspecified order.
+ *
+ * <p><b>Note:</b> if mutability is not required and the elements are
+ * non-null, use {@link ImmutableSet#copyOf(Iterable)} instead.
+ *
+ * <p><b>Note:</b> if {@code E} is an {@link Enum} type, you should create an
+ * {@link EnumSet} instead.
+ *
+ * @param elements the elements that the set should contain
+ * @return a new {@code HashSet} containing those elements (minus duplicates)
+ */
+ public static <E> HashSet<E> newHashSet(Iterator<? extends E> elements) {
+ HashSet<E> set = newHashSet();
+ while (elements.hasNext()) {
+ set.add(elements.next());
+ }
+ return set;
+ }
+
+ // LinkedHashSet
+
+ /**
+ * Creates a <i>mutable</i>, empty {@code LinkedHashSet} instance.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableSet#of()} instead.
+ *
+ * @return a new, empty {@code LinkedHashSet}
+ */
+ public static <E> LinkedHashSet<E> newLinkedHashSet() {
+ return new LinkedHashSet<E>();
+ }
+
+ /**
+ * Creates a {@code LinkedHashSet} instance, with a high enough "initial
+ * capacity" that it <i>should</i> hold {@code expectedSize} elements without
+ * growth. This behavior cannot be broadly guaranteed, but it is observed to
+ * be true for OpenJDK 1.6. It also can't be guaranteed that the method isn't
+ * inadvertently <i>oversizing</i> the returned set.
+ *
+ * @param expectedSize the number of elements you expect to add to the
+ * returned set
+ * @return a new, empty {@code LinkedHashSet} with enough capacity to hold
+ * {@code expectedSize} elements without resizing
+ * @throws IllegalArgumentException if {@code expectedSize} is negative
+ * @since 11.0
+ */
+ public static <E> LinkedHashSet<E> newLinkedHashSetWithExpectedSize(
+ int expectedSize) {
+ return new LinkedHashSet<E>(Maps.capacity(expectedSize));
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code LinkedHashSet} instance containing the
+ * given elements in order.
+ *
+ * <p><b>Note:</b> if mutability is not required and the elements are
+ * non-null, use {@link ImmutableSet#copyOf(Iterable)} instead.
+ *
+ * @param elements the elements that the set should contain, in order
+ * @return a new {@code LinkedHashSet} containing those elements (minus
+ * duplicates)
+ */
+ public static <E> LinkedHashSet<E> newLinkedHashSet(
+ Iterable<? extends E> elements) {
+ if (elements instanceof Collection) {
+ return new LinkedHashSet<E>(Collections2.cast(elements));
+ }
+ LinkedHashSet<E> set = newLinkedHashSet();
+ for (E element : elements) {
+ set.add(element);
+ }
+ return set;
+ }
+
+ // TreeSet
+
+ /**
+ * Creates a <i>mutable</i>, empty {@code TreeSet} instance sorted by the
+ * natural sort ordering of its elements.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableSortedSet#of()} instead.
+ *
+ * @return a new, empty {@code TreeSet}
+ */
+ public static <E extends Comparable> TreeSet<E> newTreeSet() {
+ return new TreeSet<E>();
+ }
+
+ /**
+ * Creates a <i>mutable</i> {@code TreeSet} instance containing the given
+ * elements sorted by their natural ordering.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@link
+ * ImmutableSortedSet#copyOf(Iterable)} instead.
+ *
+ * <p><b>Note:</b> If {@code elements} is a {@code SortedSet} with an explicit
+ * comparator, this method has different behavior than
+ * {@link TreeSet#TreeSet(SortedSet)}, which returns a {@code TreeSet} with
+ * that comparator.
+ *
+ * @param elements the elements that the set should contain
+ * @return a new {@code TreeSet} containing those elements (minus duplicates)
+ */
+ public static <E extends Comparable> TreeSet<E> newTreeSet(
+ Iterable<? extends E> elements) {
+ TreeSet<E> set = newTreeSet();
+ for (E element : elements) {
+ set.add(element);
+ }
+ return set;
+ }
+
+ /**
+ * Creates a <i>mutable</i>, empty {@code TreeSet} instance with the given
+ * comparator.
+ *
+ * <p><b>Note:</b> if mutability is not required, use {@code
+ * ImmutableSortedSet.orderedBy(comparator).build()} instead.
+ *
+ * @param comparator the comparator to use to sort the set
+ * @return a new, empty {@code TreeSet}
+ * @throws NullPointerException if {@code comparator} is null
+ */
+ public static <E> TreeSet<E> newTreeSet(Comparator<? super E> comparator) {
+ return new TreeSet<E>(checkNotNull(comparator));
+ }
+
+ /**
+ * Creates an empty {@code Set} that uses identity to determine equality. It
+ * compares object references, instead of calling {@code equals}, to
+ * determine whether a provided object matches an element in the set. For
+ * example, {@code contains} returns {@code false} when passed an object that
+ * equals a set member, but isn't the same instance. This behavior is similar
+ * to the way {@code IdentityHashMap} handles key lookups.
+ *
+ * @since 8.0
+ */
+ public static <E> Set<E> newIdentityHashSet() {
+ return Sets.newSetFromMap(Maps.<E, Boolean>newIdentityHashMap());
+ }
+
+ /**
+ * 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,
+ * the specified collection must contain at least one element, in order to
+ * determine the element type. If the collection could be empty, use
+ * {@link #complementOf(Collection, Class)} instead of this method.
+ *
+ * @param collection the collection whose complement should be stored in the
+ * enum set
+ * @return a new, modifiable {@code EnumSet} containing all values of the enum
+ * that aren't present in the given collection
+ * @throws IllegalArgumentException if {@code collection} is not an
+ * {@code EnumSet} instance and contains no elements
+ */
+ public static <E extends Enum<E>> EnumSet<E> complementOf(
+ Collection<E> collection) {
+ if (collection instanceof EnumSet) {
+ return EnumSet.complementOf((EnumSet<E>) collection);
+ }
+ checkArgument(!collection.isEmpty(),
+ "collection is empty; use the other version of this method");
+ Class<E> type = collection.iterator().next().getDeclaringClass();
+ return makeComplementByHand(collection, type);
+ }
+
+ /**
+ * Creates an {@code EnumSet} consisting of all enum values that are not in
+ * the specified collection. This is equivalent to
+ * {@link EnumSet#complementOf}, but can act on any input collection, as long
+ * as the elements are of enum type.
+ *
+ * @param collection the collection whose complement should be stored in the
+ * {@code EnumSet}
+ * @param type the type of the elements in the set
+ * @return a new, modifiable {@code EnumSet} initially containing all the
+ * values of the enum not present in the given collection
+ */
+ public static <E extends Enum<E>> EnumSet<E> complementOf(
+ Collection<E> collection, Class<E> type) {
+ checkNotNull(collection);
+ return (collection instanceof EnumSet)
+ ? EnumSet.complementOf((EnumSet<E>) collection)
+ : makeComplementByHand(collection, type);
+ }
+
+ private static <E extends Enum<E>> EnumSet<E> makeComplementByHand(
+ Collection<E> collection, Class<E> type) {
+ EnumSet<E> result = EnumSet.allOf(type);
+ result.removeAll(collection);
+ return result;
+ }
+
+ /*
+ * Regarding newSetForMap() and SetFromMap:
+ *
+ * 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
+ */
+
+ /**
+ * Returns a set backed by the specified map. The resulting set displays
+ * the same ordering, concurrency, and performance characteristics as the
+ * backing map. In essence, this factory method provides a {@link Set}
+ * implementation corresponding to any {@link Map} implementation. There is no
+ * need to use this method on a {@link Map} implementation that already has a
+ * corresponding {@link Set} implementation (such as {@link java.util.HashMap}
+ * or {@link java.util.TreeMap}).
+ *
+ * <p>Each method invocation on the set returned by this method results in
+ * exactly one method invocation on the backing map or its {@code keySet}
+ * view, with one exception. The {@code addAll} method is implemented as a
+ * sequence of {@code put} invocations on the backing map.
+ *
+ * <p>The specified map must be empty at the time this method is invoked,
+ * and should not be accessed directly after this method returns. These
+ * conditions are ensured if the map is created empty, passed directly
+ * to this method, and no reference to the map is retained, as illustrated
+ * in the following code fragment: <pre> {@code
+ *
+ * Set<Object> identityHashSet = Sets.newSetFromMap(
+ * new IdentityHashMap<Object, Boolean>());}</pre>
+ *
+ * This method has the same behavior as the JDK 6 method
+ * {@code Collections.newSetFromMap()}. The returned set is serializable if
+ * the backing map is.
+ *
+ * @param map the backing map
+ * @return the set backed by the map
+ * @throws IllegalArgumentException if {@code map} is not empty
+ */
+ public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
+ return new SetFromMap<E>(map);
+ }
+
+ private static class SetFromMap<E> extends AbstractSet<E>
+ implements Set<E>, Serializable {
+ private final Map<E, Boolean> m; // The backing map
+ private transient Set<E> s; // Its keySet
+
+ SetFromMap(Map<E, Boolean> map) {
+ checkArgument(map.isEmpty(), "Map is non-empty");
+ m = map;
+ s = map.keySet();
+ }
+
+ @Override public void clear() {
+ m.clear();
+ }
+ @Override public int size() {
+ return m.size();
+ }
+ @Override public boolean isEmpty() {
+ return m.isEmpty();
+ }
+ @Override public boolean contains(Object o) {
+ return m.containsKey(o);
+ }
+ @Override public boolean remove(Object o) {
+ return m.remove(o) != null;
+ }
+ @Override public boolean add(E e) {
+ return m.put(e, Boolean.TRUE) == null;
+ }
+ @Override public Iterator<E> iterator() {
+ return s.iterator();
+ }
+ @Override public Object[] toArray() {
+ return s.toArray();
+ }
+ @Override public <T> T[] toArray(T[] a) {
+ return s.toArray(a);
+ }
+ @Override public String toString() {
+ return s.toString();
+ }
+ @Override public int hashCode() {
+ return s.hashCode();
+ }
+ @Override public boolean equals(@Nullable Object object) {
+ return this == object || this.s.equals(object);
+ }
+ @Override public boolean containsAll(Collection<?> c) {
+ return s.containsAll(c);
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return s.removeAll(c);
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ return s.retainAll(c);
+ }
+
+ // addAll is the only inherited implementation
+ @GwtIncompatible("not needed in emulated source")
+ private static final long serialVersionUID = 0;
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ s = m.keySet();
+ }
+ }
+
+ /**
+ * An unmodifiable view of a set which may be backed by other sets; this view
+ * will change as the backing sets do. Contains methods to copy the data into
+ * a new set which will then remain stable. There is usually no reason to
+ * retain a reference of type {@code SetView}; typically, you either use it
+ * as a plain {@link Set}, or immediately invoke {@link #immutableCopy} or
+ * {@link #copyInto} and forget the {@code SetView} itself.
+ *
+ * @since 2.0 (imported from Google Collections Library)
+ */
+ public abstract static class SetView<E> extends AbstractSet<E> {
+ private SetView() {} // no subclasses but our own
+
+ /**
+ * Returns an immutable copy of the current contents of this set view.
+ * Does not support null elements.
+ *
+ * <p><b>Warning:</b> this may have unexpected results if a backing set of
+ * this view uses a nonstandard notion of equivalence, for example if it is
+ * a {@link TreeSet} using a comparator that is inconsistent with {@link
+ * Object#equals(Object)}.
+ */
+ public ImmutableSet<E> immutableCopy() {
+ return ImmutableSet.copyOf(this);
+ }
+
+ /**
+ * Copies the current contents of this set view into an existing set. This
+ * method has equivalent behavior to {@code set.addAll(this)}, assuming that
+ * all the sets involved are based on the same notion of equivalence.
+ *
+ * @return a reference to {@code set}, for convenience
+ */
+ // Note: S should logically extend Set<? super E> but can't due to either
+ // some javac bug or some weirdness in the spec, not sure which.
+ public <S extends Set<E>> S copyInto(S set) {
+ set.addAll(this);
+ return set;
+ }
+ }
+
+ /**
+ * Returns an unmodifiable <b>view</b> of the union of two sets. The returned
+ * set contains all elements that are contained in either backing set.
+ * Iterating over the returned set iterates first over all the elements of
+ * {@code set1}, then over each element of {@code set2}, in order, that is not
+ * contained in {@code set1}.
+ *
+ * <p>Results are undefined if {@code set1} and {@code set2} are sets based on
+ * different equivalence relations (as {@link HashSet}, {@link TreeSet}, and
+ * the {@link Map#keySet} of an {@code IdentityHashMap} all are).
+ *
+ * <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) {
+ checkNotNull(set1, "set1");
+ checkNotNull(set2, "set2");
+
+ final Set<? extends E> set2minus1 = difference(set2, set1);
+
+ return new SetView<E>() {
+ @Override public int size() {
+ return set1.size() + set2minus1.size();
+ }
+ @Override public boolean isEmpty() {
+ return set1.isEmpty() && set2.isEmpty();
+ }
+ @Override public Iterator<E> iterator() {
+ return Iterators.unmodifiableIterator(
+ Iterators.concat(set1.iterator(), set2minus1.iterator()));
+ }
+ @Override public boolean contains(Object object) {
+ return set1.contains(object) || set2.contains(object);
+ }
+ @Override public <S extends Set<E>> S copyInto(S set) {
+ set.addAll(set1);
+ set.addAll(set2);
+ return set;
+ }
+ @Override public ImmutableSet<E> immutableCopy() {
+ return new ImmutableSet.Builder<E>()
+ .addAll(set1).addAll(set2).build();
+ }
+ };
+ }
+
+ /**
+ * Returns an unmodifiable <b>view</b> of the intersection of two sets. The
+ * returned set contains all elements that are contained by both backing sets.
+ * The iteration order of the returned set matches that of {@code set1}.
+ *
+ * <p>Results are undefined if {@code set1} and {@code set2} are sets based
+ * on different equivalence relations (as {@code HashSet}, {@code TreeSet},
+ * and the keySet of an {@code IdentityHashMap} all are).
+ *
+ * <p><b>Note:</b> The returned view performs slightly 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.
+ * Unfortunately, since this method sets the generic type of the returned set
+ * based on the type of the first set passed, this could in rare cases force
+ * you to make a cast, for example: <pre> {@code
+ *
+ * Set<Object> aFewBadObjects = ...
+ * Set<String> manyBadStrings = ...
+ *
+ * // impossible for a non-String to be in the intersection
+ * SuppressWarnings("unchecked")
+ * Set<String> badStrings = (Set) Sets.intersection(
+ * aFewBadObjects, manyBadStrings);}</pre>
+ *
+ * This is unfortunate, but should come up only very rarely.
+ */
+ public static <E> SetView<E> intersection(
+ final Set<E> set1, final Set<?> set2) {
+ checkNotNull(set1, "set1");
+ checkNotNull(set2, "set2");
+
+ final Predicate<Object> inSet2 = Predicates.in(set2);
+ return new SetView<E>() {
+ @Override public Iterator<E> iterator() {
+ return Iterators.filter(set1.iterator(), inSet2);
+ }
+ @Override public int size() {
+ return Iterators.size(iterator());
+ }
+ @Override public boolean isEmpty() {
+ return !iterator().hasNext();
+ }
+ @Override public boolean contains(Object object) {
+ return set1.contains(object) && set2.contains(object);
+ }
+ @Override public boolean containsAll(Collection<?> collection) {
+ return set1.containsAll(collection)
+ && set2.containsAll(collection);
+ }
+ };
+ }
+
+ /**
+ * Returns an unmodifiable <b>view</b> of the difference of two sets. The
+ * returned set contains all elements that are contained by {@code set1} and
+ * not contained by {@code set2}. {@code set2} may also contain elements not
+ * present in {@code set1}; these are simply ignored. The iteration order of
+ * the returned set matches that of {@code set1}.
+ *
+ * <p>Results are undefined if {@code set1} and {@code set2} are sets based
+ * on different equivalence relations (as {@code HashSet}, {@code TreeSet},
+ * and the keySet of an {@code IdentityHashMap} all are).
+ */
+ public static <E> SetView<E> difference(
+ final Set<E> set1, final Set<?> set2) {
+ checkNotNull(set1, "set1");
+ checkNotNull(set2, "set2");
+
+ final Predicate<Object> notInSet2 = Predicates.not(Predicates.in(set2));
+ return new SetView<E>() {
+ @Override public Iterator<E> iterator() {
+ return Iterators.filter(set1.iterator(), notInSet2);
+ }
+ @Override public int size() {
+ return Iterators.size(iterator());
+ }
+ @Override public boolean isEmpty() {
+ return set2.containsAll(set1);
+ }
+ @Override public boolean contains(Object element) {
+ return set1.contains(element) && !set2.contains(element);
+ }
+ };
+ }
+
+ /**
+ * Returns an unmodifiable <b>view</b> of the symmetric difference of two
+ * sets. The returned set contains all elements that are contained in either
+ * {@code set1} or {@code set2} but not in both. The iteration order of the
+ * returned set is undefined.
+ *
+ * <p>Results are undefined if {@code set1} and {@code set2} are sets based
+ * on different equivalence relations (as {@code HashSet}, {@code TreeSet},
+ * and the keySet of an {@code IdentityHashMap} all are).
+ *
+ * @since 3.0
+ */
+ public static <E> SetView<E> symmetricDifference(
+ Set<? extends E> set1, Set<? extends E> set2) {
+ checkNotNull(set1, "set1");
+ checkNotNull(set2, "set2");
+
+ // TODO(kevinb): Replace this with a more efficient implementation
+ return difference(union(set1, set2), intersection(set1, set2));
+ }
+
+ /**
+ * Returns the elements of {@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.)
+ */
+ // TODO(kevinb): how to omit that last sentence when building GWT javadoc?
+ public static <E> Set<E> filter(
+ Set<E> unfiltered, Predicate<? super E> predicate) {
+ if (unfiltered instanceof SortedSet) {
+ return filter((SortedSet<E>) unfiltered, 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 FilteredSet<E>(
+ (Set<E>) filtered.unfiltered, combinedPredicate);
+ }
+
+ return new FilteredSet<E>(
+ checkNotNull(unfiltered), checkNotNull(predicate));
+ }
+
+ private static class FilteredSet<E> extends FilteredCollection<E>
+ implements Set<E> {
+ FilteredSet(Set<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);
+ }
+ }
+
+ /**
+ * Returns the elements of a {@code SortedSet}, {@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 11.0
+ */
+ @SuppressWarnings("unchecked")
+ public static <E> SortedSet<E> filter(
+ SortedSet<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 FilteredSortedSet<E>(
+ (SortedSet<E>) filtered.unfiltered, combinedPredicate);
+ }
+
+ return new FilteredSortedSet<E>(
+ checkNotNull(unfiltered), checkNotNull(predicate));
+ }
+
+ 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();
+ }
+
+ @Override
+ public SortedSet<E> subSet(E fromElement, E toElement) {
+ return new FilteredSortedSet<E>(((SortedSet<E>) unfiltered).subSet(fromElement, toElement),
+ predicate);
+ }
+
+ @Override
+ public SortedSet<E> headSet(E toElement) {
+ return new FilteredSortedSet<E>(((SortedSet<E>) unfiltered).headSet(toElement), predicate);
+ }
+
+ @Override
+ public SortedSet<E> tailSet(E fromElement) {
+ return new FilteredSortedSet<E>(((SortedSet<E>) unfiltered).tailSet(fromElement), predicate);
+ }
+
+ @Override
+ public E first() {
+ return iterator().next();
+ }
+
+ @Override
+ public E last() {
+ SortedSet<E> sortedUnfiltered = (SortedSet<E>) unfiltered;
+ while (true) {
+ E element = sortedUnfiltered.last();
+ if (predicate.apply(element)) {
+ return element;
+ }
+ sortedUnfiltered = sortedUnfiltered.headSet(element);
+ }
+ }
+ }
+
+ /**
+ * 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
+ * product</a>" of the sets. For example: <pre> {@code
+ *
+ * Sets.cartesianProduct(ImmutableList.of(
+ * ImmutableSet.of(1, 2),
+ * ImmutableSet.of("A", "B", "C")))}</pre>
+ *
+ * returns a set containing six lists:
+ *
+ * <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 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
+ * consumption is much smaller. When the cartesian set is constructed, the
+ * input sets are merely copied. Only as the resulting set is iterated are the
+ * individual lists created, and these are not retained after iteration.
+ *
+ * @param sets the sets to choose elements from, in the order that
+ * the elements chosen from those sets 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 set containing immutable
+ * lists
+ * @throws NullPointerException if {@code sets}, any one of the {@code sets},
+ * or any element of a provided set is null
+ * @since 2.0
+ */
+ public static <B> Set<List<B>> cartesianProduct(
+ List<? extends Set<? extends B>> sets) {
+ for (Set<? extends B> set : sets) {
+ if (set.isEmpty()) {
+ return ImmutableSet.of();
+ }
+ }
+ CartesianSet<B> cartesianSet = new CartesianSet<B>(sets);
+ return cartesianSet;
+ }
+
+ /**
+ * 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
+ * product</a>" of the sets. For example: <pre> {@code
+ *
+ * Sets.cartesianProduct(
+ * ImmutableSet.of(1, 2),
+ * ImmutableSet.of("A", "B", "C"))}</pre>
+ *
+ * returns a set containing six lists:
+ *
+ * <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 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
+ * consumption is much smaller. When the cartesian set is constructed, the
+ * input sets are merely copied. Only as the resulting set is iterated are the
+ * individual lists created, and these are not retained after iteration.
+ *
+ * @param sets the sets to choose elements from, in the order that
+ * the elements chosen from those sets 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 set containing immutable
+ * lists
+ * @throws NullPointerException if {@code sets}, any one of the {@code sets},
+ * or any element of a provided set is null
+ * @since 2.0
+ */
+ public static <B> Set<List<B>> cartesianProduct(
+ Set<? extends B>... sets) {
+ return cartesianProduct(Arrays.asList(sets));
+ }
+
+ 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());
+ }
+ } catch (ArithmeticException overflow) {
+ throw new IllegalArgumentException("cartesian product too big");
+ }
+ this.axes = builder.build();
+ size = dividend;
+ }
+
+ @Override public int size() {
+ return size;
+ }
+
+ @Override public UnmodifiableIterator<List<B>> iterator() {
+ return new AbstractIndexedListIterator<List<B>>(size) {
+ @Override
+ protected List<B> get(int index) {
+ Object[] tuple = new Object[axes.size()];
+ for (int i = 0 ; i < tuple.length; i++) {
+ tuple[i] = axes.get(i).getForIndex(index);
+ }
+
+ @SuppressWarnings("unchecked") // only B's are put in here
+ List<B> result = (ImmutableList<B>) ImmutableList.copyOf(tuple);
+ return result;
+ }
+ };
+ }
+
+ @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) {
+ // Warning: this is broken if size() == 0, so it is critical that we
+ // substitute an empty ImmutableSet to the user in place of this
+ if (object instanceof CartesianSet) {
+ CartesianSet<?> that = (CartesianSet<?>) object;
+ return this.axes.equals(that.axes);
+ }
+ return super.equals(object);
+ }
+
+ @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;
+ for (int i = 0; i < axes.size(); i++) {
+ adjust *= 31;
+ }
+ 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;
+ }
+
+ @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();
+ }
+ }
+ }
+
+ /**
+ * Returns the set of all possible subsets of {@code set}. For example,
+ * {@code powerSet(ImmutableSet.of(1, 2))} returns the set {@code {{},
+ * {1}, {2}, {1, 2}}}.
+ *
+ * <p>Elements appear in these subsets in the same iteration order as they
+ * appeared in the input set. The order in which these subsets appear in the
+ * outer set is undefined. Note that the power set of the empty set is not the
+ * empty set, but a one-element set containing the empty set.
+ *
+ * <p>The returned set and its constituent sets use {@code equals} to decide
+ * whether two elements are identical, even if the input set uses a different
+ * concept of equivalence.
+ *
+ * <p><i>Performance notes:</i> while the power set of a set with size {@code
+ * n} is of size {@code 2^n}, its memory usage is only {@code O(n)}. When the
+ * power set is constructed, the input set is merely copied. Only as the
+ * power set is iterated are the individual subsets created, and these subsets
+ * themselves occupy only a few bytes of memory regardless of their size.
+ *
+ * @param set the set of elements to construct a power set from
+ * @return the power set, as an immutable set of immutable sets
+ * @throws IllegalArgumentException if {@code set} has more than 30 unique
+ * elements (causing the power set size to exceed the {@code int} range)
+ * @throws NullPointerException if {@code set} is or contains {@code null}
+ * @see <a href="http://en.wikipedia.org/wiki/Power_set">Power set article at
+ * Wikipedia</a>
+ * @since 4.0
+ */
+ @GwtCompatible(serializable = false)
+ public static <E> Set<Set<E>> powerSet(Set<E> set) {
+ ImmutableSet<E> input = ImmutableSet.copyOf(set);
+ checkArgument(input.size() <= 30,
+ "Too many elements to create power set: %s > 30", input.size());
+ return new PowerSet<E>(input);
+ }
+
+ private static final class PowerSet<E> extends AbstractSet<Set<E>> {
+ final ImmutableSet<E> inputSet;
+ final ImmutableList<E> inputList;
+ final int powerSetSize;
+
+ PowerSet(ImmutableSet<E> input) {
+ this.inputSet = input;
+ this.inputList = input.asList();
+ this.powerSetSize = 1 << input.size();
+ }
+
+ @Override public int size() {
+ return powerSetSize;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public Iterator<Set<E>> iterator() {
+ return new AbstractIndexedListIterator<Set<E>>(powerSetSize) {
+ @Override protected Set<E> get(final int setBits) {
+ return new AbstractSet<E>() {
+ @Override public int size() {
+ return Integer.bitCount(setBits);
+ }
+ @Override public Iterator<E> iterator() {
+ return new BitFilteredSetIterator<E>(inputList, setBits);
+ }
+ };
+ }
+ };
+ }
+
+ private static final class BitFilteredSetIterator<E>
+ extends UnmodifiableIterator<E> {
+ final ImmutableList<E> input;
+ int remainingSetBits;
+
+ BitFilteredSetIterator(ImmutableList<E> input, int allSetBits) {
+ this.input = input;
+ this.remainingSetBits = allSetBits;
+ }
+
+ @Override public boolean hasNext() {
+ return remainingSetBits != 0;
+ }
+
+ @Override public E next() {
+ int index = Integer.numberOfTrailingZeros(remainingSetBits);
+ if (index == 32) {
+ throw new NoSuchElementException();
+ }
+
+ int currentElementMask = 1 << index;
+ remainingSetBits &= ~currentElementMask;
+ return input.get(index);
+ }
+ }
+
+ @Override public boolean contains(@Nullable Object obj) {
+ if (obj instanceof Set) {
+ Set<?> set = (Set<?>) obj;
+ return inputSet.containsAll(set);
+ }
+ return false;
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof PowerSet) {
+ PowerSet<?> that = (PowerSet<?>) obj;
+ return inputSet.equals(that.inputSet);
+ }
+ return super.equals(obj);
+ }
+
+ @Override public int hashCode() {
+ /*
+ * The sum of the sums of the hash codes in each subset is just the sum of
+ * each input element's hash code times the number of sets that element
+ * appears in. Each element appears in exactly half of the 2^n sets, so:
+ */
+ return inputSet.hashCode() << (inputSet.size() - 1);
+ }
+
+ @Override public String toString() {
+ return "powerSet(" + inputSet + ")";
+ }
+ }
+
+ /**
+ * An implementation for {@link Set#hashCode()}.
+ */
+ static int hashCodeImpl(Set<?> s) {
+ int hashCode = 0;
+ for (Object o : s) {
+ hashCode += o != null ? o.hashCode() : 0;
+ }
+ return hashCode;
+ }
+
+ /**
+ * An implementation for {@link Set#equals(Object)}.
+ */
+ static boolean equalsImpl(Set<?> s, @Nullable Object object){
+ if (s == object) {
+ return true;
+ }
+ if (object instanceof Set) {
+ Set<?> o = (Set<?>) object;
+
+ try {
+ return s.size() == o.size() && s.containsAll(o);
+ } catch (NullPointerException ignored) {
+ return false;
+ } catch (ClassCastException ignored) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 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
+ */
+ @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);
+ }
+
+ @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);
+ }
+
+ @Override
+ public E lower(E e) {
+ return delegate.lower(e);
+ }
+
+ @Override
+ public E floor(E e) {
+ return delegate.floor(e);
+ }
+
+ @Override
+ public E ceiling(E e) {
+ return delegate.ceiling(e);
+ }
+
+ @Override
+ public E higher(E e) {
+ return delegate.higher(e);
+ }
+
+ @Override
+ public E pollFirst() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public E pollLast() {
+ throw new UnsupportedOperationException();
+ }
+
+ 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 Iterator<E> descendingIterator() {
+ return Iterators.unmodifiableIterator(delegate.descendingIterator());
+ }
+
+ @Override
+ public NavigableSet<E> subSet(
+ E fromElement,
+ boolean fromInclusive,
+ E toElement,
+ boolean toInclusive) {
+ return unmodifiableNavigableSet(delegate.subSet(
+ fromElement,
+ fromInclusive,
+ toElement,
+ toInclusive));
+ }
+
+ @Override
+ public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+ return unmodifiableNavigableSet(delegate.headSet(toElement, inclusive));
+ }
+
+ @Override
+ public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+ return unmodifiableNavigableSet(
+ delegate.tailSet(fromElement, inclusive));
+ }
+
+ 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
+ */
+ @Beta
+ @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) {
+ boolean changed = false;
+ while (iterator.hasNext()) {
+ changed |= set.remove(iterator.next());
+ }
+ 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/SingletonImmutableList.java b/guava/src/com/google/common/collect/SingletonImmutableList.java
new file mode 100644
index 0000000..07659a0
--- /dev/null
+++ b/guava/src/com/google/common/collect/SingletonImmutableList.java
@@ -0,0 +1,128 @@
+/*
+ * 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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Preconditions;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * Implementation of {@link ImmutableList} with exactly one element.
+ *
+ * @author Hayward Chan
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // uses writeReplace(), not default serialization
+final class SingletonImmutableList<E> extends ImmutableList<E> {
+
+ final transient E element;
+
+ SingletonImmutableList(E element) {
+ this.element = checkNotNull(element);
+ }
+
+ @Override
+ public E get(int index) {
+ Preconditions.checkElementIndex(index, 1);
+ return element;
+ }
+
+ @Override public int indexOf(@Nullable Object object) {
+ return element.equals(object) ? 0 : -1;
+ }
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ return Iterators.singletonIterator(element);
+ }
+
+ @Override public int lastIndexOf(@Nullable Object object) {
+ return indexOf(object);
+ }
+
+ @Override
+ public int size() {
+ return 1;
+ }
+
+ @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
+ Preconditions.checkPositionIndexes(fromIndex, toIndex, 1);
+ return (fromIndex == toIndex) ? ImmutableList.<E>of() : this;
+ }
+
+ @Override public ImmutableList<E> reverse() {
+ return this;
+ }
+
+ @Override public boolean contains(@Nullable Object object) {
+ return element.equals(object);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof List) {
+ List<?> that = (List<?>) object;
+ return that.size() == 1 && element.equals(that.get(0));
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ // not caching hash code since it could change if the element is mutable
+ // in a way that modifies its hash code.
+ return 31 + element.hashCode();
+ }
+
+ @Override public String toString() {
+ String elementToString = element.toString();
+ return new StringBuilder(elementToString.length() + 2)
+ .append('[')
+ .append(elementToString)
+ .append(']')
+ .toString();
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public Object[] toArray() {
+ return new Object[] { element };
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ if (array.length == 0) {
+ array = ObjectArrays.newArray(array, 1);
+ } else if (array.length > 1) {
+ array[1] = null;
+ }
+ // Writes will produce ArrayStoreException when the toArray() doc requires.
+ Object[] objectArray = array;
+ objectArray[0] = element;
+ return array;
+ }
+}
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..7345a95
--- /dev/null
+++ b/guava/src/com/google/common/collect/SingletonImmutableMap.java
@@ -0,0 +1,105 @@
+/*
+ * 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;
+
+ SingletonImmutableMap(K singleKey, V singleValue) {
+ this.singleKey = singleKey;
+ this.singleValue = singleValue;
+ }
+
+ SingletonImmutableMap(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 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;
+ }
+
+ @Override
+ ImmutableSet<Entry<K, V>> createEntrySet() {
+ return ImmutableSet.of(Maps.immutableEntry(singleKey, singleValue));
+ }
+
+ @Override
+ ImmutableSet<K> createKeySet() {
+ return ImmutableSet.of(singleKey);
+ }
+
+ @Override
+ ImmutableCollection<V> createValues() {
+ return ImmutableList.of(singleValue);
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Map) {
+ Map<?, ?> that = (Map<?, ?>) object;
+ if (that.size() == 1) {
+ 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();
+ }
+}
diff --git a/guava/src/com/google/common/collect/SingletonImmutableSet.java b/guava/src/com/google/common/collect/SingletonImmutableSet.java
new file mode 100644
index 0000000..f64aac1
--- /dev/null
+++ b/guava/src/com/google/common/collect/SingletonImmutableSet.java
@@ -0,0 +1,125 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Preconditions;
+
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * Implementation of {@link ImmutableSet} with exactly one element.
+ *
+ * @author Kevin Bourrillion
+ * @author Nick Kralevich
+ */
+@GwtCompatible(serializable = true, emulated = true)
+@SuppressWarnings("serial") // uses writeReplace(), not default serialization
+final class SingletonImmutableSet<E> extends ImmutableSet<E> {
+
+ final transient E element;
+ // This is transient because it will be recalculated on the first
+ // call to hashCode().
+ //
+ // A race condition is avoided since threads will either see that the value
+ // is zero and recalculate it themselves, or two threads will see it at
+ // the same time, and both recalculate it. If the cachedHashCode is 0,
+ // it will always be recalculated, unfortunately.
+ private transient int cachedHashCode;
+
+ SingletonImmutableSet(E element) {
+ this.element = Preconditions.checkNotNull(element);
+ }
+
+ SingletonImmutableSet(E element, int hashCode) {
+ // Guaranteed to be non-null by the presence of the pre-computed hash code.
+ this.element = element;
+ cachedHashCode = hashCode;
+ }
+
+ @Override
+ public int size() {
+ return 1;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public boolean contains(Object target) {
+ return element.equals(target);
+ }
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ return Iterators.singletonIterator(element);
+ }
+
+ @Override boolean isPartialView() {
+ return false;
+ }
+
+ @Override public Object[] toArray() {
+ return new Object[] { element };
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ if (array.length == 0) {
+ array = ObjectArrays.newArray(array, 1);
+ } else if (array.length > 1) {
+ array[1] = null;
+ }
+ // Writes will produce ArrayStoreException when the toArray() doc requires.
+ Object[] objectArray = array;
+ objectArray[0] = element;
+ return array;
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Set) {
+ Set<?> that = (Set<?>) object;
+ return that.size() == 1 && element.equals(that.iterator().next());
+ }
+ return false;
+ }
+
+ @Override public final int hashCode() {
+ // Racy single-check.
+ int code = cachedHashCode;
+ if (code == 0) {
+ cachedHashCode = code = element.hashCode();
+ }
+ return code;
+ }
+
+ @Override boolean isHashCodeFast() {
+ return cachedHashCode != 0;
+ }
+
+ @Override public String toString() {
+ String elementToString = element.toString();
+ return new StringBuilder(elementToString.length() + 2)
+ .append('[')
+ .append(elementToString)
+ .append(']')
+ .toString();
+ }
+}
diff --git a/guava/src/com/google/common/collect/SingletonImmutableTable.java b/guava/src/com/google/common/collect/SingletonImmutableTable.java
new file mode 100644
index 0000000..e6e850c
--- /dev/null
+++ b/guava/src/com/google/common/collect/SingletonImmutableTable.java
@@ -0,0 +1,149 @@
+/*
+ * 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;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Objects;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * An implementation of {@link ImmutableTable} that holds a single cell.
+ *
+ * @author Gregory Kick
+ */
+@GwtCompatible
+final class SingletonImmutableTable<R, C, V> extends ImmutableTable<R, C, V> {
+ private final R singleRowKey;
+ private final C singleColumnKey;
+ private final V singleValue;
+
+ SingletonImmutableTable(R rowKey, C columnKey, V value) {
+ this.singleRowKey = checkNotNull(rowKey);
+ this.singleColumnKey = checkNotNull(columnKey);
+ this.singleValue = checkNotNull(value);
+ }
+
+ SingletonImmutableTable(Cell<R, C, V> cell) {
+ this(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
+ }
+
+ @Override public ImmutableSet<Cell<R, C, V>> cellSet() {
+ return ImmutableSet.of(
+ Tables.immutableCell(singleRowKey, singleColumnKey, singleValue));
+ }
+
+ @Override public ImmutableMap<R, V> column(C columnKey) {
+ checkNotNull(columnKey);
+ return containsColumn(columnKey)
+ ? ImmutableMap.of(singleRowKey, singleValue)
+ : ImmutableMap.<R, V>of();
+ }
+
+ @Override public ImmutableSet<C> columnKeySet() {
+ return ImmutableSet.of(singleColumnKey);
+ }
+
+ @Override public ImmutableMap<C, Map<R, V>> columnMap() {
+ return ImmutableMap.of(singleColumnKey,
+ (Map<R, V>) ImmutableMap.of(singleRowKey, singleValue));
+ }
+
+ @Override public boolean contains(@Nullable Object rowKey,
+ @Nullable Object columnKey) {
+ return containsRow(rowKey) && containsColumn(columnKey);
+ }
+
+ @Override public boolean containsColumn(@Nullable Object columnKey) {
+ return Objects.equal(this.singleColumnKey, columnKey);
+ }
+
+ @Override public boolean containsRow(@Nullable Object rowKey) {
+ return Objects.equal(this.singleRowKey, rowKey);
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ return Objects.equal(this.singleValue, value);
+ }
+
+ @Override public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
+ return contains(rowKey, columnKey) ? singleValue : null;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public ImmutableMap<C, V> row(R rowKey) {
+ checkNotNull(rowKey);
+ return containsRow(rowKey)
+ ? ImmutableMap.of(singleColumnKey, singleValue)
+ : ImmutableMap.<C, V>of();
+ }
+
+ @Override public ImmutableSet<R> rowKeySet() {
+ return ImmutableSet.of(singleRowKey);
+ }
+
+ @Override public ImmutableMap<R, Map<C, V>> rowMap() {
+ return ImmutableMap.of(singleRowKey,
+ (Map<C, V>) ImmutableMap.of(singleColumnKey, singleValue));
+ }
+
+ @Override public int size() {
+ return 1;
+ }
+
+ @Override public ImmutableCollection<V> values() {
+ return ImmutableSet.of(singleValue);
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (obj instanceof Table) {
+ Table<?, ?, ?> that = (Table<?, ?, ?>) obj;
+ if (that.size() == 1) {
+ Cell<?, ?, ?> thatCell = that.cellSet().iterator().next();
+ return Objects.equal(this.singleRowKey, thatCell.getRowKey()) &&
+ Objects.equal(this.singleColumnKey, thatCell.getColumnKey()) &&
+ Objects.equal(this.singleValue, thatCell.getValue());
+ }
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(singleRowKey, singleColumnKey, singleValue);
+ }
+
+ @Override public String toString() {
+ return new StringBuilder()
+ .append('{')
+ .append(singleRowKey)
+ .append("={")
+ .append(singleColumnKey)
+ .append('=')
+ .append(singleValue)
+ .append("}}")
+ .toString();
+ }
+}
diff --git a/guava/src/com/google/common/collect/SortedIterable.java b/guava/src/com/google/common/collect/SortedIterable.java
new file mode 100644
index 0000000..e859114
--- /dev/null
+++ b/guava/src/com/google/common/collect/SortedIterable.java
@@ -0,0 +1,42 @@
+/*
+ * 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 java.util.Comparator;
+import java.util.Iterator;
+
+/**
+ * An {@code Iterable} whose elements are sorted relative to a {@code Comparator}, typically
+ * provided at creation time.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+interface SortedIterable<T> extends Iterable<T> {
+ /**
+ * Returns the {@code Comparator} by which the elements of this iterable are ordered, or {@code
+ * Ordering.natural()} if the elements are ordered by their natural ordering.
+ */
+ Comparator<? super T> comparator();
+
+ /**
+ * Returns an iterator over elements of type {@code T}. The elements are returned in
+ * nondecreasing order according to the associated {@link #comparator}.
+ */
+ @Override
+ Iterator<T> iterator();
+}
diff --git a/guava/src/com/google/common/collect/SortedIterables.java b/guava/src/com/google/common/collect/SortedIterables.java
new file mode 100644
index 0000000..2158e9f
--- /dev/null
+++ b/guava/src/com/google/common/collect/SortedIterables.java
@@ -0,0 +1,60 @@
+/*
+ * 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 java.util.Comparator;
+import java.util.SortedSet;
+
+/**
+ * Utilities for dealing with sorted collections of all types.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+final class SortedIterables {
+ private SortedIterables() {}
+
+ /**
+ * Returns {@code true} if {@code elements} is a sorted collection using an ordering equivalent
+ * to {@code comparator}.
+ */
+ public static boolean hasSameComparator(Comparator<?> comparator, Iterable<?> elements) {
+ checkNotNull(comparator);
+ checkNotNull(elements);
+ Comparator<?> comparator2;
+ if (elements instanceof SortedSet) {
+ comparator2 = comparator((SortedSet<?>) elements);
+ } else if (elements instanceof SortedIterable) {
+ comparator2 = ((SortedIterable<?>) elements).comparator();
+ } else {
+ return false;
+ }
+ return comparator.equals(comparator2);
+ }
+
+ @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();
+ }
+ return result;
+ }
+}
diff --git a/guava/src/com/google/common/collect/SortedLists.java b/guava/src/com/google/common/collect/SortedLists.java
new file mode 100644
index 0000000..6fc0d71
--- /dev/null
+++ b/guava/src/com/google/common/collect/SortedLists.java
@@ -0,0 +1,284 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Function;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.RandomAccess;
+
+import javax.annotation.Nullable;
+
+/**
+ * Static methods pertaining to sorted {@link List} instances.
+ *
+ * In this documentation, the terms <i>greatest</i>, <i>greater</i>, <i>least</i>, and
+ * <i>lesser</i> are considered to refer to the comparator on the elements, and the terms
+ * <i>first</i> and <i>last</i> are considered to refer to the elements' ordering in a
+ * list.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+@Beta final class SortedLists {
+ private SortedLists() {}
+
+ /**
+ * A specification for which index to return if the list contains at least one element that
+ * compares as equal to the key.
+ */
+ public enum KeyPresentBehavior {
+ /**
+ * Return the index of any list element that compares as equal to the key. No guarantees are
+ * made as to which index is returned, if more than one element compares as equal to the key.
+ */
+ ANY_PRESENT {
+ @Override
+ <E> int resultIndex(
+ Comparator<? super E> comparator, E key, List<? extends E> list, int foundIndex) {
+ return foundIndex;
+ }
+ },
+ /**
+ * Return the index of the last list element that compares as equal to the key.
+ */
+ LAST_PRESENT {
+ @Override
+ <E> int resultIndex(
+ Comparator<? super E> comparator, E key, List<? extends E> list, int foundIndex) {
+ // Of course, we have to use binary search to find the precise
+ // breakpoint...
+ int lower = foundIndex;
+ int upper = list.size() - 1;
+ // Everything between lower and upper inclusive compares at >= 0.
+ while (lower < upper) {
+ int middle = (lower + upper + 1) >>> 1;
+ int c = comparator.compare(list.get(middle), key);
+ if (c > 0) {
+ upper = middle - 1;
+ } else { // c == 0
+ lower = middle;
+ }
+ }
+ return lower;
+ }
+ },
+ /**
+ * Return the index of the first list element that compares as equal to the key.
+ */
+ FIRST_PRESENT {
+ @Override
+ <E> int resultIndex(
+ Comparator<? super E> comparator, E key, List<? extends E> list, int foundIndex) {
+ // Of course, we have to use binary search to find the precise
+ // breakpoint...
+ int lower = 0;
+ int upper = foundIndex;
+ // Of course, we have to use binary search to find the precise breakpoint...
+ // Everything between lower and upper inclusive compares at <= 0.
+ while (lower < upper) {
+ int middle = (lower + upper) >>> 1;
+ int c = comparator.compare(list.get(middle), key);
+ if (c < 0) {
+ lower = middle + 1;
+ } else { // c == 0
+ upper = middle;
+ }
+ }
+ return lower;
+ }
+ },
+ /**
+ * Return the index of the first list element that compares as greater than the key, or {@code
+ * list.size()} if there is no such element.
+ */
+ FIRST_AFTER {
+ @Override
+ public <E> int resultIndex(
+ Comparator<? super E> comparator, E key, List<? extends E> list, int foundIndex) {
+ return LAST_PRESENT.resultIndex(comparator, key, list, foundIndex) + 1;
+ }
+ },
+ /**
+ * Return the index of the last list element that compares as less than the key, or {@code -1}
+ * if there is no such element.
+ */
+ LAST_BEFORE {
+ @Override
+ public <E> int resultIndex(
+ Comparator<? super E> comparator, E key, List<? extends E> list, int foundIndex) {
+ return FIRST_PRESENT.resultIndex(comparator, key, list, foundIndex) - 1;
+ }
+ };
+ abstract <E> int resultIndex(
+ Comparator<? super E> comparator, E key, List<? extends E> list, int foundIndex);
+ }
+
+ /**
+ * A specification for which index to return if the list contains no elements that compare as
+ * equal to the key.
+ */
+ public enum KeyAbsentBehavior {
+ /**
+ * Return the index of the next lower element in the list, or {@code -1} if there is no such
+ * element.
+ */
+ NEXT_LOWER {
+ @Override
+ int resultIndex(int higherIndex) {
+ return higherIndex - 1;
+ }
+ },
+ /**
+ * Return the index of the next higher element in the list, or {@code list.size()} if there is
+ * no such element.
+ */
+ NEXT_HIGHER {
+ @Override
+ public int resultIndex(int higherIndex) {
+ return higherIndex;
+ }
+ },
+ /**
+ * Return {@code ~insertionIndex}, where {@code insertionIndex} is defined as the point at
+ * which the key would be inserted into the list: the index of the next higher element in the
+ * list, or {@code list.size()} if there is no such element.
+ *
+ * <p>Note that the return value will be {@code >= 0} if and only if there is an element of the
+ * list that compares as equal to the key.
+ *
+ * <p>This is equivalent to the behavior of
+ * {@link java.util.Collections#binarySearch(List, Object)} when the key isn't present, since
+ * {@code ~insertionIndex} is equal to {@code -1 - insertionIndex}.
+ */
+ INVERTED_INSERTION_INDEX {
+ @Override
+ public int resultIndex(int higherIndex) {
+ return ~higherIndex;
+ }
+ };
+
+ abstract int resultIndex(int higherIndex);
+ }
+
+ /**
+ * Searches the specified naturally ordered list for the specified object using the binary search
+ * algorithm.
+ *
+ * <p>Equivalent to {@link #binarySearch(List, Function, Object, Comparator, KeyPresentBehavior,
+ * KeyAbsentBehavior)} using {@link Ordering#natural}.
+ */
+ public static <E extends Comparable> int binarySearch(List<? extends E> list, E e,
+ KeyPresentBehavior presentBehavior, KeyAbsentBehavior absentBehavior) {
+ checkNotNull(e);
+ return binarySearch(
+ list, checkNotNull(e), Ordering.natural(), presentBehavior, absentBehavior);
+ }
+
+ /**
+ * Binary searches the list for the specified key, using the specified key function.
+ *
+ * <p>Equivalent to {@link #binarySearch(List, Function, Object, Comparator, KeyPresentBehavior,
+ * 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,
+ KeyAbsentBehavior absentBehavior) {
+ return binarySearch(
+ list,
+ keyFunction,
+ key,
+ Ordering.natural(),
+ presentBehavior,
+ absentBehavior);
+ }
+
+ /**
+ * Binary searches the list for the specified key, using the specified key function.
+ *
+ * <p>Equivalent to
+ * {@link #binarySearch(List, Object, Comparator, KeyPresentBehavior, KeyAbsentBehavior)} using
+ * {@link Lists#transform(List, Function) Lists.transform(list, keyFunction)}.
+ */
+ public static <E, K> int binarySearch(
+ List<E> list,
+ Function<? super E, K> keyFunction,
+ @Nullable K key,
+ Comparator<? super K> keyComparator,
+ KeyPresentBehavior presentBehavior,
+ KeyAbsentBehavior absentBehavior) {
+ return binarySearch(
+ Lists.transform(list, keyFunction), key, keyComparator, presentBehavior, absentBehavior);
+ }
+
+ /**
+ * Searches the specified list for the specified object using the binary search algorithm. The
+ * list must be sorted into ascending order according to the specified comparator (as by the
+ * {@link Collections#sort(List, Comparator) Collections.sort(List, Comparator)} method), prior
+ * to making this call. If it is not sorted, the results are undefined.
+ *
+ * <p>If there are elements in the list which compare as equal to the key, the choice of
+ * {@link KeyPresentBehavior} decides which index is returned. If no elements compare as equal to
+ * the key, the choice of {@link KeyAbsentBehavior} decides which index is returned.
+ *
+ * <p>This method runs in log(n) time on random-access lists, which offer near-constant-time
+ * access to each list element.
+ *
+ * @param list the list to be searched.
+ * @param key the value to be searched for.
+ * @param comparator the comparator by which the list is ordered.
+ * @param presentBehavior the specification for what to do if at least one element of the list
+ * compares as equal to the key.
+ * @param absentBehavior the specification for what to do if no elements of the list compare as
+ * equal to the key.
+ * @return the index determined by the {@code KeyPresentBehavior}, if the key is in the list;
+ * otherwise the index determined by the {@code KeyAbsentBehavior}.
+ */
+ public static <E> int binarySearch(List<? extends E> list, @Nullable E key,
+ Comparator<? super E> comparator, KeyPresentBehavior presentBehavior,
+ KeyAbsentBehavior absentBehavior) {
+ checkNotNull(comparator);
+ checkNotNull(list);
+ checkNotNull(presentBehavior);
+ checkNotNull(absentBehavior);
+ if (!(list instanceof RandomAccess)) {
+ list = Lists.newArrayList(list);
+ }
+ // TODO(user): benchmark when it's best to do a linear search
+
+ int lower = 0;
+ int upper = list.size() - 1;
+
+ while (lower <= upper) {
+ int middle = (lower + upper) >>> 1;
+ int c = comparator.compare(key, list.get(middle));
+ if (c < 0) {
+ upper = middle - 1;
+ } else if (c > 0) {
+ lower = middle + 1;
+ } else {
+ return lower + presentBehavior.resultIndex(
+ comparator, key, list.subList(lower, upper + 1), middle - lower);
+ }
+ }
+ return absentBehavior.resultIndex(lower);
+ }
+}
diff --git a/guava/src/com/google/common/collect/SortedMapDifference.java b/guava/src/com/google/common/collect/SortedMapDifference.java
new file mode 100644
index 0000000..f44aa1a
--- /dev/null
+++ b/guava/src/com/google/common/collect/SortedMapDifference.java
@@ -0,0 +1,45 @@
+/*
+ * 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.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.SortedMap;
+
+/**
+ * An object representing the differences between two sorted maps.
+ *
+ * @author Louis Wasserman
+ * @since 8.0
+ */
+@Beta
+@GwtCompatible
+public interface SortedMapDifference<K, V> extends MapDifference<K, V> {
+
+ @Override
+ SortedMap<K, V> entriesOnlyOnLeft();
+
+ @Override
+ SortedMap<K, V> entriesOnlyOnRight();
+
+ @Override
+ SortedMap<K, V> entriesInCommon();
+
+ @Override
+ SortedMap<K, ValueDifference<V>> entriesDiffering();
+}
diff --git a/guava/src/com/google/common/collect/SortedMultiset.java b/guava/src/com/google/common/collect/SortedMultiset.java
new file mode 100644
index 0000000..5d5974a
--- /dev/null
+++ b/guava/src/com/google/common/collect/SortedMultiset.java
@@ -0,0 +1,137 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.SortedSet;
+
+/**
+ * A {@link 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 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
+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.
+ */
+ Comparator<? super E> comparator();
+
+ /**
+ * Returns the entry of the first element in this multiset, or {@code null} if
+ * this multiset is empty.
+ */
+ Entry<E> firstEntry();
+
+ /**
+ * Returns the entry of the last element in this multiset, or {@code null} if
+ * this multiset is empty.
+ */
+ Entry<E> lastEntry();
+
+ /**
+ * Returns and removes the entry associated with the lowest element in this
+ * multiset, or returns {@code null} if this multiset is empty.
+ */
+ Entry<E> pollFirstEntry();
+
+ /**
+ * Returns and removes the entry associated with the greatest element in this
+ * multiset, or returns {@code null} if this multiset is empty.
+ */
+ Entry<E> pollLastEntry();
+
+ /**
+ * Returns a {@link SortedSet} view of the distinct elements in this multiset.
+ */
+ @Override SortedSet<E> elementSet();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The iterator returns the elements in ascending order according to this
+ * multiset's comparator.
+ */
+ @Override Iterator<E> iterator();
+
+ /**
+ * Returns a descending view of this multiset. Modifications made to either
+ * map will be reflected in the other.
+ */
+ SortedMultiset<E> descendingMultiset();
+
+ /**
+ * Returns a view of this multiset restricted to the elements less than
+ * {@code upperBound}, optionally including {@code upperBound} itself. The
+ * returned multiset is a view of this multiset, so changes to one will be
+ * reflected in the other. The returned multiset supports all operations that
+ * this multiset supports.
+ *
+ * <p>The returned multiset will throw an {@link IllegalArgumentException} on
+ * attempts to add elements outside its range.
+ */
+ SortedMultiset<E> headMultiset(E upperBound, BoundType boundType);
+
+ /**
+ * Returns a view of this multiset restricted to the range between
+ * {@code lowerBound} and {@code upperBound}. The returned multiset is a view
+ * of this multiset, so changes to one will be reflected in the other. The
+ * returned multiset supports all operations that this multiset supports.
+ *
+ * <p>The returned multiset will throw an {@link IllegalArgumentException} on
+ * attempts to add elements outside its range.
+ *
+ * <p>This method is equivalent to
+ * {@code tailMultiset(lowerBound, lowerBoundType).headMultiset(upperBound,
+ * upperBoundType)}.
+ */
+ SortedMultiset<E> subMultiset(E lowerBound, BoundType lowerBoundType,
+ E upperBound, BoundType upperBoundType);
+
+ /**
+ * Returns a view of this multiset restricted to the elements greater than
+ * {@code lowerBound}, optionally including {@code lowerBound} itself. The
+ * returned multiset is a view of this multiset, so changes to one will be
+ * reflected in the other. The returned multiset supports all operations that
+ * this multiset supports.
+ *
+ * <p>The returned multiset will throw an {@link IllegalArgumentException} on
+ * attempts to add elements outside its range.
+ */
+ SortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType);
+}
diff --git a/guava/src/com/google/common/collect/SortedMultisets.java b/guava/src/com/google/common/collect/SortedMultisets.java
new file mode 100644
index 0000000..ff18b74
--- /dev/null
+++ b/guava/src/com/google/common/collect/SortedMultisets.java
@@ -0,0 +1,196 @@
+/*
+ * 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 com.google.common.collect.Multiset.Entry;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedSet;
+
+/**
+ * Provides static utility methods for creating and working with
+ * {@link SortedMultiset} instances.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+final class SortedMultisets {
+ private SortedMultisets() {
+ }
+
+ /**
+ * A skeleton implementation for {@link SortedMultiset#elementSet}.
+ */
+ static abstract class ElementSet<E> extends Multisets.ElementSet<E> implements
+ SortedSet<E> {
+ @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, BoundType.CLOSED, toElement,
+ BoundType.OPEN).elementSet();
+ }
+
+ @Override public SortedSet<E> headSet(E toElement) {
+ return multiset().headMultiset(toElement, BoundType.OPEN).elementSet();
+ }
+
+ @Override public SortedSet<E> tailSet(E fromElement) {
+ return multiset().tailMultiset(fromElement, BoundType.CLOSED)
+ .elementSet();
+ }
+
+ @Override public E first() {
+ return getElementOrThrow(multiset().firstEntry());
+ }
+
+ @Override public E last() {
+ return getElementOrThrow(multiset().lastEntry());
+ }
+ }
+
+ private static <E> E getElementOrThrow(Entry<E> entry) {
+ if (entry == null) {
+ throw new NoSuchElementException();
+ }
+ return entry.getElement();
+ }
+
+ /**
+ * A skeleton implementation of a descending multiset. Only needs
+ * {@code forwardMultiset()} and {@code entryIterator()}.
+ */
+ 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;
+ }
+
+ 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 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();
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/SortedSetMultimap.java b/guava/src/com/google/common/collect/SortedSetMultimap.java
new file mode 100644
index 0000000..1b9c641
--- /dev/null
+++ b/guava/src/com/google/common/collect/SortedSetMultimap.java
@@ -0,0 +1,114 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+
+import javax.annotation.Nullable;
+
+/**
+ * A {@code SetMultimap} whose set of values for a given key are kept sorted;
+ * 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.
+ *
+ * <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)
+ */
+@GwtCompatible
+public interface SortedSetMultimap<K, V> extends SetMultimap<K, V> {
+ // Following Javadoc copied from Multimap.
+
+ /**
+ * 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.
+ *
+ * <p>Because a {@code SortedSetMultimap} has unique sorted values for a given
+ * key, this method returns a {@link SortedSet}, instead of the
+ * {@link java.util.Collection} specified in the {@link Multimap} interface.
+ */
+ @Override
+ SortedSet<V> get(@Nullable K key);
+
+ /**
+ * Removes all values associated with a given key.
+ *
+ * <p>Because a {@code SortedSetMultimap} has unique sorted values for a given
+ * key, this method returns a {@link SortedSet}, instead of the
+ * {@link java.util.Collection} specified in the {@link Multimap} interface.
+ */
+ @Override
+ SortedSet<V> removeAll(@Nullable Object key);
+
+ /**
+ * Stores a collection of values with the same key, replacing any existing
+ * values for that key.
+ *
+ * <p>Because a {@code SortedSetMultimap} has unique sorted values for a given
+ * key, this method returns a {@link SortedSet}, instead of the
+ * {@link java.util.Collection} specified in the {@link Multimap} interface.
+ *
+ * <p>Any duplicates in {@code values} will be stored in the multimap once.
+ */
+ @Override
+ SortedSet<V> replaceValues(K key, Iterable<? extends V> values);
+
+ /**
+ * Returns a map view that associates each key with the corresponding values
+ * in the multimap. Changes to the returned map, such as element removal, will
+ * update the underlying multimap. The map does not support {@code setValue()}
+ * on its entries, {@code put}, or {@code putAll}.
+ *
+ * <p>When passed a key that is present in the map, {@code
+ * asMap().get(Object)} has the same behavior as {@link #get}, returning a
+ * live collection. When passed a key that is not present, however, {@code
+ * asMap().get(Object)} returns {@code null} instead of an empty collection.
+ *
+ * <p>Though the method signature doesn't say so explicitly, the returned map
+ * has {@link SortedSet} values.
+ */
+ @Override
+ Map<K, Collection<V>> asMap();
+
+ /**
+ * Returns the comparator that orders the multimap values, with {@code null}
+ * indicating that natural ordering is used.
+ */
+ Comparator<? super V> valueComparator();
+}
diff --git a/guava/src/com/google/common/collect/StandardRowSortedTable.java b/guava/src/com/google/common/collect/StandardRowSortedTable.java
new file mode 100644
index 0000000..fbc7518
--- /dev/null
+++ b/guava/src/com/google/common/collect/StandardRowSortedTable.java
@@ -0,0 +1,172 @@
+/*
+ * 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.GwtCompatible;
+import com.google.common.base.Supplier;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+
+/**
+ * Implementation of {@code Table} whose iteration ordering across row keys is
+ * sorted by their natural ordering or by a supplied comparator. Note that
+ * iterations across the columns keys for a single row key may or may not be
+ * ordered, depending on the implementation. When rows and columns are both
+ * sorted, it's easier to use the {@link TreeBasedTable} subclass.
+ *
+ * <p>The {@link #rowKeySet} method returns a {@link SortedSet} and the {@link
+ * #rowMap} method returns a {@link SortedMap}, instead of the {@link Set} and
+ * {@link Map} specified by the {@link Table} interface.
+ *
+ * <p>Null keys and values are not supported.
+ *
+ * <p>See the {@link StandardTable} superclass for more information about the
+ * behavior of this class.
+ *
+ * @author Jared Levy
+ */
+@GwtCompatible
+class StandardRowSortedTable<R, C, V> extends StandardTable<R, C, V>
+ implements RowSortedTable<R, C, V> {
+ /*
+ * TODO(jlevy): Consider adding headTable, tailTable, and subTable methods,
+ * which return a Table view with rows keys in a given range. Create a
+ * RowSortedTable subinterface with the revised methods?
+ */
+
+ StandardRowSortedTable(SortedMap<R, Map<C, V>> backingMap,
+ Supplier<? extends Map<C, V>> factory) {
+ super(backingMap, factory);
+ }
+
+ private SortedMap<R, Map<C, V>> sortedBackingMap() {
+ return (SortedMap<R, Map<C, V>>) backingMap;
+ }
+
+ private transient SortedSet<R> rowKeySet;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method returns a {@link SortedSet}, instead of the {@code Set}
+ * specified in the {@link Table} interface.
+ */
+ @Override public SortedSet<R> rowKeySet() {
+ SortedSet<R> result = rowKeySet;
+ return (result == null) ? rowKeySet = new RowKeySortedSet() : result;
+ }
+
+ private class RowKeySortedSet extends RowKeySet implements SortedSet<R> {
+ @Override
+ public Comparator<? super R> comparator() {
+ return sortedBackingMap().comparator();
+ }
+
+ @Override
+ public R first() {
+ return sortedBackingMap().firstKey();
+ }
+
+ @Override
+ public R last() {
+ return sortedBackingMap().lastKey();
+ }
+
+ @Override
+ public SortedSet<R> headSet(R toElement) {
+ checkNotNull(toElement);
+ return new StandardRowSortedTable<R, C, V>(
+ sortedBackingMap().headMap(toElement), factory).rowKeySet();
+ }
+
+ @Override
+ public SortedSet<R> subSet(R fromElement, R toElement) {
+ checkNotNull(fromElement);
+ checkNotNull(toElement);
+ return new StandardRowSortedTable<R, C, V>(
+ sortedBackingMap().subMap(fromElement, toElement), factory)
+ .rowKeySet();
+ }
+
+ @Override
+ public SortedSet<R> tailSet(R fromElement) {
+ checkNotNull(fromElement);
+ return new StandardRowSortedTable<R, C, V>(
+ sortedBackingMap().tailMap(fromElement), factory).rowKeySet();
+ }
+ }
+
+ private transient RowSortedMap rowMap;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method returns a {@link SortedMap}, instead of the {@code Map}
+ * specified in the {@link Table} interface.
+ */
+ @Override public SortedMap<R, Map<C, V>> rowMap() {
+ RowSortedMap result = rowMap;
+ return (result == null) ? rowMap = new RowSortedMap() : result;
+ }
+
+ private class RowSortedMap extends RowMap implements SortedMap<R, Map<C, V>> {
+ @Override
+ public Comparator<? super R> comparator() {
+ return sortedBackingMap().comparator();
+ }
+
+ @Override
+ public R firstKey() {
+ return sortedBackingMap().firstKey();
+ }
+
+ @Override
+ public R lastKey() {
+ return sortedBackingMap().lastKey();
+ }
+
+ @Override
+ public SortedMap<R, Map<C, V>> headMap(R toKey) {
+ checkNotNull(toKey);
+ return new StandardRowSortedTable<R, C, V>(
+ sortedBackingMap().headMap(toKey), factory).rowMap();
+ }
+
+ @Override
+ public SortedMap<R, Map<C, V>> subMap(R fromKey, R toKey) {
+ checkNotNull(fromKey);
+ checkNotNull(toKey);
+ return new StandardRowSortedTable<R, C, V>(
+ sortedBackingMap().subMap(fromKey, toKey), factory).rowMap();
+ }
+
+ @Override
+ public SortedMap<R, Map<C, V>> tailMap(R fromKey) {
+ checkNotNull(fromKey);
+ return new StandardRowSortedTable<R, C, V>(
+ sortedBackingMap().tailMap(fromKey), factory).rowMap();
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/StandardTable.java b/guava/src/com/google/common/collect/StandardTable.java
new file mode 100644
index 0000000..c7329c1
--- /dev/null
+++ b/guava/src/com/google/common/collect/StandardTable.java
@@ -0,0 +1,1122 @@
+/*
+ * 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 static com.google.common.collect.Maps.safeContainsKey;
+import static com.google.common.collect.Maps.safeGet;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * {@link Table} implementation backed by a map that associates row keys with
+ * column key / value secondary maps. This class provides rapid access to
+ * records by the row key alone or by both keys, but not by just the column key.
+ *
+ * <p>The views returned by {@link #column}, {@link #columnKeySet()}, and {@link
+ * #columnMap()} have iterators that don't support {@code remove()}. Otherwise,
+ * all optional operations are supported. Null row keys, columns keys, and
+ * values are not supported.
+ *
+ * <p>Lookups by row key are often faster than lookups by column key, because
+ * the data is stored in a {@code Map<R, Map<C, V>>}. A method call like {@code
+ * column(columnKey).get(rowKey)} still runs quickly, since the row key is
+ * provided. However, {@code column(columnKey).size()} takes longer, since an
+ * iteration across all row keys occurs.
+ *
+ * <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.
+ *
+ * @author Jared Levy
+ */
+@GwtCompatible
+class StandardTable<R, C, V> implements Table<R, C, V>, Serializable {
+ @GwtTransient final Map<R, Map<C, V>> backingMap;
+ @GwtTransient final Supplier<? extends Map<C, V>> factory;
+
+ StandardTable(Map<R, Map<C, V>> backingMap,
+ Supplier<? extends Map<C, V>> factory) {
+ this.backingMap = backingMap;
+ this.factory = factory;
+ }
+
+ // Accessors
+
+ @Override public boolean contains(
+ @Nullable Object rowKey, @Nullable Object columnKey) {
+ if ((rowKey == null) || (columnKey == null)) {
+ return false;
+ }
+ Map<C, V> map = safeGet(backingMap, rowKey);
+ return map != null && safeContainsKey(map, columnKey);
+ }
+
+ @Override public boolean containsColumn(@Nullable Object columnKey) {
+ if (columnKey == null) {
+ return false;
+ }
+ for (Map<C, V> map : backingMap.values()) {
+ if (safeContainsKey(map, columnKey)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean containsRow(@Nullable Object rowKey) {
+ return rowKey != null && safeContainsKey(backingMap, rowKey);
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ if (value == null) {
+ return false;
+ }
+ for (Map<C, V> map : backingMap.values()) {
+ if (map.containsValue(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
+ if ((rowKey == null) || (columnKey == null)) {
+ return null;
+ }
+ Map<C, V> map = safeGet(backingMap, rowKey);
+ return map == null ? null : safeGet(map, columnKey);
+ }
+
+ @Override public boolean isEmpty() {
+ return backingMap.isEmpty();
+ }
+
+ @Override public int size() {
+ int size = 0;
+ for (Map<C, V> map : backingMap.values()) {
+ size += map.size();
+ }
+ return size;
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Table) {
+ Table<?, ?, ?> other = (Table<?, ?, ?>) obj;
+ return cellSet().equals(other.cellSet());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return cellSet().hashCode();
+ }
+
+ /**
+ * Returns the string representation {@code rowMap().toString()}.
+ */
+ @Override public String toString() {
+ return rowMap().toString();
+ }
+
+ // Mutators
+
+ @Override public void clear() {
+ backingMap.clear();
+ }
+
+ private Map<C, V> getOrCreate(R rowKey) {
+ Map<C, V> map = backingMap.get(rowKey);
+ if (map == null) {
+ map = factory.get();
+ backingMap.put(rowKey, map);
+ }
+ return map;
+ }
+
+ @Override public V put(R rowKey, C columnKey, V value) {
+ checkNotNull(rowKey);
+ checkNotNull(columnKey);
+ checkNotNull(value);
+ return getOrCreate(rowKey).put(columnKey, value);
+ }
+
+ @Override public void putAll(
+ Table<? extends R, ? extends C, ? extends V> table) {
+ for (Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) {
+ put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
+ }
+ }
+
+ @Override public V remove(
+ @Nullable Object rowKey, @Nullable Object columnKey) {
+ if ((rowKey == null) || (columnKey == null)) {
+ return null;
+ }
+ Map<C, V> map = safeGet(backingMap, rowKey);
+ if (map == null) {
+ return null;
+ }
+ V value = map.remove(columnKey);
+ if (map.isEmpty()) {
+ backingMap.remove(rowKey);
+ }
+ return value;
+ }
+
+ private Map<R, V> removeColumn(Object column) {
+ Map<R, V> output = new LinkedHashMap<R, V>();
+ Iterator<Entry<R, Map<C, V>>> iterator
+ = backingMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry<R, Map<C, V>> entry = iterator.next();
+ V value = entry.getValue().remove(column);
+ if (value != null) {
+ output.put(entry.getKey(), value);
+ if (entry.getValue().isEmpty()) {
+ iterator.remove();
+ }
+ }
+ }
+ return output;
+ }
+
+ private boolean containsMapping(
+ Object rowKey, Object columnKey, Object value) {
+ return value != null && value.equals(get(rowKey, columnKey));
+ }
+
+ /** Remove a row key / column key / value mapping, if present. */
+ private boolean removeMapping(Object rowKey, Object columnKey, Object value) {
+ if (containsMapping(rowKey, columnKey, value)) {
+ remove(rowKey, columnKey);
+ return true;
+ }
+ return false;
+ }
+
+ // Views
+
+ /**
+ * Abstract collection whose {@code isEmpty()} returns whether the table is
+ * empty and whose {@code clear()} clears all table mappings.
+ */
+ private abstract class TableCollection<T> extends AbstractCollection<T> {
+ @Override public boolean isEmpty() {
+ return backingMap.isEmpty();
+ }
+
+ @Override public void clear() {
+ backingMap.clear();
+ }
+ }
+
+ /**
+ * Abstract set whose {@code isEmpty()} returns whether the table is empty and
+ * whose {@code clear()} clears all table mappings.
+ */
+ private abstract class TableSet<T> extends AbstractSet<T> {
+ @Override public boolean isEmpty() {
+ return backingMap.isEmpty();
+ }
+
+ @Override public void clear() {
+ backingMap.clear();
+ }
+ }
+
+ private transient CellSet cellSet;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The set's iterator traverses the mappings for the first row, the
+ * mappings for the second row, and so on.
+ *
+ * <p>Each cell is an immutable snapshot of a row key / column key / value
+ * mapping, taken at the time the cell is returned by a method call to the
+ * set or its iterator.
+ */
+ @Override public Set<Cell<R, C, V>> cellSet() {
+ CellSet result = cellSet;
+ return (result == null) ? cellSet = new CellSet() : result;
+ }
+
+ private class CellSet extends TableSet<Cell<R, C, V>> {
+ @Override public Iterator<Cell<R, C, V>> iterator() {
+ return new CellIterator();
+ }
+
+ @Override public int size() {
+ return StandardTable.this.size();
+ }
+
+ @Override public boolean contains(Object obj) {
+ if (obj instanceof Cell) {
+ Cell<?, ?, ?> cell = (Cell<?, ?, ?>) obj;
+ return containsMapping(
+ cell.getRowKey(), cell.getColumnKey(), cell.getValue());
+ }
+ return false;
+ }
+
+ @Override public boolean remove(Object obj) {
+ if (obj instanceof Cell) {
+ Cell<?, ?, ?> cell = (Cell<?, ?, ?>) obj;
+ return removeMapping(
+ cell.getRowKey(), cell.getColumnKey(), cell.getValue());
+ }
+ return false;
+ }
+ }
+
+ private class CellIterator implements Iterator<Cell<R, C, V>> {
+ final Iterator<Entry<R, Map<C, V>>> rowIterator
+ = backingMap.entrySet().iterator();
+ Entry<R, Map<C, V>> rowEntry;
+ Iterator<Entry<C, V>> columnIterator
+ = Iterators.emptyModifiableIterator();
+
+ @Override public boolean hasNext() {
+ return rowIterator.hasNext() || columnIterator.hasNext();
+ }
+
+ @Override public Cell<R, C, V> next() {
+ if (!columnIterator.hasNext()) {
+ rowEntry = rowIterator.next();
+ columnIterator = rowEntry.getValue().entrySet().iterator();
+ }
+ Entry<C, V> columnEntry = columnIterator.next();
+ return Tables.immutableCell(
+ rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue());
+ }
+
+ @Override public void remove() {
+ columnIterator.remove();
+ if (rowEntry.getValue().isEmpty()) {
+ rowIterator.remove();
+ }
+ }
+ }
+
+ @Override public Map<C, V> row(R rowKey) {
+ return new Row(rowKey);
+ }
+
+ class Row extends AbstractMap<C, V> {
+ final R rowKey;
+
+ Row(R rowKey) {
+ this.rowKey = checkNotNull(rowKey);
+ }
+
+ Map<C, V> backingRowMap;
+
+ Map<C, V> backingRowMap() {
+ return (backingRowMap == null
+ || (backingRowMap.isEmpty() && backingMap.containsKey(rowKey)))
+ ? backingRowMap = computeBackingRowMap()
+ : backingRowMap;
+ }
+
+ Map<C, V> computeBackingRowMap() {
+ return backingMap.get(rowKey);
+ }
+
+ // Call this every time we perform a removal.
+ void maintainEmptyInvariant() {
+ if (backingRowMap() != null && backingRowMap.isEmpty()) {
+ backingMap.remove(rowKey);
+ backingRowMap = null;
+ }
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ Map<C, V> backingRowMap = backingRowMap();
+ return (key != null && backingRowMap != null)
+ && Maps.safeContainsKey(backingRowMap, key);
+ }
+
+ @Override
+ public V get(Object key) {
+ Map<C, V> backingRowMap = backingRowMap();
+ return (key != null && backingRowMap != null)
+ ? Maps.safeGet(backingRowMap, key)
+ : null;
+ }
+
+ @Override
+ public V put(C key, V value) {
+ checkNotNull(key);
+ checkNotNull(value);
+ if (backingRowMap != null && !backingRowMap.isEmpty()) {
+ return backingRowMap.put(key, value);
+ }
+ return StandardTable.this.put(rowKey, key, value);
+ }
+
+ @Override
+ public V remove(Object key) {
+ try {
+ Map<C, V> backingRowMap = backingRowMap();
+ if (backingRowMap == null) {
+ return null;
+ }
+ V result = backingRowMap.remove(key);
+ maintainEmptyInvariant();
+ return result;
+ } catch (ClassCastException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void clear() {
+ Map<C, V> backingRowMap = backingRowMap();
+ if (backingRowMap != null) {
+ backingRowMap.clear();
+ }
+ maintainEmptyInvariant();
+ }
+
+ Set<C> keySet;
+
+ @Override
+ public Set<C> keySet() {
+ Set<C> result = keySet;
+ if (result == null) {
+ return keySet = new Maps.KeySet<C, V>() {
+ @Override
+ Map<C, V> map() {
+ return Row.this;
+ }
+ };
+ }
+ return result;
+ }
+
+ Set<Entry<C, V>> entrySet;
+
+ @Override
+ public Set<Entry<C, V>> entrySet() {
+ Set<Entry<C, V>> result = entrySet;
+ if (result == null) {
+ return entrySet = new RowEntrySet();
+ }
+ return result;
+ }
+
+ private class RowEntrySet extends Maps.EntrySet<C, V> {
+ @Override
+ Map<C, V> map() {
+ return Row.this;
+ }
+
+ @Override
+ public int size() {
+ Map<C, V> map = backingRowMap();
+ return (map == null) ? 0 : map.size();
+ }
+
+ @Override
+ public Iterator<Entry<C, V>> iterator() {
+ final Map<C, V> map = backingRowMap();
+ if (map == null) {
+ return Iterators.emptyModifiableIterator();
+ }
+ final Iterator<Entry<C, V>> iterator = map.entrySet().iterator();
+ return new Iterator<Entry<C, V>>() {
+ @Override public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ @Override public Entry<C, V> next() {
+ final Entry<C, V> entry = iterator.next();
+ return new ForwardingMapEntry<C, V>() {
+ @Override protected Entry<C, V> delegate() {
+ return entry;
+ }
+ @Override public V setValue(V value) {
+ return super.setValue(checkNotNull(value));
+ }
+ @Override
+ public boolean equals(Object object) {
+ // TODO(user): identify why this affects GWT tests
+ return standardEquals(object);
+ }
+ };
+ }
+
+ @Override
+ public void remove() {
+ iterator.remove();
+ maintainEmptyInvariant();
+ }
+ };
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned map's views have iterators that don't support
+ * {@code remove()}.
+ */
+ @Override public Map<R, V> column(C columnKey) {
+ return new Column(columnKey);
+ }
+
+ private class Column extends Maps.ImprovedAbstractMap<R, V> {
+ final C columnKey;
+
+ Column(C columnKey) {
+ this.columnKey = checkNotNull(columnKey);
+ }
+
+ @Override public V put(R key, V value) {
+ return StandardTable.this.put(key, columnKey, value);
+ }
+
+ @Override public V get(Object key) {
+ return StandardTable.this.get(key, columnKey);
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return StandardTable.this.contains(key, columnKey);
+ }
+
+ @Override public V remove(Object key) {
+ return StandardTable.this.remove(key, columnKey);
+ }
+
+ @Override public Set<Entry<R, V>> createEntrySet() {
+ return new EntrySet();
+ }
+
+ Values columnValues;
+
+ @Override public Collection<V> values() {
+ Values result = columnValues;
+ return (result == null) ? columnValues = new Values() : result;
+ }
+
+ /**
+ * Removes all {@code Column} mappings whose row key and value satisfy the
+ * given predicate.
+ */
+ boolean removePredicate(Predicate<? super Entry<R, V>> predicate) {
+ boolean changed = false;
+ Iterator<Entry<R, Map<C, V>>> iterator
+ = backingMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry<R, Map<C, V>> entry = iterator.next();
+ Map<C, V> map = entry.getValue();
+ V value = map.get(columnKey);
+ if (value != null
+ && predicate.apply(
+ new ImmutableEntry<R, V>(entry.getKey(), value))) {
+ map.remove(columnKey);
+ changed = true;
+ if (map.isEmpty()) {
+ iterator.remove();
+ }
+ }
+ }
+ return changed;
+ }
+
+ class EntrySet extends Sets.ImprovedAbstractSet<Entry<R, V>> {
+ @Override public Iterator<Entry<R, V>> iterator() {
+ return new EntrySetIterator();
+ }
+
+ @Override public int size() {
+ int size = 0;
+ for (Map<C, V> map : backingMap.values()) {
+ if (map.containsKey(columnKey)) {
+ size++;
+ }
+ }
+ return size;
+ }
+
+ @Override public boolean isEmpty() {
+ return !containsColumn(columnKey);
+ }
+
+ @Override public void clear() {
+ Predicate<Entry<R, V>> predicate = Predicates.alwaysTrue();
+ removePredicate(predicate);
+ }
+
+ @Override public boolean contains(Object o) {
+ if (o instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ return containsMapping(entry.getKey(), columnKey, entry.getValue());
+ }
+ return false;
+ }
+
+ @Override public boolean remove(Object obj) {
+ if (obj instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) obj;
+ return removeMapping(entry.getKey(), columnKey, entry.getValue());
+ }
+ return false;
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ return removePredicate(Predicates.not(Predicates.in(c)));
+ }
+ }
+
+ class EntrySetIterator extends AbstractIterator<Entry<R, V>> {
+ final Iterator<Entry<R, Map<C, V>>> iterator
+ = backingMap.entrySet().iterator();
+ @Override protected Entry<R, V> computeNext() {
+ while (iterator.hasNext()) {
+ final Entry<R, Map<C, V>> entry = iterator.next();
+ if (entry.getValue().containsKey(columnKey)) {
+ return new AbstractMapEntry<R, V>() {
+ @Override public R getKey() {
+ return entry.getKey();
+ }
+ @Override public V getValue() {
+ return entry.getValue().get(columnKey);
+ }
+ @Override public V setValue(V value) {
+ return entry.getValue().put(columnKey, checkNotNull(value));
+ }
+ };
+ }
+ }
+ return endOfData();
+ }
+ }
+
+ KeySet keySet;
+
+ @Override public Set<R> keySet() {
+ KeySet result = keySet;
+ return result == null ? keySet = new KeySet() : result;
+ }
+
+ class KeySet extends Sets.ImprovedAbstractSet<R> {
+ @Override public Iterator<R> iterator() {
+ return Maps.keyIterator(Column.this.entrySet().iterator());
+ }
+
+ @Override public int size() {
+ return entrySet().size();
+ }
+
+ @Override public boolean isEmpty() {
+ return !containsColumn(columnKey);
+ }
+
+ @Override public boolean contains(Object obj) {
+ return StandardTable.this.contains(obj, columnKey);
+ }
+
+ @Override public boolean remove(Object obj) {
+ return StandardTable.this.remove(obj, columnKey) != null;
+ }
+
+ @Override public void clear() {
+ entrySet().clear();
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ checkNotNull(c);
+ Predicate<Entry<R, V>> predicate = new Predicate<Entry<R, V>>() {
+ @Override
+ public boolean apply(Entry<R, V> entry) {
+ return !c.contains(entry.getKey());
+ }
+ };
+ return removePredicate(predicate);
+ }
+ }
+
+ class Values extends AbstractCollection<V> {
+ @Override public Iterator<V> iterator() {
+ return Maps.valueIterator(Column.this.entrySet().iterator());
+ }
+
+ @Override public int size() {
+ return entrySet().size();
+ }
+
+ @Override public boolean isEmpty() {
+ return !containsColumn(columnKey);
+ }
+
+ @Override public void clear() {
+ entrySet().clear();
+ }
+
+ @Override public boolean remove(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ Iterator<Map<C, V>> iterator = backingMap.values().iterator();
+ while (iterator.hasNext()) {
+ Map<C, V> map = iterator.next();
+ if (map.entrySet().remove(
+ new ImmutableEntry<C, Object>(columnKey, obj))) {
+ if (map.isEmpty()) {
+ iterator.remove();
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean removeAll(final Collection<?> c) {
+ checkNotNull(c);
+ Predicate<Entry<R, V>> predicate = new Predicate<Entry<R, V>>() {
+ @Override
+ public boolean apply(Entry<R, V> entry) {
+ return c.contains(entry.getValue());
+ }
+ };
+ return removePredicate(predicate);
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ checkNotNull(c);
+ Predicate<Entry<R, V>> predicate = new Predicate<Entry<R, V>>() {
+ @Override
+ public boolean apply(Entry<R, V> entry) {
+ return !c.contains(entry.getValue());
+ }
+ };
+ return removePredicate(predicate);
+ }
+ }
+ }
+
+ private transient RowKeySet rowKeySet;
+
+ @Override public Set<R> rowKeySet() {
+ Set<R> result = rowKeySet;
+ return (result == null) ? rowKeySet = new RowKeySet() : result;
+ }
+
+ class RowKeySet extends TableSet<R> {
+ @Override public Iterator<R> iterator() {
+ return Maps.keyIterator(rowMap().entrySet().iterator());
+ }
+
+ @Override public int size() {
+ return backingMap.size();
+ }
+
+ @Override public boolean contains(Object obj) {
+ return containsRow(obj);
+ }
+
+ @Override public boolean remove(Object obj) {
+ return (obj != null) && backingMap.remove(obj) != null;
+ }
+ }
+
+ private transient Set<C> columnKeySet;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned set has an iterator that does not support {@code remove()}.
+ *
+ * <p>The set's iterator traverses the columns of the first row, the
+ * columns of the second row, etc., skipping any columns that have
+ * appeared previously.
+ */
+ @Override
+ public Set<C> columnKeySet() {
+ Set<C> result = columnKeySet;
+ return (result == null) ? columnKeySet = new ColumnKeySet() : result;
+ }
+
+ private class ColumnKeySet extends TableSet<C> {
+ @Override public Iterator<C> iterator() {
+ return createColumnKeyIterator();
+ }
+
+ @Override public int size() {
+ return Iterators.size(iterator());
+ }
+
+ @Override public boolean remove(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ boolean changed = false;
+ Iterator<Map<C, V>> iterator = backingMap.values().iterator();
+ while (iterator.hasNext()) {
+ Map<C, V> map = iterator.next();
+ if (map.keySet().remove(obj)) {
+ changed = true;
+ if (map.isEmpty()) {
+ iterator.remove();
+ }
+ }
+ }
+ return changed;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ checkNotNull(c);
+ boolean changed = false;
+ Iterator<Map<C, V>> iterator = backingMap.values().iterator();
+ while (iterator.hasNext()) {
+ Map<C, V> map = iterator.next();
+ // map.keySet().removeAll(c) can throw a NPE when map is a TreeMap with
+ // natural ordering and c contains a null.
+ if (Iterators.removeAll(map.keySet().iterator(), c)) {
+ changed = true;
+ if (map.isEmpty()) {
+ iterator.remove();
+ }
+ }
+ }
+ return changed;
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ checkNotNull(c);
+ boolean changed = false;
+ Iterator<Map<C, V>> iterator = backingMap.values().iterator();
+ while (iterator.hasNext()) {
+ Map<C, V> map = iterator.next();
+ if (map.keySet().retainAll(c)) {
+ changed = true;
+ if (map.isEmpty()) {
+ iterator.remove();
+ }
+ }
+ }
+ return changed;
+ }
+
+ @Override public boolean contains(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ for (Map<C, V> map : backingMap.values()) {
+ if (map.containsKey(obj)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Creates an iterator that returns each column value with duplicates
+ * omitted.
+ */
+ Iterator<C> createColumnKeyIterator() {
+ return new ColumnKeyIterator();
+ }
+
+ private class ColumnKeyIterator extends AbstractIterator<C> {
+ // Use the same map type to support TreeMaps with comparators that aren't
+ // consistent with equals().
+ final Map<C, V> seen = factory.get();
+ final Iterator<Map<C, V>> mapIterator = backingMap.values().iterator();
+ Iterator<Entry<C, V>> entryIterator = Iterators.emptyIterator();
+
+ @Override protected C computeNext() {
+ while (true) {
+ if (entryIterator.hasNext()) {
+ Entry<C, V> entry = entryIterator.next();
+ if (!seen.containsKey(entry.getKey())) {
+ seen.put(entry.getKey(), entry.getValue());
+ return entry.getKey();
+ }
+ } else if (mapIterator.hasNext()) {
+ entryIterator = mapIterator.next().entrySet().iterator();
+ } else {
+ return endOfData();
+ }
+ }
+ }
+ }
+
+ private transient Values values;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The collection's iterator traverses the values for the first row,
+ * the values for the second row, and so on.
+ */
+ @Override public Collection<V> values() {
+ Values result = values;
+ return (result == null) ? values = new Values() : result;
+ }
+
+ 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();
+ }
+ };
+ }
+
+ @Override public int size() {
+ return StandardTable.this.size();
+ }
+ }
+
+ private transient RowMap rowMap;
+
+ @Override public Map<R, Map<C, V>> rowMap() {
+ RowMap result = rowMap;
+ return (result == null) ? rowMap = new RowMap() : result;
+ }
+
+ class RowMap extends Maps.ImprovedAbstractMap<R, Map<C, V>> {
+ @Override public boolean containsKey(Object key) {
+ return containsRow(key);
+ }
+
+ // performing cast only when key is in backing map and has the correct type
+ @SuppressWarnings("unchecked")
+ @Override public Map<C, V> get(Object key) {
+ return containsRow(key) ? row((R) key) : null;
+ }
+
+ @Override public Set<R> keySet() {
+ return rowKeySet();
+ }
+
+ @Override public Map<C, V> remove(Object key) {
+ return (key == null) ? null : backingMap.remove(key);
+ }
+
+ @Override protected Set<Entry<R, Map<C, V>>> createEntrySet() {
+ return new EntrySet();
+ }
+
+ 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));
+ }
+ };
+ }
+
+ @Override public int size() {
+ return backingMap.size();
+ }
+
+ @Override public boolean contains(Object obj) {
+ if (obj instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) obj;
+ return entry.getKey() != null
+ && entry.getValue() instanceof Map
+ && Collections2.safeContains(backingMap.entrySet(), entry);
+ }
+ return false;
+ }
+
+ @Override public boolean remove(Object obj) {
+ if (obj instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) obj;
+ return entry.getKey() != null
+ && entry.getValue() instanceof Map
+ && backingMap.entrySet().remove(entry);
+ }
+ return false;
+ }
+ }
+ }
+
+ private transient ColumnMap columnMap;
+
+ @Override public Map<C, Map<R, V>> columnMap() {
+ ColumnMap result = columnMap;
+ return (result == null) ? columnMap = new ColumnMap() : result;
+ }
+
+ private class ColumnMap extends Maps.ImprovedAbstractMap<C, Map<R, V>> {
+ // The cast to C occurs only when the key is in the map, implying that it
+ // has the correct type.
+ @SuppressWarnings("unchecked")
+ @Override public Map<R, V> get(Object key) {
+ return containsColumn(key) ? column((C) key) : null;
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return containsColumn(key);
+ }
+
+ @Override public Map<R, V> remove(Object key) {
+ return containsColumn(key) ? removeColumn(key) : null;
+ }
+
+ @Override public Set<Entry<C, Map<R, V>>> createEntrySet() {
+ return new ColumnMapEntrySet();
+ }
+
+ @Override public Set<C> keySet() {
+ return columnKeySet();
+ }
+
+ ColumnMapValues columnMapValues;
+
+ @Override public Collection<Map<R, V>> values() {
+ ColumnMapValues result = columnMapValues;
+ return
+ (result == null) ? columnMapValues = new ColumnMapValues() : result;
+ }
+
+ 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) {
+ return new ImmutableEntry<C, Map<R, V>>(
+ columnKey, column(columnKey));
+ }
+ };
+ }
+
+ @Override public int size() {
+ return columnKeySet().size();
+ }
+
+ @Override public boolean contains(Object obj) {
+ if (obj instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) obj;
+ if (containsColumn(entry.getKey())) {
+ // The cast to C occurs only when the key is in the map, implying
+ // that it has the correct type.
+ @SuppressWarnings("unchecked")
+ C columnKey = (C) entry.getKey();
+ return get(columnKey).equals(entry.getValue());
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean remove(Object obj) {
+ if (contains(obj)) {
+ Entry<?, ?> entry = (Entry<?, ?>) obj;
+ removeColumn(entry.getKey());
+ return true;
+ }
+ 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) {
+ boolean changed = false;
+ for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
+ if (!c.contains(new ImmutableEntry<C, Map<R, V>>(
+ columnKey, column(columnKey)))) {
+ removeColumn(columnKey);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+ }
+
+ private class ColumnMapValues extends TableCollection<Map<R, V>> {
+ @Override public Iterator<Map<R, V>> iterator() {
+ return Maps.valueIterator(ColumnMap.this.entrySet().iterator());
+ }
+
+ @Override public boolean remove(Object obj) {
+ for (Entry<C, Map<R, V>> entry : ColumnMap.this.entrySet()) {
+ if (entry.getValue().equals(obj)) {
+ removeColumn(entry.getKey());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ checkNotNull(c);
+ boolean changed = false;
+ for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
+ if (c.contains(column(columnKey))) {
+ removeColumn(columnKey);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ checkNotNull(c);
+ boolean changed = false;
+ for (C columnKey : Lists.newArrayList(columnKeySet().iterator())) {
+ if (!c.contains(column(columnKey))) {
+ removeColumn(columnKey);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ @Override public int size() {
+ return columnKeySet().size();
+ }
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/Synchronized.java b/guava/src/com/google/common/collect/Synchronized.java
new file mode 100644
index 0000000..4262b27
--- /dev/null
+++ b/guava/src/com/google/common/collect/Synchronized.java
@@ -0,0 +1,1565 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Comparator;
+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.RandomAccess;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+
+import javax.annotation.Nullable;
+
+/**
+ * Synchronized collection views. The returned synchronized collection views are
+ * serializable if the backing collection and the mutex are serializable.
+ *
+ * <p>If {@code null} is passed as the {@code mutex} parameter to any of this
+ * class's top-level methods or inner class constructors, the created object
+ * uses itself as the synchronization mutex.
+ *
+ * <p>This class should be used by other collection classes only.
+ *
+ * @author Mike Bostock
+ * @author Jared Levy
+ */
+@GwtCompatible(emulated = true)
+final class Synchronized {
+ private Synchronized() {}
+
+ static class SynchronizedObject implements Serializable {
+ final Object delegate;
+ final Object mutex;
+
+ SynchronizedObject(Object delegate, @Nullable Object mutex) {
+ this.delegate = checkNotNull(delegate);
+ this.mutex = (mutex == null) ? this : mutex;
+ }
+
+ Object delegate() {
+ return delegate;
+ }
+
+ // No equals and hashCode; see ForwardingObject for details.
+
+ @Override public String toString() {
+ synchronized (mutex) {
+ return delegate.toString();
+ }
+ }
+
+ // Serialization invokes writeObject only when it's private.
+ // The SynchronizedObject subclasses don't need a writeObject method since
+ // they don't contain any non-transient member variables, while the
+ // following writeObject() handles the SynchronizedObject members.
+
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ synchronized (mutex) {
+ stream.defaultWriteObject();
+ }
+ }
+
+ @GwtIncompatible("not needed in emulated source")
+ private static final long serialVersionUID = 0;
+ }
+
+ private static <E> Collection<E> collection(
+ Collection<E> collection, @Nullable Object mutex) {
+ return new SynchronizedCollection<E>(collection, mutex);
+ }
+
+ @VisibleForTesting static class SynchronizedCollection<E>
+ extends SynchronizedObject implements Collection<E> {
+ private SynchronizedCollection(
+ Collection<E> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override Collection<E> delegate() {
+ return (Collection<E>) super.delegate();
+ }
+
+ @Override
+ public boolean add(E e) {
+ synchronized (mutex) {
+ return delegate().add(e);
+ }
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends E> c) {
+ synchronized (mutex) {
+ return delegate().addAll(c);
+ }
+ }
+
+ @Override
+ public void clear() {
+ synchronized (mutex) {
+ delegate().clear();
+ }
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ synchronized (mutex) {
+ return delegate().contains(o);
+ }
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ synchronized (mutex) {
+ return delegate().containsAll(c);
+ }
+ }
+
+ @Override
+ public boolean isEmpty() {
+ synchronized (mutex) {
+ return delegate().isEmpty();
+ }
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return delegate().iterator(); // manually synchronized
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ synchronized (mutex) {
+ return delegate().remove(o);
+ }
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ synchronized (mutex) {
+ return delegate().removeAll(c);
+ }
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ synchronized (mutex) {
+ return delegate().retainAll(c);
+ }
+ }
+
+ @Override
+ public int size() {
+ synchronized (mutex) {
+ return delegate().size();
+ }
+ }
+
+ @Override
+ public Object[] toArray() {
+ synchronized (mutex) {
+ return delegate().toArray();
+ }
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ synchronized (mutex) {
+ return delegate().toArray(a);
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ @VisibleForTesting static <E> Set<E> set(Set<E> set, @Nullable Object mutex) {
+ return new SynchronizedSet<E>(set, mutex);
+ }
+
+ static class SynchronizedSet<E>
+ extends SynchronizedCollection<E> implements Set<E> {
+
+ SynchronizedSet(Set<E> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @Override Set<E> delegate() {
+ return (Set<E>) super.delegate();
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ synchronized (mutex) {
+ return delegate().equals(o);
+ }
+ }
+
+ @Override public int hashCode() {
+ synchronized (mutex) {
+ return delegate().hashCode();
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static <E> SortedSet<E> sortedSet(
+ SortedSet<E> set, @Nullable Object mutex) {
+ return new SynchronizedSortedSet<E>(set, mutex);
+ }
+
+ static class SynchronizedSortedSet<E> extends SynchronizedSet<E>
+ implements SortedSet<E> {
+ SynchronizedSortedSet(SortedSet<E> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @Override SortedSet<E> delegate() {
+ return (SortedSet<E>) super.delegate();
+ }
+
+ @Override
+ public Comparator<? super E> comparator() {
+ synchronized (mutex) {
+ return delegate().comparator();
+ }
+ }
+
+ @Override
+ public SortedSet<E> subSet(E fromElement, E toElement) {
+ synchronized (mutex) {
+ return sortedSet(delegate().subSet(fromElement, toElement), mutex);
+ }
+ }
+
+ @Override
+ public SortedSet<E> headSet(E toElement) {
+ synchronized (mutex) {
+ return sortedSet(delegate().headSet(toElement), mutex);
+ }
+ }
+
+ @Override
+ public SortedSet<E> tailSet(E fromElement) {
+ synchronized (mutex) {
+ return sortedSet(delegate().tailSet(fromElement), mutex);
+ }
+ }
+
+ @Override
+ public E first() {
+ synchronized (mutex) {
+ return delegate().first();
+ }
+ }
+
+ @Override
+ public E last() {
+ synchronized (mutex) {
+ return delegate().last();
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static <E> List<E> list(List<E> list, @Nullable Object mutex) {
+ return (list instanceof RandomAccess)
+ ? new SynchronizedRandomAccessList<E>(list, mutex)
+ : new SynchronizedList<E>(list, mutex);
+ }
+
+ private static class SynchronizedList<E> extends SynchronizedCollection<E>
+ implements List<E> {
+ SynchronizedList(List<E> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @Override List<E> delegate() {
+ return (List<E>) super.delegate();
+ }
+
+ @Override
+ public void add(int index, E element) {
+ synchronized (mutex) {
+ delegate().add(index, element);
+ }
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends E> c) {
+ synchronized (mutex) {
+ return delegate().addAll(index, c);
+ }
+ }
+
+ @Override
+ public E get(int index) {
+ synchronized (mutex) {
+ return delegate().get(index);
+ }
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ synchronized (mutex) {
+ return delegate().indexOf(o);
+ }
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ synchronized (mutex) {
+ return delegate().lastIndexOf(o);
+ }
+ }
+
+ @Override
+ public ListIterator<E> listIterator() {
+ return delegate().listIterator(); // manually synchronized
+ }
+
+ @Override
+ public ListIterator<E> listIterator(int index) {
+ return delegate().listIterator(index); // manually synchronized
+ }
+
+ @Override
+ public E remove(int index) {
+ synchronized (mutex) {
+ return delegate().remove(index);
+ }
+ }
+
+ @Override
+ public E set(int index, E element) {
+ synchronized (mutex) {
+ return delegate().set(index, element);
+ }
+ }
+
+ @Override
+ public List<E> subList(int fromIndex, int toIndex) {
+ synchronized (mutex) {
+ return list(delegate().subList(fromIndex, toIndex), mutex);
+ }
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ synchronized (mutex) {
+ return delegate().equals(o);
+ }
+ }
+
+ @Override public int hashCode() {
+ synchronized (mutex) {
+ return delegate().hashCode();
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static class SynchronizedRandomAccessList<E>
+ extends SynchronizedList<E> implements RandomAccess {
+ SynchronizedRandomAccessList(List<E> list, @Nullable Object mutex) {
+ super(list, mutex);
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ static <E> Multiset<E> multiset(
+ Multiset<E> multiset, @Nullable Object mutex) {
+ if (multiset instanceof SynchronizedMultiset ||
+ multiset instanceof ImmutableMultiset) {
+ return multiset;
+ }
+ return new SynchronizedMultiset<E>(multiset, mutex);
+ }
+
+ private static class SynchronizedMultiset<E> extends SynchronizedCollection<E>
+ implements Multiset<E> {
+ transient Set<E> elementSet;
+ transient Set<Entry<E>> entrySet;
+
+ SynchronizedMultiset(Multiset<E> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @Override Multiset<E> delegate() {
+ return (Multiset<E>) super.delegate();
+ }
+
+ @Override
+ public int count(Object o) {
+ synchronized (mutex) {
+ return delegate().count(o);
+ }
+ }
+
+ @Override
+ public int add(E e, int n) {
+ synchronized (mutex) {
+ return delegate().add(e, n);
+ }
+ }
+
+ @Override
+ public int remove(Object o, int n) {
+ synchronized (mutex) {
+ return delegate().remove(o, n);
+ }
+ }
+
+ @Override
+ public int setCount(E element, int count) {
+ synchronized (mutex) {
+ return delegate().setCount(element, count);
+ }
+ }
+
+ @Override
+ public boolean setCount(E element, int oldCount, int newCount) {
+ synchronized (mutex) {
+ return delegate().setCount(element, oldCount, newCount);
+ }
+ }
+
+ @Override
+ public Set<E> elementSet() {
+ synchronized (mutex) {
+ if (elementSet == null) {
+ elementSet = typePreservingSet(delegate().elementSet(), mutex);
+ }
+ return elementSet;
+ }
+ }
+
+ @Override
+ public Set<Entry<E>> entrySet() {
+ synchronized (mutex) {
+ if (entrySet == null) {
+ entrySet = typePreservingSet(delegate().entrySet(), mutex);
+ }
+ return entrySet;
+ }
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ synchronized (mutex) {
+ return delegate().equals(o);
+ }
+ }
+
+ @Override public int hashCode() {
+ synchronized (mutex) {
+ return delegate().hashCode();
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ static <K, V> Multimap<K, V> multimap(
+ Multimap<K, V> multimap, @Nullable Object mutex) {
+ if (multimap instanceof SynchronizedMultimap ||
+ multimap instanceof ImmutableMultimap) {
+ return multimap;
+ }
+ return new SynchronizedMultimap<K, V>(multimap, mutex);
+ }
+
+ private static class SynchronizedMultimap<K, V> extends SynchronizedObject
+ implements Multimap<K, V> {
+ transient Set<K> keySet;
+ transient Collection<V> valuesCollection;
+ transient Collection<Map.Entry<K, V>> entries;
+ transient Map<K, Collection<V>> asMap;
+ transient Multiset<K> keys;
+
+ @SuppressWarnings("unchecked")
+ @Override Multimap<K, V> delegate() {
+ return (Multimap<K, V>) super.delegate();
+ }
+
+ SynchronizedMultimap(Multimap<K, V> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @Override
+ public int size() {
+ synchronized (mutex) {
+ return delegate().size();
+ }
+ }
+
+ @Override
+ public boolean isEmpty() {
+ synchronized (mutex) {
+ return delegate().isEmpty();
+ }
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ synchronized (mutex) {
+ return delegate().containsKey(key);
+ }
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ synchronized (mutex) {
+ return delegate().containsValue(value);
+ }
+ }
+
+ @Override
+ public boolean containsEntry(Object key, Object value) {
+ synchronized (mutex) {
+ return delegate().containsEntry(key, value);
+ }
+ }
+
+ @Override
+ public Collection<V> get(K key) {
+ synchronized (mutex) {
+ return typePreservingCollection(delegate().get(key), mutex);
+ }
+ }
+
+ @Override
+ public boolean put(K key, V value) {
+ synchronized (mutex) {
+ return delegate().put(key, value);
+ }
+ }
+
+ @Override
+ public boolean putAll(K key, Iterable<? extends V> values) {
+ synchronized (mutex) {
+ return delegate().putAll(key, values);
+ }
+ }
+
+ @Override
+ public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ synchronized (mutex) {
+ return delegate().putAll(multimap);
+ }
+ }
+
+ @Override
+ public Collection<V> replaceValues(K key, Iterable<? extends V> values) {
+ synchronized (mutex) {
+ return delegate().replaceValues(key, values); // copy not synchronized
+ }
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ synchronized (mutex) {
+ return delegate().remove(key, value);
+ }
+ }
+
+ @Override
+ public Collection<V> removeAll(Object key) {
+ synchronized (mutex) {
+ return delegate().removeAll(key); // copy not synchronized
+ }
+ }
+
+ @Override
+ public void clear() {
+ synchronized (mutex) {
+ delegate().clear();
+ }
+ }
+
+ @Override
+ public Set<K> keySet() {
+ synchronized (mutex) {
+ if (keySet == null) {
+ keySet = typePreservingSet(delegate().keySet(), mutex);
+ }
+ return keySet;
+ }
+ }
+
+ @Override
+ public Collection<V> values() {
+ synchronized (mutex) {
+ if (valuesCollection == null) {
+ valuesCollection = collection(delegate().values(), mutex);
+ }
+ return valuesCollection;
+ }
+ }
+
+ @Override
+ public Collection<Map.Entry<K, V>> entries() {
+ synchronized (mutex) {
+ if (entries == null) {
+ entries = typePreservingCollection(delegate().entries(), mutex);
+ }
+ return entries;
+ }
+ }
+
+ @Override
+ public Map<K, Collection<V>> asMap() {
+ synchronized (mutex) {
+ if (asMap == null) {
+ asMap = new SynchronizedAsMap<K, V>(delegate().asMap(), mutex);
+ }
+ return asMap;
+ }
+ }
+
+ @Override
+ public Multiset<K> keys() {
+ synchronized (mutex) {
+ if (keys == null) {
+ keys = multiset(delegate().keys(), mutex);
+ }
+ return keys;
+ }
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ synchronized (mutex) {
+ return delegate().equals(o);
+ }
+ }
+
+ @Override public int hashCode() {
+ synchronized (mutex) {
+ return delegate().hashCode();
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ static <K, V> ListMultimap<K, V> listMultimap(
+ ListMultimap<K, V> multimap, @Nullable Object mutex) {
+ if (multimap instanceof SynchronizedListMultimap ||
+ multimap instanceof ImmutableListMultimap) {
+ return multimap;
+ }
+ return new SynchronizedListMultimap<K, V>(multimap, mutex);
+ }
+
+ private static class SynchronizedListMultimap<K, V>
+ extends SynchronizedMultimap<K, V> implements ListMultimap<K, V> {
+ SynchronizedListMultimap(
+ ListMultimap<K, V> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+ @Override ListMultimap<K, V> delegate() {
+ return (ListMultimap<K, V>) super.delegate();
+ }
+ @Override public List<V> get(K key) {
+ synchronized (mutex) {
+ return list(delegate().get(key), mutex);
+ }
+ }
+ @Override public List<V> removeAll(Object key) {
+ synchronized (mutex) {
+ return delegate().removeAll(key); // copy not synchronized
+ }
+ }
+ @Override public List<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ synchronized (mutex) {
+ return delegate().replaceValues(key, values); // copy not synchronized
+ }
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ static <K, V> SetMultimap<K, V> setMultimap(
+ SetMultimap<K, V> multimap, @Nullable Object mutex) {
+ if (multimap instanceof SynchronizedSetMultimap ||
+ multimap instanceof ImmutableSetMultimap) {
+ return multimap;
+ }
+ return new SynchronizedSetMultimap<K, V>(multimap, mutex);
+ }
+
+ private static class SynchronizedSetMultimap<K, V>
+ extends SynchronizedMultimap<K, V> implements SetMultimap<K, V> {
+ transient Set<Map.Entry<K, V>> entrySet;
+
+ SynchronizedSetMultimap(
+ SetMultimap<K, V> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+ @Override SetMultimap<K, V> delegate() {
+ return (SetMultimap<K, V>) super.delegate();
+ }
+ @Override public Set<V> get(K key) {
+ synchronized (mutex) {
+ return set(delegate().get(key), mutex);
+ }
+ }
+ @Override public Set<V> removeAll(Object key) {
+ synchronized (mutex) {
+ return delegate().removeAll(key); // copy not synchronized
+ }
+ }
+ @Override public Set<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ synchronized (mutex) {
+ return delegate().replaceValues(key, values); // copy not synchronized
+ }
+ }
+ @Override public Set<Map.Entry<K, V>> entries() {
+ synchronized (mutex) {
+ if (entrySet == null) {
+ entrySet = set(delegate().entries(), mutex);
+ }
+ return entrySet;
+ }
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ static <K, V> SortedSetMultimap<K, V> sortedSetMultimap(
+ SortedSetMultimap<K, V> multimap, @Nullable Object mutex) {
+ if (multimap instanceof SynchronizedSortedSetMultimap) {
+ return multimap;
+ }
+ return new SynchronizedSortedSetMultimap<K, V>(multimap, mutex);
+ }
+
+ private static class SynchronizedSortedSetMultimap<K, V>
+ extends SynchronizedSetMultimap<K, V> implements SortedSetMultimap<K, V> {
+ SynchronizedSortedSetMultimap(
+ SortedSetMultimap<K, V> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+ @Override SortedSetMultimap<K, V> delegate() {
+ return (SortedSetMultimap<K, V>) super.delegate();
+ }
+ @Override public SortedSet<V> get(K key) {
+ synchronized (mutex) {
+ return sortedSet(delegate().get(key), mutex);
+ }
+ }
+ @Override public SortedSet<V> removeAll(Object key) {
+ synchronized (mutex) {
+ return delegate().removeAll(key); // copy not synchronized
+ }
+ }
+ @Override public SortedSet<V> replaceValues(
+ K key, Iterable<? extends V> values) {
+ synchronized (mutex) {
+ return delegate().replaceValues(key, values); // copy not synchronized
+ }
+ }
+ @Override
+ public Comparator<? super V> valueComparator() {
+ synchronized (mutex) {
+ return delegate().valueComparator();
+ }
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ private static <E> Collection<E> typePreservingCollection(
+ Collection<E> collection, @Nullable Object mutex) {
+ if (collection instanceof SortedSet) {
+ return sortedSet((SortedSet<E>) collection, mutex);
+ }
+ if (collection instanceof Set) {
+ return set((Set<E>) collection, mutex);
+ }
+ if (collection instanceof List) {
+ return list((List<E>) collection, mutex);
+ }
+ return collection(collection, mutex);
+ }
+
+ private static <E> Set<E> typePreservingSet(
+ Set<E> set, @Nullable Object mutex) {
+ if (set instanceof SortedSet) {
+ return sortedSet((SortedSet<E>) set, mutex);
+ } else {
+ return set(set, mutex);
+ }
+ }
+
+ private static class SynchronizedAsMapEntries<K, V>
+ extends SynchronizedSet<Map.Entry<K, Collection<V>>> {
+ SynchronizedAsMapEntries(
+ Set<Map.Entry<K, Collection<V>>> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @Override public Iterator<Map.Entry<K, Collection<V>>> iterator() {
+ // Must be manually synchronized.
+ final Iterator<Map.Entry<K, Collection<V>>> iterator = super.iterator();
+ return new ForwardingIterator<Map.Entry<K, Collection<V>>>() {
+ @Override protected Iterator<Map.Entry<K, Collection<V>>> delegate() {
+ return iterator;
+ }
+
+ @Override public Map.Entry<K, Collection<V>> next() {
+ final Map.Entry<K, Collection<V>> entry = super.next();
+ return new ForwardingMapEntry<K, Collection<V>>() {
+ @Override protected Map.Entry<K, Collection<V>> delegate() {
+ return entry;
+ }
+ @Override public Collection<V> getValue() {
+ return typePreservingCollection(entry.getValue(), mutex);
+ }
+ };
+ }
+ };
+ }
+
+ // See Collections.CheckedMap.CheckedEntrySet for details on attacks.
+
+ @Override public Object[] toArray() {
+ synchronized (mutex) {
+ return ObjectArrays.toArrayImpl(delegate());
+ }
+ }
+ @Override public <T> T[] toArray(T[] array) {
+ synchronized (mutex) {
+ return ObjectArrays.toArrayImpl(delegate(), array);
+ }
+ }
+ @Override public boolean contains(Object o) {
+ synchronized (mutex) {
+ return Maps.containsEntryImpl(delegate(), o);
+ }
+ }
+ @Override public boolean containsAll(Collection<?> c) {
+ synchronized (mutex) {
+ return Collections2.containsAllImpl(delegate(), c);
+ }
+ }
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ synchronized (mutex) {
+ return Sets.equalsImpl(delegate(), o);
+ }
+ }
+ @Override public boolean remove(Object o) {
+ synchronized (mutex) {
+ return Maps.removeEntryImpl(delegate(), o);
+ }
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ synchronized (mutex) {
+ return Iterators.removeAll(delegate().iterator(), c);
+ }
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ synchronized (mutex) {
+ return Iterators.retainAll(delegate().iterator(), c);
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ @VisibleForTesting
+ static <K, V> Map<K, V> map(Map<K, V> map, @Nullable Object mutex) {
+ return new SynchronizedMap<K, V>(map, mutex);
+ }
+
+ private static class SynchronizedMap<K, V> extends SynchronizedObject
+ implements Map<K, V> {
+ transient Set<K> keySet;
+ transient Collection<V> values;
+ transient Set<Map.Entry<K, V>> entrySet;
+
+ SynchronizedMap(Map<K, V> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override Map<K, V> delegate() {
+ return (Map<K, V>) super.delegate();
+ }
+
+ @Override
+ public void clear() {
+ synchronized (mutex) {
+ delegate().clear();
+ }
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ synchronized (mutex) {
+ return delegate().containsKey(key);
+ }
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ synchronized (mutex) {
+ return delegate().containsValue(value);
+ }
+ }
+
+ @Override
+ public Set<Map.Entry<K, V>> entrySet() {
+ synchronized (mutex) {
+ if (entrySet == null) {
+ entrySet = set(delegate().entrySet(), mutex);
+ }
+ return entrySet;
+ }
+ }
+
+ @Override
+ public V get(Object key) {
+ synchronized (mutex) {
+ return delegate().get(key);
+ }
+ }
+
+ @Override
+ public boolean isEmpty() {
+ synchronized (mutex) {
+ return delegate().isEmpty();
+ }
+ }
+
+ @Override
+ public Set<K> keySet() {
+ synchronized (mutex) {
+ if (keySet == null) {
+ keySet = set(delegate().keySet(), mutex);
+ }
+ return keySet;
+ }
+ }
+
+ @Override
+ public V put(K key, V value) {
+ synchronized (mutex) {
+ return delegate().put(key, value);
+ }
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> map) {
+ synchronized (mutex) {
+ delegate().putAll(map);
+ }
+ }
+
+ @Override
+ public V remove(Object key) {
+ synchronized (mutex) {
+ return delegate().remove(key);
+ }
+ }
+
+ @Override
+ public int size() {
+ synchronized (mutex) {
+ return delegate().size();
+ }
+ }
+
+ @Override
+ public Collection<V> values() {
+ synchronized (mutex) {
+ if (values == null) {
+ values = collection(delegate().values(), mutex);
+ }
+ return values;
+ }
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ synchronized (mutex) {
+ return delegate().equals(o);
+ }
+ }
+
+ @Override public int hashCode() {
+ synchronized (mutex) {
+ return delegate().hashCode();
+ }
+ }
+
+ 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> {
+
+ SynchronizedSortedMap(SortedMap<K, V> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @Override SortedMap<K, V> delegate() {
+ return (SortedMap<K, V>) super.delegate();
+ }
+
+ @Override public Comparator<? super K> comparator() {
+ synchronized (mutex) {
+ return delegate().comparator();
+ }
+ }
+
+ @Override public K firstKey() {
+ synchronized (mutex) {
+ return delegate().firstKey();
+ }
+ }
+
+ @Override public SortedMap<K, V> headMap(K toKey) {
+ synchronized (mutex) {
+ return sortedMap(delegate().headMap(toKey), mutex);
+ }
+ }
+
+ @Override public K lastKey() {
+ synchronized (mutex) {
+ return delegate().lastKey();
+ }
+ }
+
+ @Override public SortedMap<K, V> subMap(K fromKey, K toKey) {
+ synchronized (mutex) {
+ return sortedMap(delegate().subMap(fromKey, toKey), mutex);
+ }
+ }
+
+ @Override public SortedMap<K, V> tailMap(K fromKey) {
+ synchronized (mutex) {
+ return sortedMap(delegate().tailMap(fromKey), mutex);
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ static <K, V> BiMap<K, V> biMap(BiMap<K, V> bimap, @Nullable Object mutex) {
+ if (bimap instanceof SynchronizedBiMap ||
+ bimap instanceof ImmutableBiMap) {
+ return bimap;
+ }
+ return new SynchronizedBiMap<K, V>(bimap, mutex, null);
+ }
+
+ @VisibleForTesting static class SynchronizedBiMap<K, V>
+ extends SynchronizedMap<K, V> implements BiMap<K, V>, Serializable {
+ private transient Set<V> valueSet;
+ private transient BiMap<V, K> inverse;
+
+ private SynchronizedBiMap(BiMap<K, V> delegate, @Nullable Object mutex,
+ @Nullable BiMap<V, K> inverse) {
+ super(delegate, mutex);
+ this.inverse = inverse;
+ }
+
+ @Override BiMap<K, V> delegate() {
+ return (BiMap<K, V>) super.delegate();
+ }
+
+ @Override public Set<V> values() {
+ synchronized (mutex) {
+ if (valueSet == null) {
+ valueSet = set(delegate().values(), mutex);
+ }
+ return valueSet;
+ }
+ }
+
+ @Override
+ public V forcePut(K key, V value) {
+ synchronized (mutex) {
+ return delegate().forcePut(key, value);
+ }
+ }
+
+ @Override
+ public BiMap<V, K> inverse() {
+ synchronized (mutex) {
+ if (inverse == null) {
+ inverse
+ = new SynchronizedBiMap<V, K>(delegate().inverse(), mutex, this);
+ }
+ return inverse;
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static class SynchronizedAsMap<K, V>
+ extends SynchronizedMap<K, Collection<V>> {
+ transient Set<Map.Entry<K, Collection<V>>> asMapEntrySet;
+ transient Collection<Collection<V>> asMapValues;
+
+ SynchronizedAsMap(Map<K, Collection<V>> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @Override public Collection<V> get(Object key) {
+ synchronized (mutex) {
+ Collection<V> collection = super.get(key);
+ return (collection == null) ? null
+ : typePreservingCollection(collection, mutex);
+ }
+ }
+
+ @Override public Set<Map.Entry<K, Collection<V>>> entrySet() {
+ synchronized (mutex) {
+ if (asMapEntrySet == null) {
+ asMapEntrySet = new SynchronizedAsMapEntries<K, V>(
+ delegate().entrySet(), mutex);
+ }
+ return asMapEntrySet;
+ }
+ }
+
+ @Override public Collection<Collection<V>> values() {
+ synchronized (mutex) {
+ if (asMapValues == null) {
+ asMapValues
+ = new SynchronizedAsMapValues<V>(delegate().values(), mutex);
+ }
+ return asMapValues;
+ }
+ }
+
+ @Override public boolean containsValue(Object o) {
+ // values() and its contains() method are both synchronized.
+ return values().contains(o);
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static class SynchronizedAsMapValues<V>
+ extends SynchronizedCollection<Collection<V>> {
+ SynchronizedAsMapValues(
+ Collection<Collection<V>> delegate, @Nullable Object mutex) {
+ super(delegate, mutex);
+ }
+
+ @Override public Iterator<Collection<V>> iterator() {
+ // Must be manually synchronized.
+ final Iterator<Collection<V>> iterator = super.iterator();
+ return new ForwardingIterator<Collection<V>>() {
+ @Override protected Iterator<Collection<V>> delegate() {
+ return iterator;
+ }
+ @Override public Collection<V> next() {
+ return typePreservingCollection(super.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;
+ }
+}
diff --git a/guava/src/com/google/common/collect/Table.java b/guava/src/com/google/common/collect/Table.java
new file mode 100644
index 0000000..c384bf8
--- /dev/null
+++ b/guava/src/com/google/common/collect/Table.java
@@ -0,0 +1,296 @@
+/*
+ * 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.base.Objects;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * A collection that associates an ordered pair of keys, called a row key and a
+ * column key, with a single value. A table may be sparse, with only a small
+ * fraction of row key / column key pairs possessing a corresponding value.
+ *
+ * <p>The mappings corresponding to a given row key may be viewed as a {@link
+ * Map} whose keys are the columns. The reverse is also available, associating a
+ * column with a row key / value map. Note that, in some implementations, data
+ * access by column key may have fewer supported operations or worse performance
+ * than data access by row key.
+ *
+ * <p>The methods returning collections or maps always return views of the
+ * underlying table. Updating the table can change the contents of those
+ * collections, and updating the collections will change the table.
+ *
+ * <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
+ * @param <C> the type of the table column keys
+ * @param <V> the type of the mapped values
+ * @since 7.0
+ */
+@GwtCompatible
+public interface Table<R, C, V> {
+ // TODO(jlevy): Consider adding methods similar to ConcurrentMap methods.
+
+ // Accessors
+
+ /**
+ * Returns {@code true} if the table contains a mapping with the specified
+ * row and column keys.
+ *
+ * @param rowKey key of row to search for
+ * @param columnKey key of column to search for
+ */
+ boolean contains(@Nullable Object rowKey, @Nullable Object columnKey);
+
+ /**
+ * Returns {@code true} if the table contains a mapping with the specified
+ * row key.
+ *
+ * @param rowKey key of row to search for
+ */
+ boolean containsRow(@Nullable Object rowKey);
+
+ /**
+ * Returns {@code true} if the table contains a mapping with the specified
+ * column.
+ *
+ * @param columnKey key of column to search for
+ */
+ boolean containsColumn(@Nullable Object columnKey);
+
+ /**
+ * Returns {@code true} if the table contains a mapping with the specified
+ * value.
+ *
+ * @param value value to search for
+ */
+ boolean containsValue(@Nullable Object value);
+
+ /**
+ * Returns the value corresponding to the given row and column keys, or
+ * {@code null} if no such mapping exists.
+ *
+ * @param rowKey key of row to search for
+ * @param columnKey key of column to search for
+ */
+ V get(@Nullable Object rowKey, @Nullable Object columnKey);
+
+ /** Returns {@code true} if the table contains no mappings. */
+ boolean isEmpty();
+
+ /**
+ * Returns the number of row key / column key / value mappings in the table.
+ */
+ int size();
+
+ /**
+ * Compares the specified object with this table for equality. Two tables are
+ * equal when their cell views, as returned by {@link #cellSet}, are equal.
+ */
+ @Override
+ boolean equals(@Nullable Object obj);
+
+ /**
+ * Returns the hash code for this table. The hash code of a table is defined
+ * as the hash code of its cell view, as returned by {@link #cellSet}.
+ */
+ @Override
+ int hashCode();
+
+ // Mutators
+
+ /** Removes all mappings from the table. */
+ void clear();
+
+ /**
+ * Associates the specified value with the specified keys. If the table
+ * already contained a mapping for those keys, the old value is replaced with
+ * the specified value.
+ *
+ * @param rowKey row key that the value should be associated with
+ * @param columnKey column key that the value should be associated with
+ * @param value value to be associated with the specified keys
+ * @return the value previously associated with the keys, or {@code null} if
+ * no mapping existed for the keys
+ */
+ V put(R rowKey, C columnKey, V value);
+
+ /**
+ * Copies all mappings from the specified table to this table. The effect is
+ * equivalent to calling {@link #put} with each row key / column key / value
+ * mapping in {@code table}.
+ *
+ * @param table the table to add to this table
+ */
+ void putAll(Table<? extends R, ? extends C, ? extends V> table);
+
+ /**
+ * Removes the mapping, if any, associated with the given keys.
+ *
+ * @param rowKey row key of mapping to be removed
+ * @param columnKey column key of mapping to be removed
+ * @return the value previously associated with the keys, or {@code null} if
+ * no such value existed
+ */
+ V remove(@Nullable Object rowKey, @Nullable Object columnKey);
+
+ // Views
+
+ /**
+ * Returns a view of all mappings that have the given row key. For each row
+ * key / column key / value mapping in the table with that row key, the
+ * returned map associates the column key with the value. If no mappings in
+ * the table have the provided row key, an empty map is returned.
+ *
+ * <p>Changes to the returned map will update the underlying table, and vice
+ * versa.
+ *
+ * @param rowKey key of row to search for in the table
+ * @return the corresponding map from column keys to values
+ */
+ Map<C, V> row(R rowKey);
+
+ /**
+ * Returns a view of all mappings that have the given column key. For each row
+ * key / column key / value mapping in the table with that column key, the
+ * returned map associates the row key with the value. If no mappings in the
+ * table have the provided column key, an empty map is returned.
+ *
+ * <p>Changes to the returned map will update the underlying table, and vice
+ * versa.
+ *
+ * @param columnKey key of column to search for in the table
+ * @return the corresponding map from row keys to values
+ */
+ Map<R, V> column(C columnKey);
+
+ /**
+ * Returns a set of all row key / column key / value triplets. Changes to the
+ * returned set will update the underlying table, and vice versa. The cell set
+ * does not support the {@code add} or {@code addAll} methods.
+ *
+ * @return set of table cells consisting of row key / column key / value
+ * triplets
+ */
+ Set<Cell<R, C, V>> cellSet();
+
+ /**
+ * Returns a set of row keys that have one or more values in the table.
+ * Changes to the set will update the underlying table, and vice versa.
+ *
+ * @return set of row keys
+ */
+ Set<R> rowKeySet();
+
+ /**
+ * Returns a set of column keys that have one or more values in the table.
+ * Changes to the set will update the underlying table, and vice versa.
+ *
+ * @return set of column keys
+ */
+ Set<C> columnKeySet();
+
+ /**
+ * Returns a collection of all values, which may contain duplicates. Changes
+ * to the returned collection will update the underlying table, and vice
+ * versa.
+ *
+ * @return collection of values
+ */
+ Collection<V> values();
+
+ /**
+ * Returns a view that associates each row key with the corresponding map from
+ * column keys to values. Changes to the returned map will update this table.
+ * The returned map does not support {@code put()} or {@code putAll()}, or
+ * {@code setValue()} on its entries.
+ *
+ * <p>In contrast, the maps returned by {@code rowMap().get()} have the same
+ * behavior as those returned by {@link #row}. Those maps may support {@code
+ * setValue()}, {@code put()}, and {@code putAll()}.
+ *
+ * @return a map view from each row key to a secondary map from column keys to
+ * values
+ */
+ Map<R, Map<C, V>> rowMap();
+
+ /**
+ * Returns a view that associates each column key with the corresponding map
+ * from row keys to values. Changes to the returned map will update this
+ * table. The returned map does not support {@code put()} or {@code putAll()},
+ * or {@code setValue()} on its entries.
+ *
+ * <p>In contrast, the maps returned by {@code columnMap().get()} have the
+ * same behavior as those returned by {@link #column}. Those maps may support
+ * {@code setValue()}, {@code put()}, and {@code putAll()}.
+ *
+ * @return a map view from each column key to a secondary map from row keys to
+ * values
+ */
+ Map<C, Map<R, V>> columnMap();
+
+ /**
+ * Row key / column key / value triplet corresponding to a mapping in a table.
+ *
+ * @since 7.0
+ */
+ interface Cell<R, C, V> {
+ /**
+ * Returns the row key of this cell.
+ */
+ R getRowKey();
+
+ /**
+ * Returns the column key of this cell.
+ */
+ C getColumnKey();
+
+ /**
+ * Returns the value of this cell.
+ */
+ V getValue();
+
+ /**
+ * Compares the specified object with this cell for equality. Two cells are
+ * equal when they have equal row keys, column keys, and values.
+ */
+ @Override
+ boolean equals(@Nullable Object obj);
+
+ /**
+ * Returns the hash code of this cell.
+ *
+ * <p>The hash code of a table cell is equal to {@link
+ * Objects#hashCode}{@code (e.getRowKey(), e.getColumnKey(), e.getValue())}.
+ */
+ @Override
+ int hashCode();
+ }
+}
diff --git a/guava/src/com/google/common/collect/Tables.java b/guava/src/com/google/common/collect/Tables.java
new file mode 100644
index 0000000..028aba3
--- /dev/null
+++ b/guava/src/com/google/common/collect/Tables.java
@@ -0,0 +1,753 @@
+/*
+ * 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.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.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Collections2.TransformedCollection;
+import com.google.common.collect.Table.Cell;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+
+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
+public final class Tables {
+ private Tables() {}
+
+ /**
+ * Returns an immutable cell with the specified row key, column key, and
+ * value.
+ *
+ * <p>The returned cell is serializable.
+ *
+ * @param rowKey the row key to be associated with the returned cell
+ * @param columnKey the column key to be associated with the returned cell
+ * @param value the value to be associated with the returned cell
+ */
+ public static <R, C, V> Cell<R, C, V> immutableCell(
+ @Nullable R rowKey, @Nullable C columnKey, @Nullable V value) {
+ return new ImmutableCell<R, C, V>(rowKey, columnKey, value);
+ }
+
+ static final class ImmutableCell<R, C, V>
+ extends AbstractCell<R, C, V> implements Serializable {
+ private final R rowKey;
+ private final C columnKey;
+ private final V value;
+
+ ImmutableCell(
+ @Nullable R rowKey, @Nullable C columnKey, @Nullable V value) {
+ this.rowKey = rowKey;
+ this.columnKey = columnKey;
+ this.value = value;
+ }
+
+ @Override
+ public R getRowKey() {
+ return rowKey;
+ }
+ @Override
+ public C getColumnKey() {
+ return columnKey;
+ }
+ @Override
+ public V getValue() {
+ return value;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ abstract static class AbstractCell<R, C, V> implements Cell<R, C, V> {
+ // needed for serialization
+ AbstractCell() {}
+
+ @Override public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Cell) {
+ Cell<?, ?, ?> other = (Cell<?, ?, ?>) obj;
+ return Objects.equal(getRowKey(), other.getRowKey())
+ && Objects.equal(getColumnKey(), other.getColumnKey())
+ && Objects.equal(getValue(), other.getValue());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(getRowKey(), getColumnKey(), getValue());
+ }
+
+ @Override public String toString() {
+ return "(" + getRowKey() + "," + getColumnKey() + ")=" + getValue();
+ }
+ }
+
+ /**
+ * Creates a transposed view of a given table that flips its row and column
+ * keys. In other words, calling {@code get(columnKey, rowKey)} on the
+ * generated table always returns the same value as calling {@code
+ * get(rowKey, columnKey)} on the original table. Updating the original table
+ * changes the contents of the transposed table and vice versa.
+ *
+ * <p>The returned table supports update operations as long as the input table
+ * supports the analogous operation with swapped rows and columns. For
+ * example, in a {@link HashBasedTable} instance, {@code
+ * rowKeySet().iterator()} supports {@code remove()} but {@code
+ * columnKeySet().iterator()} doesn't. With a transposed {@link
+ * HashBasedTable}, it's the other way around.
+ */
+ public static <R, C, V> Table<C, R, V> transpose(Table<R, C, V> table) {
+ return (table instanceof TransposeTable)
+ ? ((TransposeTable<R, C, V>) table).original
+ : new TransposeTable<C, R, V>(table);
+ }
+
+ private static class TransposeTable<C, R, V> implements Table<C, R, V> {
+ final Table<R, C, V> original;
+
+ TransposeTable(Table<R, C, V> original) {
+ this.original = checkNotNull(original);
+ }
+
+ @Override
+ public void clear() {
+ original.clear();
+ }
+
+ @Override
+ public Map<C, V> column(R columnKey) {
+ return original.row(columnKey);
+ }
+
+ @Override
+ public Set<R> columnKeySet() {
+ return original.rowKeySet();
+ }
+
+ @Override
+ public Map<R, Map<C, V>> columnMap() {
+ return original.rowMap();
+ }
+
+ @Override
+ public boolean contains(
+ @Nullable Object rowKey, @Nullable Object columnKey) {
+ return original.contains(columnKey, rowKey);
+ }
+
+ @Override
+ public boolean containsColumn(@Nullable Object columnKey) {
+ return original.containsRow(columnKey);
+ }
+
+ @Override
+ public boolean containsRow(@Nullable Object rowKey) {
+ return original.containsColumn(rowKey);
+ }
+
+ @Override
+ public boolean containsValue(@Nullable Object value) {
+ return original.containsValue(value);
+ }
+
+ @Override
+ public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
+ return original.get(columnKey, rowKey);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return original.isEmpty();
+ }
+
+ @Override
+ public V put(C rowKey, R columnKey, V value) {
+ return original.put(columnKey, rowKey, value);
+ }
+
+ @Override
+ public void putAll(Table<? extends C, ? extends R, ? extends V> table) {
+ original.putAll(transpose(table));
+ }
+
+ @Override
+ public V remove(@Nullable Object rowKey, @Nullable Object columnKey) {
+ return original.remove(columnKey, rowKey);
+ }
+
+ @Override
+ public Map<R, V> row(C rowKey) {
+ return original.column(rowKey);
+ }
+
+ @Override
+ public Set<C> rowKeySet() {
+ return original.columnKeySet();
+ }
+
+ @Override
+ public Map<C, Map<R, V>> rowMap() {
+ return original.columnMap();
+ }
+
+ @Override
+ public int size() {
+ return original.size();
+ }
+
+ @Override
+ public Collection<V> values() {
+ return original.values();
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Table) {
+ Table<?, ?, ?> other = (Table<?, ?, ?>) obj;
+ return cellSet().equals(other.cellSet());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return cellSet().hashCode();
+ }
+
+ @Override public String toString() {
+ return rowMap().toString();
+ }
+
+ // Will cast TRANSPOSE_CELL to a type that always succeeds
+ private static final Function<Cell<?, ?, ?>, Cell<?, ?, ?>> TRANSPOSE_CELL =
+ new Function<Cell<?, ?, ?>, Cell<?, ?, ?>>() {
+ @Override
+ public Cell<?, ?, ?> apply(Cell<?, ?, ?> cell) {
+ return immutableCell(
+ cell.getColumnKey(), cell.getRowKey(), cell.getValue());
+ }
+ };
+
+ CellSet cellSet;
+
+ @Override
+ public Set<Cell<C, R, V>> cellSet() {
+ CellSet result = cellSet;
+ return (result == null) ? cellSet = new CellSet() : result;
+ }
+
+ class CellSet extends TransformedCollection<Cell<R, C, V>, Cell<C, R, V>>
+ implements Set<Cell<C, R, V>> {
+ // Casting TRANSPOSE_CELL to a type that always succeeds
+ @SuppressWarnings("unchecked")
+ CellSet() {
+ super(original.cellSet(), (Function) TRANSPOSE_CELL);
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof Set)) {
+ return false;
+ }
+ Set<?> os = (Set<?>) obj;
+ if (os.size() != size()) {
+ return false;
+ }
+ return containsAll(os);
+ }
+
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+
+ @Override public boolean contains(Object obj) {
+ if (obj instanceof Cell) {
+ Cell<?, ?, ?> cell = (Cell<?, ?, ?>) obj;
+ return original.cellSet().contains(immutableCell(
+ cell.getColumnKey(), cell.getRowKey(), cell.getValue()));
+ }
+ return false;
+ }
+
+ @Override public boolean remove(Object obj) {
+ if (obj instanceof Cell) {
+ Cell<?, ?, ?> cell = (Cell<?, ?, ?>) obj;
+ return original.cellSet().remove(immutableCell(
+ cell.getColumnKey(), cell.getRowKey(), cell.getValue()));
+ }
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Creates a table that uses the specified backing map and factory. It can
+ * generate a table based on arbitrary {@link Map} classes.
+ *
+ * <p>The {@code factory}-generated and {@code backingMap} classes determine
+ * the table iteration order. However, the table's {@code row()} method
+ * returns instances of a different class than {@code factory.get()} does.
+ *
+ * <p>Call this method only when the simpler factory methods in classes like
+ * {@link HashBasedTable} and {@link TreeBasedTable} won't suffice.
+ *
+ * <p>The views returned by the {@code Table} methods {@link Table#column},
+ * {@link Table#columnKeySet}, and {@link Table#columnMap} have iterators that
+ * don't support {@code remove()}. Otherwise, all optional operations are
+ * supported. Null row keys, columns keys, and values are not supported.
+ *
+ * <p>Lookups by row key are often faster than lookups by column key, because
+ * the data is stored in a {@code Map<R, Map<C, V>>}. A method call like
+ * {@code column(columnKey).get(rowKey)} still runs quickly, since the row key
+ * is provided. However, {@code column(columnKey).size()} takes longer, since
+ * an iteration across all row keys occurs.
+ *
+ * <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>The table is serializable if {@code backingMap}, {@code factory}, the
+ * maps generated by {@code factory}, and the table contents are all
+ * serializable.
+ *
+ * <p>Note: the table assumes complete ownership over of {@code backingMap}
+ * and the maps returned by {@code factory}. Those objects should not be
+ * manually updated and they should not use soft, weak, or phantom references.
+ *
+ * @param backingMap place to store the mapping from each row key to its
+ * corresponding column key / value map
+ * @param factory supplier of new, empty maps that will each hold all column
+ * key / value mappings for a given row key
+ * @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());
+ checkNotNull(factory);
+ // TODO(jlevy): Wrap factory to validate that the supplied maps are empty?
+ return new StandardTable<R, C, V>(backingMap, factory);
+ }
+
+ /**
+ * Returns a view of a table where each value is transformed by a function.
+ * All other properties of the table, such as iteration order, are left
+ * intact.
+ *
+ * <p>Changes in the underlying table are reflected in this view. Conversely,
+ * this view supports removal operations, and these are reflected in the
+ * underlying table.
+ *
+ * <p>It's acceptable for the underlying table to contain null keys, and even
+ * null values provided that the function is capable of accepting null input.
+ * The transformed table might contain null values, if the function sometimes
+ * gives a null result.
+ *
+ * <p>The returned table is not thread-safe or serializable, even if the
+ * underlying table is.
+ *
+ * <p>The function is applied lazily, invoked when needed. This is necessary
+ * for the returned table to be a view, but it means that the function will be
+ * applied many times for bulk operations like {@link Table#containsValue} and
+ * {@code Table.toString()}. For this to perform well, {@code function} should
+ * be fast. To avoid lazy evaluation when the returned table doesn't need to
+ * be a view, copy the returned table into a new table of your choosing.
+ *
+ * @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);
+ }
+
+ private static class TransformedTable<R, C, V1, V2>
+ implements Table<R, C, V2> {
+ final Table<R, C, V1> fromTable;
+ final Function<? super V1, V2> function;
+
+ TransformedTable(
+ Table<R, C, V1> fromTable, Function<? super V1, V2> function) {
+ this.fromTable = checkNotNull(fromTable);
+ this.function = checkNotNull(function);
+ }
+
+ @Override public boolean contains(Object rowKey, Object columnKey) {
+ return fromTable.contains(rowKey, columnKey);
+ }
+
+ @Override public boolean containsRow(Object rowKey) {
+ return fromTable.containsRow(rowKey);
+ }
+
+ @Override public boolean containsColumn(Object columnKey) {
+ return fromTable.containsColumn(columnKey);
+ }
+
+ @Override public boolean containsValue(Object value) {
+ return values().contains(value);
+ }
+
+ @Override public V2 get(Object rowKey, Object columnKey) {
+ // The function is passed a null input only when the table contains a null
+ // value.
+ return contains(rowKey, columnKey)
+ ? function.apply(fromTable.get(rowKey, columnKey)) : null;
+ }
+
+ @Override public boolean isEmpty() {
+ return fromTable.isEmpty();
+ }
+
+ @Override public int size() {
+ return fromTable.size();
+ }
+
+ @Override public void clear() {
+ fromTable.clear();
+ }
+
+ @Override public V2 put(R rowKey, C columnKey, V2 value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void putAll(
+ Table<? extends R, ? extends C, ? extends V2> table) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public V2 remove(Object rowKey, Object columnKey) {
+ return contains(rowKey, columnKey)
+ ? function.apply(fromTable.remove(rowKey, columnKey)) : null;
+ }
+
+ @Override public Map<C, V2> row(R rowKey) {
+ return Maps.transformValues(fromTable.row(rowKey), function);
+ }
+
+ @Override public Map<R, V2> column(C columnKey) {
+ return Maps.transformValues(fromTable.column(columnKey), function);
+ }
+
+ Function<Cell<R, C, V1>, Cell<R, C, V2>> cellFunction() {
+ return new Function<Cell<R, C, V1>, Cell<R, C, V2>>() {
+ @Override public Cell<R, C, V2> apply(Cell<R, C, V1> cell) {
+ return immutableCell(
+ cell.getRowKey(), cell.getColumnKey(),
+ function.apply(cell.getValue()));
+ }
+ };
+ }
+
+ class CellSet extends TransformedCollection<Cell<R, C, V1>, Cell<R, C, V2>>
+ implements Set<Cell<R, C, V2>> {
+ CellSet() {
+ super(fromTable.cellSet(), cellFunction());
+ }
+ @Override public boolean equals(Object obj) {
+ return Sets.equalsImpl(this, obj);
+ }
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+ @Override public boolean contains(Object obj) {
+ if (obj instanceof Cell) {
+ Cell<?, ?, ?> cell = (Cell<?, ?, ?>) obj;
+ if (!Objects.equal(
+ cell.getValue(), get(cell.getRowKey(), cell.getColumnKey()))) {
+ return false;
+ }
+ return cell.getValue() != null
+ || fromTable.contains(cell.getRowKey(), cell.getColumnKey());
+ }
+ return false;
+ }
+ @Override public boolean remove(Object obj) {
+ if (contains(obj)) {
+ Cell<?, ?, ?> cell = (Cell<?, ?, ?>) obj;
+ fromTable.remove(cell.getRowKey(), cell.getColumnKey());
+ return true;
+ }
+ return false;
+ }
+ }
+
+ CellSet cellSet;
+
+ @Override public Set<Cell<R, C, V2>> cellSet() {
+ return (cellSet == null) ? cellSet = new CellSet() : cellSet;
+ }
+
+ @Override public Set<R> rowKeySet() {
+ return fromTable.rowKeySet();
+ }
+
+ @Override public Set<C> columnKeySet() {
+ return fromTable.columnKeySet();
+ }
+
+ Collection<V2> values;
+
+ @Override public Collection<V2> values() {
+ return (values == null)
+ ? values = Collections2.transform(fromTable.values(), function)
+ : values;
+ }
+
+ Map<R, Map<C, V2>> createRowMap() {
+ Function<Map<C, V1>, Map<C, V2>> rowFunction =
+ new Function<Map<C, V1>, Map<C, V2>>() {
+ @Override public Map<C, V2> apply(Map<C, V1> row) {
+ return Maps.transformValues(row, function);
+ }
+ };
+ return Maps.transformValues(fromTable.rowMap(), rowFunction);
+ }
+
+ Map<R, Map<C, V2>> rowMap;
+
+ @Override public Map<R, Map<C, V2>> rowMap() {
+ return (rowMap == null) ? rowMap = createRowMap() : rowMap;
+ }
+
+ Map<C, Map<R, V2>> createColumnMap() {
+ Function<Map<R, V1>, Map<R, V2>> columnFunction =
+ new Function<Map<R, V1>, Map<R, V2>>() {
+ @Override public Map<R, V2> apply(Map<R, V1> column) {
+ return Maps.transformValues(column, function);
+ }
+ };
+ return Maps.transformValues(fromTable.columnMap(), columnFunction);
+ }
+
+ Map<C, Map<R, V2>> columnMap;
+
+ @Override public Map<C, Map<R, V2>> columnMap() {
+ return (columnMap == null) ? columnMap = createColumnMap() : columnMap;
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof Table) {
+ Table<?, ?, ?> other = (Table<?, ?, ?>) obj;
+ return cellSet().equals(other.cellSet());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return cellSet().hashCode();
+ }
+
+ @Override public String toString() {
+ return rowMap().toString();
+ }
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified table. This method allows modules to provide
+ * users with "read-only" access to internal tables. Query operations on the returned table
+ * "read through" to the specified table, and attempts to modify the returned table, whether
+ * direct or via its collection views, result in an {@code UnsupportedOperationException}.
+ *
+ * <p>The returned table will be serializable if the specified table is serializable.
+ *
+ * <p>Consider using an {@link ImmutableTable}, which is guaranteed never to change.
+ *
+ * @param table
+ * the table for which an unmodifiable view is to be returned
+ * @return an unmodifiable view of the specified table
+ * @since 11.0
+ */
+ public static <R, C, V> Table<R, C, V> unmodifiableTable(
+ Table<? extends R, ? extends C, ? extends V> table) {
+ return new UnmodifiableTable<R, C, V>(table);
+ }
+
+ private static class UnmodifiableTable<R, C, V>
+ extends ForwardingTable<R, C, V> implements Serializable {
+ final Table<? extends R, ? extends C, ? extends V> delegate;
+
+ UnmodifiableTable(Table<? extends R, ? extends C, ? extends V> delegate) {
+ this.delegate = checkNotNull(delegate);
+ }
+
+ @SuppressWarnings("unchecked") // safe, covariant cast
+ @Override
+ protected Table<R, C, V> delegate() {
+ return (Table<R, C, V>) delegate;
+ }
+
+ @Override
+ public Set<Cell<R, C, V>> cellSet() {
+ return Collections.unmodifiableSet(super.cellSet());
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<R, V> column(@Nullable C columnKey) {
+ return Collections.unmodifiableMap(super.column(columnKey));
+ }
+
+ @Override
+ public Set<C> columnKeySet() {
+ return Collections.unmodifiableSet(super.columnKeySet());
+ }
+
+ @Override
+ public Map<C, Map<R, V>> columnMap() {
+ Function<Map<R, V>, Map<R, V>> wrapper = unmodifiableWrapper();
+ return Collections.unmodifiableMap(Maps.transformValues(super.columnMap(), wrapper));
+ }
+
+ @Override
+ public V put(@Nullable R rowKey, @Nullable C columnKey, @Nullable V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V remove(@Nullable Object rowKey, @Nullable Object columnKey) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<C, V> row(@Nullable R rowKey) {
+ return Collections.unmodifiableMap(super.row(rowKey));
+ }
+
+ @Override
+ public Set<R> rowKeySet() {
+ return Collections.unmodifiableSet(super.rowKeySet());
+ }
+
+ @Override
+ public Map<R, Map<C, V>> rowMap() {
+ Function<Map<C, V>, Map<C, V>> wrapper = unmodifiableWrapper();
+ return Collections.unmodifiableMap(Maps.transformValues(super.rowMap(), wrapper));
+ }
+
+ @Override
+ public Collection<V> values() {
+ return Collections.unmodifiableCollection(super.values());
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns an unmodifiable view of the specified row-sorted table. This method allows modules to
+ * provide users with "read-only" access to internal tables. Query operations on the returned
+ * table "read through" to the specified table, and attemps to modify the returned table, whether
+ * direct or via its collection views, result in an {@code UnsupportedOperationException}.
+ *
+ * <p>The returned table will be serializable if the specified table is serializable.
+ *
+ * @param table the row-sorted table for which an unmodifiable view is to be returned
+ * @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) {
+ /*
+ * It's not ? extends R, because it's technically not covariant in R. Specifically,
+ * table.rowMap().comparator() could return a comparator that only works for the ? extends R.
+ * Collections.unmodifiableSortedMap makes the same distinction.
+ */
+ return new UnmodifiableRowSortedMap<R, C, V>(table);
+ }
+
+ static final class UnmodifiableRowSortedMap<R, C, V> extends UnmodifiableTable<R, C, V>
+ implements RowSortedTable<R, C, V> {
+
+ public UnmodifiableRowSortedMap(RowSortedTable<R, ? extends C, ? extends V> delegate) {
+ super(delegate);
+ }
+
+ @Override
+ protected RowSortedTable<R, C, V> delegate() {
+ return (RowSortedTable<R, C, V>) super.delegate();
+ }
+
+ @Override
+ public SortedMap<R, Map<C, V>> rowMap() {
+ Function<Map<C, V>, Map<C, V>> wrapper = unmodifiableWrapper();
+ return Collections.unmodifiableSortedMap(Maps.transformValues(delegate().rowMap(), wrapper));
+ }
+
+ @Override
+ public SortedSet<R> rowKeySet() {
+ return Collections.unmodifiableSortedSet(delegate().rowKeySet());
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <K, V> Function<Map<K, V>, Map<K, V>> unmodifiableWrapper() {
+ return (Function) UNMODIFIABLE_WRAPPER;
+ }
+
+ private static final Function<? extends Map<?, ?>, ? extends Map<?, ?>> UNMODIFIABLE_WRAPPER =
+ new Function<Map<Object, Object>, Map<Object, Object>>() {
+ @Override
+ public Map<Object, Object> apply(Map<Object, Object> input) {
+ return Collections.unmodifiableMap(input);
+ }
+ };
+}
diff --git a/guava/src/com/google/common/collect/TransformedImmutableSet.java b/guava/src/com/google/common/collect/TransformedImmutableSet.java
new file mode 100644
index 0000000..a6a59c9
--- /dev/null
+++ b/guava/src/com/google/common/collect/TransformedImmutableSet.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.util.Iterator;
+
+/**
+ * An {@code ImmutableSet} whose elements are derived by transforming another collection's elements,
+ * useful for {@code ImmutableMap.keySet()}.
+ *
+ * @author Jesse Wilson
+ */
+@GwtCompatible(emulated = true)
+abstract class TransformedImmutableSet<D, E> extends ImmutableSet<E> {
+ /*
+ * TODO(cpovirk): using an abstract source() method instead of a field could simplify
+ * ImmutableMapKeySet, which currently has to pass in entrySet() manually
+ */
+ final ImmutableCollection<D> source;
+ final int hashCode;
+
+ TransformedImmutableSet(ImmutableCollection<D> source) {
+ this.source = source;
+ this.hashCode = Sets.hashCodeImpl(this);
+ }
+
+ TransformedImmutableSet(ImmutableCollection<D> source, int hashCode) {
+ this.source = source;
+ this.hashCode = hashCode;
+ }
+
+ abstract E transform(D element);
+
+ @Override
+ public int size() {
+ return source.size();
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public UnmodifiableIterator<E> iterator() {
+ final Iterator<D> backingIterator = source.iterator();
+ return new UnmodifiableIterator<E>() {
+ @Override
+ public boolean hasNext() {
+ return backingIterator.hasNext();
+ }
+
+ @Override
+ public E next() {
+ return transform(backingIterator.next());
+ }
+ };
+ }
+
+ @Override public Object[] toArray() {
+ return toArray(new Object[size()]);
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return ObjectArrays.toArrayImpl(this, array);
+ }
+
+ @Override public final int hashCode() {
+ return hashCode;
+ }
+
+ @GwtIncompatible("unused")
+ @Override boolean isHashCodeFast() {
+ return true;
+ }
+}
diff --git a/guava/src/com/google/common/collect/TransformedIterator.java b/guava/src/com/google/common/collect/TransformedIterator.java
new file mode 100644
index 0000000..c082d7d
--- /dev/null
+++ b/guava/src/com/google/common/collect/TransformedIterator.java
@@ -0,0 +1,55 @@
+/*
+ * 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
new file mode 100644
index 0000000..c743030
--- /dev/null
+++ b/guava/src/com/google/common/collect/TransformedListIterator.java
@@ -0,0 +1,71 @@
+/*
+ * 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
new file mode 100644
index 0000000..2ead64e
--- /dev/null
+++ b/guava/src/com/google/common/collect/TreeBasedTable.java
@@ -0,0 +1,380 @@
+/*
+ * 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.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.Function;
+import com.google.common.base.Supplier;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+
+import javax.annotation.Nullable;
+
+/**
+ * Implementation of {@code Table} whose row keys and column keys are ordered
+ * by their natural ordering or by supplied comparators. When constructing a
+ * {@code TreeBasedTable}, you may provide comparators for the row keys and
+ * the column keys, or you may use natural ordering for both.
+ *
+ * <p>The {@link #rowKeySet} method returns a {@link SortedSet} and the {@link
+ * #rowMap} method returns a {@link SortedMap}, instead of the {@link Set} and
+ * {@link Map} specified by the {@link Table} interface.
+ *
+ * <p>The views returned by {@link #column}, {@link #columnKeySet()}, and {@link
+ * #columnMap()} have iterators that don't support {@code remove()}. Otherwise,
+ * all optional operations are supported. Null row keys, columns keys, and
+ * values are not supported.
+ *
+ * <p>Lookups by row key are often faster than lookups by column key, because
+ * the data is stored in a {@code Map<R, Map<C, V>>}. A method call like {@code
+ * column(columnKey).get(rowKey)} still runs quickly, since the row key is
+ * provided. However, {@code column(columnKey).size()} takes longer, since an
+ * iteration across all row keys occurs.
+ *
+ * <p>Because a {@code TreeBasedTable} has unique sorted values for a given
+ * row, both {@code row(rowKey)} and {@code rowMap().get(rowKey)} are {@link
+ * SortedMap} instances, instead of the {@link Map} specified in the {@link
+ * Table} interface.
+ *
+ * <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
+ * @author Louis Wasserman
+ * @since 7.0
+ */
+@GwtCompatible(serializable = true)
+@Beta
+public class TreeBasedTable<R, C, V> extends StandardRowSortedTable<R, C, V> {
+ private final Comparator<? super C> columnComparator;
+
+ private static class Factory<C, V>
+ implements Supplier<TreeMap<C, V>>, Serializable {
+ final Comparator<? super C> comparator;
+ Factory(Comparator<? super C> comparator) {
+ this.comparator = comparator;
+ }
+ @Override
+ public TreeMap<C, V> get() {
+ return new TreeMap<C, V>(comparator);
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Creates an empty {@code TreeBasedTable} that uses the natural orderings
+ * of both row and column keys.
+ *
+ * <p>The method signature specifies {@code R extends Comparable} with a raw
+ * {@link Comparable}, instead of {@code R extends Comparable<? super R>},
+ * and the same for {@code C}. That's necessary to support classes defined
+ * without generics.
+ */
+ public static <R extends Comparable, C extends Comparable, V>
+ TreeBasedTable<R, C, V> create() {
+ return new TreeBasedTable<R, C, V>(Ordering.natural(),
+ Ordering.natural());
+ }
+
+ /**
+ * Creates an empty {@code TreeBasedTable} that is ordered by the specified
+ * comparators.
+ *
+ * @param rowComparator the comparator that orders the row keys
+ * @param columnComparator the comparator that orders the column keys
+ */
+ public static <R, C, V> TreeBasedTable<R, C, V> create(
+ Comparator<? super R> rowComparator,
+ Comparator<? super C> columnComparator) {
+ checkNotNull(rowComparator);
+ checkNotNull(columnComparator);
+ return new TreeBasedTable<R, C, V>(rowComparator, columnComparator);
+ }
+
+ /**
+ * Creates a {@code TreeBasedTable} with the same mappings and sort order
+ * as the specified {@code TreeBasedTable}.
+ */
+ public static <R, C, V> TreeBasedTable<R, C, V> create(
+ TreeBasedTable<R, C, ? extends V> table) {
+ TreeBasedTable<R, C, V> result
+ = new TreeBasedTable<R, C, V>(
+ table.rowComparator(), table.columnComparator());
+ result.putAll(table);
+ return result;
+ }
+
+ TreeBasedTable(Comparator<? super R> rowComparator,
+ Comparator<? super C> columnComparator) {
+ super(new TreeMap<R, Map<C, V>>(rowComparator),
+ new Factory<C, V>(columnComparator));
+ this.columnComparator = columnComparator;
+ }
+
+ // TODO(jlevy): Move to StandardRowSortedTable?
+
+ /**
+ * Returns the comparator that orders the rows. With natural ordering,
+ * {@link Ordering#natural()} is returned.
+ */
+ public Comparator<? super R> rowComparator() {
+ return rowKeySet().comparator();
+ }
+
+ /**
+ * Returns the comparator that orders the columns. With natural ordering,
+ * {@link Ordering#natural()} is returned.
+ */
+ public Comparator<? super C> columnComparator() {
+ return columnComparator;
+ }
+
+ // TODO(user): make column return a SortedMap
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code TreeBasedTable} has unique sorted values for a given
+ * row, this method returns a {@link SortedMap}, instead of the {@link Map}
+ * specified in the {@link Table} interface.
+ * @since 10.0
+ * (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility"
+ * >mostly source-compatible</a> since 7.0)
+ */
+ @Override
+ public SortedMap<C, V> row(R rowKey) {
+ return new TreeRow(rowKey);
+ }
+
+ private class TreeRow extends Row implements SortedMap<C, V> {
+ @Nullable final C lowerBound;
+ @Nullable final C upperBound;
+
+ TreeRow(R rowKey) {
+ this(rowKey, null, null);
+ }
+
+ TreeRow(R rowKey, @Nullable C lowerBound, @Nullable C upperBound) {
+ super(rowKey);
+ this.lowerBound = lowerBound;
+ this.upperBound = upperBound;
+ checkArgument(lowerBound == null || upperBound == null
+ || compare(lowerBound, upperBound) <= 0);
+ }
+
+ @Override public Comparator<? super C> comparator() {
+ return columnComparator();
+ }
+
+ int compare(Object a, Object b) {
+ // pretend we can compare anything
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ Comparator<Object> cmp = (Comparator) comparator();
+ return cmp.compare(a, b);
+ }
+
+ boolean rangeContains(@Nullable Object o) {
+ return o != null && (lowerBound == null || compare(lowerBound, o) <= 0)
+ && (upperBound == null || compare(upperBound, o) > 0);
+ }
+
+ @Override public SortedMap<C, V> subMap(C fromKey, C toKey) {
+ checkArgument(rangeContains(checkNotNull(fromKey))
+ && rangeContains(checkNotNull(toKey)));
+ return new TreeRow(rowKey, fromKey, toKey);
+ }
+
+ @Override public SortedMap<C, V> headMap(C toKey) {
+ checkArgument(rangeContains(checkNotNull(toKey)));
+ return new TreeRow(rowKey, lowerBound, toKey);
+ }
+
+ @Override public SortedMap<C, V> tailMap(C fromKey) {
+ checkArgument(rangeContains(checkNotNull(fromKey)));
+ return new TreeRow(rowKey, fromKey, upperBound);
+ }
+
+ @Override public C firstKey() {
+ SortedMap<C, V> backing = backingRowMap();
+ if (backing == null) {
+ throw new NoSuchElementException();
+ }
+ return backingRowMap().firstKey();
+ }
+
+ @Override public C lastKey() {
+ SortedMap<C, V> backing = backingRowMap();
+ if (backing == null) {
+ throw new NoSuchElementException();
+ }
+ return backingRowMap().lastKey();
+ }
+
+ transient SortedMap<C, V> wholeRow;
+
+ /*
+ * If the row was previously empty, we check if there's a new row here every
+ * time we're queried.
+ */
+ SortedMap<C, V> wholeRow() {
+ if (wholeRow == null
+ || (wholeRow.isEmpty() && backingMap.containsKey(rowKey))) {
+ wholeRow = (SortedMap<C, V>) backingMap.get(rowKey);
+ }
+ return wholeRow;
+ }
+
+ @Override
+ SortedMap<C, V> backingRowMap() {
+ return (SortedMap<C, V>) super.backingRowMap();
+ }
+
+ @Override
+ SortedMap<C, V> computeBackingRowMap() {
+ SortedMap<C, V> map = wholeRow();
+ if (map != null) {
+ if (lowerBound != null) {
+ map = map.tailMap(lowerBound);
+ }
+ if (upperBound != null) {
+ map = map.headMap(upperBound);
+ }
+ return map;
+ }
+ return null;
+ }
+
+ @Override
+ void maintainEmptyInvariant() {
+ if (wholeRow() != null && wholeRow.isEmpty()) {
+ backingMap.remove(rowKey);
+ wholeRow = null;
+ backingRowMap = null;
+ }
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return rangeContains(key) && super.containsKey(key);
+ }
+
+ @Override public V put(C key, V value) {
+ checkArgument(rangeContains(checkNotNull(key)));
+ return super.put(key, value);
+ }
+ }
+
+ // rowKeySet() and rowMap() are defined here so they appear in the Javadoc.
+
+ @Override public SortedSet<R> rowKeySet() {
+ return super.rowKeySet();
+ }
+
+ @Override public SortedMap<R, Map<C, V>> rowMap() {
+ return super.rowMap();
+ }
+
+ // Overriding so NullPointerTester test passes.
+
+ @Override public boolean contains(
+ @Nullable Object rowKey, @Nullable Object columnKey) {
+ return super.contains(rowKey, columnKey);
+ }
+
+ @Override public boolean containsColumn(@Nullable Object columnKey) {
+ return super.containsColumn(columnKey);
+ }
+
+ @Override public boolean containsRow(@Nullable Object rowKey) {
+ return super.containsRow(rowKey);
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ return super.containsValue(value);
+ }
+
+ @Override public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
+ return super.get(rowKey, columnKey);
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ return super.equals(obj);
+ }
+
+ @Override public V remove(
+ @Nullable Object rowKey, @Nullable Object columnKey) {
+ return super.remove(rowKey, columnKey);
+ }
+
+ /**
+ * Overridden column iterator to return columns values in globally sorted
+ * order.
+ */
+ @Override
+ Iterator<C> createColumnKeyIterator() {
+ final Comparator<? super C> comparator = columnComparator();
+
+ final Iterator<C> merged =
+ Iterators.mergeSorted(Iterables.transform(backingMap.values(),
+ new Function<Map<C, V>, Iterator<C>>() {
+ @Override
+ public Iterator<C> apply(Map<C, V> input) {
+ return input.keySet().iterator();
+ }
+ }), comparator);
+
+ return new AbstractIterator<C>() {
+ C lastValue;
+
+ @Override
+ protected C computeNext() {
+ while (merged.hasNext()) {
+ C next = merged.next();
+ boolean duplicate =
+ lastValue != null && comparator.compare(next, lastValue) == 0;
+
+ // Keep looping till we find a non-duplicate value.
+ if (!duplicate) {
+ lastValue = next;
+ return lastValue;
+ }
+ }
+
+ lastValue = null; // clear reference to unused data
+ return endOfData();
+ }
+ };
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/TreeMultimap.java b/guava/src/com/google/common/collect/TreeMultimap.java
new file mode 100644
index 0000000..3bd49ae
--- /dev/null
+++ b/guava/src/com/google/common/collect/TreeMultimap.java
@@ -0,0 +1,201 @@
+/*
+ * 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.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * Implementation of {@code Multimap} whose keys and values are ordered by
+ * their natural ordering or by supplied comparators. 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 comparators or comparables used must be <i>consistent
+ * with equals</i> as explained by the {@link Comparable} class specification.
+ * Otherwise, the resulting multiset will violate the general contract of {@link
+ * SetMultimap}, which it is specified in terms of {@link Object#equals}.
+ *
+ * <p>The collections returned by {@code keySet} and {@code asMap} iterate
+ * through the keys according to the key comparator ordering or the natural
+ * ordering of the keys. Similarly, {@code get}, {@code removeAll}, and {@code
+ * replaceValues} return collections that iterate through the values according
+ * to the value comparator ordering or the natural ordering of the values. The
+ * collections generated by {@code entries}, {@code keys}, and {@code values}
+ * iterate across the keys according to the above key ordering, and for each
+ * key they iterate across the values according to the value ordering.
+ *
+ * <p>The multimap does not store duplicate key-value pairs. Adding a new
+ * key-value pair equal to an existing key-value pair has no effect.
+ *
+ * <p>Null keys and values are permitted (provided, of course, that the
+ * respective comparators support them). All optional multimap methods are
+ * supported, and all returned views are modifiable.
+ *
+ * <p>This class is not threadsafe when any concurrent operations update the
+ * multimap. Concurrent read operations will work correctly. To allow concurrent
+ * 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
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible(serializable = true, emulated = true)
+public class TreeMultimap<K, V> extends AbstractSortedSetMultimap<K, V> {
+ private transient Comparator<? super K> keyComparator;
+ private transient Comparator<? super V> valueComparator;
+
+ /**
+ * Creates an empty {@code TreeMultimap} ordered by the natural ordering of
+ * its keys and values.
+ */
+ public static <K extends Comparable, V extends Comparable>
+ TreeMultimap<K, V> create() {
+ return new TreeMultimap<K, V>(Ordering.natural(), Ordering.natural());
+ }
+
+ /**
+ * Creates an empty {@code TreeMultimap} instance using explicit comparators.
+ * Neither comparator may be null; use {@link Ordering#natural()} to specify
+ * natural order.
+ *
+ * @param keyComparator the comparator that determines the key ordering
+ * @param valueComparator the comparator that determines the value ordering
+ */
+ public static <K, V> TreeMultimap<K, V> create(
+ Comparator<? super K> keyComparator,
+ Comparator<? super V> valueComparator) {
+ return new TreeMultimap<K, V>(checkNotNull(keyComparator),
+ checkNotNull(valueComparator));
+ }
+
+ /**
+ * Constructs a {@code TreeMultimap}, ordered by the natural ordering of its
+ * keys and values, with the same mappings as the specified multimap.
+ *
+ * @param multimap the multimap whose contents are copied to this multimap
+ */
+ public static <K extends Comparable, V extends Comparable>
+ TreeMultimap<K, V> create(Multimap<? extends K, ? extends V> multimap) {
+ return new TreeMultimap<K, V>(Ordering.natural(), Ordering.natural(),
+ multimap);
+ }
+
+ TreeMultimap(Comparator<? super K> keyComparator,
+ Comparator<? super V> valueComparator) {
+ super(new TreeMap<K, Collection<V>>(keyComparator));
+ this.keyComparator = keyComparator;
+ this.valueComparator = valueComparator;
+ }
+
+ private TreeMultimap(Comparator<? super K> keyComparator,
+ Comparator<? super V> valueComparator,
+ Multimap<? extends K, ? extends V> multimap) {
+ this(keyComparator, valueComparator);
+ putAll(multimap);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Creates an empty {@code TreeSet} for a collection of values for one key.
+ *
+ * @return a new {@code TreeSet} containing a collection of values for one
+ * key
+ */
+ @Override SortedSet<V> createCollection() {
+ return new TreeSet<V>(valueComparator);
+ }
+
+ /**
+ * Returns the comparator that orders the multimap keys.
+ */
+ public Comparator<? super K> keyComparator() {
+ return keyComparator;
+ }
+
+ @Override
+ public Comparator<? super V> valueComparator() {
+ return valueComparator;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code TreeMultimap} has unique sorted keys, this method
+ * returns a {@link SortedSet}, instead of the {@link java.util.Set} specified
+ * in the {@link Multimap} interface.
+ */
+ @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 SortedMap}, instead of the {@link java.util.Map} specified
+ * in the {@link Multimap} interface.
+ */
+ @Override public SortedMap<K, Collection<V>> asMap() {
+ return (SortedMap<K, Collection<V>>) super.asMap();
+ }
+
+ /**
+ * @serialData key comparator, value comparator, number of distinct keys, and
+ * then for each distinct key: the key, number of values for that key, and
+ * key values
+ */
+ @GwtIncompatible("java.io.ObjectOutputStream")
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(keyComparator());
+ stream.writeObject(valueComparator());
+ Serialization.writeMultimap(this, stream);
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ keyComparator = checkNotNull((Comparator<? super K>) stream.readObject());
+ valueComparator = checkNotNull((Comparator<? super V>) stream.readObject());
+ setMap(new TreeMap<K, Collection<V>>(keyComparator));
+ Serialization.populateMultimap(this, stream);
+ }
+
+ @GwtIncompatible("not needed in emulated source")
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/TreeMultiset.java b/guava/src/com/google/common/collect/TreeMultiset.java
new file mode 100644
index 0000000..6876cd0
--- /dev/null
+++ b/guava/src/com/google/common/collect/TreeMultiset.java
@@ -0,0 +1,982 @@
+/*
+ * 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.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 java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.annotation.Nullable;
+
+/**
+ * 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>.
+ *
+ * @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 {
+
+ /**
+ * 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.
+ */
+ 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}.
+ *
+ * @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) {
+ return (comparator == null)
+ ? 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.
+ *
+ * <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.
+ */
+ 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;
+ }
+
+ 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>>();
+ }
+
+ /**
+ * A function which can be summed across a subtree.
+ */
+ private enum Aggregate {
+ SIZE {
+ @Override
+ int nodeAggregate(AvlNode<?> node) {
+ return node.elemCount;
+ }
+
+ @Override
+ long treeAggregate(@Nullable AvlNode<?> root) {
+ return (root == null) ? 0 : root.totalCount;
+ }
+ },
+ DISTINCT {
+ @Override
+ int nodeAggregate(AvlNode<?> node) {
+ return 1;
+ }
+
+ @Override
+ long treeAggregate(@Nullable AvlNode<?> root) {
+ return (root == null) ? 0 : root.distinctElements;
+ }
+ };
+ abstract int nodeAggregate(AvlNode<?> node);
+
+ abstract long treeAggregate(@Nullable AvlNode<?> root);
+ }
+
+ 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;
+ }
+
+ 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);
+ }
+ }
+
+ private long aggregateAboveRange(Aggregate aggr, @Nullable AvlNode<E> node) {
+ if (node == null) {
+ return 0;
+ }
+ 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();
+ }
+ } else {
+ return aggr.treeAggregate(node.right) + aggr.nodeAggregate(node)
+ + aggregateAboveRange(aggr, node.left);
+ }
+ }
+
+ @Override
+ public int size() {
+ return Ints.saturatedCast(aggregateForEntries(Aggregate.SIZE));
+ }
+
+ @Override
+ int distinctElements() {
+ return Ints.saturatedCast(aggregateForEntries(Aggregate.DISTINCT));
+ }
+
+ @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;
+ }
+ return root.count(comparator(), e);
+ } catch (ClassCastException e) {
+ return 0;
+ } catch (NullPointerException e) {
+ return 0;
+ }
+ }
+
+ @Override
+ public int add(@Nullable E element, int occurrences) {
+ checkArgument(occurrences >= 0, "occurrences must be >= 0 but was %s", occurrences);
+ 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];
+ }
+
+ @Override
+ public int remove(@Nullable Object element, int occurrences) {
+ checkArgument(occurrences >= 0, "occurrences must be >= 0 but was %s", occurrences);
+ 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);
+ } 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];
+ }
+
+ @Override
+ public boolean setCount(@Nullable E element, int oldCount, int newCount) {
+ checkArgument(newCount >= 0);
+ checkArgument(oldCount >= 0);
+ 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;
+ }
+
+ 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;
+ }
+ }
+ };
+ }
+
+ /**
+ * 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;
+ }
+
+ @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>> entryIterator() {
+ return new Iterator<Entry<E>>() {
+ AvlNode<E> current = firstNode();
+ Entry<E> prevEntry;
+
+ @Override
+ public boolean hasNext() {
+ if (current == null) {
+ return false;
+ } else if (range.tooHigh(current.getElement())) {
+ current = null;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ @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;
+ }
+
+ @Override
+ public void remove() {
+ checkState(prevEntry != null);
+ setCount(prevEntry.getElement(), 0);
+ prevEntry = null;
+ }
+ };
+ }
+
+ @Override
+ Iterator<Entry<E>> descendingEntryIterator() {
+ return new Iterator<Entry<E>>() {
+ AvlNode<E> current = lastNode();
+ Entry<E> prevEntry = null;
+
+ @Override
+ public boolean hasNext() {
+ if (current == null) {
+ return false;
+ } else if (range.tooLow(current.getElement())) {
+ current = null;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ @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 void remove() {
+ checkState(prevEntry != null);
+ setCount(prevEntry.getElement(), 0);
+ prevEntry = null;
+ }
+ };
+ }
+
+ @Override
+ public SortedMultiset<E> headMultiset(@Nullable E upperBound, BoundType boundType) {
+ return new TreeMultiset<E>(rootReference, range.intersect(GeneralRange.upTo(
+ comparator(),
+ upperBound,
+ boundType)), header);
+ }
+
+ @Override
+ public SortedMultiset<E> tailMultiset(@Nullable E lowerBound, BoundType boundType) {
+ return new TreeMultiset<E>(rootReference, range.intersect(GeneralRange.downTo(
+ comparator(),
+ lowerBound,
+ boundType)), header);
+ }
+
+ static int distinctElements(@Nullable AvlNode<?> node) {
+ return (node == null) ? 0 : node.distinctElements;
+ }
+
+ 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;
+ }
+ }
+
+ 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 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) {
+ 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;
+ }
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ left = initLeft.remove(comparator, e, count, result);
+
+ 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;
+ }
+
+ right = initRight.remove(comparator, e, count, result);
+
+ if (result[0] > 0) {
+ if (count >= result[0]) {
+ this.distinctElements--;
+ this.totalCount -= result[0];
+ } else {
+ this.totalCount -= count;
+ }
+ }
+ return rebalance();
+ }
+
+ // removing count from me!
+ result[0] = elemCount;
+ if (count >= elemCount) {
+ return deleteMe();
+ } else {
+ this.elemCount -= count;
+ this.totalCount -= count;
+ return this;
+ }
+ }
+
+ 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;
+ }
+
+ 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);
+
+ 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;
+ }
+
+ 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];
+ }
+ 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;
+ }
+
+ 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();
+ }
+ }
+
+ // 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();
+ }
+ }
+
+ // Removes the maximum node from this subtree to be reused elsewhere
+ private AvlNode<E> removeMax(AvlNode<E> node) {
+ if (right == null) {
+ return left;
+ } else {
+ right = right.removeMax(node);
+ distinctElements--;
+ totalCount -= node.elemCount;
+ return rebalance();
+ }
+ }
+
+ 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 void recompute() {
+ recomputeMultiset();
+ recomputeHeight();
+ }
+
+ 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;
+ }
+ }
+
+ private int balanceFactor() {
+ return height(left) - height(right);
+ }
+
+ 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 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;
+ }
+
+ private static long totalCount(@Nullable AvlNode<?> node) {
+ return (node == null) ? 0 : node.totalCount;
+ }
+
+ 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);
+ }
+ }
+
+ @Override
+ public E getElement() {
+ return elem;
+ }
+
+ @Override
+ public int getCount() {
+ return elemCount;
+ }
+
+ @Override
+ public String toString() {
+ return Multisets.immutableEntry(getElement(), getCount()).toString();
+ }
+ }
+
+ 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.
+ */
+
+ /**
+ * @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 {
+ stream.defaultWriteObject();
+ stream.writeObject(elementSet().comparator());
+ Serialization.writeMultiset(this, stream);
+ }
+
+ @GwtIncompatible("java.io.ObjectInputStream")
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ @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,
+ 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.populateMultiset(this, stream);
+ }
+
+ @GwtIncompatible("not needed in emulated source") private static final long serialVersionUID = 1;
+}
diff --git a/guava/src/com/google/common/collect/TreeRangeSet.java b/guava/src/com/google/common/collect/TreeRangeSet.java
new file mode 100644
index 0000000..6c0fa5c
--- /dev/null
+++ b/guava/src/com/google/common/collect/TreeRangeSet.java
@@ -0,0 +1,203 @@
+/*
+ * 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.GwtIncompatible;
+
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.NavigableMap;
+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
+ */
+@GwtIncompatible("uses NavigableMap") final class TreeRangeSet<C extends Comparable>
+ extends RangeSet<C> {
+ // TODO(user): override inefficient defaults
+
+ private final NavigableMap<Cut<C>, Range<C>> rangesByLowerCut;
+
+ /**
+ * Creates an empty {@code TreeRangeSet} instance.
+ */
+ public static <C extends Comparable> TreeRangeSet<C> create() {
+ return new TreeRangeSet<C>(new TreeMap<Cut<C>, Range<C>>());
+ }
+
+ private TreeRangeSet(NavigableMap<Cut<C>, Range<C>> rangesByLowerCut) {
+ this.rangesByLowerCut = 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 rangesByLowerCut.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 = rangesByLowerCut.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 = rangesByLowerCut.floorEntry(range.lowerBound);
+ return floorEntry != null && floorEntry.getValue().encloses(range);
+ }
+
+ @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 = rangesByLowerCut.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 = rangesByLowerCut.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.
+ rangesByLowerCut.subMap(lbToAdd, ubToAdd).clear();
+
+ replaceRangeWithSameLowerBound(new Range<C>(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 = rangesByLowerCut.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 (rangeBelowLB.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
+ // { < > }
+ replaceRangeWithSameLowerBound(
+ new Range<C>(rangeToRemove.upperBound, rangeBelowLB.upperBound));
+ }
+ replaceRangeWithSameLowerBound(
+ new Range<C>(rangeBelowLB.lowerBound, rangeToRemove.lowerBound));
+ }
+ }
+
+ Entry<Cut<C>, Range<C>> entryBelowUB = rangesByLowerCut.floorEntry(rangeToRemove.upperBound);
+ if (entryBelowUB != null) {
+ // { >
+ Range<C> rangeBelowUB = entryBelowUB.getValue();
+ if (rangeBelowUB.upperBound.compareTo(rangeToRemove.upperBound) >= 0) {
+ // { > }
+ replaceRangeWithSameLowerBound(
+ new Range<C>(rangeToRemove.upperBound, rangeBelowUB.upperBound));
+ }
+ }
+
+ rangesByLowerCut.subMap(rangeToRemove.lowerBound, rangeToRemove.upperBound).clear();
+ }
+
+ private void replaceRangeWithSameLowerBound(Range<C> range) {
+ if (range.isEmpty()) {
+ rangesByLowerCut.remove(range.lowerBound);
+ } else {
+ rangesByLowerCut.put(range.lowerBound, range);
+ }
+ }
+
+ private transient RangeSet<C> complement;
+
+ @Override
+ public RangeSet<C> complement() {
+ RangeSet<C> result = complement;
+ return (result == null) ? complement = createComplement() : result;
+ }
+
+ private RangeSet<C> createComplement() {
+ return new StandardComplement<C>(this);
+ }
+}
diff --git a/guava/src/com/google/common/collect/UnmodifiableIterator.java b/guava/src/com/google/common/collect/UnmodifiableIterator.java
new file mode 100644
index 0000000..5cff61b
--- /dev/null
+++ b/guava/src/com/google/common/collect/UnmodifiableIterator.java
@@ -0,0 +1,43 @@
+/*
+ * 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.Iterator;
+
+/**
+ * An iterator that does not support {@link #remove}.
+ *
+ * @author Jared Levy
+ * @since 2.0 (imported from Google Collections Library)
+ */
+@GwtCompatible
+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
+ */
+ @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
new file mode 100644
index 0000000..fa71bdc
--- /dev/null
+++ b/guava/src/com/google/common/collect/UnmodifiableListIterator.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import java.util.ListIterator;
+
+/**
+ * A list iterator that does not support {@link #remove}, {@link #add}, or
+ * {@link #set}.
+ *
+ * @since 7.0
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+public abstract class UnmodifiableListIterator<E>
+ extends UnmodifiableIterator<E> implements ListIterator<E> {
+ /** Constructor for use by subclasses. */
+ protected UnmodifiableListIterator() {}
+
+ /**
+ * Guaranteed to throw an exception and leave the underlying data unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public final void add(E e) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the underlying data unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ @Override public final void set(E e) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/guava/src/com/google/common/collect/UsingToStringOrdering.java b/guava/src/com/google/common/collect/UsingToStringOrdering.java
new file mode 100644
index 0000000..d1c9feb
--- /dev/null
+++ b/guava/src/com/google/common/collect/UsingToStringOrdering.java
@@ -0,0 +1,45 @@
+/*
+ * 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 com.google.common.annotations.GwtCompatible;
+
+import java.io.Serializable;
+
+/** An ordering that uses the reverse of the natural order of the values. */
+@GwtCompatible(serializable = true)
+final class UsingToStringOrdering
+ extends Ordering<Object> implements Serializable {
+ static final UsingToStringOrdering INSTANCE = new UsingToStringOrdering();
+
+ @Override public int compare(Object left, Object right) {
+ return left.toString().compareTo(right.toString());
+ }
+
+ // preserve singleton-ness, so equals() and hashCode() work correctly
+ private Object readResolve() {
+ return INSTANCE;
+ }
+
+ @Override public String toString() {
+ return "Ordering.usingToString()";
+ }
+
+ private UsingToStringOrdering() {}
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/collect/WellBehavedMap.java b/guava/src/com/google/common/collect/WellBehavedMap.java
new file mode 100644
index 0000000..c68cc5e
--- /dev/null
+++ b/guava/src/com/google/common/collect/WellBehavedMap.java
@@ -0,0 +1,98 @@
+/*
+ * 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 java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 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.
+ *
+ * @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
+ * {@code Set<K> keySet()} and transforming it to
+ * {@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);
+ }
+
+ @Override protected Map<K, V> delegate() {
+ return delegate;
+ }
+
+ @Override public Set<Entry<K, V>> entrySet() {
+ Set<Entry<K, V>> es = entrySet;
+ if (es != null) {
+ return es;
+ }
+ return entrySet = new EntrySet();
+ }
+
+ private final class EntrySet extends Maps.EntrySet<K, V> {
+ @Override
+ Map<K, V> map() {
+ return WellBehavedMap.this;
+ }
+
+ @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);
+ }
+ };
+ }
+ };
+ }
+ }
+}
diff --git a/guava/src/com/google/common/collect/package-info.java b/guava/src/com/google/common/collect/package-info.java
new file mode 100644
index 0000000..054b944
--- /dev/null
+++ b/guava/src/com/google/common/collect/package-info.java
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains generic collection interfaces and implementations, and
+ * other utilities for working with collections. It is a part of the open-source
+ * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
+ *
+ * <h2>Collection Types</h2>
+ *
+ * <dl>
+ * <dt>{@link com.google.common.collect.BiMap}
+ * <dd>An extension of {@link java.util.Map} that guarantees the uniqueness of
+ * its values as well as that of its keys. This is sometimes called an
+ * "invertible map," since the restriction on values enables it to support
+ * an {@linkplain com.google.common.collect.BiMap#inverse inverse view} --
+ * which is another instance of {@code BiMap}.
+ *
+ * <dt>{@link com.google.common.collect.Multiset}
+ * <dd>An extension of {@link java.util.Collection} that may contain duplicate
+ * values like a {@link java.util.List}, yet has order-independent equality
+ * like a {@link java.util.Set}. One typical use for a multiset is to
+ * represent a histogram.
+ *
+ * <dt>{@link com.google.common.collect.Multimap}
+ * <dd>A new type, which is similar to {@link java.util.Map}, but may contain
+ * multiple entries with the same key. Some behaviors of
+ * {@link com.google.common.collect.Multimap} are left unspecified and are
+ * provided only by the subtypes mentioned below.
+ *
+ * <dt>{@link com.google.common.collect.ListMultimap}
+ * <dd>An extension of {@link com.google.common.collect.Multimap} which permits
+ * duplicate entries, supports random access of values for a particular key,
+ * and has <i>partially order-dependent equality</i> as defined by
+ * {@link com.google.common.collect.ListMultimap#equals(Object)}. {@code
+ * ListMultimap} takes its name from the fact that the {@linkplain
+ * com.google.common.collect.ListMultimap#get collection of values}
+ * associated with a given key fulfills the {@link java.util.List} contract.
+ *
+ * <dt>{@link com.google.common.collect.SetMultimap}
+ * <dd>An extension of {@link com.google.common.collect.Multimap} which has
+ * order-independent equality and does not allow duplicate entries; that is,
+ * while a key may appear twice in a {@code SetMultimap}, each must map to a
+ * different value. {@code SetMultimap} takes its name from the fact that
+ * the {@linkplain com.google.common.collect.SetMultimap#get collection of
+ * values} associated with a given key fulfills the {@link java.util.Set}
+ * contract.
+ *
+ * <dt>{@link com.google.common.collect.SortedSetMultimap}
+ * <dd>An extension of {@link com.google.common.collect.SetMultimap} for which
+ * the {@linkplain com.google.common.collect.SortedSetMultimap#get
+ * collection values} associated with a given key is a
+ * {@link java.util.SortedSet}.
+ *
+ * <dt>{@link com.google.common.collect.Table}
+ * <dd>A new type, which is similar to {@link java.util.Map}, but which indexes
+ * its values by an ordered pair of keys, a row key and column key.
+ *
+ * <dt>{@link com.google.common.collect.ClassToInstanceMap}
+ * <dd>An extension of {@link java.util.Map} that associates a raw type with an
+ * instance of that type.
+ * </dl>
+ *
+ * <h2>Collection Implementations</h2>
+ *
+ * <h3>of {@link java.util.List}</h3>
+ * <ul>
+ * <li>{@link com.google.common.collect.ImmutableList}
+ * </ul>
+ *
+ * <h3>of {@link java.util.Set}</h3>
+ * <ul>
+ * <li>{@link com.google.common.collect.ImmutableSet}
+ * <li>{@link com.google.common.collect.ImmutableSortedSet}
+ * <li>{@link com.google.common.collect.ContiguousSet} (see {@code Ranges})
+ * </ul>
+ *
+ * <h3>of {@link java.util.Map}</h3>
+ * <ul>
+ * <li>{@link com.google.common.collect.ImmutableMap}
+ * <li>{@link com.google.common.collect.ImmutableSortedMap}
+ * <li>{@link com.google.common.collect.MapMaker}
+ * </ul>
+ *
+ * <h3>of {@link com.google.common.collect.BiMap}</h3>
+ * <ul>
+ * <li>{@link com.google.common.collect.ImmutableBiMap}
+ * <li>{@link com.google.common.collect.HashBiMap}
+ * <li>{@link com.google.common.collect.EnumBiMap}
+ * <li>{@link com.google.common.collect.EnumHashBiMap}
+ * </ul>
+ *
+ * <h3>of {@link com.google.common.collect.Multiset}</h3>
+ * <ul>
+ * <li>{@link com.google.common.collect.ImmutableMultiset}
+ * <li>{@link com.google.common.collect.HashMultiset}
+ * <li>{@link com.google.common.collect.LinkedHashMultiset}
+ * <li>{@link com.google.common.collect.TreeMultiset}
+ * <li>{@link com.google.common.collect.EnumMultiset}
+ * <li>{@link com.google.common.collect.ConcurrentHashMultiset}
+ * </ul>
+ *
+ * <h3>of {@link com.google.common.collect.Multimap}</h3>
+ * <ul>
+ * <li>{@link com.google.common.collect.ImmutableMultimap}
+ * <li>{@link com.google.common.collect.ImmutableListMultimap}
+ * <li>{@link com.google.common.collect.ImmutableSetMultimap}
+ * <li>{@link com.google.common.collect.ArrayListMultimap}
+ * <li>{@link com.google.common.collect.HashMultimap}
+ * <li>{@link com.google.common.collect.TreeMultimap}
+ * <li>{@link com.google.common.collect.LinkedHashMultimap}
+ * <li>{@link com.google.common.collect.LinkedListMultimap}
+ * </ul>
+ *
+ * <h3>of {@link com.google.common.collect.Table}</h3>
+ * <ul>
+ * <li>{@link com.google.common.collect.ImmutableTable}
+ * <li>{@link com.google.common.collect.ArrayTable}
+ * <li>{@link com.google.common.collect.HashBasedTable}
+ * <li>{@link com.google.common.collect.TreeBasedTable}
+ * </ul>
+ *
+ * <h3>of {@link com.google.common.collect.ClassToInstanceMap}</h3>
+ * <ul>
+ * <li>{@link com.google.common.collect.ImmutableClassToInstanceMap}
+ * <li>{@link com.google.common.collect.MutableClassToInstanceMap}
+ * </ul>
+ *
+ * <h2>Classes of static utility methods</h2>
+ *
+ * <ul>
+ * <li>{@link com.google.common.collect.Collections2}
+ * <li>{@link com.google.common.collect.Iterators}
+ * <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.Tables}
+ * <li>{@link com.google.common.collect.ObjectArrays}
+ * </ul>
+ *
+ * <h2>Comparison</h2>
+ *
+ * <ul>
+ * <li>{@link com.google.common.collect.Ordering}
+ * <li>{@link com.google.common.collect.ComparisonChain}
+ * </ul>
+ *
+ * <h2>Abstract implementations</h2>
+ *
+ * <ul>
+ * <li>{@link com.google.common.collect.AbstractIterator}
+ * <li>{@link com.google.common.collect.AbstractSequentialIterator}
+ * <li>{@link com.google.common.collect.ImmutableCollection}
+ * <li>{@link com.google.common.collect.UnmodifiableIterator}
+ * <li>{@link com.google.common.collect.UnmodifiableListIterator}
+ * </ul>
+ *
+ * <h2>Ranges</h2>
+ *
+ * <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}
+ * </ul>
+ *
+ * <h2>Other</h2>
+ *
+ * <ul>
+ * <li>{@link com.google.common.collect.Interner},
+ * {@link com.google.common.collect.Interners}
+ * <li>{@link com.google.common.collect.Constraint},
+ * {@link com.google.common.collect.Constraints}
+ * <li>{@link com.google.common.collect.MapConstraint},
+ * {@link com.google.common.collect.MapConstraints}
+ * <li>{@link com.google.common.collect.MapDifference},
+ * {@link com.google.common.collect.SortedMapDifference}
+ * <li>{@link com.google.common.collect.MinMaxPriorityQueue}
+ * <li>{@link com.google.common.collect.PeekingIterator}
+ * </ul>
+ *
+ * <h2>Forwarding collections</h2>
+ *
+ * <ul>
+ * <li>{@link com.google.common.collect.ForwardingCollection}
+ * <li>{@link com.google.common.collect.ForwardingConcurrentMap}
+ * <li>{@link com.google.common.collect.ForwardingIterator}
+ * <li>{@link com.google.common.collect.ForwardingList}
+ * <li>{@link com.google.common.collect.ForwardingListIterator}
+ * <li>{@link com.google.common.collect.ForwardingListMultimap}
+ * <li>{@link com.google.common.collect.ForwardingMap}
+ * <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.ForwardingSortedSet}
+ * <li>{@link com.google.common.collect.ForwardingSortedSetMultimap}
+ * <li>{@link com.google.common.collect.ForwardingTable}
+ * </ul>
+ */
+@javax.annotation.ParametersAreNonnullByDefault
+package com.google.common.collect;
diff --git a/guava/src/com/google/common/eventbus/AllowConcurrentEvents.java b/guava/src/com/google/common/eventbus/AllowConcurrentEvents.java
new file mode 100644
index 0000000..f614598
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/AllowConcurrentEvents.java
@@ -0,0 +1,41 @@
+/*
+ * 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.eventbus;
+
+import com.google.common.annotations.Beta;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks an event handling method as being thread-safe. This annotation
+ * indicates that EventBus may invoke the event handler simultaneously from
+ * multiple threads.
+ *
+ * <p>This does not mark the method as an event handler, and so should be used
+ * in combination with {@link Subscribe}.
+ *
+ * @author Cliff Biffle
+ * @since 10.0
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Beta
+public @interface AllowConcurrentEvents {
+}
diff --git a/guava/src/com/google/common/eventbus/AnnotatedHandlerFinder.java b/guava/src/com/google/common/eventbus/AnnotatedHandlerFinder.java
new file mode 100644
index 0000000..1ab63ac
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/AnnotatedHandlerFinder.java
@@ -0,0 +1,106 @@
+/*
+ * 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.eventbus;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.reflect.TypeToken;
+
+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.
+ *
+ * @author Cliff Biffle
+ * @author Louis Wasserman
+ */
+class AnnotatedHandlerFinder implements HandlerFindingStrategy {
+ /**
+ * {@inheritDoc}
+ *
+ * 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();
+ Set<? extends Class<?>> supers = TypeToken.of(clazz).getTypes().rawTypes();
+
+ 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];
+ EventHandler handler = makeHandler(listener, method);
+
+ methodsInListener.put(eventType, handler);
+ break;
+ }
+ } catch (NoSuchMethodException ignored) {
+ // Move on.
+ }
+ }
+ }
+ return methodsInListener;
+ }
+
+ /**
+ * Creates an {@code EventHandler} for subsequently calling {@code method} on
+ * {@code listener}.
+ * Selects an EventHandler implementation based on the annotations on
+ * {@code method}.
+ *
+ * @param listener object bearing the event handler method.
+ * @param method the event handler method to wrap in an EventHandler.
+ * @return an EventHandler that will call {@code method} on {@code listener}
+ * when invoked.
+ */
+ private static EventHandler makeHandler(Object listener, Method method) {
+ EventHandler wrapper;
+ if (methodIsDeclaredThreadSafe(method)) {
+ wrapper = new EventHandler(listener, method);
+ } else {
+ wrapper = new SynchronizedEventHandler(listener, method);
+ }
+ return wrapper;
+ }
+
+ /**
+ * Checks whether {@code method} is thread-safe, as indicated by the
+ * {@link AllowConcurrentEvents} annotation.
+ *
+ * @param method handler method to check.
+ * @return {@code true} if {@code handler} is marked as thread-safe,
+ * {@code false} otherwise.
+ */
+ private static boolean methodIsDeclaredThreadSafe(Method method) {
+ return method.getAnnotation(AllowConcurrentEvents.class) != null;
+ }
+}
diff --git a/guava/src/com/google/common/eventbus/AsyncEventBus.java b/guava/src/com/google/common/eventbus/AsyncEventBus.java
new file mode 100644
index 0000000..81ed4fe
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/AsyncEventBus.java
@@ -0,0 +1,101 @@
+/*
+ * 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.eventbus;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.Executor;
+
+/**
+ * An {@link EventBus} that takes the Executor of your choice and uses it to
+ * dispatch events, allowing dispatch to occur asynchronously.
+ *
+ * @author Cliff Biffle
+ * @since 10.0
+ */
+@Beta
+public class AsyncEventBus extends EventBus {
+ private final Executor executor;
+
+ /** the queue of events is shared across all threads */
+ private final ConcurrentLinkedQueue<EventWithHandler> eventsToDispatch =
+ new ConcurrentLinkedQueue<EventWithHandler>();
+
+ /**
+ * Creates a new AsyncEventBus that will use {@code executor} to dispatch
+ * events. Assigns {@code identifier} as the bus's name for logging purposes.
+ *
+ * @param identifier short name for the bus, for logging purposes.
+ * @param executor Executor to use to dispatch events. It is the caller's
+ * responsibility to shut down the executor after the last event has
+ * been posted to this event bus.
+ */
+ public AsyncEventBus(String identifier, Executor executor) {
+ super(identifier);
+ this.executor = executor;
+ }
+
+ /**
+ * Creates a new AsyncEventBus that will use {@code executor} to dispatch
+ * events.
+ *
+ * @param executor Executor to use to dispatch events. It is the caller's
+ * responsibility to shut down the executor after the last event has
+ * been posted to this event bus.
+ */
+ public AsyncEventBus(Executor executor) {
+ this.executor = executor;
+ }
+
+ @Override
+ void enqueueEvent(Object event, EventHandler handler) {
+ eventsToDispatch.offer(new EventWithHandler(event, handler));
+ }
+
+ /**
+ * 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) {
+ EventWithHandler eventWithHandler = eventsToDispatch.poll();
+ if (eventWithHandler == null) {
+ break;
+ }
+
+ dispatch(eventWithHandler.event, eventWithHandler.handler);
+ }
+ }
+
+ /**
+ * Calls the {@link #executor} to dispatch {@code event} to {@code handler}.
+ */
+ @Override
+ 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
new file mode 100644
index 0000000..8265d5a
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/DeadEvent.java
@@ -0,0 +1,69 @@
+/*
+ * 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.eventbus;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Wraps an event that was posted, but which had no subscribers and thus could
+ * not be delivered.
+ *
+ * <p>Subscribing a DeadEvent handler is useful for debugging or logging, as it
+ * can detect misconfigurations in a system's event distribution.
+ *
+ * @author Cliff Biffle
+ * @since 10.0
+ */
+@Beta
+public class DeadEvent {
+
+ private final Object source;
+ private final Object event;
+
+ /**
+ * Creates a new DeadEvent.
+ *
+ * @param source object broadcasting the DeadEvent (generally the
+ * {@link EventBus}).
+ * @param event the event that could not be delivered.
+ */
+ public DeadEvent(Object source, Object event) {
+ this.source = source;
+ this.event = event;
+ }
+
+ /**
+ * Returns the object that originated this event (<em>not</em> the object that
+ * originated the wrapped event). This is generally an {@link EventBus}.
+ *
+ * @return the source of this event.
+ */
+ public Object getSource() {
+ return source;
+ }
+
+ /**
+ * Returns the wrapped, 'dead' event, which the system was unable to deliver
+ * to any registered handler.
+ *
+ * @return the 'dead' event that could not be delivered.
+ */
+ public Object getEvent() {
+ return event;
+ }
+
+}
diff --git a/guava/src/com/google/common/eventbus/EventBus.java b/guava/src/com/google/common/eventbus/EventBus.java
new file mode 100644
index 0000000..37d6044
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/EventBus.java
@@ -0,0 +1,358 @@
+/*
+ * 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.eventbus;
+
+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.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.reflect.TypeToken;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.Map.Entry;
+import java.util.Set;
+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;
+
+/**
+ * Dispatches events to listeners, and provides ways for listeners to register
+ * themselves.
+ *
+ * <p>The EventBus allows publish-subscribe-style communication between
+ * components without requiring the components to explicitly register with one
+ * another (and thus be aware of each other). It is designed exclusively to
+ * replace 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.
+ *
+ * <h2>Receiving Events</h2>
+ * To receive events, an object should:<ol>
+ * <li>Expose a public method, known as the <i>event handler</i>, which accepts
+ * a single argument of the type of event desired;</li>
+ * <li>Mark it with a {@link Subscribe} annotation;</li>
+ * <li>Pass itself to an EventBus instance's {@link #register(Object)} method.
+ * </li>
+ * </ol>
+ *
+ * <h2>Posting Events</h2>
+ * To post an event, simply provide the event object to the
+ * {@link #post(Object)} method. The EventBus instance will determine the type
+ * of event and route it to all registered listeners.
+ *
+ * <p>Events are routed based on their type &mdash; an event will be delivered
+ * to any handler for any type to which the event is <em>assignable.</em> This
+ * includes implemented interfaces, all superclasses, and all interfaces
+ * implemented by superclasses.
+ *
+ * <p>When {@code post} is called, all registered handlers for an event are run
+ * in sequence, so handlers should be reasonably quick. If an event may trigger
+ * an extended process (such as a database load), spawn a thread or queue it for
+ * later. (For a convenient way to do this, use an {@link AsyncEventBus}.)
+ *
+ * <h2>Handler Methods</h2>
+ * Event handler methods must accept only one argument: the event.
+ *
+ * <p>Handlers should not, in general, throw. If they do, the EventBus will
+ * catch and log the exception. This is rarely the right solution for error
+ * handling and should not be relied upon; it is intended solely to help find
+ * problems during development.
+ *
+ * <p>The EventBus guarantees that it will not call a handler method from
+ * multiple threads simultaneously, unless the method explicitly allows it by
+ * bearing the {@link AllowConcurrentEvents} annotation. If this annotation is
+ * not present, handler methods need not worry about being reentrant, unless
+ * also called from outside the EventBus.
+ *
+ * <h2>Dead Events</h2>
+ * If an event is posted, but no registered handlers can accept it, it is
+ * considered "dead." To give the system a second chance to handle dead events,
+ * they are wrapped in an instance of {@link DeadEvent} and reposted.
+ *
+ * <p>If a handler for a supertype of all events (such as Object) is registered,
+ * no event will ever be considered dead, and no DeadEvents will be generated.
+ * Accordingly, while DeadEvent extends {@link Object}, a handler registered to
+ * 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
+ */
+@Beta
+public class EventBus {
+
+ /**
+ * All registered event handlers, indexed by event type.
+ */
+ private final SetMultimap<Class<?>, EventHandler> handlersByType =
+ Multimaps.newSetMultimap(new ConcurrentHashMap<Class<?>, Collection<EventHandler>>(),
+ new Supplier<Set<EventHandler>>() {
+ @Override
+ public Set<EventHandler> get() {
+ return newHandlerSet();
+ }
+ });
+
+ /**
+ * Logger for event dispatch failures. Named by the fully-qualified name of
+ * this class, followed by the identifier provided at construction.
+ */
+ private final Logger logger;
+
+ /**
+ * Strategy for finding handler methods in registered objects. Currently,
+ * only the {@link AnnotatedHandlerFinder} is supported, but this is
+ * encapsulated for future expansion.
+ */
+ private final HandlerFindingStrategy finder = new AnnotatedHandlerFinder();
+
+ /** queues of events for the current thread to dispatch */
+ private final ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>>
+ eventsToDispatch =
+ new ThreadLocal<ConcurrentLinkedQueue<EventWithHandler>>() {
+ @Override protected ConcurrentLinkedQueue<EventWithHandler> initialValue() {
+ return new ConcurrentLinkedQueue<EventWithHandler>();
+ }
+ };
+
+ /** true if the current thread is currently dispatching an event */
+ private final ThreadLocal<Boolean> isDispatching =
+ new ThreadLocal<Boolean>() {
+ @Override protected Boolean initialValue() {
+ return false;
+ }
+ };
+
+ /**
+ * A thread-safe cache for flattenHierarchy(). The Class class is immutable.
+ */
+ private final LoadingCache<Class<?>, Set<Class<?>>> flattenHierarchyCache =
+ CacheBuilder.newBuilder()
+ .weakKeys()
+ .build(new CacheLoader<Class<?>, Set<Class<?>>>() {
+ @SuppressWarnings({"unchecked", "rawtypes"}) // safe cast
+ @Override
+ public Set<Class<?>> load(Class<?> concreteClass) throws Exception {
+ return (Set) TypeToken.of(concreteClass).getTypes().rawTypes();
+ }
+ });
+
+ /**
+ * Creates a new EventBus named "default".
+ */
+ public EventBus() {
+ this("default");
+ }
+
+ /**
+ * Creates a new EventBus with the given {@code identifier}.
+ *
+ * @param identifier a brief name for this bus, for logging purposes. Should
+ * be a valid Java identifier.
+ */
+ public EventBus(String identifier) {
+ logger = Logger.getLogger(EventBus.class.getName() + "." + identifier);
+ }
+
+ /**
+ * Registers all handler methods on {@code object} to receive events.
+ * Handler methods are selected and classified using this EventBus's
+ * {@link HandlerFindingStrategy}; the default strategy is the
+ * {@link AnnotatedHandlerFinder}.
+ *
+ * @param object object whose handler methods should be registered.
+ */
+ public void register(Object object) {
+ handlersByType.putAll(finder.findAllHandlers(object));
+ }
+
+ /**
+ * Unregisters all handler methods on a registered {@code object}.
+ *
+ * @param object object whose handler methods should be unregistered.
+ * @throws IllegalArgumentException if the object was not previously registered.
+ */
+ public void unregister(Object object) {
+ Multimap<Class<?>, EventHandler> methodsInListener = finder.findAllHandlers(object);
+ for (Entry<Class<?>, Collection<EventHandler>> entry : methodsInListener.asMap().entrySet()) {
+ Set<EventHandler> currentHandlers = getHandlersForEventType(entry.getKey());
+ Collection<EventHandler> eventMethodsInListener = entry.getValue();
+
+ if (currentHandlers == null || !currentHandlers.containsAll(entry.getValue())) {
+ throw new IllegalArgumentException(
+ "missing event handler for an annotated method. Is " + object + " registered?");
+ }
+ currentHandlers.removeAll(eventMethodsInListener);
+ }
+ }
+
+ /**
+ * Posts an event to all registered handlers. This method will return
+ * successfully after the event has been posted to all handlers, and
+ * regardless of any exceptions thrown by handlers.
+ *
+ * <p>If no handlers have been subscribed for {@code event}'s class, and
+ * {@code event} is not already a {@link DeadEvent}, it will be wrapped in a
+ * DeadEvent and reposted.
+ *
+ * @param event event to post.
+ */
+ @SuppressWarnings("deprecation") // only deprecated for external subclasses
+ public void post(Object event) {
+ Set<Class<?>> dispatchTypes = flattenHierarchy(event.getClass());
+
+ boolean dispatched = false;
+ for (Class<?> eventType : dispatchTypes) {
+ Set<EventHandler> wrappers = getHandlersForEventType(eventType);
+
+ if (wrappers != null && !wrappers.isEmpty()) {
+ dispatched = true;
+ for (EventHandler wrapper : wrappers) {
+ enqueueEvent(event, wrapper);
+ }
+ }
+ }
+
+ if (!dispatched && !(event instanceof DeadEvent)) {
+ post(new DeadEvent(this, event));
+ }
+
+ dispatchQueuedEvents();
+ }
+
+ /**
+ * Queue the {@code event} for dispatch during
+ * {@link #dispatchQueuedEvents()}. Events are queued in-order of occurrence
+ * so they can be dispatched in the same order.
+ */
+ void enqueueEvent(Object event, EventHandler handler) {
+ eventsToDispatch.get().offer(new EventWithHandler(event, handler));
+ }
+
+ /**
+ * 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.
+ *
+ * @deprecated This method should not be overridden outside of the eventbus package. It is
+ * scheduled for removal in Guava 14.0.
+ */
+ @Deprecated
+ 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.
+ if (isDispatching.get()) {
+ return;
+ }
+
+ isDispatching.set(true);
+ try {
+ while (true) {
+ EventWithHandler eventWithHandler = eventsToDispatch.get().poll();
+ if (eventWithHandler == null) {
+ break;
+ }
+
+ dispatch(eventWithHandler.event, eventWithHandler.handler);
+ }
+ } finally {
+ isDispatching.set(false);
+ }
+ }
+
+ /**
+ * Dispatches {@code event} to the handler in {@code wrapper}. This method
+ * is an appropriate override point for subclasses that wish to make
+ * event delivery asynchronous.
+ *
+ * @param event event to dispatch.
+ * @param wrapper wrapper that will call the handler.
+ */
+ void dispatch(Object event, EventHandler wrapper) {
+ try {
+ wrapper.handleEvent(event);
+ } catch (InvocationTargetException e) {
+ logger.log(Level.SEVERE,
+ "Could not dispatch event: " + event + " to handler " + wrapper, e);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ 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.
+ *
+ * @param concreteClass class whose type hierarchy will be retrieved.
+ * @return {@code clazz}'s complete type hierarchy, flattened and uniqued.
+ */
+ @VisibleForTesting
+ Set<Class<?>> flattenHierarchy(Class<?> concreteClass) {
+ try {
+ return flattenHierarchyCache.get(concreteClass);
+ } catch (ExecutionException e) {
+ throw Throwables.propagate(e.getCause());
+ }
+ }
+
+ /** simple struct representing an event and it's handler */
+ static class EventWithHandler {
+ final Object event;
+ final EventHandler handler;
+ public EventWithHandler(Object event, EventHandler 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
new file mode 100644
index 0000000..a072462
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/EventHandler.java
@@ -0,0 +1,109 @@
+/*
+ * 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.eventbus;
+
+import com.google.common.base.Preconditions;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Wraps a single-argument 'handler' method on a specific object.
+ *
+ * <p>This class only verifies the suitability of the method and event type if
+ * something fails. Callers are expected to verify their uses of this class.
+ *
+ * <p>Two EventHandlers are equivalent when they refer to the same method on the
+ * same object (not class). This property is used to ensure that no handler
+ * method is registered more than once.
+ *
+ * @author Cliff Biffle
+ */
+class EventHandler {
+
+ /** Object sporting the handler method. */
+ private final Object target;
+ /** Handler method. */
+ private final Method method;
+
+ /**
+ * Creates a new EventHandler to wrap {@code method} on @{code target}.
+ *
+ * @param target object to which the method applies.
+ * @param method handler method.
+ */
+ EventHandler(Object target, Method method) {
+ Preconditions.checkNotNull(target,
+ "EventHandler target cannot be null.");
+ Preconditions.checkNotNull(method, "EventHandler method cannot be null.");
+
+ this.target = target;
+ this.method = method;
+ method.setAccessible(true);
+ }
+
+ /**
+ * Invokes the wrapped handler method to handle {@code event}.
+ *
+ * @param event event to handle
+ * @throws InvocationTargetException if the wrapped method throws any
+ * {@link Throwable} that is not an {@link Error} ({@code Error}s are
+ * propagated as-is).
+ */
+ public void handleEvent(Object event) throws InvocationTargetException {
+ try {
+ method.invoke(target, new Object[] { event });
+ } catch (IllegalArgumentException e) {
+ throw new Error("Method rejected target/argument: " + event, e);
+ } catch (IllegalAccessException e) {
+ throw new Error("Method became inaccessible: " + event, e);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof Error) {
+ throw (Error) e.getCause();
+ }
+ throw e;
+ }
+ }
+
+ @Override public String toString() {
+ return "[wrapper " + method + "]";
+ }
+
+ @Override public int hashCode() {
+ final int PRIME = 31;
+ return (PRIME + method.hashCode()) * PRIME + target.hashCode();
+ }
+
+ @Override public boolean equals(Object obj) {
+ if(this == obj) {
+ return true;
+ }
+
+ if(obj == null) {
+ 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
new file mode 100644
index 0000000..7144203
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/HandlerFindingStrategy.java
@@ -0,0 +1,42 @@
+/*
+ * 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.eventbus;
+
+import com.google.common.collect.Multimap;
+
+/**
+ * A method for finding event handler methods in objects, for use by
+ * {@link EventBus}.
+ *
+ * @author Cliff Biffle
+ */
+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}s.
+ *
+ * @param source object whose handlers are desired.
+ * @return EventHandler objects for each handler method, organized by event
+ * type.
+ *
+ * @throws IllegalArgumentException if {@code source} is not appropriate for
+ * this strategy (in ways that this interface does not define).
+ */
+ Multimap<Class<?>, EventHandler> findAllHandlers(Object source);
+
+}
diff --git a/guava/src/com/google/common/eventbus/Subscribe.java b/guava/src/com/google/common/eventbus/Subscribe.java
new file mode 100644
index 0000000..34cb587
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/Subscribe.java
@@ -0,0 +1,46 @@
+/*
+ * 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.eventbus;
+
+import com.google.common.annotations.Beta;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a method as an event handler, as used by
+ * {@link AnnotatedHandlerFinder} and {@link EventBus}.
+ *
+ * <p>The type of event will be indicated by the method's first (and only)
+ * parameter. If this annotation is applied to methods with zero parameters,
+ * or more than one parameter, the object containing the method will not be able
+ * to register for event delivery from the {@link EventBus}.
+ *
+ * <p>Unless also annotated with @{@link AllowConcurrentEvents}, event handler
+ * methods will be invoked serially by each event bus that they are registered
+ * with.
+ *
+ * @author Cliff Biffle
+ * @since 10.0
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Beta
+public @interface Subscribe {
+}
diff --git a/guava/src/com/google/common/eventbus/SynchronizedEventHandler.java b/guava/src/com/google/common/eventbus/SynchronizedEventHandler.java
new file mode 100644
index 0000000..2792704
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/SynchronizedEventHandler.java
@@ -0,0 +1,48 @@
+/*
+ * 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.eventbus;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Wraps a single-argument 'handler' method on a specific object, and ensures
+ * that only one thread may enter the method at a time.
+ *
+ * <p>Beyond synchronization, this class behaves identically to
+ * {@link EventHandler}.
+ *
+ * @author Cliff Biffle
+ */
+class SynchronizedEventHandler extends EventHandler {
+ /**
+ * Creates a new SynchronizedEventHandler to wrap {@code method} on
+ * {@code target}.
+ *
+ * @param target object to which the method applies.
+ * @param method handler method.
+ */
+ public SynchronizedEventHandler(Object target, Method method) {
+ super(target, method);
+ }
+
+ @Override public synchronized void handleEvent(Object event)
+ throws InvocationTargetException {
+ super.handleEvent(event);
+ }
+
+}
diff --git a/guava/src/com/google/common/eventbus/package-info.java b/guava/src/com/google/common/eventbus/package-info.java
new file mode 100644
index 0000000..28637cd
--- /dev/null
+++ b/guava/src/com/google/common/eventbus/package-info.java
@@ -0,0 +1,254 @@
+/*
+ * 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.
+ */
+
+/**
+ * The EventBus allows publish-subscribe-style communication between components
+ * without requiring the components to explicitly register with one another
+ * (and thus be aware of each other). It is designed exclusively to replace
+ * 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>
+ *
+ * Converting an existing EventListener-based system to use the EventBus is
+ * easy.
+ *
+ * <h3>For Listeners</h3>
+ * To listen for a specific flavor of event (say, a CustomerChangeEvent)...
+ * <ul>
+ * <li><strong>...in traditional Java events:</strong> implement an interface
+ * defined with the event &mdash; such as CustomerChangeEventListener.</li>
+ * <li><strong>...with EventBus:</strong> create a method that accepts
+ * CustomerChangeEvent as its sole argument, and mark it with the
+ * {@link com.google.common.eventbus.Subscribe} annotation.</li>
+ * </ul>
+ *
+ * <p>To register your listener methods with the event producers...
+ * <ul>
+ * <li><strong>...in traditional Java events:</strong> pass your object to each
+ * producer's {@code registerCustomerChangeEventListener} method. These
+ * methods are rarely defined in common interfaces, so in addition to
+ * knowing every possible producer, you must also know its type.</li>
+ * <li><strong>...with EventBus:</strong> pass your object to the
+ * {@link com.google.common.eventbus.EventBus#register(Object)} method on an
+ * EventBus. You'll need to
+ * make sure that your object shares an EventBus instance with the event
+ * producers.</li>
+ * </ul>
+ *
+ * <p>To listen for a common event supertype (such as EventObject or Object)...
+ * <ul>
+ * <li><strong>...in traditional Java events:</strong> not easy.</li>
+ * <li><strong>...with EventBus:</strong> events are automatically dispatched to
+ * listeners of any supertype, allowing listeners for interface types
+ * or "wildcard listeners" for Object.</li>
+ * </ul>
+ *
+ * <p>To listen for and detect events that were dispatched without listeners...
+ * <ul>
+ * <li><strong>...in traditional Java events:</strong> add code to each
+ * event-dispatching method (perhaps using AOP).</li>
+ * <li><strong>...with EventBus:</strong> subscribe to {@link
+ * com.google.common.eventbus.DeadEvent}. The
+ * EventBus will notify you of any events that were posted but not
+ * delivered. (Handy for debugging.)</li>
+ * </ul>
+ *
+ * <h3>For Producers</h3>
+ * To keep track of listeners to your events...
+ * <ul>
+ * <li><strong>...in traditional Java events:</strong> write code to manage
+ * a list of listeners to your object, including synchronization, or use a
+ * utility class like EventListenerList.</li>
+ * <li><strong>...with EventBus:</strong> EventBus does this for you.</li>
+ * </ul>
+ *
+ * <p>To dispatch an event to listeners...
+ * <ul>
+ * <li><strong>...in traditional Java events:</strong> write a method to
+ * dispatch events to each event listener, including error isolation and
+ * (if desired) asynchronicity.</li>
+ * <li><strong>...with EventBus:</strong> pass the event object to an EventBus's
+ * {@link com.google.common.eventbus.EventBus#post(Object)} method.</li>
+ * </ul>
+ *
+ * <h2>Glossary</h2>
+ *
+ * The EventBus system and code use the following terms to discuss event
+ * distribution:
+ * <dl>
+ * <dt>Event</dt><dd>Any object that may be <em>posted</em> to a bus.</dd>
+ * <dt>Subscribing</dt><dd>The act of registering a <em>listener</em> with an
+ * EventBus, so that its <em>handler methods</em> will receive events.</dd>
+ * <dt>Listener</dt><dd>An object that wishes to receive events, by exposing
+ * <em>handler methods</em>.</dt>
+ * <dt>Handler method</dt><dd>A public method that the EventBus should use to
+ * deliver <em>posted</em> events. Handler methods are marked by the
+ * {@link com.google.common.eventbus.Subscribe} annotation.</dd>
+ * <dt>Posting an event</dt><dd>Making the event available to any
+ * <em>listeners</em> through the EventBus.</dt>
+ * </dl>
+ *
+ * <h2>FAQ</h2>
+ * <h3>Why must I create my own Event Bus, rather than using a singleton?</h3>
+ *
+ * The Event Bus doesn't specify how you use it; there's nothing stopping your
+ * application from having separate EventBus instances for each component, or
+ * using separate instances to separate events by context or topic. This also
+ * makes it trivial to set up and tear down EventBus objects in your tests.
+ *
+ * <p>Of course, if you'd like to have a process-wide EventBus singleton,
+ * there's nothing stopping you from doing it that way. Simply have your
+ * container (such as Guice) create the EventBus as a singleton at global scope
+ * (or stash it in a static field, if you're into that sort of thing).
+ *
+ * <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>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
+ * intentions just as explicitly as implementing an interface (or perhaps more
+ * so), while leaving you free to place event handler methods wherever you wish
+ * and give them intention-revealing names.
+ *
+ * <p>Traditional Java Events use a listener interface which typically sports
+ * only a handful of methods -- typically one. This has a number of
+ * disadvantages:
+ * <ul>
+ * <li>Any one class can only implement a single response to a given event.
+ * <li>Listener interface methods may conflict.
+ * <li>The method must be named after the event (e.g. {@code
+ * handleChangeEvent}), rather than its purpose (e.g. {@code
+ * recordChangeInJournal}).
+ * <li>Each event usually has its own interface, without a common parent
+ * interface for a family of events (e.g. all UI events).
+ * </ul>
+ *
+ * <p>The difficulties in implementing this cleanly has given rise to a pattern,
+ * particularly common in Swing apps, of using tiny anonymous classes to
+ * implement event listener interfaces.
+ *
+ * <p>Compare these two cases: <pre>
+ * class ChangeRecorder {
+ * void setCustomer(Customer cust) {
+ * cust.addChangeListener(new ChangeListener() {
+ * void customerChanged(ChangeEvent e) {
+ * recordChange(e.getChange());
+ * }
+ * };
+ * }
+ * }
+ *
+ * // Class is typically registered by the container.
+ * class EventBusChangeRecorder {
+ * &#064;Subscribe void recordCustomerChange(ChangeEvent e) {
+ * recordChange(e.getChange());
+ * }
+ * }</pre>
+ *
+ * The intent is actually clearer in the second case: there's less noise code,
+ * and the event handler has a clear and meaningful name.
+ *
+ * <h3>What about a generic {@code Handler<T>} interface?</h3>
+ * Some have proposed a generic {@code Handler<T>} interface for EventBus
+ * listeners. This runs into issues with Java's use of type erasure, not to
+ * mention problems in usability.
+ *
+ * <p>Let's say the interface looked something like the following: <pre> {@code
+ * interface Handler<T> {
+ * void handleEvent(T event);
+ * }}</pre>
+ *
+ * Due to erasure, no single class can implement a generic interface more than
+ * once with different type parameters. This is a giant step backwards from
+ * traditional Java Events, where even if {@code actionPerformed} and {@code
+ * keyPressed} aren't very meaningful names, at least you can implement both
+ * methods!
+ *
+ * <h3>Doesn't EventBus destroy static typing and eliminate automated
+ * refactoring support?</h3>
+ * Some have freaked out about EventBus's {@code register(Object)} and {@code
+ * post(Object)} methods' use of the {@code Object} type.
+ *
+ * <p>{@code Object} is used here for a good reason: the Event Bus library
+ * places no restrictions on the types of either your event listeners (as in
+ * {@code register(Object)}) or the events themselves (in {@code post(Object)}).
+ *
+ * <p>Event handler methods, on the other hand, must explicitly declare their
+ * argument type -- the type of event desired (or one of its supertypes). Thus,
+ * searching for references to an event class will instantly find all handler
+ * methods for that event, and renaming the type will affect all handler methods
+ * within view of your IDE (and any code that creates the event).
+ *
+ * <p>It's true that you can rename your {@code @Subscribed} event handler
+ * methods at will; Event Bus will not stop this or do anything to propagate the
+ * rename because, to Event Bus, the names of your handler methods are
+ * irrelevant. Test code that calls the methods directly, of course, will be
+ * affected by your renaming -- but that's what your refactoring tools are for.
+ *
+ * <h3>What happens if I {@code register} a listener without any handler
+ * methods?</h3>
+ * Nothing at all.
+ *
+ * <p>The Event Bus was designed to integrate with containers and module
+ * systems, with Guice as the prototypical example. In these cases, it's
+ * convenient to have the container/factory/environment pass <i>every</i>
+ * created object to an EventBus's {@code register(Object)} method.
+ *
+ * <p>This way, any object created by the container/factory/environment can
+ * hook into the system's event model simply by exposing handler methods.
+ *
+ * <h3>What Event Bus problems can be detected at compile time?</h3>
+ * Any problem that can be unambiguously detected by Java's type system. For
+ * example, defining a handler method for a nonexistent event type.
+ *
+ * <h3>What Event Bus problems can be detected immediately at registration?</h3>
+ * Immediately upon invoking {@code register(Object)} , the listener being
+ * registered is checked for the <i>well-formedness</i> of its handler methods.
+ * Specifically, any methods marked with {@code @Subscribe} must take only a
+ * single argument.
+ *
+ * <p>Any violations of this rule will cause an {@code IllegalArgumentException}
+ * to be thrown.
+ *
+ * <p>(This check could be moved to compile-time using APT, a solution we're
+ * researching.)
+ *
+ * <h3>What Event Bus problems may only be detected later, at runtime?</h3>
+ * If a component posts events with no registered listeners, it <i>may</i>
+ * indicate an error (typically an indication that you missed a
+ * {@code @Subscribe} annotation, or that the listening component is not loaded).
+ *
+ * <p>(Note that this is <i>not necessarily</i> indicative of a problem. There
+ * are many cases where an application will deliberately ignore a posted event,
+ * particularly if the event is coming from code you don't control.)
+ *
+ * <p>To handle such events, register a handler method for the {@code DeadEvent}
+ * class. Whenever EventBus receives an event with no registered handlers, it
+ * will turn it into a {@code DeadEvent} and pass it your way -- allowing you to
+ * log it or otherwise recover.
+ *
+ * <h3>How do I test event listeners and their handler methods?</h3>
+ * Because handler methods on your listener classes are normal methods, you can
+ * simply call them from your test code to simulate the EventBus.
+ */
+package com.google.common.eventbus;
diff --git a/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java b/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java
new file mode 100644
index 0000000..e0b074f
--- /dev/null
+++ b/guava/src/com/google/common/hash/AbstractCompositeHashFunction.java
@@ -0,0 +1,148 @@
+/*
+ * 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.hash;
+
+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
+ */
+abstract class AbstractCompositeHashFunction extends AbstractStreamingHashFunction {
+ final HashFunction[] functions;
+
+ AbstractCompositeHashFunction(HashFunction... functions) {
+ 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
+ * the hashers are the same order as the functions given to the constructor.
+ */
+ // 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];
+ for (int i = 0; i < hashers.length; i++) {
+ hashers[i] = functions[i].newHasher();
+ }
+ return new Hasher() {
+ @Override public Hasher putByte(byte b) {
+ for (Hasher hasher : hashers) {
+ hasher.putByte(b);
+ }
+ return this;
+ }
+
+ @Override public Hasher putBytes(byte[] bytes) {
+ for (Hasher hasher : hashers) {
+ hasher.putBytes(bytes);
+ }
+ return this;
+ }
+
+ @Override public Hasher putBytes(byte[] bytes, int off, int len) {
+ for (Hasher hasher : hashers) {
+ hasher.putBytes(bytes, off, len);
+ }
+ return this;
+ }
+
+ @Override public Hasher putShort(short s) {
+ for (Hasher hasher : hashers) {
+ hasher.putShort(s);
+ }
+ return this;
+ }
+
+ @Override public Hasher putInt(int i) {
+ for (Hasher hasher : hashers) {
+ hasher.putInt(i);
+ }
+ return this;
+ }
+
+ @Override public Hasher putLong(long l) {
+ for (Hasher hasher : hashers) {
+ hasher.putLong(l);
+ }
+ return this;
+ }
+
+ @Override public Hasher putFloat(float f) {
+ for (Hasher hasher : hashers) {
+ hasher.putFloat(f);
+ }
+ return this;
+ }
+
+ @Override public Hasher putDouble(double d) {
+ for (Hasher hasher : hashers) {
+ hasher.putDouble(d);
+ }
+ return this;
+ }
+
+ @Override public Hasher putBoolean(boolean b) {
+ for (Hasher hasher : hashers) {
+ hasher.putBoolean(b);
+ }
+ return this;
+ }
+
+ @Override public Hasher putChar(char c) {
+ for (Hasher hasher : hashers) {
+ hasher.putChar(c);
+ }
+ return this;
+ }
+
+ @Override public Hasher putString(CharSequence chars) {
+ for (Hasher hasher : hashers) {
+ hasher.putString(chars);
+ }
+ return this;
+ }
+
+ @Override public Hasher putString(CharSequence chars, Charset charset) {
+ for (Hasher hasher : hashers) {
+ hasher.putString(chars, charset);
+ }
+ return this;
+ }
+
+ @Override public <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
+ for (Hasher hasher : hashers) {
+ hasher.putObject(instance, funnel);
+ }
+ return this;
+ }
+
+ @Override public HashCode hash() {
+ return makeHash(hashers);
+ }
+ };
+ }
+
+ 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
new file mode 100644
index 0000000..f60f928
--- /dev/null
+++ b/guava/src/com/google/common/hash/AbstractHasher.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.hash;
+
+import java.nio.charset.Charset;
+
+/**
+ * An abstract hasher, implementing {@link #putBoolean(boolean)}, {@link #putDouble(double)},
+ * {@link #putFloat(float)}, {@link #putString(CharSequence)}, and
+ * {@link #putString(CharSequence, Charset)} as prescribed by {@link Hasher}.
+ *
+ * @author Dimitris Andreou
+ */
+abstract class AbstractHasher implements Hasher {
+ @Override public final Hasher putBoolean(boolean b) {
+ return putByte(b ? (byte) 1 : (byte) 0);
+ }
+
+ @Override public final Hasher putDouble(double d) {
+ return putLong(Double.doubleToRawLongBits(d));
+ }
+
+ @Override public final Hasher putFloat(float f) {
+ return putInt(Float.floatToRawIntBits(f));
+ }
+
+ @Override public Hasher putString(CharSequence charSequence) {
+ for (int i = 0, len = charSequence.length(); i < len; i++) {
+ putChar(charSequence.charAt(i));
+ }
+ return this;
+ }
+
+ @Override public Hasher putString(CharSequence charSequence, Charset charset) {
+ return putBytes(charSequence.toString().getBytes(charset));
+ }
+}
diff --git a/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java b/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java
new file mode 100644
index 0000000..28a9c92
--- /dev/null
+++ b/guava/src/com/google/common/hash/AbstractNonStreamingHashFunction.java
@@ -0,0 +1,158 @@
+/*
+ * 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.hash;
+
+import com.google.common.base.Preconditions;
+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
+ */
+abstract class AbstractNonStreamingHashFunction implements HashFunction {
+ @Override
+ public Hasher newHasher() {
+ return new BufferingHasher(32);
+ }
+
+ @Override
+ public Hasher newHasher(int expectedInputSize) {
+ Preconditions.checkArgument(expectedInputSize >= 0);
+ return new BufferingHasher(expectedInputSize);
+ }
+
+ @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.
+ */
+ private final class BufferingHasher extends AbstractHasher {
+ final ExposedByteArrayOutputStream stream;
+ static final int BOTTOM_BYTE = 0xFF;
+
+ BufferingHasher(int expectedInputSize) {
+ this.stream = new ExposedByteArrayOutputStream(expectedInputSize);
+ }
+
+ @Override
+ public Hasher putByte(byte b) {
+ stream.write(b);
+ return this;
+ }
+
+ @Override
+ public Hasher putBytes(byte[] bytes) {
+ try {
+ stream.write(bytes);
+ } catch (IOException e) {
+ throw Throwables.propagate(e);
+ }
+ return this;
+ }
+
+ @Override
+ public Hasher putBytes(byte[] bytes, int off, int len) {
+ stream.write(bytes, off, len);
+ return this;
+ }
+
+ @Override
+ public Hasher putShort(short s) {
+ stream.write(s & BOTTOM_BYTE);
+ stream.write((s >>> 8) & BOTTOM_BYTE);
+ return this;
+ }
+
+ @Override
+ public Hasher putInt(int i) {
+ stream.write(i & BOTTOM_BYTE);
+ stream.write((i >>> 8) & BOTTOM_BYTE);
+ stream.write((i >>> 16) & BOTTOM_BYTE);
+ stream.write((i >>> 24) & BOTTOM_BYTE);
+ return this;
+ }
+
+ @Override
+ public Hasher putLong(long l) {
+ for (int i = 0; i < 64; i += 8) {
+ stream.write((byte) ((l >>> i) & BOTTOM_BYTE));
+ }
+ return this;
+ }
+
+ @Override
+ public Hasher putChar(char c) {
+ stream.write(c & BOTTOM_BYTE);
+ stream.write((c >>> 8) & BOTTOM_BYTE);
+ return this;
+ }
+
+ @Override
+ public <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
+ funnel.funnel(instance, this);
+ return this;
+ }
+
+ @Override
+ public HashCode hash() {
+ 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) {
+ super(expectedInputSize);
+ }
+ byte[] byteArray() {
+ return buf;
+ }
+ int length() {
+ return count;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java b/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java
new file mode 100644
index 0000000..a5ba342
--- /dev/null
+++ b/guava/src/com/google/common/hash/AbstractStreamingHashFunction.java
@@ -0,0 +1,253 @@
+/*
+ * 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.hash;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.Preconditions;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * Skeleton implementation of {@link HashFunction}. Provides default implementations which
+ * invokes the appropriate method on {@link #newHasher()}, then return the result of
+ * {@link Hasher#hash}.
+ *
+ * <p>Invocations of {@link #newHasher(int)} also delegate to {@linkplain #newHasher()}, ignoring
+ * the expected input size parameter.
+ *
+ * @author Kevin Bourrillion
+ */
+abstract class AbstractStreamingHashFunction implements HashFunction {
+ @Override public HashCode hashString(CharSequence input) {
+ return newHasher().putString(input).hash();
+ }
+
+ @Override public HashCode hashString(CharSequence input, Charset charset) {
+ 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();
+ }
+
+ @Override public HashCode hashBytes(byte[] input) {
+ return newHasher().putBytes(input).hash();
+ }
+
+ @Override public HashCode hashBytes(byte[] input, int off, int len) {
+ return newHasher().putBytes(input, off, len).hash();
+ }
+
+ @Override public Hasher newHasher(int expectedInputSize) {
+ Preconditions.checkArgument(expectedInputSize >= 0);
+ return newHasher();
+ }
+
+ /**
+ * 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
+ */
+ // TODO(kevinb): this class still needs some design-and-document-for-inheritance love
+ protected static abstract class AbstractStreamingHasher extends AbstractHasher {
+ /** Buffer via which we pass data to the hash algorithm (the implementor) */
+ private final ByteBuffer buffer;
+
+ /** Number of bytes to be filled before process() invocation(s). */
+ private final int bufferSize;
+
+ /** Number of bytes processed per process() invocation. */
+ private final int chunkSize;
+
+ /**
+ * Constructor for use by subclasses. This hasher instance will process chunks of the specified
+ * size.
+ *
+ * @param chunkSize the number of bytes available per {@link #process(ByteBuffer)} invocation;
+ * must be at least 4
+ */
+ protected AbstractStreamingHasher(int chunkSize) {
+ this(chunkSize, chunkSize);
+ }
+
+ /**
+ * Constructor for use by subclasses. This hasher instance will process chunks of the specified
+ * size, using an internal buffer of {@code bufferSize} size, which must be a multiple of
+ * {@code chunkSize}.
+ *
+ * @param chunkSize the number of bytes available per {@link #process(ByteBuffer)} invocation;
+ * must be at least 4
+ * @param bufferSize the size of the internal buffer. Must be a multiple of chunkSize
+ */
+ protected AbstractStreamingHasher(int chunkSize, int bufferSize) {
+ // TODO(kevinb): check more preconditions (as bufferSize >= chunkSize) if this is ever public
+ checkArgument(bufferSize % chunkSize == 0);
+
+ // TODO(user): benchmark performance difference with longer buffer
+ this.buffer = ByteBuffer
+ .allocate(bufferSize + 7) // always space for a single primitive
+ .order(ByteOrder.LITTLE_ENDIAN);
+ this.bufferSize = bufferSize;
+ this.chunkSize = chunkSize;
+ }
+
+ /**
+ * Processes the available bytes of the buffer (at most {@code chunk} bytes).
+ */
+ protected abstract void process(ByteBuffer bb);
+
+ /**
+ * This is invoked for the last bytes of the input, which are not enough to
+ * fill a whole chunk. The passed {@code ByteBuffer} is guaranteed to be
+ * non-empty.
+ *
+ * <p>This implementation simply pads with zeros and delegates to
+ * {@link #process(ByteBuffer)}.
+ */
+ protected void processRemaining(ByteBuffer bb) {
+ bb.position(bb.limit()); // move at the end
+ bb.limit(chunkSize + 7); // get ready to pad with longs
+ while (bb.position() < chunkSize) {
+ bb.putLong(0);
+ }
+ bb.limit(chunkSize);
+ bb.flip();
+ process(bb);
+ }
+
+ @Override
+ public final Hasher putBytes(byte[] bytes) {
+ return putBytes(bytes, 0, bytes.length);
+ }
+
+ @Override
+ public final Hasher putBytes(byte[] bytes, int off, int len) {
+ return putBytes(ByteBuffer.wrap(bytes, off, len).order(ByteOrder.LITTLE_ENDIAN));
+ }
+
+ 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);
+ munchIfFull();
+ return this;
+ }
+
+ // First add just enough to fill buffer size, and munch that
+ int bytesToCopy = bufferSize - buffer.position();
+ for (int i = 0; i < bytesToCopy; i++) {
+ buffer.put(readBuffer.get());
+ }
+ munch(); // buffer becomes empty here, since chunkSize divides bufferSize
+
+ // Now process directly from the rest of the input buffer
+ while (readBuffer.remaining() >= chunkSize) {
+ process(readBuffer);
+ }
+
+ // Finally stick the remainder back in our usual buffer
+ buffer.put(readBuffer);
+ return this;
+ }
+
+ @Override
+ public final Hasher putString(CharSequence charSequence) {
+ for (int i = 0; i < charSequence.length(); i++) {
+ putChar(charSequence.charAt(i));
+ }
+ return this;
+ }
+
+ @Override
+ public final Hasher putByte(byte b) {
+ buffer.put(b);
+ munchIfFull();
+ return this;
+ }
+
+ @Override
+ public final Hasher putShort(short s) {
+ buffer.putShort(s);
+ munchIfFull();
+ return this;
+ }
+
+ @Override
+ public final Hasher putChar(char c) {
+ buffer.putChar(c);
+ munchIfFull();
+ return this;
+ }
+
+ @Override
+ public final Hasher putInt(int i) {
+ buffer.putInt(i);
+ munchIfFull();
+ return this;
+ }
+
+ @Override
+ public final Hasher putLong(long l) {
+ buffer.putLong(l);
+ munchIfFull();
+ return this;
+ }
+
+ @Override
+ public final <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
+ funnel.funnel(instance, this);
+ return this;
+ }
+
+ @Override
+ public final HashCode hash() {
+ munch();
+ buffer.flip();
+ if (buffer.remaining() > 0) {
+ processRemaining(buffer);
+ }
+ return makeHash();
+ }
+
+ abstract HashCode makeHash();
+
+ // Process pent-up data in chunks
+ private void munchIfFull() {
+ if (buffer.remaining() < 8) {
+ // buffer is full; not enough room for a primitive. We have at least one full chunk.
+ munch();
+ }
+ }
+
+ private void munch() {
+ buffer.flip();
+ while (buffer.remaining() >= chunkSize) {
+ // we could limit the buffer to ensure process() does not read more than
+ // chunkSize number of bytes, but we trust the implementations
+ process(buffer);
+ }
+ buffer.compact(); // preserve any remaining data that do not make a full chunk
+ }
+ }
+}
diff --git a/guava/src/com/google/common/hash/BloomFilter.java b/guava/src/com/google/common/hash/BloomFilter.java
new file mode 100644
index 0000000..8fe6ba7
--- /dev/null
+++ b/guava/src/com/google/common/hash/BloomFilter.java
@@ -0,0 +1,310 @@
+/*
+ * 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.hash;
+
+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.Preconditions;
+import com.google.common.hash.BloomFilterStrategies.BitArray;
+
+import java.io.Serializable;
+
+/**
+ * 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,
+ * 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
+ * how they work.
+ *
+ *
+ * @param <T> the type of instances that the {@code BloomFilter} accepts
+ * @author Dimitris Andreou
+ * @author Kevin Bourrillion
+ * @since 11.0
+ */
+@Beta
+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.
+ */
+ <T> boolean 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.
+ */
+ <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 */
+ 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.
+ */
+ private BloomFilter(BitArray bits, int numHashFunctions, Funnel<T> funnel,
+ Strategy strategy) {
+ Preconditions.checkArgument(numHashFunctions > 0, "numHashFunctions zero or negative");
+ this.bits = checkNotNull(bits);
+ this.numHashFunctions = numHashFunctions;
+ this.funnel = checkNotNull(funnel);
+ this.strategy = strategy;
+
+ /*
+ * This only exists to forbid BFs that cannot use the compact persistent representation.
+ * If it ever throws, at a user who was not intending to use that representation, we should
+ * reconsider
+ */
+ if (numHashFunctions > 255) {
+ throw new AssertionError("Currently we don't allow BloomFilters that would use more than" +
+ "255 hash functions, please contact the guava team");
+ }
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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 falsePositiveProbability} 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.
+ */
+ public double expectedFalsePositiveProbability() {
+ return Math.pow((double) bits.bitCount() / bits.size(), numHashFunctions);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation uses reference equality to compare funnels.
+ */
+ @Override public boolean equals(Object o) {
+ if (o instanceof BloomFilter) {
+ BloomFilter<?> that = (BloomFilter<?>) o;
+ return this.numHashFunctions == that.numHashFunctions
+ && this.bits.equals(that.bits)
+ && this.funnel == that.funnel
+ && this.strategy == that.strategy;
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return bits.hashCode();
+ }
+
+ @VisibleForTesting int getHashCount() {
+ return numHashFunctions;
+ }
+
+ /**
+ * 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
+ * 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
+ * {@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 falsePositiveProbability the desired false positive probability (must be positive and
+ * less than 1.0)
+ * @return a {@code BloomFilter}
+ */
+ public static <T> BloomFilter<T> create(Funnel<T> funnel, int expectedInsertions /* n */,
+ double falsePositiveProbability) {
+ checkNotNull(funnel);
+ checkArgument(expectedInsertions >= 0, "Expected insertions cannot be negative");
+ checkArgument(falsePositiveProbability > 0.0 & falsePositiveProbability < 1.0,
+ "False positive probability in (0.0, 1.0)");
+ if (expectedInsertions == 0) {
+ expectedInsertions = 1;
+ }
+ /*
+ * 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!
+ */
+ int numBits = optimalNumOfBits(expectedInsertions, falsePositiveProbability);
+ int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);
+ 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
+ * of insertions, and a default expected false positive probability of 3%.
+ *
+ * <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
+ * {@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}
+ */
+ 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
+ }
+
+ /*
+ * 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
+ * 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(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
+ * 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 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;
+ this.funnel = bf.funnel;
+ this.strategy = bf.strategy;
+ }
+ Object readResolve() {
+ return new BloomFilter<T>(new BitArray(data), numHashFunctions, funnel, strategy);
+ }
+ private static final long serialVersionUID = 1;
+ }
+}
diff --git a/guava/src/com/google/common/hash/BloomFilterStrategies.java b/guava/src/com/google/common/hash/BloomFilterStrategies.java
new file mode 100644
index 0000000..9709e0b
--- /dev/null
+++ b/guava/src/com/google/common/hash/BloomFilterStrategies.java
@@ -0,0 +1,137 @@
+/*
+ * 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.hash;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+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
+ * 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
+ */
+enum BloomFilterStrategies implements BloomFilter.Strategy {
+ /**
+ * See "Less Hashing, Same Performance: Building a Better Bloom Filter" by Adam Kirsch and
+ * Michael Mitzenmacher. The paper argues that this trick doesn't significantly deteriorate the
+ * 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,
+ int numHashFunctions, BitArray bits) {
+ // 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());
+ }
+ return bitsChanged;
+ }
+
+ @Override public <T> boolean mightContain(T object, Funnel<? super T> funnel,
+ int numHashFunctions, BitArray bits) {
+ 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++) {
+ int nextHash = hash1 + i * hash2;
+ if (nextHash < 0) {
+ nextHash = ~nextHash;
+ }
+ if (!bits.get(nextHash % bits.size())) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ // 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(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;
+ }
+
+ boolean get(int index) {
+ return (data[index >> 6] & (1L << index)) != 0;
+ }
+
+ /** Number of bits */
+ 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/Funnel.java b/guava/src/com/google/common/hash/Funnel.java
new file mode 100644
index 0000000..dbe0596
--- /dev/null
+++ b/guava/src/com/google/common/hash/Funnel.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.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}.
+ *
+ * @author Dimitris Andreou
+ * @since 11.0
+ */
+@Beta
+public interface Funnel<T> extends Serializable {
+
+ /**
+ * 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 11.0 version, {@code PrimitiveSink} was still called {@code Sink})
+ */
+ void funnel(T from, PrimitiveSink into);
+}
diff --git a/guava/src/com/google/common/hash/Funnels.java b/guava/src/com/google/common/hash/Funnels.java
new file mode 100644
index 0000000..7f76202
--- /dev/null
+++ b/guava/src/com/google/common/hash/Funnels.java
@@ -0,0 +1,148 @@
+/*
+ * 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.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
+ */
+@Beta
+public final class Funnels {
+ private Funnels() {}
+
+ /**
+ * Returns a funnel that extracts the bytes from a {@code byte} array.
+ */
+ public static Funnel<byte[]> byteArrayFunnel() {
+ return ByteArrayFunnel.INSTANCE;
+ }
+
+ private enum ByteArrayFunnel implements Funnel<byte[]> {
+ INSTANCE;
+
+ public void funnel(byte[] from, PrimitiveSink into) {
+ into.putBytes(from);
+ }
+
+ @Override public String toString() {
+ return "Funnels.byteArrayFunnel()";
+ }
+ }
+
+ /**
+ * Returns a funnel that extracts the characters from a {@code CharSequence}.
+ */
+ public static Funnel<CharSequence> stringFunnel() {
+ return StringFunnel.INSTANCE;
+ }
+
+ private enum StringFunnel implements Funnel<CharSequence> {
+ INSTANCE;
+
+ public void funnel(CharSequence from, PrimitiveSink into) {
+ into.putString(from);
+ }
+
+ @Override public String toString() {
+ 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
new file mode 100644
index 0000000..ecd8706
--- /dev/null
+++ b/guava/src/com/google/common/hash/HashCode.java
@@ -0,0 +1,120 @@
+/*
+ * 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.hash;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Ints;
+
+import java.security.MessageDigest;
+
+/**
+ * An immutable hash code of arbitrary bit length.
+ *
+ * @author Dimitris Andreou
+ * @since 11.0
+ */
+@Beta
+public abstract class HashCode {
+ HashCode() {}
+
+ /**
+ * Returns the first four bytes of {@linkplain #asBytes() this hashcode's bytes}, converted to
+ * an {@code int} value in little-endian order.
+ */
+ public abstract int asInt();
+
+ /**
+ * Returns the first eight bytes of {@linkplain #asBytes() this hashcode's bytes}, converted to
+ * a {@code long} value in little-endian order.
+ *
+ * @throws IllegalStateException if {@code bits() < 64}
+ */
+ public abstract long asLong();
+
+ /**
+ * 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.
+ */
+ // TODO(user): consider ByteString here, when that is available
+ public abstract byte[] asBytes();
+
+ /**
+ * Copies bytes from this hash code into {@code dest}.
+ *
+ * @param dest the byte array into which the hash code will be written
+ * @param offset the start offset in the data
+ * @param maxLength the maximum number of bytes to write
+ * @return the number of bytes written to {@code dest}
+ * @throws IndexOutOfBoundsException if there is not enough room in {@code dest}
+ */
+ public int writeBytesTo(byte[] dest, int offset, int maxLength) {
+ byte[] hash = asBytes();
+ maxLength = Ints.min(maxLength, hash.length);
+ Preconditions.checkPositionIndexes(offset, offset + maxLength, dest.length);
+ System.arraycopy(hash, 0, dest, offset, maxLength);
+ return maxLength;
+ }
+
+ /**
+ * Returns the number of bits in this hash code; a positive multiple of 32.
+ */
+ public abstract int bits();
+
+ @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
+ // hash code, in which case we don't want to leak timing information
+ return MessageDigest.isEqual(this.asBytes(), that.asBytes());
+ }
+ return false;
+ }
+
+ /**
+ * Returns a "Java hash code" for this {@code HashCode} instance; this is well-defined
+ * (so, for example, you can safely put {@code HashCode} instances into a {@code
+ * HashSet}) but is otherwise probably not what you want to use.
+ */
+ @Override public int hashCode() {
+ /*
+ * As long as the hash function that produced this isn't of horrible quality, this
+ * won't be of horrible quality either.
+ */
+ return asInt();
+ }
+
+ /**
+ * Returns a string containing each byte of {@link #asBytes}, in order, as a two-digit unsigned
+ * hexadecimal number in lower case.
+ *
+ * <p>Note that if the output is considered to be a single hexadecimal number, this hash code's
+ * bytes are the <i>big-endian</i> representation of that number. This may be surprising since
+ * everything else in the hashing API uniformly treats multibyte values as little-endian. But
+ * this format conveniently matches that of utilities such as the UNIX {@code md5sum} command.
+ */
+ @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]);
+ }
+ return sb.toString();
+ }
+
+ private static final char[] hexDigits = "0123456789abcdef".toCharArray();
+}
diff --git a/guava/src/com/google/common/hash/HashCodes.java b/guava/src/com/google/common/hash/HashCodes.java
new file mode 100644
index 0000000..3aa3424
--- /dev/null
+++ b/guava/src/com/google/common/hash/HashCodes.java
@@ -0,0 +1,171 @@
+/*
+ * 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.hash;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.annotations.Beta;
+
+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
+ */
+@Beta
+public 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) {
+ return new IntHashCode(hash);
+ }
+
+ private static final class IntHashCode extends HashCode implements Serializable {
+ final int hash;
+
+ IntHashCode(int hash) {
+ this.hash = hash;
+ }
+
+ @Override public int bits() {
+ return 32;
+ }
+
+ @Override public byte[] asBytes() {
+ return new byte[] {
+ (byte) hash,
+ (byte) (hash >> 8),
+ (byte) (hash >> 16),
+ (byte) (hash >> 24)};
+ }
+
+ @Override public int asInt() {
+ return hash;
+ }
+
+ @Override public long asLong() {
+ throw new IllegalStateException("this HashCode only has 32 bits; cannot create a long");
+ }
+
+ 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) {
+ return new LongHashCode(hash);
+ }
+
+ private static final class LongHashCode extends HashCode implements Serializable {
+ final long hash;
+
+ LongHashCode(long hash) {
+ this.hash = hash;
+ }
+
+ @Override public int bits() {
+ return 64;
+ }
+
+ @Override public byte[] asBytes() {
+ return new byte[] {
+ (byte) hash,
+ (byte) (hash >> 8),
+ (byte) (hash >> 16),
+ (byte) (hash >> 24),
+ (byte) (hash >> 32),
+ (byte) (hash >> 40),
+ (byte) (hash >> 48),
+ (byte) (hash >> 56)};
+ }
+
+ @Override public int asInt() {
+ return (int) hash;
+ }
+
+ @Override public long asLong() {
+ 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 must be at least of length 4.
+ */
+ public static HashCode fromBytes(byte[] bytes) {
+ checkArgument(bytes.length >= 4, "A HashCode must contain at least 4 bytes.");
+ 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) {
+ return new BytesHashCode(bytes);
+ }
+
+ private static final class BytesHashCode extends HashCode implements Serializable {
+ final byte[] bytes;
+
+ BytesHashCode(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ @Override public int bits() {
+ return bytes.length * 8;
+ }
+
+ @Override public byte[] asBytes() {
+ return bytes.clone();
+ }
+
+ @Override public int asInt() {
+ return (bytes[0] & 0xFF)
+ | ((bytes[1] & 0xFF) << 8)
+ | ((bytes[2] & 0xFF) << 16)
+ | ((bytes[3] & 0xFF) << 24);
+ }
+
+ @Override public long asLong() {
+ 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)
+ | ((bytes[3] & 0xFFL) << 24)
+ | ((bytes[4] & 0xFFL) << 32)
+ | ((bytes[5] & 0xFFL) << 40)
+ | ((bytes[6] & 0xFFL) << 48)
+ | ((bytes[7] & 0xFFL) << 56);
+ }
+
+ 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
new file mode 100644
index 0000000..328fd35
--- /dev/null
+++ b/guava/src/com/google/common/hash/HashFunction.java
@@ -0,0 +1,207 @@
+/*
+ * 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.hash;
+
+import com.google.common.annotations.Beta;
+import com.google.common.primitives.Ints;
+
+import java.nio.charset.Charset;
+
+/**
+ * A hash function is a collision-averse pure function that maps an arbitrary block of
+ * data to a number called a <i>hash code</i>.
+ *
+ * <h3>Definition</h3>
+ *
+ * <p>Unpacking this definition:
+ *
+ * <ul>
+ * <li><b>block of data:</b> the input for a hash function is always, in concept, an
+ * ordered byte array. This hashing API accepts an arbitrary sequence of byte and
+ * multibyte values (via {@link Hasher}), but this is merely a convenience; these are
+ * always translated into raw byte sequences under the covers.
+ *
+ * <li><b>hash code:</b> each hash function always yields hash codes of the same fixed bit
+ * length (given by {@link #bits}). For example, {@link Hashing#sha1} produces a
+ * 160-bit number, while {@link Hashing#murmur3_32()} yields only 32 bits. Because a
+ * {@code long} value is clearly insufficient to hold all hash code values, this API
+ * 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.
+ *
+ * <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
+ * hash function strives to <i>some</i> degree to make this unlikely. (Without this
+ * condition, a function that always returns zero could be called a hash function. It
+ * is not.)
+ * </ul>
+ *
+ * <p>Summarizing the last two points: "equal yield equal <i>always</i>; unequal yield
+ * unequal <i>often</i>." This is the most important characteristic of all hash functions.
+ *
+ * <h3>Desirable properties</h3>
+ *
+ * <p>A high-quality hash function strives for some subset of the following virtues:
+ *
+ * <ul>
+ * <li><b>collision-resistant:</b> while the definition above requires making at least
+ * <i>some</i> token attempt, one measure of the quality of a hash function is <i>how
+ * well</i> it succeeds at this goal. Important note: it may be easy to achieve the
+ * theoretical minimum collision rate when using completely <i>random</i> sample
+ * input. The true test of a hash function is how it performs on representative
+ * real-world data, which tends to contain many hidden patterns and clumps. The goal
+ * of a good hash function is to stamp these patterns out as thoroughly as possible.
+ *
+ * <li><b>bit-dispersing:</b> masking out any <i>single bit</i> from a hash code should
+ * yield only the expected <i>twofold</i> increase to all collision rates. Informally,
+ * the "information" in the hash code should be as evenly "spread out" through the
+ * hash code's bits as possible. The result is that, for example, when choosing a
+ * bucket in a hash table of size 2^8, <i>any</i> eight bits could be consistently
+ * used.
+ *
+ * <li><b>cryptographic:</b> certain hash functions such as {@link Hashing#sha512} are
+ * designed to make it as infeasible as possible to reverse-engineer the input that
+ * produced a given hash code, or even to discover <i>any</i> two distinct inputs that
+ * yield the same result. These are called <i>cryptographic hash functions</i>. But,
+ * whenever it is learned that either of these feats has become computationally
+ * feasible, the function is deemed "broken" and should no longer be used for secure
+ * purposes. (This is the likely eventual fate of <i>all</i> cryptographic hashes.)
+ *
+ * <li><b>fast:</b> perhaps self-explanatory, but often the most important consideration.
+ * We have published <a href="#noWeHaventYet">microbenchmark results</a> for many
+ * common hash functions.
+ * </ul>
+ *
+ * <h3>Providing input to a hash function</h3>
+ *
+ * <p>The primary way to provide the data that your hash function should act on is via a
+ * {@link Hasher}. Obtain a new hasher from the hash function using {@link #newHasher},
+ * "push" the relevant data into it using methods like {@link Hasher#putBytes(byte[])},
+ * and finally ask for the {@code HashCode} when finished using {@link Hasher#hash}. (See
+ * an {@linkplain #newHasher example} of this.)
+ *
+ * <p>If all you want to hash is a single byte array, string or {@code long} value, there
+ * are convenient shortcut methods defined directly on {@link HashFunction} to make this
+ * easier.
+ *
+ * <p>Hasher accepts primitive data types, but can also accept any Object of type {@code
+ * T} provided that you implement a {@link Funnel Funnel<T>} to specify how to "feed" data
+ * from that object into the function. (See {@linkplain Hasher#putObject an example} of
+ * this.)
+ *
+ * <p><b>Compatibility note:</b> Throughout this API, multibyte values are always
+ * interpreted in <i>little-endian</i> order. That is, hashing the byte array {@code
+ * {0x01, 0x02, 0x03, 0x04}} is equivalent to hashing the {@code int} value {@code
+ * 0x04030201}. If this isn't what you need, methods such as {@link Integer#reverseBytes}
+ * and {@link Ints#toByteArray} will help.
+ *
+ * <h3>Relationship to {@link Object#hashCode}</h3>
+ *
+ * <p>Java's baked-in concept of hash codes is constrained to 32 bits, and provides no
+ * separation between hash algorithms and the data they act on, so alternate hash
+ * algorithms can't be easily substituted. Also, implementations of {@code hashCode} tend
+ * to be poor-quality, in part because they end up depending on <i>other</i> existing
+ * poor-quality {@code hashCode} implementations, including those in many JDK classes.
+ *
+ * <p>{@code Object.hashCode} implementations tend to be very fast, but have weak
+ * collision prevention and <i>no</i> expectation of bit dispersion. This leaves them
+ * perfectly suitable for use in hash tables, because extra collisions cause only a slight
+ * performance hit, while poor bit dispersion is easily corrected using a secondary hash
+ * function (which all reasonable hash table implementations in Java use). For the many
+ * uses of hash functions beyond data structures, however, {@code Object.hashCode} almost
+ * always falls short -- hence this library.
+ *
+ * @author Kevin Bourrillion
+ * @since 11.0
+ */
+@Beta
+public interface HashFunction {
+ /**
+ * Begins a new hash code computation by returning an initialized, stateful {@code
+ * Hasher} instance that is ready to receive data. Example: <pre> {@code
+ *
+ * HashFunction hf = Hashing.md5();
+ * HashCode hc = hf.newHasher()
+ * .putLong(id)
+ * .putString(name)
+ * .hash();}</pre>
+ */
+ Hasher newHasher();
+
+ /**
+ * 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).
+ */
+ 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);
+
+ /**
+ * Shortcut for {@code newHasher().putLong(input).hash()}; returns the hash code for the
+ * given {@code long} value, interpreted in little-endian byte order. The implementation
+ * <i>might</i> perform better than its longhand equivalent, but should not perform worse.
+ */
+ HashCode hashLong(long input);
+
+ /**
+ * Shortcut for {@code newHasher().putBytes(input).hash()}. The implementation
+ * <i>might</i> perform better than its longhand equivalent, but should not perform
+ * worse.
+ */
+ HashCode hashBytes(byte[] input);
+
+ /**
+ * 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.
+ *
+ * @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > bytes.length}
+ * or {@code len < 0}
+ */
+ HashCode hashBytes(byte[] input, int off, int len);
+
+ /**
+ * Shortcut for {@code newHasher().putString(input).hash()}. The implementation <i>might</i>
+ * perform better than its longhand equivalent, but should not perform worse. Note that no
+ * character encoding is performed; the low byte and high byte of each character are hashed
+ * directly (in that order). This is equivalent to using
+ * {@code hashString(input, Charsets.UTF_16LE)}.
+ */
+ HashCode hashString(CharSequence input);
+
+ /**
+ * Shortcut for {@code newHasher().putString(input, charset).hash()}. Characters are encoded
+ * using the given {@link Charset}. The implementation <i>might</i> perform better than its
+ * longhand equivalent, but should not perform worse.
+ */
+ HashCode hashString(CharSequence input, Charset charset);
+
+ /**
+ * Returns the number of bits (a multiple of 32) that each hash code produced by this
+ * hash function has.
+ */
+ int bits();
+}
diff --git a/guava/src/com/google/common/hash/Hasher.java b/guava/src/com/google/common/hash/Hasher.java
new file mode 100644
index 0000000..ddb4ca6
--- /dev/null
+++ b/guava/src/com/google/common/hash/Hasher.java
@@ -0,0 +1,75 @@
+/*
+ * 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.hash;
+
+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
+ * in little-endian order.
+ *
+ * @author Kevin Bourrillion
+ * @since 11.0
+ */
+@Beta
+public interface Hasher extends PrimitiveSink {
+ @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.
+ */
+ @Override Hasher putString(CharSequence charSequence);
+
+ /**
+ * Equivalent to {@code putBytes(charSequence.toString().getBytes(charset))}.
+ */
+ @Override Hasher putString(CharSequence charSequence, Charset charset);
+
+ /**
+ * A simple convenience for {@code funnel.funnel(object, this)}.
+ */
+ <T> Hasher putObject(T instance, Funnel<? super T> funnel);
+
+ /**
+ * 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.
+ */
+ HashCode hash();
+}
diff --git a/guava/src/com/google/common/hash/Hashing.java b/guava/src/com/google/common/hash/Hashing.java
new file mode 100644
index 0000000..b748bc3
--- /dev/null
+++ b/guava/src/com/google/common/hash/Hashing.java
@@ -0,0 +1,336 @@
+/*
+ * 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.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.primitives.UnsignedInts;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.util.Iterator;
+
+/**
+ * Static methods to obtain {@link HashFunction} instances, and other static
+ * hashing-related utilities.
+ *
+ * @author Kevin Bourrillion
+ * @author Dimitris Andreou
+ * @author Kurt Alfred Kluever
+ * @since 11.0
+ */
+@Beta
+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
+ */
+ public static HashFunction goodFastHash(int minimumBits) {
+ 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 new ConcatenatedHashFunction(hashFunctions);
+ }
+
+ /**
+ * Returns a hash function implementing the
+ * <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);
+ }
+
+ /**
+ * Returns a hash function implementing the
+ * <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 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.
+ */
+ public static HashFunction murmur3_128(int seed) {
+ return new Murmur3_128HashFunction(seed);
+ }
+
+ /**
+ * 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.
+ */
+ public static HashFunction murmur3_128() {
+ return MURMUR3_128;
+ }
+
+ 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}.
+ */
+ public static HashFunction md5() {
+ return 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}.
+ */
+ public static HashFunction sha1() {
+ return SHA_1;
+ }
+
+ 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}.
+ */
+ public static HashFunction sha256() {
+ return SHA_256;
+ }
+
+ 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}.
+ */
+ public static HashFunction sha512() {
+ return SHA_512;
+ }
+
+ private static final HashFunction SHA_512 = new MessageDigestHashFunction("SHA-512");
+
+ // Lazy initiliazation holder class idiom.
+
+ /**
+ * 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.
+ */
+ public static long padToLong(HashCode hashCode) {
+ return (hashCode.bits() < 64) ? UnsignedInts.toLong(hashCode.asInt()) : hashCode.asLong();
+ }
+
+ /**
+ * Assigns to {@code hashCode} a "bucket" in the range {@code [0, buckets)}, in a uniform
+ * manner that minimizes the need for remapping as {@code buckets} grows. That is,
+ * {@code consistentHash(h, n)} equals:
+ *
+ * <ul>
+ * <li>{@code n - 1}, with approximate probability {@code 1/n}
+ * <li>{@code consistentHash(h, n - 1)}, otherwise (probability {@code 1 - 1/n})
+ * </ul>
+ *
+ * <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(padToLong(hashCode), buckets);
+ }
+
+ /**
+ * Assigns to {@code input} a "bucket" in the range {@code [0, buckets)}, in a uniform
+ * manner that minimizes the need for remapping as {@code buckets} grows. That is,
+ * {@code consistentHash(h, n)} equals:
+ *
+ * <ul>
+ * <li>{@code n - 1}, with approximate probability {@code 1/n}
+ * <li>{@code consistentHash(h, n - 1)}, otherwise (probability {@code 1 - 1/n})
+ * </ul>
+ *
+ * <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);
+ int candidate = 0;
+ int next;
+
+ // Jump from bucket to bucket until we go out of range
+ while (true) {
+ next = (int) ((candidate + 1) / generator.nextDouble());
+ if (next >= 0 && next < buckets) {
+ candidate = next;
+ } else {
+ return candidate;
+ }
+ }
+ }
+
+ /**
+ * Returns a hash code, having the same bit length as each of the input hash codes,
+ * that combines the information of these hash codes in an ordered fashion. That
+ * is, whenever two equal hash codes are produced by two calls to this method, it
+ * is <i>as likely as possible</i> that each was computed from the <i>same</i>
+ * input hash codes in the <i>same</i> order.
+ *
+ * @throws IllegalArgumentException if {@code hashCodes} is empty, or the hash codes
+ * do not all have the same bit length
+ */
+ public static HashCode combineOrdered(Iterable<HashCode> hashCodes) {
+ Iterator<HashCode> iterator = hashCodes.iterator();
+ checkArgument(iterator.hasNext(), "Must be at least 1 hash code to combine.");
+ int bits = iterator.next().bits();
+ byte[] resultBytes = new byte[bits / 8];
+ for (HashCode hashCode : hashCodes) {
+ byte[] nextBytes = hashCode.asBytes();
+ checkArgument(nextBytes.length == resultBytes.length,
+ "All hashcodes must have the same bit length.");
+ for (int i = 0; i < nextBytes.length; i++) {
+ resultBytes[i] = (byte) (resultBytes[i] * 37 ^ nextBytes[i]);
+ }
+ }
+ return HashCodes.fromBytesNoCopy(resultBytes);
+ }
+
+ /**
+ * Returns a hash code, having the same bit length as each of the input hash codes,
+ * that combines the information of these hash codes in an unordered fashion. That
+ * is, whenever two equal hash codes are produced by two calls to this method, it
+ * is <i>as likely as possible</i> that each was computed from the <i>same</i>
+ * input hash codes in <i>some</i> order.
+ *
+ * @throws IllegalArgumentException if {@code hashCodes} is empty, or the hash codes
+ * do not all have the same bit length
+ */
+ public static HashCode combineUnordered(Iterable<HashCode> hashCodes) {
+ Iterator<HashCode> iterator = hashCodes.iterator();
+ checkArgument(iterator.hasNext(), "Must be at least 1 hash code to combine.");
+ byte[] resultBytes = new byte[iterator.next().bits() / 8];
+ for (HashCode hashCode : hashCodes) {
+ byte[] nextBytes = hashCode.asBytes();
+ checkArgument(nextBytes.length == resultBytes.length,
+ "All hashcodes must have the same bit length.");
+ for (int i = 0; i < nextBytes.length; i++) {
+ resultBytes[i] += nextBytes[i];
+ }
+ }
+ return HashCodes.fromBytesNoCopy(resultBytes);
+ }
+
+ /**
+ * Checks that the passed argument is positive, and ceils it to a multiple of 32.
+ */
+ static int checkPositiveAndMakeMultipleOf32(int bits) {
+ checkArgument(bits > 0, "Number of bits must be positive");
+ 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;
+
+ ConcatenatedHashFunction(HashFunction... functions) {
+ super(functions);
+ int bitSum = 0;
+ for (HashFunction function : functions) {
+ bitSum += function.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);
+ }
+
+ @Override
+ public int bits() {
+ return bits;
+ }
+ }
+
+ 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
new file mode 100644
index 0000000..9f52e9a
--- /dev/null
+++ b/guava/src/com/google/common/hash/MessageDigestHashFunction.java
@@ -0,0 +1,169 @@
+/*
+ * 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.hash;
+
+import static com.google.common.base.Preconditions.checkPositionIndexes;
+import static com.google.common.base.Preconditions.checkState;
+
+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;
+
+/**
+ * {@link HashFunction} adapter for {@link MessageDigest}s.
+ *
+ * @author Kevin Bourrillion
+ * @author Dimitris Andreou
+ */
+final class MessageDigestHashFunction extends AbstractStreamingHashFunction {
+ private final String algorithmName;
+ private final int bits;
+
+ MessageDigestHashFunction(String algorithmName) {
+ this.algorithmName = algorithmName;
+ this.bits = getMessageDigest(algorithmName).getDigestLength() * 8;
+ }
+
+ public int bits() {
+ return bits;
+ }
+
+ private static MessageDigest getMessageDigest(String algorithmName) {
+ try {
+ return MessageDigest.getInstance(algorithmName);
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override public Hasher newHasher() {
+ return new MessageDigestHasher(getMessageDigest(algorithmName));
+ }
+
+ private static class MessageDigestHasher implements Hasher {
+ private final MessageDigest digest;
+ private final ByteBuffer scratch; // lazy convenience
+ private boolean done;
+
+ private MessageDigestHasher(MessageDigest digest) {
+ this.digest = digest;
+ this.scratch = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
+ }
+
+ @Override public Hasher putByte(byte b) {
+ checkNotDone();
+ digest.update(b);
+ return this;
+ }
+
+ @Override public Hasher putBytes(byte[] bytes) {
+ checkNotDone();
+ digest.update(bytes);
+ return this;
+ }
+
+ @Override public Hasher putBytes(byte[] bytes, int off, int len) {
+ checkNotDone();
+ checkPositionIndexes(off, off + len, bytes.length);
+ digest.update(bytes, off, len);
+ return this;
+ }
+
+ @Override public Hasher putShort(short s) {
+ checkNotDone();
+ scratch.putShort(s);
+ digest.update(scratch.array(), 0, Shorts.BYTES);
+ scratch.clear();
+ return this;
+ }
+
+ @Override public Hasher putInt(int i) {
+ checkNotDone();
+ scratch.putInt(i);
+ digest.update(scratch.array(), 0, Ints.BYTES);
+ scratch.clear();
+ return this;
+ }
+
+ @Override public Hasher putLong(long l) {
+ checkNotDone();
+ scratch.putLong(l);
+ digest.update(scratch.array(), 0, Longs.BYTES);
+ scratch.clear();
+ return this;
+ }
+
+ @Override public Hasher putFloat(float f) {
+ checkNotDone();
+ scratch.putFloat(f);
+ digest.update(scratch.array(), 0, 4);
+ scratch.clear();
+ return this;
+ }
+
+ @Override public Hasher putDouble(double d) {
+ checkNotDone();
+ 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) {
+ return putBytes(charSequence.toString().getBytes(charset));
+ }
+
+ @Override public <T> Hasher putObject(T instance, Funnel<? super T> funnel) {
+ checkNotDone();
+ funnel.funnel(instance, this);
+ return this;
+ }
+
+ private void checkNotDone() {
+ checkState(!done, "Cannot use Hasher after calling #hash() on it");
+ }
+
+ public HashCode hash() {
+ done = true;
+ return HashCodes.fromBytesNoCopy(digest.digest());
+ }
+ }
+}
diff --git a/guava/src/com/google/common/hash/Murmur3_128HashFunction.java b/guava/src/com/google/common/hash/Murmur3_128HashFunction.java
new file mode 100644
index 0000000..c3ec8d8
--- /dev/null
+++ b/guava/src/com/google/common/hash/Murmur3_128HashFunction.java
@@ -0,0 +1,172 @@
+/*
+ * 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.hash;
+
+import static com.google.common.primitives.UnsignedBytes.toInt;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * See http://smhasher.googlecode.com/svn/trunk/MurmurHash3.cpp
+ * MurmurHash3_x64_128
+ *
+ * @author Austin Appleby
+ * @author Dimitris Andreou
+ */
+final class Murmur3_128HashFunction extends AbstractStreamingHashFunction implements Serializable {
+ // TODO(user): when the shortcuts are implemented, update BloomFilterStrategies
+ private final int seed;
+
+ Murmur3_128HashFunction(int seed) {
+ this.seed = seed;
+ }
+
+ @Override public int bits() {
+ return 128;
+ }
+
+ @Override public Hasher newHasher() {
+ return new Murmur3_128Hasher(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;
+
+ Murmur3_128Hasher(int seed) {
+ super(CHUNK_SIZE);
+ this.h1 = seed;
+ this.h2 = seed;
+ this.length = 0;
+ }
+
+ @Override protected void process(ByteBuffer bb) {
+ long k1 = bb.getLong();
+ long k2 = bb.getLong();
+ bmix64(k1, k2);
+ length += CHUNK_SIZE;
+ }
+
+ private void bmix64(long k1, long k2) {
+ h1 ^= mixK1(k1);
+
+ h1 = Long.rotateLeft(h1, 27);
+ h1 += h2;
+ h1 = h1 * 5 + 0x52dce729;
+
+ h2 ^= mixK2(k2);
+
+ h2 = Long.rotateLeft(h2, 31);
+ h2 += h1;
+ h2 = h2 * 5 + 0x38495ab5;
+ }
+
+ @Override protected void processRemaining(ByteBuffer bb) {
+ long k1 = 0;
+ long k2 = 0;
+ length += bb.remaining();
+ switch (bb.remaining()) {
+ case 15:
+ k2 ^= (long) toInt(bb.get(14)) << 48; // fall through
+ case 14:
+ k2 ^= (long) toInt(bb.get(13)) << 40; // fall through
+ case 13:
+ k2 ^= (long) toInt(bb.get(12)) << 32; // fall through
+ case 12:
+ k2 ^= (long) toInt(bb.get(11)) << 24; // fall through
+ case 11:
+ k2 ^= (long) toInt(bb.get(10)) << 16; // fall through
+ case 10:
+ k2 ^= (long) toInt(bb.get(9)) << 8; // fall through
+ case 9:
+ k2 ^= (long) toInt(bb.get(8)); // fall through
+ case 8:
+ k1 ^= bb.getLong();
+ break;
+ case 7:
+ k1 ^= (long) toInt(bb.get(6)) << 48; // fall through
+ case 6:
+ k1 ^= (long) toInt(bb.get(5)) << 40; // fall through
+ case 5:
+ k1 ^= (long) toInt(bb.get(4)) << 32; // fall through
+ case 4:
+ k1 ^= (long) toInt(bb.get(3)) << 24; // fall through
+ case 3:
+ k1 ^= (long) toInt(bb.get(2)) << 16; // fall through
+ case 2:
+ k1 ^= (long) toInt(bb.get(1)) << 8; // fall through
+ case 1:
+ k1 ^= (long) toInt(bb.get(0));
+ break;
+ default:
+ throw new AssertionError("Should never get here.");
+ }
+ h1 ^= mixK1(k1);
+ h2 ^= mixK2(k2);
+ }
+
+ @Override public HashCode makeHash() {
+ h1 ^= length;
+ h2 ^= length;
+
+ h1 += h2;
+ h2 += h1;
+
+ h1 = fmix64(h1);
+ h2 = fmix64(h2);
+
+ h1 += h2;
+ h2 += h1;
+
+ return HashCodes.fromBytesNoCopy(ByteBuffer
+ .wrap(new byte[CHUNK_SIZE])
+ .order(ByteOrder.LITTLE_ENDIAN)
+ .putLong(h1)
+ .putLong(h2)
+ .array());
+ }
+
+ private static long fmix64(long k) {
+ k ^= k >>> 33;
+ k *= 0xff51afd7ed558ccdL;
+ k ^= k >>> 33;
+ k *= 0xc4ceb9fe1a85ec53L;
+ 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
new file mode 100644
index 0000000..0a1f850
--- /dev/null
+++ b/guava/src/com/google/common/hash/Murmur3_32HashFunction.java
@@ -0,0 +1,158 @@
+/*
+ * 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.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
+ */
+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;
+ }
+
+ @Override public int bits() {
+ return 32;
+ }
+
+ @Override public Hasher newHasher() {
+ return new Murmur3_32Hasher(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;
+
+ Murmur3_32Hasher(int seed) {
+ super(CHUNK_SIZE);
+ this.h1 = seed;
+ this.length = 0;
+ }
+
+ @Override protected void process(ByteBuffer bb) {
+ int k1 = Murmur3_32HashFunction.mixK1(bb.getInt());
+ h1 = Murmur3_32HashFunction.mixH1(h1, k1);
+ length += CHUNK_SIZE;
+ }
+
+ @Override protected void processRemaining(ByteBuffer bb) {
+ length += bb.remaining();
+ int k1 = 0;
+ 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));
+ break;
+ default:
+ throw new AssertionError("Should never get here.");
+ }
+ h1 ^= Murmur3_32HashFunction.mixK1(k1);
+ }
+
+ @Override public HashCode makeHash() {
+ return Murmur3_32HashFunction.fmix(h1, length);
+ }
+ }
+
+ private static final long serialVersionUID = 0L;
+}
diff --git a/guava/src/com/google/common/hash/PrimitiveSink.java b/guava/src/com/google/common/hash/PrimitiveSink.java
new file mode 100644
index 0000000..c851a1e
--- /dev/null
+++ b/guava/src/com/google/common/hash/PrimitiveSink.java
@@ -0,0 +1,102 @@
+/*
+ * 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.hash;
+
+import com.google.common.annotations.Beta;
+
+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})
+ */
+@Beta
+public interface PrimitiveSink {
+ /**
+ * Puts a byte into this sink.
+ *
+ * @param b a byte
+ * @return this instance
+ */
+ PrimitiveSink putByte(byte b);
+
+ /**
+ * Puts an array of bytes into this sink.
+ *
+ * @param bytes a byte array
+ * @return this instance
+ */
+ PrimitiveSink putBytes(byte[] bytes);
+
+ /**
+ * Puts a chunk of an array of bytes into this sink. {@code bytes[off]} is the first byte written,
+ * {@code bytes[off + len - 1]} is the last.
+ *
+ * @param bytes a byte array
+ * @param off the start offset in the array
+ * @param len the number of bytes to write
+ * @return this instance
+ * @throws IndexOutOfBoundsException if {@code off < 0} or {@code off + len > bytes.length} or
+ * {@code len < 0}
+ */
+ PrimitiveSink putBytes(byte[] bytes, int off, int len);
+
+ /**
+ * Puts a short into this sink.
+ */
+ PrimitiveSink putShort(short s);
+
+ /**
+ * Puts an int into this sink.
+ */
+ PrimitiveSink putInt(int i);
+
+ /**
+ * Puts a long into this sink.
+ */
+ PrimitiveSink putLong(long l);
+
+ /**
+ * Puts a float into this sink.
+ */
+ PrimitiveSink putFloat(float f);
+
+ /**
+ * Puts a double into this sink.
+ */
+ PrimitiveSink putDouble(double d);
+
+ /**
+ * Puts a boolean into this sink.
+ */
+ PrimitiveSink putBoolean(boolean b);
+
+ /**
+ * Puts a character into this sink.
+ */
+ PrimitiveSink putChar(char c);
+
+ /**
+ * Puts a string into this sink.
+ */
+ PrimitiveSink putString(CharSequence charSequence);
+
+ /**
+ * Puts a string into this sink using the given charset.
+ */
+ PrimitiveSink 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
new file mode 100644
index 0000000..7df4e73
--- /dev/null
+++ b/guava/src/com/google/common/hash/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+// 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;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/guava/src/com/google/common/io/AppendableWriter.java b/guava/src/com/google/common/io/AppendableWriter.java
new file mode 100644
index 0000000..8033e46
--- /dev/null
+++ b/guava/src/com/google/common/io/AppendableWriter.java
@@ -0,0 +1,117 @@
+/*
+ * 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.io;
+
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * 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
+ * be delegated to the target.
+ *
+ * @author Alan Green
+ * @author Sebastian Kanthak
+ * @since 1.0
+ */
+class AppendableWriter extends Writer {
+ private final Appendable target;
+ private boolean closed;
+
+ /**
+ * Creates a new writer that appends everything it writes to {@code target}.
+ *
+ * @param target target to which to append output
+ */
+ AppendableWriter(Appendable target) {
+ this.target = target;
+ }
+
+ /*
+ * Abstract methods from Writer
+ */
+
+ @Override public void write(char cbuf[], int off, int len)
+ throws IOException {
+ checkNotClosed();
+ // It turns out that creating a new String is usually as fast, or faster
+ // than wrapping cbuf in a light-weight CharSequence.
+ target.append(new String(cbuf, off, len));
+ }
+
+ @Override public void flush() throws IOException {
+ checkNotClosed();
+ if (target instanceof Flushable) {
+ ((Flushable) target).flush();
+ }
+ }
+
+ @Override public void close() throws IOException {
+ this.closed = true;
+ if (target instanceof Closeable) {
+ ((Closeable) target).close();
+ }
+ }
+
+ /*
+ * Override a few functions for performance reasons to avoid creating
+ * unnecessary strings.
+ */
+
+ @Override public void write(int c) throws IOException {
+ checkNotClosed();
+ target.append((char) c);
+ }
+
+ @Override public void write(String str) throws IOException {
+ checkNotClosed();
+ target.append(str);
+ }
+
+ @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);
+ }
+
+ @Override public Writer append(char c) throws IOException {
+ checkNotClosed();
+ target.append(c);
+ return this;
+ }
+
+ @Override public Writer append(CharSequence charSeq) throws IOException {
+ checkNotClosed();
+ target.append(charSeq);
+ return this;
+ }
+
+ @Override public Writer append(CharSequence charSeq, int start, int end)
+ throws IOException {
+ checkNotClosed();
+ target.append(charSeq, start, end);
+ return this;
+ }
+
+ private void checkNotClosed() throws IOException {
+ if (closed) {
+ throw new IOException("Cannot write to a closed writer.");
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/ByteArrayDataInput.java b/guava/src/com/google/common/io/ByteArrayDataInput.java
new file mode 100644
index 0000000..3f4a467
--- /dev/null
+++ b/guava/src/com/google/common/io/ByteArrayDataInput.java
@@ -0,0 +1,65 @@
+/*
+ * 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.io;
+
+import java.io.DataInput;
+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.
+ *
+ * @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/ByteArrayDataOutput.java b/guava/src/com/google/common/io/ByteArrayDataOutput.java
new file mode 100644
index 0000000..4d3dd97
--- /dev/null
+++ b/guava/src/com/google/common/io/ByteArrayDataOutput.java
@@ -0,0 +1,55 @@
+/*
+ * 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.io;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * An extension of {@code DataOutput} for writing to in-memory byte arrays; its
+ * methods offer identical functionality but do not throw {@link IOException}.
+ *
+ * @author Jayaprabhakar Kadarkarai
+ * @since 1.0
+ */
+public interface ByteArrayDataOutput extends DataOutput {
+ @Override void write(int b);
+ @Override void write(byte b[]);
+ @Override void write(byte b[], int off, int len);
+ @Override void writeBoolean(boolean v);
+ @Override void writeByte(int v);
+ @Override void writeShort(int v);
+ @Override void writeChar(int v);
+ @Override void writeInt(int v);
+ @Override void writeLong(long v);
+ @Override void writeFloat(float v);
+ @Override void writeDouble(double v);
+ @Override void writeChars(String s);
+ @Override void writeUTF(String s);
+
+ /**
+ * @deprecated This method is dangerous as it discards the high byte of
+ * every character. For UTF-8, use {@code write(s.getBytes(Charsets.UTF_8))}.
+ */
+ @Deprecated @Override void writeBytes(String s);
+
+ /**
+ * Returns the contents that have been written to this instance,
+ * as a byte array.
+ */
+ byte[] toByteArray();
+}
diff --git a/guava/src/com/google/common/io/ByteProcessor.java b/guava/src/com/google/common/io/ByteProcessor.java
new file mode 100644
index 0000000..71953be
--- /dev/null
+++ b/guava/src/com/google/common/io/ByteProcessor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+
+import java.io.IOException;
+
+/**
+ * A callback interface to process bytes from a stream.
+ *
+ * <p>{@link #processBytes} will be called for each line that is read, and
+ * should return {@code false} when you want to stop processing.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public interface ByteProcessor<T> {
+ /**
+ * This method will be called for each chunk of bytes in an
+ * input stream. The implementation should process the bytes
+ * from {@code buf[off]} through {@code buf[off + len - 1]}
+ * (inclusive).
+ *
+ * @param buf the byte array containing the data to process
+ * @param off the initial offset into the array
+ * @param len the length of data to be processed
+ * @return true to continue processing, false to stop
+ */
+ boolean processBytes(byte[] buf, int off, int len) throws IOException;
+
+ /** Return the result of processing all the bytes. */
+ T getResult();
+}
diff --git a/guava/src/com/google/common/io/ByteStreams.java b/guava/src/com/google/common/io/ByteStreams.java
new file mode 100644
index 0000000..388504e
--- /dev/null
+++ b/guava/src/com/google/common/io/ByteStreams.java
@@ -0,0 +1,871 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+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.util.Arrays;
+import java.util.zip.Checksum;
+
+/**
+ * Provides utility methods for working with byte arrays and I/O streams.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class ByteStreams {
+ private static final int BUF_SIZE = 0x1000; // 4K
+
+ private ByteStreams() {}
+
+ /**
+ * Returns a factory that will supply instances of
+ * {@link ByteArrayInputStream} that read from the given byte array.
+ *
+ * @param b the input buffer
+ * @return the factory
+ */
+ public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
+ byte[] b) {
+ return newInputStreamSupplier(b, 0, b.length);
+ }
+
+ /**
+ * Returns a factory that will supply instances of
+ * {@link ByteArrayInputStream} that read from the given byte array.
+ *
+ * @param b the input buffer
+ * @param off the offset in the buffer of the first byte to read
+ * @param len the maximum number of bytes to read from the buffer
+ * @return the factory
+ */
+ public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
+ final byte[] b, final int off, final int len) {
+ return new InputSupplier<ByteArrayInputStream>() {
+ @Override
+ public ByteArrayInputStream getInput() {
+ return new ByteArrayInputStream(b, off, len);
+ }
+ };
+ }
+
+ /**
+ * Writes a byte array to an output stream from the given supplier.
+ *
+ * @param from the bytes to write
+ * @param to the output supplier
+ * @throws IOException if an I/O error occurs
+ */
+ public static void write(byte[] from,
+ OutputSupplier<? extends OutputStream> to) throws IOException {
+ Preconditions.checkNotNull(from);
+ boolean threw = true;
+ OutputStream out = to.getOutput();
+ try {
+ out.write(from);
+ threw = false;
+ } finally {
+ Closeables.close(out, threw);
+ }
+ }
+
+ /**
+ * Opens input and output streams from the given suppliers, copies all
+ * bytes from the input to the output, and closes the streams.
+ *
+ * @param from the input factory
+ * @param to the output factory
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(InputSupplier<? extends InputStream> from,
+ OutputSupplier<? extends OutputStream> to) throws IOException {
+ 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);
+ }
+ }
+
+ /**
+ * Opens an input stream from the supplier, copies all bytes from the
+ * input to the output, and closes the input stream. Does not close
+ * or flush the output stream.
+ *
+ * @param from the input factory
+ * @param to the output stream to write to
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(InputSupplier<? extends InputStream> from,
+ OutputStream to) throws IOException {
+ 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.
+ *
+ * @param from the input stream to read from
+ * @param to the output factory
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ * @since 10.0
+ */
+ public static long copy(InputStream from,
+ OutputSupplier<? extends OutputStream> to) throws IOException {
+ boolean threw = true;
+ OutputStream out = to.getOutput();
+ try {
+ long count = copy(from, out);
+ threw = false;
+ return count;
+ } finally {
+ Closeables.close(out, threw);
+ }
+ }
+
+ /**
+ * Copies all bytes from the input stream to the output stream.
+ * Does not close or flush either stream.
+ *
+ * @param from the input stream to read from
+ * @param to the output stream to write to
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(InputStream from, OutputStream to)
+ throws IOException {
+ byte[] buf = new byte[BUF_SIZE];
+ long total = 0;
+ while (true) {
+ int r = from.read(buf);
+ if (r == -1) {
+ break;
+ }
+ to.write(buf, 0, r);
+ total += r;
+ }
+ return total;
+ }
+
+ /**
+ * Copies all bytes from the readable channel to the writable channel.
+ * Does not close or flush either channel.
+ *
+ * @param from the readable channel to read from
+ * @param to the writable channel to write to
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(ReadableByteChannel from,
+ WritableByteChannel to) throws IOException {
+ ByteBuffer buf = ByteBuffer.allocate(BUF_SIZE);
+ long total = 0;
+ while (from.read(buf) != -1) {
+ buf.flip();
+ while (buf.hasRemaining()) {
+ total += to.write(buf);
+ }
+ buf.clear();
+ }
+ return total;
+ }
+
+ /**
+ * Reads all bytes from an input stream into a byte array.
+ * Does not close the stream.
+ *
+ * @param in the input stream to read from
+ * @return a byte array containing all the bytes from the stream
+ * @throws IOException if an I/O error occurs
+ */
+ public static byte[] toByteArray(InputStream in) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copy(in, out);
+ return out.toByteArray();
+ }
+
+ /**
+ * Returns the data from a {@link InputStream} factory as a byte array.
+ *
+ * @param supplier the factory
+ * @throws IOException if an I/O error occurs
+ */
+ public static byte[] toByteArray(
+ InputSupplier<? extends InputStream> supplier) throws IOException {
+ boolean threw = true;
+ InputStream in = supplier.getInput();
+ try {
+ byte[] result = toByteArray(in);
+ threw = false;
+ return result;
+ } finally {
+ Closeables.close(in, threw);
+ }
+ }
+
+ /**
+ * Returns a new {@link ByteArrayDataInput} instance to read from the {@code
+ * bytes} array from the beginning.
+ */
+ public static ByteArrayDataInput newDataInput(byte[] bytes) {
+ return new ByteArrayDataInputStream(bytes);
+ }
+
+ /**
+ * Returns a new {@link ByteArrayDataInput} instance to read from the {@code
+ * bytes} array, starting at the given position.
+ *
+ * @throws IndexOutOfBoundsException if {@code start} is negative or greater
+ * than the length of the array
+ */
+ public static ByteArrayDataInput newDataInput(byte[] bytes, int start) {
+ Preconditions.checkPositionIndex(start, bytes.length);
+ return new ByteArrayDataInputStream(bytes, start);
+ }
+
+ private static class ByteArrayDataInputStream implements ByteArrayDataInput {
+ final DataInput input;
+
+ ByteArrayDataInputStream(byte[] bytes) {
+ this.input = new DataInputStream(new ByteArrayInputStream(bytes));
+ }
+
+ ByteArrayDataInputStream(byte[] bytes, int start) {
+ this.input = new DataInputStream(
+ new ByteArrayInputStream(bytes, start, bytes.length - start));
+ }
+
+ @Override public void readFully(byte b[]) {
+ try {
+ input.readFully(b);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public void readFully(byte b[], int off, int len) {
+ try {
+ input.readFully(b, off, len);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public int skipBytes(int n) {
+ try {
+ return input.skipBytes(n);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public boolean readBoolean() {
+ try {
+ return input.readBoolean();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public byte readByte() {
+ try {
+ return input.readByte();
+ } catch (EOFException e) {
+ throw new IllegalStateException(e);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public int readUnsignedByte() {
+ try {
+ return input.readUnsignedByte();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public short readShort() {
+ try {
+ return input.readShort();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public int readUnsignedShort() {
+ try {
+ return input.readUnsignedShort();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public char readChar() {
+ try {
+ return input.readChar();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public int readInt() {
+ try {
+ return input.readInt();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public long readLong() {
+ try {
+ return input.readLong();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public float readFloat() {
+ try {
+ return input.readFloat();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public double readDouble() {
+ try {
+ return input.readDouble();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public String readLine() {
+ try {
+ return input.readLine();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public String readUTF() {
+ try {
+ return input.readUTF();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ /**
+ * Returns a new {@link ByteArrayDataOutput} instance with a default size.
+ */
+ public static ByteArrayDataOutput newDataOutput() {
+ return new ByteArrayDataOutputStream();
+ }
+
+ /**
+ * Returns a new {@link ByteArrayDataOutput} instance sized to hold
+ * {@code size} bytes before resizing.
+ *
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ public static ByteArrayDataOutput newDataOutput(int size) {
+ Preconditions.checkArgument(size >= 0, "Invalid size: %s", size);
+ return new ByteArrayDataOutputStream(size);
+ }
+
+ @SuppressWarnings("deprecation") // for writeBytes
+ private static class ByteArrayDataOutputStream
+ implements ByteArrayDataOutput {
+
+ final DataOutput output;
+ final ByteArrayOutputStream byteArrayOutputSteam;
+
+ ByteArrayDataOutputStream() {
+ this(new ByteArrayOutputStream());
+ }
+
+ ByteArrayDataOutputStream(int size) {
+ this(new ByteArrayOutputStream(size));
+ }
+
+ ByteArrayDataOutputStream(ByteArrayOutputStream byteArrayOutputSteam) {
+ this.byteArrayOutputSteam = byteArrayOutputSteam;
+ output = new DataOutputStream(byteArrayOutputSteam);
+ }
+
+ @Override public void write(int b) {
+ try {
+ output.write(b);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void write(byte[] b) {
+ try {
+ output.write(b);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void write(byte[] b, int off, int len) {
+ try {
+ output.write(b, off, len);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeBoolean(boolean v) {
+ try {
+ output.writeBoolean(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeByte(int v) {
+ try {
+ output.writeByte(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeBytes(String s) {
+ try {
+ output.writeBytes(s);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeChar(int v) {
+ try {
+ output.writeChar(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeChars(String s) {
+ try {
+ output.writeChars(s);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeDouble(double v) {
+ try {
+ output.writeDouble(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeFloat(float v) {
+ try {
+ output.writeFloat(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeInt(int v) {
+ try {
+ output.writeInt(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeLong(long v) {
+ try {
+ output.writeLong(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeShort(int v) {
+ try {
+ output.writeShort(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeUTF(String s) {
+ try {
+ output.writeUTF(s);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public byte[] toByteArray() {
+ return byteArrayOutputSteam.toByteArray();
+ }
+
+ }
+
+ // 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;
+ }
+ }
+ } finally {
+ Closeables.close(in, threw);
+ }
+ }
+
+ /**
+ * Returns true if the supplied input streams contain the same bytes.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ public static boolean equal(InputSupplier<? extends InputStream> supplier1,
+ InputSupplier<? extends InputStream> supplier2) throws IOException {
+ 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);
+ }
+ }
+
+ /**
+ * Attempts to read enough bytes from the stream to fill the given byte array,
+ * with the same behavior as {@link DataInput#readFully(byte[])}.
+ * Does not close the stream.
+ *
+ * @param in the input stream to read from.
+ * @param b the buffer into which the data is read.
+ * @throws EOFException if this stream reaches the end before reading all
+ * the bytes.
+ * @throws IOException if an I/O error occurs.
+ */
+ public static void readFully(InputStream in, byte[] b) throws IOException {
+ readFully(in, b, 0, b.length);
+ }
+
+ /**
+ * Attempts to read {@code len} bytes from the stream into the given array
+ * starting at {@code off}, with the same behavior as
+ * {@link DataInput#readFully(byte[], int, int)}. Does not close the
+ * stream.
+ *
+ * @param in the input stream to read from.
+ * @param b the buffer into which the data is read.
+ * @param off an int specifying the offset into the data.
+ * @param len an int specifying the number of bytes to read.
+ * @throws EOFException if this stream reaches the end before reading all
+ * the bytes.
+ * @throws IOException if an I/O error occurs.
+ */
+ public static void readFully(InputStream in, byte[] b, int off, int len)
+ throws IOException {
+ if (read(in, b, off, len) != len) {
+ throw new EOFException();
+ }
+ }
+
+ /**
+ * Discards {@code n} bytes of data from the input stream. This method
+ * will block until the full amount has been skipped. Does not close the
+ * stream.
+ *
+ * @param in the input stream to read from
+ * @param n the number of bytes to skip
+ * @throws EOFException if this stream reaches the end before skipping all
+ * the bytes
+ * @throws IOException if an I/O error occurs, or the stream does not
+ * support skipping
+ */
+ public static void skipFully(InputStream in, long n) throws IOException {
+ while (n > 0) {
+ long amt = in.skip(n);
+ if (amt == 0) {
+ // Force a blocking read to avoid infinite loop
+ if (in.read() == -1) {
+ throw new EOFException();
+ }
+ n--;
+ } else {
+ n -= amt;
+ }
+ }
+ }
+
+ /**
+ * Process the bytes of a supplied stream
+ *
+ * @param supplier the input stream factory
+ * @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
+ */
+ public static <T> T readBytes(InputSupplier<? extends InputStream> supplier,
+ ByteProcessor<T> processor) throws IOException {
+ byte[] buf = new byte[BUF_SIZE];
+ boolean threw = true;
+ InputStream in = supplier.getInput();
+ try {
+ int amt;
+ do {
+ amt = in.read(buf);
+ if (amt == -1) {
+ threw = false;
+ break;
+ }
+ } while (processor.processBytes(buf, 0, amt));
+ return processor.getResult();
+ } finally {
+ Closeables.close(in, threw);
+ }
+ }
+
+ /**
+ * Computes and returns the checksum value for a supplied input stream.
+ * The checksum object is reset when this method returns successfully.
+ *
+ * @param supplier the input stream factory
+ * @param checksum the checksum object
+ * @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
+ */
+ 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();
+ checksum.reset();
+ return result;
+ }
+ });
+ }
+
+ /**
+ * Computes the hash code of the data supplied by {@code supplier} using {@code
+ * hashFunction}.
+ *
+ * @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
+ * @throws IOException if an I/O error occurs
+ * @since 12.0
+ */
+ public static HashCode hash(
+ InputSupplier<? extends InputStream> supplier, HashFunction hashFunction)
+ throws IOException {
+ Hasher hasher = hashFunction.newHasher();
+ copy(supplier, Funnels.asOutputStream(hasher));
+ return hasher.hash();
+ }
+
+ /**
+ * Reads some bytes from an input stream and stores them into the buffer array
+ * {@code b}. This method blocks until {@code len} bytes of input data have
+ * been read into the array, or end of file is detected. The number of bytes
+ * read is returned, possibly zero. Does not close the stream.
+ *
+ * <p>A caller can detect EOF if the number of bytes read is less than
+ * {@code len}. All subsequent calls on the same stream will return zero.
+ *
+ * <p>If {@code b} is null, a {@code NullPointerException} is thrown. If
+ * {@code off} is negative, or {@code len} is negative, or {@code off+len} is
+ * greater than the length of the array {@code b}, then an
+ * {@code IndexOutOfBoundsException} is thrown. If {@code len} is zero, then
+ * no bytes are read. Otherwise, the first byte read is stored into element
+ * {@code b[off]}, the next one into {@code b[off+1]}, and so on. The number
+ * of bytes read is, at most, equal to {@code len}.
+ *
+ * @param in the input stream to read from
+ * @param b the buffer into which the data is read
+ * @param off an int specifying the offset into the data
+ * @param len an int specifying the number of bytes to read
+ * @return the number of bytes read
+ * @throws IOException if an I/O error occurs
+ */
+ public static int read(InputStream in, byte[] b, int off, int len)
+ throws IOException {
+ if (len < 0) {
+ throw new IndexOutOfBoundsException("len is negative");
+ }
+ int total = 0;
+ while (total < len) {
+ int result = in.read(b, off + total, len - total);
+ if (result == -1) {
+ break;
+ }
+ total += result;
+ }
+ return total;
+ }
+
+ /**
+ * Returns an {@link InputSupplier} that returns input streams from the
+ * an underlying supplier, where each stream starts at the given
+ * offset and is limited to the specified number of bytes.
+ *
+ * @param supplier the supplier from which to get the raw streams
+ * @param offset the offset in bytes into the underlying stream where
+ * the returned streams will start
+ * @param length the maximum length of the returned streams
+ * @throws IllegalArgumentException if offset or length are negative
+ */
+ public static InputSupplier<InputStream> slice(
+ final InputSupplier<? extends InputStream> supplier,
+ final long offset,
+ final long 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);
+ }
+ };
+ }
+
+ /**
+ * Joins multiple {@link InputStream} suppliers into a single supplier.
+ * Streams returned from the supplier will contain the concatenated data from
+ * the streams of the underlying suppliers.
+ *
+ * <p>Only one underlying input stream will be open at a time. Closing the
+ * joined stream will close the open underlying stream.
+ *
+ * <p>Reading from the joined stream will throw a {@link NullPointerException}
+ * if any of the suppliers are null or return null.
+ *
+ * @param suppliers the suppliers to concatenate
+ * @return a supplier that will return a stream containing the concatenated
+ * stream data
+ */
+ public static InputSupplier<InputStream> join(final
+ Iterable<? extends InputSupplier<? extends InputStream>> suppliers) {
+ return new InputSupplier<InputStream>() {
+ @Override public InputStream getInput() throws IOException {
+ return new MultiInputStream(suppliers.iterator());
+ }
+ };
+ }
+
+ /** Varargs form of {@link #join(Iterable)}. */
+ public static InputSupplier<InputStream> join(
+ InputSupplier<? extends InputStream>... suppliers) {
+ return join(Arrays.asList(suppliers));
+ }
+}
diff --git a/guava/src/com/google/common/io/CharStreams.java b/guava/src/com/google/common/io/CharStreams.java
new file mode 100644
index 0000000..6a70375
--- /dev/null
+++ b/guava/src/com/google/common/io/CharStreams.java
@@ -0,0 +1,441 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Provides utility methods for working with character streams.
+ *
+ * <p>All method parameters must be non-null unless documented otherwise.
+ *
+ * <p>Some of the methods in this class take arguments with a generic type of
+ * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of
+ * those interfaces. Similarly for {@code Appendable & Closeable} and
+ * {@link java.io.Writer}.
+ *
+ * @author Chris Nokleberg
+ * @author Bin Zhu
+ * @since 1.0
+ */
+@Beta
+public final class CharStreams {
+ private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes)
+
+ private CharStreams() {}
+
+ /**
+ * Returns a factory that will supply instances of {@link StringReader} that
+ * read a string value.
+ *
+ * @param value the string to read
+ * @return the factory
+ */
+ public static InputSupplier<StringReader> newReaderSupplier(
+ final String value) {
+ Preconditions.checkNotNull(value);
+ return new InputSupplier<StringReader>() {
+ @Override
+ public StringReader getInput() {
+ return new StringReader(value);
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link InputStreamReader},
+ * 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
+ * @return the factory
+ */
+ public static InputSupplier<InputStreamReader> newReaderSupplier(
+ final InputSupplier<? extends InputStream> in, final Charset charset) {
+ Preconditions.checkNotNull(in);
+ Preconditions.checkNotNull(charset);
+ return new InputSupplier<InputStreamReader>() {
+ @Override
+ public InputStreamReader getInput() throws IOException {
+ return new InputStreamReader(in.getInput(), charset);
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link OutputStreamWriter},
+ * 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
+ * @return the factory
+ */
+ public static OutputSupplier<OutputStreamWriter> newWriterSupplier(
+ final OutputSupplier<? extends OutputStream> out, final Charset charset) {
+ Preconditions.checkNotNull(out);
+ Preconditions.checkNotNull(charset);
+ return new OutputSupplier<OutputStreamWriter>() {
+ @Override
+ public OutputStreamWriter getOutput() throws IOException {
+ return new OutputStreamWriter(out.getOutput(), charset);
+ }
+ };
+ }
+
+ /**
+ * Writes a character sequence (such as a string) to an appendable
+ * object from the given supplier.
+ *
+ * @param from the character sequence to write
+ * @param to the output supplier
+ * @throws IOException if an I/O error occurs
+ */
+ public static <W extends Appendable & Closeable> void write(CharSequence from,
+ OutputSupplier<W> to) throws IOException {
+ Preconditions.checkNotNull(from);
+ boolean threw = true;
+ W out = to.getOutput();
+ try {
+ out.append(from);
+ threw = false;
+ } finally {
+ Closeables.close(out, threw);
+ }
+ }
+
+ /**
+ * Opens {@link Readable} and {@link Appendable} objects from the
+ * given factories, copies all characters between the two, and closes
+ * them.
+ *
+ * @param from the input factory
+ * @param to the output factory
+ * @return the number of characters copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable,
+ W extends Appendable & Closeable> long copy(InputSupplier<R> from,
+ OutputSupplier<W> to) throws IOException {
+ 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);
+ }
+ }
+
+ /**
+ * Opens a {@link Readable} object from the supplier, copies all characters
+ * to the {@link Appendable} object, and closes the input. Does not close
+ * or flush the output.
+ *
+ * @param from the input factory
+ * @param to the object to write to
+ * @return the number of characters copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable> long copy(
+ InputSupplier<R> from, Appendable to) throws IOException {
+ boolean threw = true;
+ R in = from.getInput();
+ try {
+ long count = copy(in, to);
+ threw = false;
+ return count;
+ } finally {
+ Closeables.close(in, threw);
+ }
+ }
+
+ /**
+ * Copies all characters between the {@link Readable} and {@link Appendable}
+ * objects. Does not close or flush either object.
+ *
+ * @param from the object to read from
+ * @param to the object to write to
+ * @return the number of characters copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(Readable from, Appendable to) throws IOException {
+ CharBuffer buf = CharBuffer.allocate(BUF_SIZE);
+ long total = 0;
+ while (from.read(buf) != -1) {
+ buf.flip();
+ to.append(buf);
+ total += buf.remaining();
+ buf.clear();
+ }
+ return total;
+ }
+
+ /**
+ * Reads all characters from a {@link Readable} object into a {@link String}.
+ * Does not close the {@code Readable}.
+ *
+ * @param r the object to read from
+ * @return a string containing all the characters
+ * @throws IOException if an I/O error occurs
+ */
+ public static String toString(Readable r) throws IOException {
+ return toStringBuilder(r).toString();
+ }
+
+ /**
+ * Returns the characters from a {@link Readable} & {@link Closeable} object
+ * supplied by a factory as a {@link String}.
+ *
+ * @param supplier the factory to read from
+ * @return a string containing all the characters
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable> String toString(
+ InputSupplier<R> supplier) throws IOException {
+ return toStringBuilder(supplier).toString();
+ }
+
+ /**
+ * Reads all characters from a {@link Readable} object into a new
+ * {@link StringBuilder} instance. Does not close the {@code Readable}.
+ *
+ * @param r the object to read from
+ * @return a {@link StringBuilder} containing all the characters
+ * @throws IOException if an I/O error occurs
+ */
+ private static StringBuilder toStringBuilder(Readable r) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ copy(r, sb);
+ return sb;
+ }
+
+ /**
+ * 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.
+ *
+ * @param supplier the factory to read from
+ * @return the first line, or null if the reader is empty
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable> String readFirstLine(
+ InputSupplier<R> supplier) throws IOException {
+ boolean threw = true;
+ R r = supplier.getInput();
+ try {
+ String line = new LineReader(r).readLine();
+ threw = false;
+ return line;
+ } finally {
+ Closeables.close(r, threw);
+ }
+ }
+
+ /**
+ * Reads all of the lines from a {@link Readable} & {@link Closeable} object
+ * supplied by a factory. The lines do not include line-termination
+ * characters, but do include other leading and trailing whitespace.
+ *
+ * @param supplier the factory to read from
+ * @return a mutable {@link List} containing all the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable> List<String> readLines(
+ InputSupplier<R> supplier) throws IOException {
+ boolean threw = true;
+ R r = supplier.getInput();
+ try {
+ List<String> result = readLines(r);
+ threw = false;
+ return result;
+ } finally {
+ Closeables.close(r, threw);
+ }
+ }
+
+ /**
+ * Reads all of the lines from a {@link Readable} object. The lines do
+ * not include line-termination characters, but do include other
+ * leading and trailing whitespace.
+ *
+ * <p>Does not close the {@code Readable}. If reading files or resources you
+ * should use the {@link Files#readLines} and {@link Resources#readLines}
+ * methods.
+ *
+ * @param r the object to read from
+ * @return a mutable {@link List} containing all the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static List<String> readLines(Readable r) throws IOException {
+ List<String> result = new ArrayList<String>();
+ LineReader lineReader = new LineReader(r);
+ String line;
+ while ((line = lineReader.readLine()) != null) {
+ result.add(line);
+ }
+ return result;
+ }
+
+ /**
+ * 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.
+ *
+ * @param supplier the factory to read from
+ * @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
+ */
+ public static <R extends Readable & Closeable, T> T readLines(
+ InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException {
+ boolean threw = true;
+ R r = supplier.getInput();
+ try {
+ LineReader lineReader = new LineReader(r);
+ String line;
+ while ((line = lineReader.readLine()) != null) {
+ if (!callback.processLine(line)) {
+ break;
+ }
+ }
+ threw = false;
+ } finally {
+ Closeables.close(r, threw);
+ }
+ return callback.getResult();
+ }
+
+ /**
+ * Joins multiple {@link Reader} suppliers into a single supplier.
+ * Reader returned from the supplier will contain the concatenated data
+ * from the readers of the underlying suppliers.
+ *
+ * <p>Reading from the joined reader will throw a {@link NullPointerException}
+ * if any of the suppliers are null or return null.
+ *
+ * <p>Only one underlying reader will be open at a time. Closing the
+ * joined reader will close the open underlying reader.
+ *
+ * @param suppliers the suppliers to concatenate
+ * @return a supplier that will return a reader containing the concatenated
+ * data
+ */
+ public static InputSupplier<Reader> join(
+ final Iterable<? extends InputSupplier<? extends Reader>> suppliers) {
+ return new InputSupplier<Reader>() {
+ @Override public Reader getInput() throws IOException {
+ return new MultiReader(suppliers.iterator());
+ }
+ };
+ }
+
+ /** Varargs form of {@link #join(Iterable)}. */
+ public static InputSupplier<Reader> join(
+ InputSupplier<? extends Reader>... suppliers) {
+ return join(Arrays.asList(suppliers));
+ }
+
+ /**
+ * Discards {@code n} characters of data from the reader. This method
+ * will block until the full amount has been skipped. Does not close the
+ * reader.
+ *
+ * @param reader the reader to read from
+ * @param n the number of characters to skip
+ * @throws EOFException if this stream reaches the end before skipping all
+ * the bytes
+ * @throws IOException if an I/O error occurs
+ */
+ public static void skipFully(Reader reader, long n) throws IOException {
+ while (n > 0) {
+ long amt = reader.skip(n);
+ if (amt == 0) {
+ // force a blocking read
+ if (reader.read() == -1) {
+ throw new EOFException();
+ }
+ n--;
+ } else {
+ n -= amt;
+ }
+ }
+ }
+
+ /**
+ * Returns a Writer that sends all output to the given {@link Appendable}
+ * target. Closing the writer will close the target if it is {@link
+ * Closeable}, and flushing the writer will flush the target if it is {@link
+ * java.io.Flushable}.
+ *
+ * @param target the object to which output will be sent
+ * @return a new Writer object, unless target is a Writer, in which case the
+ * target is returned
+ */
+ public static Writer asWriter(Appendable target) {
+ if (target instanceof Writer) {
+ return (Writer) target;
+ }
+ return new AppendableWriter(target);
+ }
+}
diff --git a/guava/src/com/google/common/io/Closeables.java b/guava/src/com/google/common/io/Closeables.java
new file mode 100644
index 0000000..e619887
--- /dev/null
+++ b/guava/src/com/google/common/io/Closeables.java
@@ -0,0 +1,104 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.annotation.Nullable;
+
+/**
+ * Utility methods for working with {@link Closeable} objects.
+ *
+ * @author Michael Lancaster
+ * @since 1.0
+ */
+@Beta
+public final class Closeables {
+ @VisibleForTesting static final Logger logger
+ = Logger.getLogger(Closeables.class.getName());
+
+ 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).
+ *
+ * <p>If {@code swallowIOException} is true then we never throw
+ * {@code IOException} but merely log it.
+ *
+ * <p>Example:
+ *
+ * <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}.
+ */
+ public static void close(@Nullable Closeable closeable,
+ boolean swallowIOException) throws IOException {
+ if (closeable == null) {
+ return;
+ }
+ try {
+ closeable.close();
+ } catch (IOException e) {
+ if (swallowIOException) {
+ logger.log(Level.WARNING,
+ "IOException thrown while closing Closeable.", e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * 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
+ */
+ public static void closeQuietly(@Nullable Closeable closeable) {
+ try {
+ close(closeable, true);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "IOException should not have been thrown.", e);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/CountingInputStream.java b/guava/src/com/google/common/io/CountingInputStream.java
new file mode 100644
index 0000000..d11c8ec
--- /dev/null
+++ b/guava/src/com/google/common/io/CountingInputStream.java
@@ -0,0 +1,90 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An {@link InputStream} that counts the number of bytes read.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class CountingInputStream extends FilterInputStream {
+
+ private long count;
+ private long mark = -1;
+
+ /**
+ * Wraps another input stream, counting the number of bytes read.
+ *
+ * @param in the input stream to be wrapped
+ */
+ public CountingInputStream(InputStream in) {
+ super(in);
+ }
+
+ /** Returns the number of bytes read. */
+ public long getCount() {
+ return count;
+ }
+
+ @Override public int read() throws IOException {
+ int result = in.read();
+ if (result != -1) {
+ count++;
+ }
+ return result;
+ }
+
+ @Override public int read(byte[] b, int off, int len) throws IOException {
+ int result = in.read(b, off, len);
+ if (result != -1) {
+ count += result;
+ }
+ return result;
+ }
+
+ @Override public long skip(long n) throws IOException {
+ long result = in.skip(n);
+ count += result;
+ return result;
+ }
+
+ @Override public synchronized void mark(int readlimit) {
+ in.mark(readlimit);
+ mark = count;
+ // it's okay to mark even if mark isn't supported, as reset won't work
+ }
+
+ @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");
+ }
+
+ in.reset();
+ count = mark;
+ }
+}
diff --git a/guava/src/com/google/common/io/CountingOutputStream.java b/guava/src/com/google/common/io/CountingOutputStream.java
new file mode 100644
index 0000000..5f57714
--- /dev/null
+++ b/guava/src/com/google/common/io/CountingOutputStream.java
@@ -0,0 +1,59 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An OutputStream that counts the number of bytes written.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class CountingOutputStream extends FilterOutputStream {
+
+ private long count;
+
+ /**
+ * Wraps another output stream, counting the number of bytes written.
+ *
+ * @param out the output stream to be wrapped
+ */
+ public CountingOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ /** Returns the number of bytes written. */
+ public long getCount() {
+ return count;
+ }
+
+ @Override public void write(byte[] b, int off, int len) throws IOException {
+ out.write(b, off, len);
+ count += len;
+ }
+
+ @Override public void write(int b) throws IOException {
+ out.write(b);
+ count++;
+ }
+}
diff --git a/guava/src/com/google/common/io/FileBackedOutputStream.java b/guava/src/com/google/common/io/FileBackedOutputStream.java
new file mode 100644
index 0000000..ce593b2
--- /dev/null
+++ b/guava/src/com/google/common/io/FileBackedOutputStream.java
@@ -0,0 +1,210 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * An {@link OutputStream} that starts buffering to a byte array, but
+ * switches to file buffering once the data reaches a configurable size.
+ *
+ * <p>This class is thread-safe.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class FileBackedOutputStream extends OutputStream {
+
+ private final int fileThreshold;
+ private final boolean resetOnFinalize;
+ private final InputSupplier<InputStream> supplier;
+
+ private OutputStream out;
+ private MemoryOutput memory;
+ private File file;
+
+ /** ByteArrayOutputStream that exposes its internals. */
+ private static class MemoryOutput extends ByteArrayOutputStream {
+ byte[] getBuffer() {
+ return buf;
+ }
+
+ int getCount() {
+ return count;
+ }
+ }
+
+ /** Returns the file holding the data (possibly null). */
+ @VisibleForTesting synchronized File getFile() {
+ return file;
+ }
+
+ /**
+ * Creates a new instance that uses the given file threshold, and does
+ * not reset the data when the {@link InputSupplier} returned by
+ * {@link #getSupplier} is finalized.
+ *
+ * @param fileThreshold the number of bytes before the stream should
+ * switch to buffering to a file
+ */
+ public FileBackedOutputStream(int fileThreshold) {
+ this(fileThreshold, false);
+ }
+
+ /**
+ * Creates a new instance that uses the given file threshold, and
+ * optionally resets the data when the {@link InputSupplier} returned
+ * by {@link #getSupplier} is finalized.
+ *
+ * @param fileThreshold the number of bytes before the stream should
+ * switch to buffering to a file
+ * @param resetOnFinalize if true, the {@link #reset} method will
+ * be called when the {@link InputSupplier} returned by {@link
+ * #getSupplier} is finalized
+ */
+ public FileBackedOutputStream(int fileThreshold, boolean resetOnFinalize) {
+ this.fileThreshold = fileThreshold;
+ this.resetOnFinalize = resetOnFinalize;
+ memory = new MemoryOutput();
+ out = memory;
+
+ if (resetOnFinalize) {
+ supplier = new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return openStream();
+ }
+
+ @Override protected void finalize() {
+ try {
+ reset();
+ } catch (Throwable t) {
+ t.printStackTrace(System.err);
+ }
+ }
+ };
+ } else {
+ supplier = new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return openStream();
+ }
+ };
+ }
+ }
+
+ /**
+ * Returns a supplier that may be used to retrieve the data buffered
+ * by this stream.
+ */
+ public InputSupplier<InputStream> getSupplier() {
+ return supplier;
+ }
+
+ private synchronized InputStream openStream() throws IOException {
+ if (file != null) {
+ return new FileInputStream(file);
+ } else {
+ return new ByteArrayInputStream(
+ memory.getBuffer(), 0, memory.getCount());
+ }
+ }
+
+ /**
+ * Calls {@link #close} if not already closed, and then resets this
+ * object back to its initial state, for reuse. If data was buffered
+ * to a file, it will be deleted.
+ *
+ * @throws IOException if an I/O error occurred while deleting the file buffer
+ */
+ public synchronized void reset() throws IOException {
+ try {
+ close();
+ } finally {
+ if (memory == null) {
+ memory = new MemoryOutput();
+ } else {
+ memory.reset();
+ }
+ out = memory;
+ if (file != null) {
+ File deleteMe = file;
+ file = null;
+ if (!deleteMe.delete()) {
+ throw new IOException("Could not delete: " + deleteMe);
+ }
+ }
+ }
+ }
+
+ @Override public synchronized void write(int b) throws IOException {
+ update(1);
+ out.write(b);
+ }
+
+ @Override public synchronized void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ @Override public synchronized void write(byte[] b, int off, int len)
+ throws IOException {
+ update(len);
+ out.write(b, off, len);
+ }
+
+ @Override public synchronized void close() throws IOException {
+ out.close();
+ }
+
+ @Override public synchronized void flush() throws IOException {
+ out.flush();
+ }
+
+ /**
+ * Checks if writing {@code len} bytes would go over threshold, and
+ * switches to file buffering if so.
+ */
+ private void update(int len) throws IOException {
+ if (file == null && (memory.getCount() + len > fileThreshold)) {
+ File temp = File.createTempFile("FileBackedOutputStream", null);
+ if (resetOnFinalize) {
+ // Finalizers are not guaranteed to be called on system shutdown;
+ // this is insurance.
+ temp.deleteOnExit();
+ }
+ FileOutputStream transfer = new FileOutputStream(temp);
+ transfer.write(memory.getBuffer(), 0, memory.getCount());
+ transfer.flush();
+
+ // We've successfully transferred the data; switch to writing to file
+ out = transfer;
+ file = temp;
+ memory = null;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/Files.java b/guava/src/com/google/common/io/Files.java
new file mode 100644
index 0000000..71b5dee
--- /dev/null
+++ b/guava/src/com/google/common/io/Files.java
@@ -0,0 +1,780 @@
+/*
+ * 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.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.Joiner;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.HashFunction;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.RandomAccessFile;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.Checksum;
+
+/**
+ * Provides utility methods for working with files.
+ *
+ * <p>All method parameters must be non-null unless documented otherwise.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class Files {
+
+ /** Maximum loop count when creating temp directories. */
+ private static final int TEMP_DIR_ATTEMPTS = 10000;
+
+ private Files() {}
+
+ /**
+ * Returns a buffered reader that reads from 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
+ * @return the buffered reader
+ */
+ public static BufferedReader newReader(File file, Charset charset)
+ throws FileNotFoundException {
+ return new BufferedReader(
+ new InputStreamReader(new FileInputStream(file), charset));
+ }
+
+ /**
+ * Returns a buffered writer that writes 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
+ * @return the buffered writer
+ */
+ public static BufferedWriter newWriter(File file, Charset charset)
+ throws FileNotFoundException {
+ return new BufferedWriter(
+ new OutputStreamWriter(new FileOutputStream(file), charset));
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link FileInputStream}
+ * that read from a file.
+ *
+ * @param file the file to read from
+ * @return the factory
+ */
+ public static InputSupplier<FileInputStream> newInputStreamSupplier(
+ final File file) {
+ Preconditions.checkNotNull(file);
+ return new InputSupplier<FileInputStream>() {
+ @Override
+ public FileInputStream getInput() throws IOException {
+ return new FileInputStream(file);
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link FileOutputStream}
+ * that write to a file.
+ *
+ * @param file the file to write to
+ * @return the factory
+ */
+ public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
+ File file) {
+ return newOutputStreamSupplier(file, false);
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link FileOutputStream}
+ * that write to or append to a file.
+ *
+ * @param file the file to write to
+ * @param append if true, the encoded characters will be appended to the file;
+ * otherwise the file is overwritten
+ * @return the factory
+ */
+ public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
+ final File file, final boolean append) {
+ Preconditions.checkNotNull(file);
+ return new OutputSupplier<FileOutputStream>() {
+ @Override
+ public FileOutputStream getOutput() throws IOException {
+ return new FileOutputStream(file, append);
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of
+ * {@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
+ * @return the factory
+ */
+ public static InputSupplier<InputStreamReader> newReaderSupplier(File file,
+ Charset charset) {
+ return CharStreams.newReaderSupplier(newInputStreamSupplier(file), charset);
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link OutputStreamWriter}
+ * 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
+ * @return the factory
+ */
+ public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
+ Charset charset) {
+ return newWriterSupplier(file, charset, false);
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link OutputStreamWriter}
+ * 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 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.newWriterSupplier(newOutputStreamSupplier(file, append),
+ charset);
+ }
+
+ /**
+ * Reads all bytes from a file into a byte array.
+ *
+ * @param file the file to read from
+ * @return a byte array containing all the bytes from file
+ * @throws IllegalArgumentException if the file is bigger than the largest
+ * possible byte array (2^31 - 1)
+ * @throws IOException if an I/O error occurs
+ */
+ public static byte[] toByteArray(File file) throws IOException {
+ 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;
+ }
+ }
+
+ /**
+ * Reads all characters from a file into a {@link String}, 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
+ * @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 new String(toByteArray(file), charset.name());
+ }
+
+ /**
+ * Copies to a file all bytes from an {@link InputStream} supplied by a
+ * factory.
+ *
+ * @param from the input factory
+ * @param to the destination file
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(InputSupplier<? extends InputStream> from, File to)
+ throws IOException {
+ ByteStreams.copy(from, newOutputStreamSupplier(to));
+ }
+
+ /**
+ * Overwrites a file with the contents of a byte array.
+ *
+ * @param from the bytes to write
+ * @param to the destination file
+ * @throws IOException if an I/O error occurs
+ */
+ public static void write(byte[] from, File to) throws IOException {
+ ByteStreams.write(from, newOutputStreamSupplier(to));
+ }
+
+ /**
+ * Copies all bytes from a file to an {@link OutputStream} supplied by
+ * a factory.
+ *
+ * @param from the source file
+ * @param to the output factory
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(File from, OutputSupplier<? extends OutputStream> to)
+ throws IOException {
+ ByteStreams.copy(newInputStreamSupplier(from), to);
+ }
+
+ /**
+ * Copies all bytes from a file to an output stream.
+ *
+ * @param from the source file
+ * @param to the output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(File from, OutputStream to) throws IOException {
+ ByteStreams.copy(newInputStreamSupplier(from), to);
+ }
+
+ /**
+ * Copies all the bytes from one file to another.
+ *.
+ * @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 {
+ Preconditions.checkArgument(!from.equals(to),
+ "Source %s and destination %s must be different", from, to);
+ copy(newInputStreamSupplier(from), to);
+ }
+
+ /**
+ * Copies to a file all characters from a {@link Readable} and
+ * {@link Closeable} object supplied by a factory, using the given
+ * character set.
+ *
+ * @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
+ * @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.copy(from, newWriterSupplier(to, charset));
+ }
+
+ /**
+ * Writes a character sequence (such as a string) to a file using the given
+ * character set.
+ *
+ * @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
+ * @throws IOException if an I/O error occurs
+ */
+ public static void write(CharSequence from, File to, Charset charset)
+ throws IOException {
+ write(from, to, charset, false);
+ }
+
+ /**
+ * Appends a character sequence (such as a string) to a file using the given
+ * character set.
+ *
+ * @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
+ * @throws IOException if an I/O error occurs
+ */
+ public static void append(CharSequence from, File to, Charset charset)
+ throws IOException {
+ write(from, to, charset, true);
+ }
+
+ /**
+ * Private helper method. Writes a character sequence to a file,
+ * optionally appending.
+ *
+ * @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 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 {
+ CharStreams.write(from, newWriterSupplier(to, charset, append));
+ }
+
+ /**
+ * Copies all characters from a file to a {@link Appendable} &
+ * {@link Closeable} object supplied by a factory, 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 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 {
+ CharStreams.copy(newReaderSupplier(from, charset), to);
+ }
+
+ /**
+ * Copies all characters from a file to an appendable object,
+ * 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 to the appendable object
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(File from, Charset charset, Appendable to)
+ throws IOException {
+ CharStreams.copy(newReaderSupplier(from, charset), to);
+ }
+
+ /**
+ * Returns true if the files contains the same bytes.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ public static boolean equal(File file1, File file2) throws IOException {
+ if (file1 == file2 || file1.equals(file2)) {
+ return true;
+ }
+
+ /*
+ * Some operating systems may return zero as the length for files
+ * denoting system-dependent entities such as devices or pipes, in
+ * which case we must fall back on comparing the bytes directly.
+ */
+ long len1 = file1.length();
+ long len2 = file2.length();
+ if (len1 != 0 && len2 != 0 && len1 != len2) {
+ return false;
+ }
+ return ByteStreams.equal(newInputStreamSupplier(file1),
+ newInputStreamSupplier(file2));
+ }
+
+ /**
+ * Atomically creates a new directory somewhere beneath the system's
+ * temporary directory (as defined by the {@code java.io.tmpdir} system
+ * property), and returns its name.
+ *
+ * <p>Use this method instead of {@link File#createTempFile(String, String)}
+ * when you wish to create a directory, not a regular file. A common pitfall
+ * is to call {@code createTempFile}, delete the file and create a
+ * directory in its place, but this leads a race condition which can be
+ * exploited to create security vulnerabilities, especially when executable
+ * files are to be written into the directory.
+ *
+ * <p>This method assumes that the temporary volume is writable, has free
+ * inodes and free blocks, and that it will not be called thousands of times
+ * per second.
+ *
+ * @return the newly-created directory
+ * @throws IllegalStateException if the directory could not be created
+ */
+ public static File createTempDir() {
+ File baseDir = new File(System.getProperty("java.io.tmpdir"));
+ String baseName = System.currentTimeMillis() + "-";
+
+ for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
+ File tempDir = new File(baseDir, baseName + counter);
+ if (tempDir.mkdir()) {
+ return tempDir;
+ }
+ }
+ throw new IllegalStateException("Failed to create directory within "
+ + TEMP_DIR_ATTEMPTS + " attempts (tried "
+ + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')');
+ }
+
+ /**
+ * Creates an empty file or updates the last updated timestamp on the
+ * same as the unix command of the same name.
+ *
+ * @param file the file to create or update
+ * @throws IOException if an I/O error occurs
+ */
+ public static void touch(File file) throws IOException {
+ if (!file.createNewFile()
+ && !file.setLastModified(System.currentTimeMillis())) {
+ throw new IOException("Unable to update modification time of " + file);
+ }
+ }
+
+ /**
+ * Creates any necessary but nonexistent parent directories of the specified
+ * file. Note that if this operation fails it may have succeeded in creating
+ * some (but not all) of the necessary parent directories.
+ *
+ * @throws IOException if an I/O error occurs, or if any necessary but
+ * nonexistent parent directories of the specified file could not be
+ * created.
+ * @since 4.0
+ */
+ public static void createParentDirs(File file) throws IOException {
+ File parent = file.getCanonicalFile().getParentFile();
+ if (parent == null) {
+ /*
+ * The given directory is a filesystem root. All zero of its ancestors
+ * exist. This doesn't mean that the root itself exists -- consider x:\ on
+ * a Windows machine without such a drive -- or even that the caller can
+ * create it, but this method makes no such guarantees even for non-root
+ * files.
+ */
+ return;
+ }
+ parent.mkdirs();
+ if (!parent.isDirectory()) {
+ throw new IOException("Unable to create parent directories of " + file);
+ }
+ }
+
+ /**
+ * Moves the file from one path to another. This method can rename a file or
+ * move it to a different directory, like the Unix {@code mv} command.
+ *
+ * @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 move(File from, File to) throws IOException {
+ Preconditions.checkNotNull(to);
+ Preconditions.checkArgument(!from.equals(to),
+ "Source %s and destination %s must be different", from, to);
+
+ if (!from.renameTo(to)) {
+ copy(from, to);
+ if (!from.delete()) {
+ if (!to.delete()) {
+ throw new IOException("Unable to delete " + to);
+ }
+ throw new IOException("Unable to delete " + from);
+ }
+ }
+ }
+
+ /**
+ * Reads the first line from a file. The line does not include
+ * line-termination characters, but does include other leading and
+ * 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
+ * @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 CharStreams.readFirstLine(Files.newReaderSupplier(file, charset));
+ }
+
+ /**
+ * Reads all of the lines from a file. The lines do not include
+ * line-termination characters, but do include other leading and
+ * 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
+ * @return a mutable {@link List} containing all the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static List<String> readLines(File file, Charset charset)
+ throws IOException {
+ return CharStreams.readLines(Files.newReaderSupplier(file, charset));
+ }
+
+ /**
+ * Streams lines from a {@link File}, stopping when our callback returns
+ * 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 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(Files.newReaderSupplier(file, charset),
+ callback);
+ }
+
+ /**
+ * Process the bytes of a file.
+ *
+ * <p>(If this seems too complicated, maybe you're looking for
+ * {@link #toByteArray}.)
+ *
+ * @param file the file to read
+ * @param processor the object to which the bytes of the file are passed.
+ * @return the result of the byte processor
+ * @throws IOException if an I/O error occurs
+ */
+ public static <T> T readBytes(File file, ByteProcessor<T> processor)
+ throws IOException {
+ return ByteStreams.readBytes(newInputStreamSupplier(file), processor);
+ }
+
+ /**
+ * Computes and returns the checksum value for a file.
+ * The checksum object is reset when this method returns successfully.
+ *
+ * @param file the file to read
+ * @param checksum the checksum object
+ * @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
+ */
+ 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}.
+ *
+ * @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
+ * @throws IOException if an I/O error occurs
+ * @since 12.0
+ */
+ public static HashCode hash(File file, HashFunction hashFunction)
+ throws IOException {
+ return ByteStreams.hash(newInputStreamSupplier(file), hashFunction);
+ }
+
+ /**
+ * Fully maps a file read-only in to memory as per
+ * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}.
+ *
+ * <p>Files are mapped from offset 0 to its length.
+ *
+ * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
+ *
+ * @param file the file to map
+ * @return a read-only buffer reflecting {@code file}
+ * @throws FileNotFoundException if the {@code file} does not exist
+ * @throws IOException if an I/O error occurs
+ *
+ * @see FileChannel#map(MapMode, long, long)
+ * @since 2.0
+ */
+ public static MappedByteBuffer map(File file) throws IOException {
+ return map(file, MapMode.READ_ONLY);
+ }
+
+ /**
+ * Fully maps a file in to memory as per
+ * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}
+ * using the requested {@link MapMode}.
+ *
+ * <p>Files are mapped from offset 0 to its length.
+ *
+ * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
+ *
+ * @param file the file to map
+ * @param mode the mode to use when mapping {@code file}
+ * @return a buffer reflecting {@code file}
+ * @throws FileNotFoundException if the {@code file} does not exist
+ * @throws IOException if an I/O error occurs
+ *
+ * @see FileChannel#map(MapMode, long, long)
+ * @since 2.0
+ */
+ public static MappedByteBuffer map(File file, MapMode mode)
+ throws IOException {
+ if (!file.exists()) {
+ throw new FileNotFoundException(file.toString());
+ }
+ return map(file, mode, file.length());
+ }
+
+ /**
+ * Maps a file in to memory as per
+ * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}
+ * using the requested {@link MapMode}.
+ *
+ * <p>Files are mapped from offset 0 to {@code size}.
+ *
+ * <p>If the mode is {@link MapMode#READ_WRITE} and the file does not exist,
+ * it will be created with the requested {@code size}. Thus this method is
+ * useful for creating memory mapped files which do not yet exist.
+ *
+ * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
+ *
+ * @param file the file to map
+ * @param mode the mode to use when mapping {@code file}
+ * @return a buffer reflecting {@code file}
+ * @throws IOException if an I/O error occurs
+ *
+ * @see FileChannel#map(MapMode, long, long)
+ * @since 2.0
+ */
+ public static MappedByteBuffer map(File file, MapMode mode, long size)
+ throws FileNotFoundException, IOException {
+ RandomAccessFile raf =
+ new RandomAccessFile(file, mode == MapMode.READ_ONLY ? "r" : "rw");
+
+ boolean threw = true;
+ try {
+ MappedByteBuffer mbb = map(raf, mode, size);
+ threw = false;
+ return mbb;
+ } finally {
+ Closeables.close(raf, threw);
+ }
+ }
+
+ private static MappedByteBuffer map(RandomAccessFile raf, MapMode mode,
+ long size) throws IOException {
+ FileChannel channel = raf.getChannel();
+
+ boolean threw = true;
+ try {
+ MappedByteBuffer mbb = channel.map(mode, 0, size);
+ threw = false;
+ return mbb;
+ } finally {
+ Closeables.close(channel, threw);
+ }
+ }
+
+ /**
+ * Returns the lexically cleaned form of the path name, <i>usually</i> (but
+ * not always) equivalent to the original. The following heuristics are used:
+ *
+ * <ul>
+ * <li>empty string becomes .
+ * <li>. stays as .
+ * <li>fold out ./
+ * <li>fold out ../ when possible
+ * <li>collapse multiple slashes
+ * <li>delete trailing slashes (unless the path is just "/")
+ * </ul>
+ *
+ * These heuristics do not always match the behavior of the filesystem. In
+ * particular, consider the path {@code a/../b}, which {@code simplifyPath}
+ * will change to {@code b}. If {@code a} is a symlink to {@code x}, {@code
+ * a/../b} may refer to a sibling of {@code x}, rather than the sibling of
+ * {@code a} referred to by {@code b}.
+ *
+ * @since 11.0
+ */
+ public static String simplifyPath(String pathname) {
+ if (pathname.length() == 0) {
+ return ".";
+ }
+
+ // split the path apart
+ Iterable<String> components =
+ Splitter.on('/').omitEmptyStrings().split(pathname);
+ List<String> path = new ArrayList<String>();
+
+ // resolve ., .., and //
+ for (String component : components) {
+ if (component.equals(".")) {
+ continue;
+ } else if (component.equals("..")) {
+ if (path.size() > 0 && !path.get(path.size() - 1).equals("..")) {
+ path.remove(path.size() - 1);
+ } else {
+ path.add("..");
+ }
+ } else {
+ path.add(component);
+ }
+ }
+
+ // put it back together
+ String result = Joiner.on('/').join(path);
+ if (pathname.charAt(0) == '/') {
+ result = "/" + result;
+ }
+
+ while (result.startsWith("/../")) {
+ result = result.substring(3);
+ }
+ if (result.equals("/..")) {
+ result = "/";
+ } else if ("".equals(result)) {
+ result = ".";
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the <a href="http://en.wikipedia.org/wiki/Filename_extension">file
+ * extension</a> for the given file name, or the empty string if the file has
+ * no extension. The result does not include the '{@code .}'.
+ *
+ * @since 11.0
+ */
+ public static String getFileExtension(String fileName) {
+ checkNotNull(fileName);
+ int dotIndex = fileName.lastIndexOf('.');
+ return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
+ }
+}
diff --git a/guava/src/com/google/common/io/Flushables.java b/guava/src/com/google/common/io/Flushables.java
new file mode 100644
index 0000000..68ff860
--- /dev/null
+++ b/guava/src/com/google/common/io/Flushables.java
@@ -0,0 +1,80 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+
+import java.io.Flushable;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Utility methods for working with {@link Flushable} objects.
+ *
+ * @author Michael Lancaster
+ * @since 1.0
+ */
+@Beta
+public final class Flushables {
+ private static final Logger logger
+ = Logger.getLogger(Flushables.class.getName());
+
+ private Flushables() {}
+
+ /**
+ * Flush a {@link Flushable}, with control over whether an
+ * {@code IOException} may be thrown.
+ *
+ * <p>If {@code swallowIOException} is true, then we don't rethrow
+ * {@code IOException}, but merely log it.
+ *
+ * @param flushable the {@code Flushable} object to be flushed.
+ * @param swallowIOException if true, don't propagate IO exceptions
+ * thrown by the {@code flush} method
+ * @throws IOException if {@code swallowIOException} is false and
+ * {@link Flushable#flush} throws an {@code IOException}.
+ * @see Closeables#close
+ */
+ public static void flush(Flushable flushable, boolean swallowIOException)
+ throws IOException {
+ try {
+ flushable.flush();
+ } catch (IOException e) {
+ if (swallowIOException) {
+ logger.log(Level.WARNING,
+ "IOException thrown while flushing Flushable.", e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Equivalent to calling {@code flush(flushable, true)}, but with no
+ * {@code IOException} in the signature.
+ *
+ * @param flushable the {@code Flushable} object to be flushed.
+ */
+ public static void flushQuietly(Flushable flushable) {
+ try {
+ flush(flushable, true);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "IOException should not have been thrown.", e);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/InputSupplier.java b/guava/src/com/google/common/io/InputSupplier.java
new file mode 100644
index 0000000..2b6a4ad
--- /dev/null
+++ b/guava/src/com/google/common/io/InputSupplier.java
@@ -0,0 +1,40 @@
+/*
+ * 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.io;
+
+import java.io.IOException;
+
+/**
+ * A factory for readable streams of bytes or characters.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+public interface InputSupplier<T> {
+
+ /**
+ * Returns an object that encapsulates a readable resource.
+ * <p>
+ * Like {@link Iterable#iterator}, this method may be called repeatedly to
+ * get independent channels to the same underlying resource.
+ * <p>
+ * Where the channel maintains a position within the resource, moving that
+ * cursor within one channel should not affect the starting position of
+ * channels returned by other calls.
+ */
+ T getInput() throws IOException;
+}
diff --git a/guava/src/com/google/common/io/LimitInputStream.java b/guava/src/com/google/common/io/LimitInputStream.java
new file mode 100644
index 0000000..e9d963d
--- /dev/null
+++ b/guava/src/com/google/common/io/LimitInputStream.java
@@ -0,0 +1,104 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An InputStream that limits the number of bytes which can be read.
+ *
+ * @author Charles Fry
+ * @since 1.0
+ */
+@Beta
+public final class LimitInputStream extends FilterInputStream {
+
+ private long left;
+ private long mark = -1;
+
+ /**
+ * Wraps another input stream, 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
+ */
+ public LimitInputStream(InputStream in, long limit) {
+ super(in);
+ Preconditions.checkNotNull(in);
+ Preconditions.checkArgument(limit >= 0, "limit must be non-negative");
+ left = limit;
+ }
+
+ @Override public int available() throws IOException {
+ return (int) Math.min(in.available(), left);
+ }
+
+ @Override public synchronized void mark(int readlimit) {
+ in.mark(readlimit);
+ mark = left;
+ // it's okay to mark even if mark isn't supported, as reset won't work
+ }
+
+ @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");
+ }
+
+ 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;
+ }
+}
diff --git a/guava/src/com/google/common/io/LineBuffer.java b/guava/src/com/google/common/io/LineBuffer.java
new file mode 100644
index 0000000..1f1c8dc
--- /dev/null
+++ b/guava/src/com/google/common/io/LineBuffer.java
@@ -0,0 +1,117 @@
+/*
+ * 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.io;
+
+import java.io.IOException;
+
+/**
+ * Package-protected abstract class that implements the line reading
+ * algorithm used by {@link LineReader}. Line separators are per {@link
+ * java.io.BufferedReader}: line feed, carriage return, or carriage
+ * return followed immediately by a linefeed.
+ *
+ * <p>Subclasses must implement {@link #handleLine}, call {@link #add}
+ * to pass character data, and call {@link #finish} at the end of stream.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+abstract class LineBuffer {
+ /** Holds partial line contents. */
+ private StringBuilder line = new StringBuilder();
+ /** Whether a line ending with a CR is pending processing. */
+ private boolean sawReturn;
+
+ /**
+ * Process additional characters from the stream. When a line separator
+ * is found the contents of the line and the line separator itself
+ * are passed to the abstract {@link #handleLine} method.
+ *
+ * @param cbuf the character buffer to process
+ * @param off the offset into the buffer
+ * @param len the number of characters to process
+ * @throws IOException if an I/O error occurs
+ * @see #finish
+ */
+ protected void add(char[] cbuf, int off, int len) throws IOException {
+ int pos = off;
+ if (sawReturn && len > 0) {
+ // Last call to add ended with a CR; we can handle the line now.
+ if (finishLine(cbuf[pos] == '\n')) {
+ pos++;
+ }
+ }
+
+ int start = pos;
+ for (int end = off + len; pos < end; pos++) {
+ switch (cbuf[pos]) {
+ case '\r':
+ line.append(cbuf, start, pos - start);
+ sawReturn = true;
+ if (pos + 1 < end) {
+ if (finishLine(cbuf[pos + 1] == '\n')) {
+ pos++;
+ }
+ }
+ start = pos + 1;
+ break;
+
+ case '\n':
+ line.append(cbuf, start, pos - start);
+ finishLine(true);
+ start = pos + 1;
+ break;
+ }
+ }
+ line.append(cbuf, start, off + len - start);
+ }
+
+ /** Called when a line is complete. */
+ private boolean finishLine(boolean sawNewline) throws IOException {
+ handleLine(line.toString(), sawReturn
+ ? (sawNewline ? "\r\n" : "\r")
+ : (sawNewline ? "\n" : ""));
+ line = new StringBuilder();
+ sawReturn = false;
+ return sawNewline;
+ }
+
+ /**
+ * Subclasses must call this method after finishing character processing,
+ * in order to ensure that any unterminated line in the buffer is
+ * passed to {@link #handleLine}.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ protected void finish() throws IOException {
+ if (sawReturn || line.length() > 0) {
+ finishLine(false);
+ }
+ }
+
+ /**
+ * Called for each line found in the character data passed to
+ * {@link #add}.
+ *
+ * @param line a line of text (possibly empty), without any line separators
+ * @param end the line separator; one of {@code "\r"}, {@code "\n"},
+ * {@code "\r\n"}, or {@code ""}
+ * @throws IOException if an I/O error occurs
+ */
+ protected abstract void handleLine(String line, String end)
+ throws IOException;
+}
diff --git a/guava/src/com/google/common/io/LineProcessor.java b/guava/src/com/google/common/io/LineProcessor.java
new file mode 100644
index 0000000..9ee6a0f
--- /dev/null
+++ b/guava/src/com/google/common/io/LineProcessor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+
+import java.io.IOException;
+
+/**
+ * A callback to be used with the streaming {@code readLines} methods.
+ *
+ * <p>{@link #processLine} will be called for each line that is read, and
+ * should return {@code false} when you want to stop processing.
+ *
+ * @author Miles Barr
+ * @since 1.0
+ */
+@Beta
+public interface LineProcessor<T> {
+
+ /**
+ * This method will be called once for each line.
+ *
+ * @param line the line read from the input, without delimiter
+ * @return true to continue processing, false to stop
+ */
+ boolean processLine(String line) throws IOException;
+
+ /** Return the result of processing all the lines. */
+ T getResult();
+}
diff --git a/guava/src/com/google/common/io/LineReader.java b/guava/src/com/google/common/io/LineReader.java
new file mode 100644
index 0000000..69ae0cf
--- /dev/null
+++ b/guava/src/com/google/common/io/LineReader.java
@@ -0,0 +1,87 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.CharBuffer;
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * A class for reading lines of text. Provides the same functionality
+ * as {@link java.io.BufferedReader#readLine()} but for all {@link Readable}
+ * objects, not just instances of {@link Reader}.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class LineReader {
+ private final Readable readable;
+ private final Reader reader;
+ private final char[] buf = new char[0x1000]; // 4K
+ private final CharBuffer cbuf = CharBuffer.wrap(buf);
+
+ private final Queue<String> lines = new LinkedList<String>();
+ private final LineBuffer lineBuf = new LineBuffer() {
+ @Override protected void handleLine(String line, String end) {
+ lines.add(line);
+ }
+ };
+
+ /**
+ * Creates a new instance that will read lines from the given
+ * {@code Readable} object.
+ */
+ public LineReader(Readable readable) {
+ Preconditions.checkNotNull(readable);
+ this.readable = readable;
+ this.reader = (readable instanceof Reader) ? (Reader) readable : null;
+ }
+
+ /**
+ * Reads a line of text. A line is considered to be terminated by any
+ * one of a line feed ({@code '\n'}), a carriage return
+ * ({@code '\r'}), or a carriage return followed immediately by a linefeed
+ * ({@code "\r\n"}).
+ *
+ * @return a {@code String} containing the contents of the line, not
+ * including any line-termination characters, or {@code null} if the
+ * end of the stream has been reached.
+ * @throws IOException if an I/O error occurs
+ */
+ public String readLine() throws IOException {
+ while (lines.peek() == null) {
+ cbuf.clear();
+ // The default implementation of Reader#read(CharBuffer) allocates a
+ // temporary char[], so we call Reader#read(char[], int, int) instead.
+ int read = (reader != null)
+ ? reader.read(buf, 0, buf.length)
+ : readable.read(cbuf);
+ if (read == -1) {
+ lineBuf.finish();
+ break;
+ }
+ lineBuf.add(buf, 0, read);
+ }
+ return lines.poll();
+ }
+}
diff --git a/guava/src/com/google/common/io/LittleEndianDataInputStream.java b/guava/src/com/google/common/io/LittleEndianDataInputStream.java
new file mode 100644
index 0000000..e60d22f
--- /dev/null
+++ b/guava/src/com/google/common/io/LittleEndianDataInputStream.java
@@ -0,0 +1,232 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Ints;
+import com.google.common.primitives.Longs;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An implementation of {@link DataInput} that uses little-endian byte ordering
+ * for reading {@code short}, {@code int}, {@code float}, {@code double}, and
+ * {@code long} values.
+ * <p>
+ * <b>Note:</b> This class intentionally violates the specification of its
+ * supertype {@code DataInput}, which explicitly requires big-endian byte order.
+ *
+ * @author Chris Nokleberg
+ * @author Keith Bottner
+ * @since 8.0
+ */
+@Beta
+public final class LittleEndianDataInputStream extends FilterInputStream
+ implements DataInput {
+
+ /**
+ * Creates a {@code LittleEndianDataInputStream} that wraps the given stream.
+ *
+ * @param in the stream to delegate to
+ */
+ public LittleEndianDataInputStream(InputStream in) {
+ super(Preconditions.checkNotNull(in));
+ }
+
+ /**
+ * This method will throw an {@link UnsupportedOperationException}.
+ */
+ @Override
+ public String readLine() {
+ throw new UnsupportedOperationException("readLine is not supported");
+ }
+
+ @Override
+ public void readFully(byte[] b) throws IOException {
+ ByteStreams.readFully(this, b);
+ }
+
+ @Override
+ public void readFully(byte[] b, int off, int len) throws IOException {
+ ByteStreams.readFully(this, b, off, len);
+ }
+
+ @Override
+ public int skipBytes(int n) throws IOException {
+ return (int) in.skip(n);
+ }
+
+ @Override
+ public int readUnsignedByte() throws IOException {
+ int b1 = in.read();
+ if (0 > b1) {
+ throw new EOFException();
+ }
+
+ return b1;
+ }
+
+ /**
+ * Reads an unsigned {@code short} as specified by
+ * {@link DataInputStream#readUnsignedShort()}, except using little-endian
+ * byte order.
+ *
+ * @return the next two bytes of the input stream, interpreted as an
+ * unsigned 16-bit integer in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public int readUnsignedShort() throws IOException {
+ byte b1 = readAndCheckByte();
+ byte b2 = readAndCheckByte();
+
+ return Ints.fromBytes((byte) 0, (byte) 0, b2, b1);
+ }
+
+ /**
+ * Reads an integer as specified by {@link DataInputStream#readInt()}, except
+ * using little-endian byte order.
+ *
+ * @return the next four bytes of the input stream, interpreted as an
+ * {@code int} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public int readInt() throws IOException {
+ byte b1 = readAndCheckByte();
+ byte b2 = readAndCheckByte();
+ byte b3 = readAndCheckByte();
+ byte b4 = readAndCheckByte();
+
+ return Ints.fromBytes( b4, b3, b2, b1);
+ }
+
+ /**
+ * Reads a {@code long} as specified by {@link DataInputStream#readLong()},
+ * except using little-endian byte order.
+ *
+ * @return the next eight bytes of the input stream, interpreted as a
+ * {@code long} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public long readLong() throws IOException {
+ byte b1 = readAndCheckByte();
+ byte b2 = readAndCheckByte();
+ byte b3 = readAndCheckByte();
+ byte b4 = readAndCheckByte();
+ byte b5 = readAndCheckByte();
+ byte b6 = readAndCheckByte();
+ byte b7 = readAndCheckByte();
+ byte b8 = readAndCheckByte();
+
+ return Longs.fromBytes(b8, b7, b6, b5, b4, b3, b2, b1);
+ }
+
+ /**
+ * Reads a {@code float} as specified by {@link DataInputStream#readFloat()},
+ * except using little-endian byte order.
+ *
+ * @return the next four bytes of the input stream, interpreted as a
+ * {@code float} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public float readFloat() throws IOException {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ /**
+ * Reads a {@code double} as specified by
+ * {@link DataInputStream#readDouble()}, except using little-endian byte
+ * order.
+ *
+ * @return the next eight bytes of the input stream, interpreted as a
+ * {@code double} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public double readDouble() throws IOException {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ @Override
+ public String readUTF() throws IOException {
+ return new DataInputStream(in).readUTF();
+ }
+
+ /**
+ * Reads a {@code short} as specified by {@link DataInputStream#readShort()},
+ * except using little-endian byte order.
+ *
+ * @return the next two bytes of the input stream, interpreted as a
+ * {@code short} in little-endian byte order.
+ * @throws IOException if an I/O error occurs.
+ */
+ @Override
+ public short readShort() throws IOException {
+ return (short) readUnsignedShort();
+ }
+
+ /**
+ * Reads a char as specified by {@link DataInputStream#readChar()}, except
+ * using little-endian byte order.
+ *
+ * @return the next two bytes of the input stream, interpreted as a
+ * {@code char} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public char readChar() throws IOException {
+ return (char) readUnsignedShort();
+ }
+
+ @Override
+ public byte readByte() throws IOException {
+ return (byte) readUnsignedByte();
+ }
+
+ @Override
+ public boolean readBoolean() throws IOException {
+ return readUnsignedByte() != 0;
+ }
+
+ /**
+ * Reads a byte from the input stream checking that the end of file (EOF)
+ * has not been encountered.
+ *
+ * @return byte read from input
+ * @throws IOException if an error is encountered while reading
+ * @throws EOFException if the end of file (EOF) is encountered.
+ */
+ private byte readAndCheckByte() throws IOException, EOFException {
+ int b1 = in.read();
+
+ if (-1 == b1) {
+ throw new EOFException();
+ }
+
+ return (byte) b1;
+ }
+
+}
diff --git a/guava/src/com/google/common/io/LittleEndianDataOutputStream.java b/guava/src/com/google/common/io/LittleEndianDataOutputStream.java
new file mode 100644
index 0000000..1725ae0
--- /dev/null
+++ b/guava/src/com/google/common/io/LittleEndianDataOutputStream.java
@@ -0,0 +1,164 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Longs;
+
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An implementation of {@link DataOutput} that uses little-endian byte ordering
+ * for writing {@code char}, {@code short}, {@code int}, {@code float}, {@code
+ * double}, and {@code long} values.
+ * <p>
+ * <b>Note:</b> This class intentionally violates the specification of its
+ * supertype {@code DataOutput}, which explicitly requires big-endian byte
+ * order.
+ *
+ * @author Chris Nokleberg
+ * @author Keith Bottner
+ * @since 8.0
+ */
+@Beta
+public class LittleEndianDataOutputStream extends FilterOutputStream
+ implements DataOutput {
+
+ /**
+ * Creates a {@code LittleEndianDataOutputStream} that wraps the given stream.
+ *
+ * @param out the stream to delegate to
+ */
+ public LittleEndianDataOutputStream(OutputStream out) {
+ super(new DataOutputStream(Preconditions.checkNotNull(out)));
+ }
+
+ @Override public void write(byte[] b, int off, int len) throws IOException {
+ // Override slow FilterOutputStream impl
+ out.write(b, off, len);
+ }
+
+ @Override public void writeBoolean(boolean v) throws IOException {
+ ((DataOutputStream) out).writeBoolean(v);
+ }
+
+ @Override public void writeByte(int v) throws IOException {
+ ((DataOutputStream) out).writeByte(v);
+ }
+
+ /**
+ * @deprecated The semantics of {@code writeBytes(String s)} are considered
+ * dangerous. Please use {@link #writeUTF(String s)},
+ * {@link #writeChars(String s)} or another write method instead.
+ */
+ @Deprecated
+ @Override public void writeBytes(String s) throws IOException {
+ ((DataOutputStream) out).writeBytes(s);
+ }
+
+ /**
+ * Writes a char as specified by {@link DataOutputStream#writeChar(int)},
+ * except using little-endian byte order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeChar(int v) throws IOException {
+ writeShort(v);
+ }
+
+ /**
+ * Writes a {@code String} as specified by
+ * {@link DataOutputStream#writeChars(String)}, except each character is
+ * written using little-endian byte order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeChars(String s) throws IOException {
+ for (int i = 0; i < s.length(); i++) {
+ writeChar(s.charAt(i));
+ }
+ }
+
+ /**
+ * Writes a {@code double} as specified by
+ * {@link DataOutputStream#writeDouble(double)}, except using little-endian
+ * byte order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeDouble(double v) throws IOException {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ /**
+ * Writes a {@code float} as specified by
+ * {@link DataOutputStream#writeFloat(float)}, except using little-endian byte
+ * order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeFloat(float v) throws IOException {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ /**
+ * Writes an {@code int} as specified by
+ * {@link DataOutputStream#writeInt(int)}, except using little-endian byte
+ * order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeInt(int v) throws IOException {
+ out.write(0xFF & v);
+ out.write(0xFF & (v >> 8));
+ out.write(0xFF & (v >> 16));
+ out.write(0xFF & (v >> 24));
+ }
+
+ /**
+ * Writes a {@code long} as specified by
+ * {@link DataOutputStream#writeLong(long)}, except using little-endian byte
+ * order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeLong(long v) throws IOException {
+ byte[] bytes = Longs.toByteArray(Long.reverseBytes(v));
+ write(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Writes a {@code short} as specified by
+ * {@link DataOutputStream#writeShort(int)}, except using little-endian byte
+ * order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeShort(int v) throws IOException {
+ out.write(0xFF & v);
+ out.write(0xFF & (v >> 8));
+ }
+
+ @Override public void writeUTF(String str) throws IOException {
+ ((DataOutputStream) out).writeUTF(str);
+ }
+}
diff --git a/guava/src/com/google/common/io/MultiInputStream.java b/guava/src/com/google/common/io/MultiInputStream.java
new file mode 100644
index 0000000..f8f1a0b
--- /dev/null
+++ b/guava/src/com/google/common/io/MultiInputStream.java
@@ -0,0 +1,115 @@
+/*
+ * 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.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+
+/**
+ * An {@link InputStream} that concatenates multiple substreams. At most
+ * one stream will be open at a time.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+final class MultiInputStream extends InputStream {
+
+ private Iterator<? extends InputSupplier<? extends InputStream>> it;
+ private InputStream in;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param it an iterator of I/O suppliers that will provide each substream
+ */
+ public MultiInputStream(
+ Iterator<? extends InputSupplier<? extends InputStream>> it)
+ throws IOException {
+ this.it = it;
+ advance();
+ }
+
+ @Override public void close() throws IOException {
+ if (in != null) {
+ try {
+ in.close();
+ } finally {
+ in = null;
+ }
+ }
+ }
+
+ /**
+ * Closes the current input stream and opens the next one, if any.
+ */
+ private void advance() throws IOException {
+ close();
+ if (it.hasNext()) {
+ in = it.next().getInput();
+ }
+ }
+
+ @Override public int available() throws IOException {
+ if (in == null) {
+ return 0;
+ }
+ return in.available();
+ }
+
+ @Override public boolean markSupported() {
+ return false;
+ }
+
+ @Override public int read() throws IOException {
+ if (in == null) {
+ return -1;
+ }
+ int result = in.read();
+ if (result == -1) {
+ advance();
+ return read();
+ }
+ return result;
+ }
+
+ @Override public int read(byte[] b, int off, int len) throws IOException {
+ if (in == null) {
+ return -1;
+ }
+ int result = in.read(b, off, len);
+ if (result == -1) {
+ advance();
+ return read(b, off, len);
+ }
+ return result;
+ }
+
+ @Override public long skip(long n) throws IOException {
+ if (in == null || n <= 0) {
+ return 0;
+ }
+ long result = in.skip(n);
+ if (result != 0) {
+ return result;
+ }
+ if (read() == -1) {
+ return 0;
+ }
+ return 1 + in.skip(n - 1);
+ }
+}
diff --git a/guava/src/com/google/common/io/MultiReader.java b/guava/src/com/google/common/io/MultiReader.java
new file mode 100644
index 0000000..6757a26
--- /dev/null
+++ b/guava/src/com/google/common/io/MultiReader.java
@@ -0,0 +1,90 @@
+/*
+ * 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.io;
+
+import com.google.common.base.Preconditions;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Iterator;
+
+/**
+ * A {@link Reader} that concatenates multiple readers.
+ *
+ * @author Bin Zhu
+ * @since 1.0
+ */
+class MultiReader extends Reader {
+ private final Iterator<? extends InputSupplier<? extends Reader>> it;
+ private Reader current;
+
+ MultiReader(Iterator<? extends InputSupplier<? extends Reader>> readers)
+ throws IOException {
+ this.it = readers;
+ advance();
+ }
+
+ /**
+ * Closes the current reader and opens the next one, if any.
+ */
+ private void advance() throws IOException {
+ close();
+ if (it.hasNext()) {
+ current = it.next().getInput();
+ }
+ }
+
+ @Override public int read(char cbuf[], int off, int len) throws IOException {
+ if (current == null) {
+ return -1;
+ }
+ int result = current.read(cbuf, off, len);
+ if (result == -1) {
+ advance();
+ return read(cbuf, off, len);
+ }
+ return result;
+ }
+
+ @Override public long skip(long n) throws IOException {
+ Preconditions.checkArgument(n >= 0, "n is negative");
+ if (n > 0) {
+ while (current != null) {
+ long result = current.skip(n);
+ if (result > 0) {
+ return result;
+ }
+ advance();
+ }
+ }
+ return 0;
+ }
+
+ @Override public boolean ready() throws IOException {
+ return (current != null) && current.ready();
+ }
+
+ @Override public void close() throws IOException {
+ if (current != null) {
+ try {
+ current.close();
+ } finally {
+ current = null;
+ }
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/NullOutputStream.java b/guava/src/com/google/common/io/NullOutputStream.java
new file mode 100644
index 0000000..1c1e98e
--- /dev/null
+++ b/guava/src/com/google/common/io/NullOutputStream.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2004 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 com.google.common.annotations.Beta;
+
+import java.io.OutputStream;
+
+/**
+ * Implementation of {@link OutputStream} that simply discards written bytes.
+ *
+ * @author Spencer Kimball
+ * @since 1.0
+ */
+@Beta
+public final class NullOutputStream extends OutputStream {
+ /** Discards the specified byte. */
+ @Override public void write(int b) {
+ }
+
+ /** Discards the specified byte array. */
+ @Override public void write(byte[] b, int off, int len) {
+ }
+}
diff --git a/guava/src/com/google/common/io/OutputSupplier.java b/guava/src/com/google/common/io/OutputSupplier.java
new file mode 100644
index 0000000..185082c
--- /dev/null
+++ b/guava/src/com/google/common/io/OutputSupplier.java
@@ -0,0 +1,40 @@
+/*
+ * 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.io;
+
+import java.io.IOException;
+
+/**
+ * A factory for writable streams of bytes or characters.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+public interface OutputSupplier<T> {
+
+ /**
+ * Returns an object that encapsulates a writable resource.
+ * <p>
+ * Like {@link Iterable#iterator}, this method may be called repeatedly to
+ * get independent channels to the same underlying resource.
+ * <p>
+ * Where the channel maintains a position within the resource, moving that
+ * cursor within one channel should not affect the starting position of
+ * channels returned by other calls.
+ */
+ T getOutput() throws IOException;
+}
diff --git a/guava/src/com/google/common/io/PatternFilenameFilter.java b/guava/src/com/google/common/io/PatternFilenameFilter.java
new file mode 100644
index 0000000..2859277
--- /dev/null
+++ b/guava/src/com/google/common/io/PatternFilenameFilter.java
@@ -0,0 +1,62 @@
+/*
+ * 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.io;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.regex.Pattern;
+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.
+ *
+ * @author Apple Chow
+ * @since 1.0
+ */
+@Beta
+public final class PatternFilenameFilter implements FilenameFilter {
+
+ private final Pattern pattern;
+
+ /**
+ * Constructs a pattern file name filter object.
+ * @param patternStr the pattern string on which to filter file names
+ *
+ * @throws PatternSyntaxException if pattern compilation fails (runtime)
+ */
+ public PatternFilenameFilter(String patternStr) {
+ this(Pattern.compile(patternStr));
+ }
+
+ /**
+ * Constructs a pattern file name filter object.
+ * @param pattern the pattern on which to filter file names
+ */
+ public PatternFilenameFilter(Pattern pattern) {
+ this.pattern = Preconditions.checkNotNull(pattern);
+ }
+
+ @Override public boolean accept(@Nullable File dir, String fileName) {
+ return pattern.matcher(fileName).matches();
+ }
+}
diff --git a/guava/src/com/google/common/io/Resources.java b/guava/src/com/google/common/io/Resources.java
new file mode 100644
index 0000000..1bb8067
--- /dev/null
+++ b/guava/src/com/google/common/io/Resources.java
@@ -0,0 +1,173 @@
+/*
+ * 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.io;
+
+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;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.List;
+
+/**
+ * Provides utility methods for working with resources in the classpath.
+ * Note that even though these methods use {@link URL} parameters, they
+ * are usually not appropriate for HTTP or other non-classpath resources.
+ *
+ * <p>All method parameters must be non-null unless documented otherwise.
+ *
+ * @author Chris Nokleberg
+ * @author Ben Yu
+ * @since 1.0
+ */
+@Beta
+public final class Resources {
+ private Resources() {}
+
+ /**
+ * Returns a factory that will supply instances of {@link InputStream} that
+ * read from the given URL.
+ *
+ * @param url the URL to read from
+ * @return the factory
+ */
+ public static InputSupplier<InputStream> newInputStreamSupplier(
+ final URL url) {
+ checkNotNull(url);
+ return new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return url.openStream();
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of
+ * {@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
+ * @return the factory
+ */
+ public static InputSupplier<InputStreamReader> newReaderSupplier(
+ URL url, Charset charset) {
+ return CharStreams.newReaderSupplier(newInputStreamSupplier(url), charset);
+ }
+
+ /**
+ * Reads all bytes from a URL into a byte array.
+ *
+ * @param url the URL to read from
+ * @return a byte array containing all the bytes from the URL
+ * @throws IOException if an I/O error occurs
+ */
+ public static byte[] toByteArray(URL url) throws IOException {
+ return ByteStreams.toByteArray(newInputStreamSupplier(url));
+ }
+
+ /**
+ * Reads all characters from a URL into a {@link String}, 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
+ * @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 CharStreams.toString(newReaderSupplier(url, charset));
+ }
+
+ /**
+ * Streams lines from a URL, stopping when our callback returns false, or we
+ * 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 callback the 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(URL url, Charset charset,
+ LineProcessor<T> callback) throws IOException {
+ return CharStreams.readLines(newReaderSupplier(url, charset), callback);
+ }
+
+ /**
+ * Reads all of the lines from a URL. The lines do not include
+ * line-termination characters, but do include other leading and trailing
+ * 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
+ * @return a mutable {@link List} containing all the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static List<String> readLines(URL url, Charset charset)
+ throws IOException {
+ return CharStreams.readLines(newReaderSupplier(url, charset));
+ }
+
+ /**
+ * Copies all bytes from a URL to an output stream.
+ *
+ * @param from the URL to read from
+ * @param to the output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(URL from, OutputStream to) throws IOException {
+ ByteStreams.copy(newInputStreamSupplier(from), to);
+ }
+
+ /**
+ * Returns a {@code URL} pointing to {@code resourceName} if the resource is
+ * found in the class path. {@code Resources.class.getClassLoader()} is used
+ * to locate the resource.
+ *
+ * @throws IllegalArgumentException if resource is not found
+ */
+ public static URL getResource(String resourceName) {
+ URL url = Resources.class.getClassLoader().getResource(resourceName);
+ checkArgument(url != null, "resource %s not found.", resourceName);
+ return url;
+ }
+
+ /**
+ * Returns a {@code URL} pointing to {@code resourceName} that is relative to
+ * {@code contextClass}, if the resource is found in the class path.
+ *
+ * @throws IllegalArgumentException if resource is not found
+ */
+ public static URL getResource(Class<?> contextClass, String resourceName) {
+ URL url = contextClass.getResource(resourceName);
+ checkArgument(url != null, "resource %s relative to %s not found.",
+ resourceName, contextClass.getName());
+ return url;
+ }
+}
diff --git a/guava/src/com/google/common/io/package-info.java b/guava/src/com/google/common/io/package-info.java
new file mode 100644
index 0000000..f5f83ad
--- /dev/null
+++ b/guava/src/com/google/common/io/package-info.java
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains utility methods and classes for working with Java I/O,
+ * for example input streams, output streams, readers, writers, and files.
+ *
+ * <p>Many of the methods are based on the
+ * {@link com.google.common.io.InputSupplier} and
+ * {@link com.google.common.io.OutputSupplier} interfaces. They are used as
+ * factories for I/O objects that might throw {@link java.io.IOException} when
+ * being created. The advantage of using a factory is that the helper methods in
+ * this package can take care of closing the resource properly, even if an
+ * exception is thrown. The {@link com.google.common.io.ByteStreams},
+ * {@link com.google.common.io.CharStreams}, and
+ * {@link com.google.common.io.Files} classes all have static helper methods to
+ * create new factories and to work with them.
+ *
+ * <p>This package is a part of the open-source
+ * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
+ *
+ * @author Chris Nokleberg
+ */
+@ParametersAreNonnullByDefault
+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
new file mode 100644
index 0000000..1645627
--- /dev/null
+++ b/guava/src/com/google/common/math/BigIntegerMath.java
@@ -0,0 +1,451 @@
+/*
+ * 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.math;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+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.math.RoundingMode.CEILING;
+import static java.math.RoundingMode.FLOOR;
+import static java.math.RoundingMode.HALF_EVEN;
+
+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 java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class for arithmetic on values of type {@code BigInteger}.
+ *
+ * <p>The implementations of many methods in this class are based on material from Henry S. Warren,
+ * Jr.'s <i>Hacker's Delight</i>, (Addison Wesley, 2002).
+ *
+ * <p>Similar functionality for {@code int} and for {@code long} can be found in
+ * {@link IntMath} and {@link LongMath} respectively.
+ *
+ * @author Louis Wasserman
+ * @since 11.0
+ */
+@Beta
+@GwtCompatible(emulated = true)
+public final class BigIntegerMath {
+ /**
+ * Returns {@code true} if {@code x} represents a power of two.
+ */
+ public static boolean isPowerOfTwo(BigInteger x) {
+ checkNotNull(x);
+ return x.signum() > 0 && x.getLowestSetBit() == x.bitLength() - 1;
+ }
+
+ /**
+ * Returns the base-2 logarithm of {@code x}, rounded according to the specified rounding mode.
+ *
+ * @throws IllegalArgumentException if {@code x <= 0}
+ * @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
+ * is not a power of two
+ */
+ @SuppressWarnings("fallthrough")
+ public static int log2(BigInteger x, RoundingMode mode) {
+ checkPositive("x", checkNotNull(x));
+ int logFloor = x.bitLength() - 1;
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(isPowerOfTwo(x)); // fall through
+ case DOWN:
+ case FLOOR:
+ return logFloor;
+
+ case UP:
+ case CEILING:
+ return isPowerOfTwo(x) ? logFloor : logFloor + 1;
+
+ case HALF_DOWN:
+ case HALF_UP:
+ case HALF_EVEN:
+ if (logFloor < SQRT2_PRECOMPUTE_THRESHOLD) {
+ BigInteger halfPower = SQRT2_PRECOMPUTED_BITS.shiftRight(
+ SQRT2_PRECOMPUTE_THRESHOLD - logFloor);
+ if (x.compareTo(halfPower) <= 0) {
+ return logFloor;
+ } else {
+ return logFloor + 1;
+ }
+ }
+ /*
+ * Since sqrt(2) is irrational, log2(x) - logFloor cannot be exactly 0.5
+ *
+ * To determine which side of logFloor.5 the logarithm is, we compare x^2 to 2^(2 *
+ * logFloor + 1).
+ */
+ BigInteger x2 = x.pow(2);
+ int logX2Floor = x2.bitLength() - 1;
+ return (logX2Floor < 2 * logFloor + 1) ? logFloor : logFloor + 1;
+
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /*
+ * The maximum number of bits in a square root for which we'll precompute an explicit half power
+ * of two. This can be any value, but higher values incur more class load time and linearly
+ * increasing memory consumption.
+ */
+ @VisibleForTesting static final int SQRT2_PRECOMPUTE_THRESHOLD = 256;
+
+ @VisibleForTesting static final BigInteger SQRT2_PRECOMPUTED_BITS =
+ new BigInteger("16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667322a", 16);
+
+ /**
+ * Returns the base-10 logarithm of {@code x}, rounded according to the specified rounding mode.
+ *
+ * @throws IllegalArgumentException if {@code x <= 0}
+ * @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);
+ if (fitsInLong(x)) {
+ 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);
+ }
+ }
+
+ int floorLog = approxLog10;
+ BigInteger floorPow = approxPow;
+ int floorCmp = approxCmp;
+
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(floorCmp == 0);
+ // fall through
+ case FLOOR:
+ case DOWN:
+ return floorLog;
+
+ case CEILING:
+ case UP:
+ return floorPow.equals(x) ? floorLog : floorLog + 1;
+
+ case HALF_DOWN:
+ case HALF_UP:
+ case HALF_EVEN:
+ // Since sqrt(10) is irrational, log10(x) - floorLog can never be exactly 0.5
+ BigInteger x2 = x.pow(2);
+ BigInteger halfPowerSquared = floorPow.pow(2).multiply(BigInteger.TEN);
+ return (x2.compareTo(halfPowerSquared) <= 0) ? floorLog : floorLog + 1;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ 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.
+ *
+ * @throws IllegalArgumentException if {@code x < 0}
+ * @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);
+ if (fitsInLong(x)) {
+ return BigInteger.valueOf(LongMath.sqrt(x.longValue(), mode));
+ }
+ BigInteger sqrtFloor = sqrtFloor(x);
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(sqrtFloor.pow(2).equals(x)); // fall through
+ case FLOOR:
+ case DOWN:
+ return sqrtFloor;
+ case CEILING:
+ case UP:
+ return sqrtFloor.pow(2).equals(x) ? sqrtFloor : sqrtFloor.add(BigInteger.ONE);
+ case HALF_DOWN:
+ case HALF_UP:
+ case HALF_EVEN:
+ BigInteger halfSquare = sqrtFloor.pow(2).add(sqrtFloor);
+ /*
+ * We wish to test whether or not x <= (sqrtFloor + 0.5)^2 = halfSquare + 0.25. Since both
+ * x and halfSquare are integers, this is equivalent to testing whether or not x <=
+ * halfSquare.
+ */
+ return (halfSquare.compareTo(x) >= 0) ? sqrtFloor : sqrtFloor.add(BigInteger.ONE);
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ @GwtIncompatible("TODO")
+ private static BigInteger sqrtFloor(BigInteger x) {
+ /*
+ * Adapted from Hacker's Delight, Figure 11-1.
+ *
+ * Using DoubleUtils.bigToDouble, getting a double approximation of x is extremely fast, and
+ * then we can get a double approximation of the square root. Then, we iteratively improve this
+ * guess with an application of Newton's method, which sets guess := (guess + (x / guess)) / 2.
+ * This iteration has the following two properties:
+ *
+ * a) every iteration (except potentially the first) has guess >= floor(sqrt(x)). This is
+ * because guess' is the arithmetic mean of guess and x / guess, sqrt(x) is the geometric mean,
+ * and the arithmetic mean is always higher than the geometric mean.
+ *
+ * b) this iteration converges to floor(sqrt(x)). In fact, the number of correct digits doubles
+ * with each iteration, so this algorithm takes O(log(digits)) iterations.
+ *
+ * We start out with a double-precision approximation, which may be higher or lower than the
+ * true value. Therefore, we perform at least one Newton iteration to get a guess that's
+ * definitely >= floor(sqrt(x)), and then continue the iteration until we reach a fixed point.
+ */
+ BigInteger sqrt0;
+ int log2 = log2(x, FLOOR);
+ if(log2 < Double.MAX_EXPONENT) {
+ sqrt0 = sqrtApproxWithDoubles(x);
+ } else {
+ int shift = (log2 - DoubleUtils.SIGNIFICAND_BITS) & ~1; // even!
+ /*
+ * We have that x / 2^shift < 2^54. Our initial approximation to sqrtFloor(x) will be
+ * 2^(shift/2) * sqrtApproxWithDoubles(x / 2^shift).
+ */
+ sqrt0 = sqrtApproxWithDoubles(x.shiftRight(shift)).shiftLeft(shift >> 1);
+ }
+ BigInteger sqrt1 = sqrt0.add(x.divide(sqrt0)).shiftRight(1);
+ if (sqrt0.equals(sqrt1)) {
+ return sqrt0;
+ }
+ do {
+ sqrt0 = sqrt1;
+ sqrt1 = sqrt0.add(x.divide(sqrt0)).shiftRight(1);
+ } while (sqrt1.compareTo(sqrt0) < 0);
+ return sqrt0;
+ }
+
+ @GwtIncompatible("TODO")
+ private static BigInteger sqrtApproxWithDoubles(BigInteger x) {
+ return DoubleMath.roundToBigInteger(Math.sqrt(DoubleUtils.bigToDouble(x)), HALF_EVEN);
+ }
+
+ /**
+ * Returns the result of dividing {@code p} by {@code q}, rounding using the specified
+ * {@code RoundingMode}.
+ *
+ * @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);
+ return pDec.divide(qDec, 0, mode).toBigIntegerExact();
+ }
+
+ /**
+ * Returns {@code n!}, that is, the product of the first {@code n} positive
+ * integers, or {@code 1} if {@code n == 0}.
+ *
+ * <p><b>Warning</b>: the result takes <i>O(n log n)</i> space, so use cautiously.
+ *
+ * <p>This uses an efficient binary recursive algorithm to compute the factorial
+ * with balanced multiplies. It also removes all the 2s from the intermediate
+ * products (shifting them back in at the end).
+ *
+ * @throws IllegalArgumentException if {@code n < 0}
+ */
+ public static BigInteger factorial(int n) {
+ 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]);
+ }
+
+ // Pre-allocate space for our list of intermediate BigIntegers.
+ int approxSize = IntMath.divide(n * IntMath.log2(n, CEILING), Long.SIZE, CEILING);
+ 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];
+ // Strip off 2s from this value.
+ int shift = Long.numberOfTrailingZeros(product);
+ product >>= shift;
+
+ // Use floor(log2(num)) + 1 to prevent overflow of multiplication.
+ int productBits = LongMath.log2(product, FLOOR) + 1;
+ int bits = LongMath.log2(startingNumber, FLOOR) + 1;
+ // Check for the next power of two boundary, to save us a CLZ operation.
+ int nextPowerOfTwo = 1 << (bits - 1);
+
+ // Iteratively multiply the longs as big as they can go.
+ for (long num = startingNumber; num <= n; num++) {
+ // Check to see if the floor(log2(num)) + 1 has changed.
+ if ((num & nextPowerOfTwo) != 0) {
+ nextPowerOfTwo <<= 1;
+ bits++;
+ }
+ // Get rid of the 2s in num.
+ int tz = Long.numberOfTrailingZeros(num);
+ long normalizedNum = num >> tz;
+ shift += tz;
+ // Adjust floor(log2(num)) + 1.
+ int normalizedBits = bits - tz;
+ // If it won't fit in a long, then we store off the intermediate product.
+ if (normalizedBits + productBits >= Long.SIZE) {
+ bignums.add(BigInteger.valueOf(product));
+ product = 1;
+ productBits = 0;
+ }
+ product *= normalizedNum;
+ productBits = LongMath.log2(product, FLOOR) + 1;
+ }
+ // Check for leftovers.
+ if (product > 1) {
+ bignums.add(BigInteger.valueOf(product));
+ }
+ // Efficiently multiply all the intermediate products together.
+ return listProduct(bignums).shiftLeft(shift);
+ }
+
+ static BigInteger listProduct(List<BigInteger> nums) {
+ return listProduct(nums, 0, nums.size());
+ }
+
+ static BigInteger listProduct(List<BigInteger> nums, int start, int end) {
+ switch (end - start) {
+ case 0:
+ return BigInteger.ONE;
+ case 1:
+ return nums.get(start);
+ case 2:
+ return nums.get(start).multiply(nums.get(start + 1));
+ case 3:
+ return nums.get(start).multiply(nums.get(start + 1)).multiply(nums.get(start + 2));
+ default:
+ // Otherwise, split the list in half and recursively do this.
+ int m = (end + start) >>> 1;
+ return listProduct(nums, start, m).multiply(listProduct(nums, m, end));
+ }
+ }
+
+ /**
+ * Returns {@code n} choose {@code k}, also known as the binomial coefficient of {@code n} and
+ * {@code k}, that is, {@code n! / (k! (n - k)!)}.
+ *
+ * <p><b>Warning</b>: the result can take as much as <i>O(k log n)</i> space.
+ *
+ * @throws IllegalArgumentException if {@code n < 0}, {@code k < 0}, or {@code k > n}
+ */
+ public static BigInteger binomial(int n, int k) {
+ checkNonNegative("n", n);
+ checkNonNegative("k", k);
+ checkArgument(k <= n, "k (%s) > n (%s)", k, n);
+ if (k > (n >> 1)) {
+ k = n - 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;
+ }
+ }
+ return accum
+ .multiply(BigInteger.valueOf(numeratorAccum))
+ .divide(BigInteger.valueOf(denominatorAccum));
+ }
+
+ // Returns true if BigInteger.valueOf(x.longValue()).equals(x).
+ @GwtIncompatible("TODO")
+ static boolean fitsInLong(BigInteger x) {
+ return x.bitLength() <= Long.SIZE - 1;
+ }
+
+ private BigIntegerMath() {}
+}
diff --git a/guava/src/com/google/common/math/DoubleMath.java b/guava/src/com/google/common/math/DoubleMath.java
new file mode 100644
index 0000000..95e8fb4
--- /dev/null
+++ b/guava/src/com/google/common/math/DoubleMath.java
@@ -0,0 +1,379 @@
+/*
+ * 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.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.getSignificand;
+import static com.google.common.math.DoubleUtils.isFinite;
+import static com.google.common.math.DoubleUtils.isNormal;
+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.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.primitives.Booleans;
+
+import java.math.BigInteger;
+import java.math.RoundingMode;
+
+/**
+ * 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
+ * as rounding x according to the specified mode.
+ */
+ static double roundIntermediate(double x, RoundingMode mode) {
+ if (!isFinite(x)) {
+ throw new ArithmeticException("input is infinite or NaN");
+ }
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(isMathematicalInteger(x));
+ return x;
+
+ case FLOOR:
+ if (x >= 0.0 || isMathematicalInteger(x)) {
+ return x;
+ } else {
+ return x - 1.0;
+ }
+
+ case CEILING:
+ if (x <= 0.0 || isMathematicalInteger(x)) {
+ return x;
+ } else {
+ return x + 1.0;
+ }
+
+ case DOWN:
+ return x;
+
+ case UP:
+ if (isMathematicalInteger(x)) {
+ return x;
+ } else {
+ return x + Math.copySign(1.0, x);
+ }
+
+ case HALF_EVEN:
+ return rint(x);
+
+ case HALF_UP: {
+ double z = rint(x);
+ if (abs(x - z) == 0.5) {
+ return x + copySign(0.5, x);
+ } else {
+ return z;
+ }
+ }
+
+ case HALF_DOWN: {
+ double z = rint(x);
+ if (abs(x - z) == 0.5) {
+ return x;
+ } else {
+ return z;
+ }
+ }
+
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Returns the {@code int} value that is equal to {@code x} rounded with the specified rounding
+ * mode, if possible.
+ *
+ * @throws ArithmeticException if
+ * <ul>
+ * <li>{@code x} is infinite or NaN
+ * <li>{@code x}, after being rounded to a mathematical integer using the specified
+ * rounding mode, is either less than {@code Integer.MIN_VALUE} or greater than {@code
+ * Integer.MAX_VALUE}
+ * <li>{@code x} is not a mathematical integer and {@code mode} is
+ * {@link RoundingMode#UNNECESSARY}
+ * </ul>
+ */
+ public static int roundToInt(double x, RoundingMode mode) {
+ double z = roundIntermediate(x, mode);
+ checkInRange(z > MIN_INT_AS_DOUBLE - 1.0 & z < MAX_INT_AS_DOUBLE + 1.0);
+ return (int) z;
+ }
+
+ private static final double MIN_INT_AS_DOUBLE = -0x1p31;
+ private static final double MAX_INT_AS_DOUBLE = 0x1p31 - 1.0;
+
+ /**
+ * Returns the {@code long} value that is equal to {@code x} rounded with the specified rounding
+ * mode, if possible.
+ *
+ * @throws ArithmeticException if
+ * <ul>
+ * <li>{@code x} is infinite or NaN
+ * <li>{@code x}, after being rounded to a mathematical integer using the specified
+ * rounding mode, is either less than {@code Long.MIN_VALUE} or greater than {@code
+ * Long.MAX_VALUE}
+ * <li>{@code x} is not a mathematical integer and {@code mode} is
+ * {@link RoundingMode#UNNECESSARY}
+ * </ul>
+ */
+ public static long roundToLong(double x, RoundingMode mode) {
+ double z = roundIntermediate(x, mode);
+ checkInRange(MIN_LONG_AS_DOUBLE - z < 1.0 & z < MAX_LONG_AS_DOUBLE_PLUS_ONE);
+ return (long) z;
+ }
+
+ private static final double MIN_LONG_AS_DOUBLE = -0x1p63;
+ /*
+ * We cannot store Long.MAX_VALUE as a double without losing precision. Instead, we store
+ * Long.MAX_VALUE + 1 == -Long.MIN_VALUE, and then offset all comparisons by 1.
+ */
+ private static final double MAX_LONG_AS_DOUBLE_PLUS_ONE = 0x1p63;
+
+ /**
+ * Returns the {@code BigInteger} value that is equal to {@code x} rounded with the specified
+ * rounding mode, if possible.
+ *
+ * @throws ArithmeticException if
+ * <ul>
+ * <li>{@code x} is infinite or NaN
+ * <li>{@code x} is not a mathematical integer and {@code mode} is
+ * {@link RoundingMode#UNNECESSARY}
+ * </ul>
+ */
+ public static BigInteger roundToBigInteger(double x, RoundingMode mode) {
+ x = roundIntermediate(x, mode);
+ if (MIN_LONG_AS_DOUBLE - x < 1.0 & x < MAX_LONG_AS_DOUBLE_PLUS_ONE) {
+ return BigInteger.valueOf((long) x);
+ }
+ int exponent = getExponent(x);
+ long significand = getSignificand(x);
+ BigInteger result = BigInteger.valueOf(significand).shiftLeft(exponent - SIGNIFICAND_BITS);
+ return (x < 0) ? result.negate() : result;
+ }
+
+ /**
+ * Returns {@code true} if {@code x} is exactly equal to {@code 2^k} for some finite integer
+ * {@code k}.
+ */
+ public static boolean isPowerOfTwo(double x) {
+ return x > 0.0 && isFinite(x) && LongMath.isPowerOfTwo(getSignificand(x));
+ }
+
+ /**
+ * Returns the base 2 logarithm of a double value.
+ *
+ * <p>Special cases:
+ * <ul>
+ * <li>If {@code x} is NaN or less than zero, the result is NaN.
+ * <li>If {@code x} is positive infinity, the result is positive infinity.
+ * <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>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
+ }
+
+ private static final double LN_2 = log(2);
+
+ /**
+ * Returns the base 2 logarithm of a double value, rounded with the specified rounding mode to an
+ * {@code int}.
+ *
+ * <p>Regardless of the rounding mode, this is faster than {@code (int) log2(x)}.
+ *
+ * @throws IllegalArgumentException if {@code x <= 0.0}, {@code x} is NaN, or {@code x} is
+ * infinite
+ */
+ @SuppressWarnings("fallthrough")
+ public static int log2(double x, RoundingMode mode) {
+ checkArgument(x > 0.0 && isFinite(x), "x must be positive and finite");
+ int exponent = getExponent(x);
+ if (!isNormal(x)) {
+ return log2(x * IMPLICIT_BIT, mode) - SIGNIFICAND_BITS;
+ // Do the calculation on a normal value.
+ }
+ // x is positive, finite, and normal
+ boolean increment;
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(isPowerOfTwo(x));
+ // fall through
+ case FLOOR:
+ increment = false;
+ break;
+ case CEILING:
+ increment = !isPowerOfTwo(x);
+ break;
+ case DOWN:
+ increment = exponent < 0 & !isPowerOfTwo(x);
+ break;
+ case UP:
+ increment = exponent >= 0 & !isPowerOfTwo(x);
+ break;
+ case HALF_DOWN:
+ case HALF_EVEN:
+ case HALF_UP:
+ double xScaled = scaleNormalize(x);
+ // sqrt(2) is irrational, and the spec is relative to the "exact numerical result,"
+ // so log2(x) is never exactly exponent + 0.5.
+ increment = (xScaled * xScaled) > 2.0;
+ break;
+ default:
+ throw new AssertionError();
+ }
+ return increment ? exponent + 1 : exponent;
+ }
+
+ /**
+ * 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));
+ }
+
+ /**
+ * Returns {@code n!}, that is, the product of the first {@code n} positive
+ * integers, {@code 1} if {@code n == 0}, or e n!}, or
+ * {@link Double#POSITIVE_INFINITY} if {@code n! > Double.MAX_VALUE}.
+ *
+ * <p>The result is within 1 ulp of the true value.
+ *
+ * @throws IllegalArgumentException if {@code n < 0}
+ */
+ public static double factorial(int n) {
+ checkNonNegative("n", n);
+ if (n > MAX_FACTORIAL) {
+ return Double.POSITIVE_INFINITY;
+ } else {
+ // Multiplying the last (n & 0xf) values into their own accumulator gives a more accurate
+ // 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 * EVERY_SIXTEENTH_FACTORIAL[n >> 4];
+ }
+ }
+
+ @VisibleForTesting
+ static final int MAX_FACTORIAL = 170;
+
+ @VisibleForTesting
+ static final double[] EVERY_SIXTEENTH_FACTORIAL = {
+ 0x1.0p0,
+ 0x1.30777758p44,
+ 0x1.956ad0aae33a4p117,
+ 0x1.ee69a78d72cb6p202,
+ 0x1.fe478ee34844ap295,
+ 0x1.c619094edabffp394,
+ 0x1.3638dd7bd6347p498,
+ 0x1.7cac197cfe503p605,
+ 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
+ */
+ @Beta
+ 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
+ */
+ @Beta
+ 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
new file mode 100644
index 0000000..6cd94e3
--- /dev/null
+++ b/guava/src/com/google/common/math/DoubleUtils.java
@@ -0,0 +1,148 @@
+/*
+ * 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.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;
+
+/**
+ * Utilities for {@code double} primitives.
+ *
+ * @author Louis Wasserman
+ */
+final class DoubleUtils {
+ private DoubleUtils() {
+ }
+
+ static double nextDown(double d) {
+ return -Math.nextUp(-d);
+ }
+
+ // The mask for the significand, according to the {@link
+ // Double#doubleToRawLongBits(double)} spec.
+ static final long SIGNIFICAND_MASK = 0x000fffffffffffffL;
+
+ // The mask for the exponent, according to the {@link
+ // Double#doubleToRawLongBits(double)} spec.
+ static final long EXPONENT_MASK = 0x7ff0000000000000L;
+
+ // The mask for the sign, according to the {@link
+ // Double#doubleToRawLongBits(double)} spec.
+ static final long SIGN_MASK = 0x8000000000000000L;
+
+ static final int SIGNIFICAND_BITS = 52;
+
+ static final int EXPONENT_BIAS = 1023;
+
+ /**
+ * The implicit 1 bit that is omitted in significands of normal doubles.
+ */
+ static final long IMPLICIT_BIT = SIGNIFICAND_MASK + 1;
+
+ static long getSignificand(double d) {
+ checkArgument(isFinite(d), "not a normal value");
+ int exponent = getExponent(d);
+ long bits = doubleToRawLongBits(d);
+ bits &= SIGNIFICAND_MASK;
+ return (exponent == MIN_EXPONENT - 1)
+ ? bits << 1
+ : bits | IMPLICIT_BIT;
+ }
+
+ static boolean isFinite(double d) {
+ return getExponent(d) <= MAX_EXPONENT;
+ }
+
+ static boolean isNormal(double d) {
+ return getExponent(d) >= MIN_EXPONENT;
+ }
+
+ /*
+ * Returns x scaled by a power of 2 such that it is in the range [1, 2). Assumes x is positive,
+ * normal, and finite.
+ */
+ static double scaleNormalize(double x) {
+ long significand = doubleToRawLongBits(x) & SIGNIFICAND_MASK;
+ return longBitsToDouble(significand | ONE_BITS);
+ }
+
+ static double bigToDouble(BigInteger x) {
+ // This is an extremely fast implementation of BigInteger.doubleValue(). JDK patch pending.
+ BigInteger absX = x.abs();
+ int exponent = absX.bitLength() - 1;
+ // exponent == floor(log2(abs(x)))
+ if (exponent < Long.SIZE - 1) {
+ return x.longValue();
+ } else if (exponent > MAX_EXPONENT) {
+ return x.signum() * POSITIVE_INFINITY;
+ }
+
+ /*
+ * We need the top SIGNIFICAND_BITS + 1 bits, including the "implicit" one bit. To make
+ * rounding easier, we pick out the top SIGNIFICAND_BITS + 2 bits, so we have one to help us
+ * round up or down. twiceSignifFloor will contain the top SIGNIFICAND_BITS + 2 bits, and
+ * signifFloor the top SIGNIFICAND_BITS + 1.
+ *
+ * It helps to consider the real number signif = absX * 2^(SIGNIFICAND_BITS - exponent).
+ */
+ int shift = exponent - SIGNIFICAND_BITS - 1;
+ long twiceSignifFloor = absX.shiftRight(shift).longValue();
+ long signifFloor = twiceSignifFloor >> 1;
+ signifFloor &= SIGNIFICAND_MASK; // remove the implied bit
+
+ /*
+ * We round up if either the fractional part of signif is strictly greater than 0.5 (which is
+ * true if the 0.5 bit is set and any lower bit is set), or if the fractional part of signif is
+ * >= 0.5 and signifFloor is odd (which is true if both the 0.5 bit and the 1 bit are set).
+ */
+ boolean increment = (twiceSignifFloor & 1) != 0
+ && ((signifFloor & 1) != 0 || absX.getLowestSetBit() < shift);
+ long signifRounded = increment ? signifFloor + 1 : signifFloor;
+ long bits = (long) ((exponent + EXPONENT_BIAS)) << SIGNIFICAND_BITS;
+ bits += signifRounded;
+ /*
+ * If signifRounded == 2^53, we'd need to set all of the significand bits to zero and add 1 to
+ * the exponent. This is exactly the behavior we get from just adding signifRounded to bits
+ * directly. If the exponent is MAX_DOUBLE_EXPONENT, we round up (correctly) to
+ * 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;
+ }
+ }
+
+ private static final long ONE_BITS = doubleToRawLongBits(1.0);
+}
diff --git a/guava/src/com/google/common/math/IntMath.java b/guava/src/com/google/common/math/IntMath.java
new file mode 100644
index 0000000..5230211
--- /dev/null
+++ b/guava/src/com/google/common/math/IntMath.java
@@ -0,0 +1,551 @@
+/*
+ * 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.math;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.math.MathPreconditions.checkNoOverflow;
+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;
+
+import java.math.BigInteger;
+import java.math.RoundingMode;
+
+/**
+ * A class for arithmetic on values of type {@code int}. Where possible, methods are defined and
+ * named analogously to their {@code BigInteger} counterparts.
+ *
+ * <p>The implementations of many methods in this class are based on material from Henry S. Warren,
+ * Jr.'s <i>Hacker's Delight</i>, (Addison Wesley, 2002).
+ *
+ * <p>Similar functionality for {@code long} and for {@link BigInteger} can be found in
+ * {@link LongMath} and {@link BigIntegerMath} respectively. For other common operations on
+ * {@code int} values, see {@link com.google.common.primitives.Ints}.
+ *
+ * @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 &&, ||
+
+ /**
+ * Returns {@code true} if {@code x} represents a power of two.
+ *
+ * <p>This differs from {@code Integer.bitCount(x) == 1}, because
+ * {@code Integer.bitCount(Integer.MIN_VALUE) == 1}, but {@link Integer#MIN_VALUE} is not a power
+ * of two.
+ */
+ public static boolean isPowerOfTwo(int x) {
+ return x > 0 & (x & (x - 1)) == 0;
+ }
+
+ /**
+ * Returns the base-2 logarithm of {@code x}, rounded according to the specified rounding mode.
+ *
+ * @throws IllegalArgumentException if {@code x <= 0}
+ * @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
+ * is not a power of two
+ */
+ @SuppressWarnings("fallthrough")
+ public static int log2(int x, RoundingMode mode) {
+ checkPositive("x", x);
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(isPowerOfTwo(x));
+ // fall through
+ case DOWN:
+ case FLOOR:
+ return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(x);
+
+ case UP:
+ case CEILING:
+ return Integer.SIZE - Integer.numberOfLeadingZeros(x - 1);
+
+ case HALF_DOWN:
+ case HALF_UP:
+ case HALF_EVEN:
+ // Since sqrt(2) is irrational, log2(x) - logFloor cannot be exactly 0.5
+ int leadingZeros = Integer.numberOfLeadingZeros(x);
+ int cmp = MAX_POWER_OF_SQRT2_UNSIGNED >>> leadingZeros;
+ // floor(2^(logFloor + 0.5))
+ int logFloor = (Integer.SIZE - 1) - leadingZeros;
+ return (x <= cmp) ? logFloor : logFloor + 1;
+
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ /** The biggest half power of two that can fit in an unsigned int. */
+ @VisibleForTesting static final int MAX_POWER_OF_SQRT2_UNSIGNED = 0xB504F333;
+
+ /**
+ * Returns the base-10 logarithm of {@code x}, rounded according to the specified rounding mode.
+ *
+ * @throws IllegalArgumentException if {@code x <= 0}
+ * @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
+ * is not a power of ten
+ */
+ @GwtIncompatible("need BigIntegerMath to adequately test")
+ @SuppressWarnings("fallthrough")
+ public static int log10(int x, RoundingMode mode) {
+ checkPositive("x", x);
+ int logFloor = log10Floor(x);
+ int floorPow = POWERS_OF_10[logFloor];
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(x == floorPow);
+ // fall through
+ case FLOOR:
+ case DOWN:
+ return logFloor;
+ case CEILING:
+ case UP:
+ return (x == floorPow) ? logFloor : logFloor + 1;
+ case HALF_DOWN:
+ case HALF_UP:
+ case HALF_EVEN:
+ // sqrt(10) is irrational, so log10(x) - logFloor is never exactly 0.5
+ 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 = MAX_LOG10_FOR_LEADING_ZEROS[Integer.numberOfLeadingZeros(x)];
+ // y is the higher of the two possible values of floor(log10(x))
+
+ int sgn = (x - POWERS_OF_10[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;
+ }
+
+ // MAX_LOG10_FOR_LEADING_ZEROS[i] == floor(log10(2^(Long.SIZE - i)))
+ @VisibleForTesting static final byte[] MAX_LOG10_FOR_LEADING_ZEROS = {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};
+
+ // 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};
+
+ /**
+ * Returns {@code b} to the {@code k}th power. Even if the result overflows, it will be equal to
+ * {@code BigInteger.valueOf(b).pow(k).intValue()}. This implementation runs in {@code O(log k)}
+ * time.
+ *
+ * <p>Compare {@link #checkedPow}, which throws an {@link ArithmeticException} upon overflow.
+ *
+ * @throws IllegalArgumentException if {@code k < 0}
+ */
+ @GwtIncompatible("failing tests")
+ public static int pow(int b, int k) {
+ checkNonNegative("exponent", k);
+ switch (b) {
+ case 0:
+ return (k == 0) ? 1 : 0;
+ case 1:
+ return 1;
+ case (-1):
+ return ((k & 1) == 0) ? 1 : -1;
+ case 2:
+ return (k < Integer.SIZE) ? (1 << k) : 0;
+ case (-2):
+ if (k < Integer.SIZE) {
+ return ((k & 1) == 0) ? (1 << k) : -(1 << k);
+ } else {
+ return 0;
+ }
+ }
+ for (int accum = 1;; k >>= 1) {
+ switch (k) {
+ case 0:
+ return accum;
+ case 1:
+ return b * accum;
+ default:
+ accum *= ((k & 1) == 0) ? 1 : b;
+ b *= b;
+ }
+ }
+ }
+
+ /**
+ * Returns the square root of {@code x}, rounded with the specified rounding mode.
+ *
+ * @throws IllegalArgumentException if {@code x < 0}
+ * @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and
+ * {@code sqrt(x)} is not an integer
+ */
+ @GwtIncompatible("need BigIntegerMath to adequately test")
+ @SuppressWarnings("fallthrough")
+ public static int sqrt(int x, RoundingMode mode) {
+ checkNonNegative("x", x);
+ int sqrtFloor = sqrtFloor(x);
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(sqrtFloor * sqrtFloor == x); // fall through
+ case FLOOR:
+ case DOWN:
+ return sqrtFloor;
+ case CEILING:
+ case UP:
+ return (sqrtFloor * sqrtFloor == x) ? sqrtFloor : sqrtFloor + 1;
+ case HALF_DOWN:
+ case HALF_UP:
+ case HALF_EVEN:
+ int halfSquare = sqrtFloor * sqrtFloor + sqrtFloor;
+ /*
+ * We wish to test whether or not x <= (sqrtFloor + 0.5)^2 = halfSquare + 0.25.
+ * Since both x and halfSquare are integers, this is equivalent to testing whether or not
+ * x <= halfSquare. (We have to deal with overflow, though.)
+ */
+ return (x <= halfSquare | halfSquare < 0) ? sqrtFloor : sqrtFloor + 1;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ private static int sqrtFloor(int x) {
+ // There is no loss of precision in converting an int to a double, according to
+ // http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.2
+ return (int) Math.sqrt(x);
+ }
+
+ /**
+ * Returns the result of dividing {@code p} by {@code q}, rounding using the specified
+ * {@code RoundingMode}.
+ *
+ * @throws ArithmeticException if {@code q == 0}, or if {@code mode == UNNECESSARY} and {@code a}
+ * is not an integer multiple of {@code b}
+ */
+ @SuppressWarnings("fallthrough")
+ public static int divide(int p, int q, RoundingMode mode) {
+ checkNotNull(mode);
+ if (q == 0) {
+ throw new ArithmeticException("/ by zero"); // for GWT
+ }
+ int div = p / q;
+ int rem = p - q * div; // equal to p % q
+
+ if (rem == 0) {
+ return div;
+ }
+
+ /*
+ * Normal Java division rounds towards 0, consistently with RoundingMode.DOWN. We just have to
+ * deal with the cases where rounding towards 0 is wrong, which typically depends on the sign of
+ * p / q.
+ *
+ * signum is 1 if p and q are both nonnegative or both negative, and -1 otherwise.
+ */
+ int signum = 1 | ((p ^ q) >> (Integer.SIZE - 1));
+ boolean increment;
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(rem == 0);
+ // fall through
+ case DOWN:
+ increment = false;
+ break;
+ case UP:
+ increment = true;
+ break;
+ case CEILING:
+ increment = signum > 0;
+ break;
+ case FLOOR:
+ increment = signum < 0;
+ break;
+ case HALF_EVEN:
+ case HALF_DOWN:
+ case HALF_UP:
+ int absRem = abs(rem);
+ int cmpRemToHalfDivisor = absRem - (abs(q) - absRem);
+ // subtracting two nonnegative ints can't overflow
+ // cmpRemToHalfDivisor has the same sign as compare(abs(rem), abs(q) / 2).
+ if (cmpRemToHalfDivisor == 0) { // exactly on the half mark
+ increment = (mode == HALF_UP || (mode == HALF_EVEN & (div & 1) != 0));
+ } else {
+ increment = cmpRemToHalfDivisor > 0; // closer to the UP value
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+ return increment ? div + signum : div;
+ }
+
+ /**
+ * Returns {@code x mod m}. This differs from {@code x % m} in that it always returns a
+ * non-negative result.
+ *
+ * <p>For example:<pre> {@code
+ *
+ * mod(7, 4) == 3
+ * mod(-7, 4) == 1
+ * mod(-1, 4) == 3
+ * mod(-8, 4) == 0
+ * mod(8, 4) == 0}</pre>
+ *
+ * @throws ArithmeticException if {@code m <= 0}
+ */
+ public static int mod(int x, int m) {
+ if (m <= 0) {
+ throw new ArithmeticException("Modulus " + m + " must be > 0");
+ }
+ int result = x % m;
+ return (result >= 0) ? result : result + m;
+ }
+
+ /**
+ * Returns the greatest common divisor of {@code a, b}. Returns {@code 0} if
+ * {@code a == 0 && b == 0}.
+ *
+ * @throws IllegalArgumentException if {@code a < 0} or {@code b < 0}
+ */
+ public static int gcd(int a, int b) {
+ /*
+ * The reason we require both arguments to be >= 0 is because otherwise, what do you return on
+ * gcd(0, Integer.MIN_VALUE)? BigInteger.gcd would return positive 2^31, but positive 2^31
+ * isn't an int.
+ */
+ 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
+ }
+ return a << min(aTwos, bTwos);
+ }
+
+ /**
+ * Returns the sum of {@code a} and {@code b}, provided it does not overflow.
+ *
+ * @throws ArithmeticException if {@code a + b} overflows in signed {@code int} arithmetic
+ */
+ public static int checkedAdd(int a, int b) {
+ long result = (long) a + b;
+ checkNoOverflow(result == (int) result);
+ return (int) result;
+ }
+
+ /**
+ * Returns the difference of {@code a} and {@code b}, provided it does not overflow.
+ *
+ * @throws ArithmeticException if {@code a - b} overflows in signed {@code int} arithmetic
+ */
+ public static int checkedSubtract(int a, int b) {
+ long result = (long) a - b;
+ checkNoOverflow(result == (int) result);
+ return (int) result;
+ }
+
+ /**
+ * Returns the product of {@code a} and {@code b}, provided it does not overflow.
+ *
+ * @throws ArithmeticException if {@code a * b} overflows in signed {@code int} arithmetic
+ */
+ public static int checkedMultiply(int a, int b) {
+ long result = (long) a * b;
+ checkNoOverflow(result == (int) result);
+ return (int) result;
+ }
+
+ /**
+ * Returns the {@code b} to the {@code k}th power, provided it does not overflow.
+ *
+ * <p>{@link #pow} may be faster, but does not check for overflow.
+ *
+ * @throws ArithmeticException if {@code b} to the {@code k}th power overflows in signed
+ * {@code int} arithmetic
+ */
+ public static int checkedPow(int b, int k) {
+ checkNonNegative("exponent", k);
+ switch (b) {
+ case 0:
+ return (k == 0) ? 1 : 0;
+ case 1:
+ return 1;
+ case (-1):
+ return ((k & 1) == 0) ? 1 : -1;
+ case 2:
+ checkNoOverflow(k < Integer.SIZE - 1);
+ return 1 << k;
+ case (-2):
+ checkNoOverflow(k < Integer.SIZE);
+ return ((k & 1) == 0) ? 1 << k : -1 << k;
+ }
+ int accum = 1;
+ while (true) {
+ switch (k) {
+ case 0:
+ return accum;
+ case 1:
+ return checkedMultiply(accum, b);
+ default:
+ if ((k & 1) != 0) {
+ accum = checkedMultiply(accum, b);
+ }
+ k >>= 1;
+ if (k > 0) {
+ checkNoOverflow(-FLOOR_SQRT_MAX_INT <= b & b <= FLOOR_SQRT_MAX_INT);
+ b *= b;
+ }
+ }
+ }
+ }
+
+ @VisibleForTesting static final int FLOOR_SQRT_MAX_INT = 46340;
+
+ /**
+ * Returns {@code n!}, that is, the product of the first {@code n} positive
+ * integers, {@code 1} if {@code n == 0}, or {@link Integer#MAX_VALUE} if the
+ * result does not fit in a {@code int}.
+ *
+ * @throws IllegalArgumentException if {@code n < 0}
+ */
+ public static int factorial(int n) {
+ checkNonNegative("n", n);
+ return (n < FACTORIALS.length) ? FACTORIALS[n] : Integer.MAX_VALUE;
+ }
+
+ static final int[] FACTORIALS = {
+ 1,
+ 1,
+ 1 * 2,
+ 1 * 2 * 3,
+ 1 * 2 * 3 * 4,
+ 1 * 2 * 3 * 4 * 5,
+ 1 * 2 * 3 * 4 * 5 * 6,
+ 1 * 2 * 3 * 4 * 5 * 6 * 7,
+ 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8,
+ 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9,
+ 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10,
+ 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11,
+ 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12};
+
+ /**
+ * Returns {@code n} choose {@code k}, also known as the binomial coefficient of {@code n} and
+ * {@code k}, or {@link Integer#MAX_VALUE} if the result does not fit in an {@code int}.
+ *
+ * @throws IllegalArgumentException if {@code n < 0}, {@code k < 0} or {@code k > n}
+ */
+ @GwtIncompatible("need BigIntegerMath to adequately test")
+ public static int binomial(int n, int k) {
+ checkNonNegative("n", n);
+ checkNonNegative("k", k);
+ checkArgument(k <= n, "k (%s) > n (%s)", k, n);
+ if (k > (n >> 1)) {
+ k = n - k;
+ }
+ if (k >= BIGGEST_BINOMIALS.length || n > BIGGEST_BINOMIALS[k]) {
+ return Integer.MAX_VALUE;
+ }
+ switch (k) {
+ case 0:
+ return 1;
+ case 1:
+ return n;
+ default:
+ long result = 1;
+ for (int i = 0; i < k; i++) {
+ result *= n - i;
+ result /= i + 1;
+ }
+ return (int) result;
+ }
+ }
+
+ // 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,
+ 2345,
+ 477,
+ 193,
+ 110,
+ 75,
+ 58,
+ 49,
+ 43,
+ 39,
+ 37,
+ 35,
+ 34,
+ 34,
+ 33
+ };
+
+ private IntMath() {}
+}
diff --git a/guava/src/com/google/common/math/LongMath.java b/guava/src/com/google/common/math/LongMath.java
new file mode 100644
index 0000000..8334097
--- /dev/null
+++ b/guava/src/com/google/common/math/LongMath.java
@@ -0,0 +1,675 @@
+/*
+ * 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.math;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.math.MathPreconditions.checkNoOverflow;
+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;
+
+import java.math.BigInteger;
+import java.math.RoundingMode;
+
+/**
+ * A class for arithmetic on values of type {@code long}. Where possible, methods are defined and
+ * named analogously to their {@code BigInteger} counterparts.
+ *
+ * <p>The implementations of many methods in this class are based on material from Henry S. Warren,
+ * Jr.'s <i>Hacker's Delight</i>, (Addison Wesley, 2002).
+ *
+ * <p>Similar functionality for {@code int} and for {@link BigInteger} can be found in
+ * {@link IntMath} and {@link BigIntegerMath} respectively. For other common operations on
+ * {@code long} values, see {@link com.google.common.primitives.Longs}.
+ *
+ * @author Louis Wasserman
+ * @since 11.0
+ */
+@Beta
+@GwtCompatible(emulated = true)
+public final class LongMath {
+ // NOTE: Whenever both tests are cheap and functional, it's faster to use &, | instead of &&, ||
+
+ /**
+ * Returns {@code true} if {@code x} represents a power of two.
+ *
+ * <p>This differs from {@code Long.bitCount(x) == 1}, because
+ * {@code Long.bitCount(Long.MIN_VALUE) == 1}, but {@link Long#MIN_VALUE} is not a power of two.
+ */
+ public static boolean isPowerOfTwo(long x) {
+ return x > 0 & (x & (x - 1)) == 0;
+ }
+
+ /**
+ * Returns the base-2 logarithm of {@code x}, rounded according to the specified rounding mode.
+ *
+ * @throws IllegalArgumentException if {@code x <= 0}
+ * @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
+ * is not a power of two
+ */
+ @SuppressWarnings("fallthrough")
+ public static int log2(long x, RoundingMode mode) {
+ checkPositive("x", x);
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(isPowerOfTwo(x));
+ // fall through
+ case DOWN:
+ case FLOOR:
+ return (Long.SIZE - 1) - Long.numberOfLeadingZeros(x);
+
+ case UP:
+ case CEILING:
+ return Long.SIZE - Long.numberOfLeadingZeros(x - 1);
+
+ case HALF_DOWN:
+ case HALF_UP:
+ case HALF_EVEN:
+ // Since sqrt(2) is irrational, log2(x) - logFloor cannot be exactly 0.5
+ int leadingZeros = Long.numberOfLeadingZeros(x);
+ long cmp = MAX_POWER_OF_SQRT2_UNSIGNED >>> leadingZeros;
+ // floor(2^(logFloor + 0.5))
+ int logFloor = (Long.SIZE - 1) - leadingZeros;
+ return (x <= cmp) ? logFloor : logFloor + 1;
+
+ default:
+ throw new AssertionError("impossible");
+ }
+ }
+
+ /** The biggest half power of two that fits into an unsigned long */
+ @VisibleForTesting static final long MAX_POWER_OF_SQRT2_UNSIGNED = 0xB504F333F9DE6484L;
+
+ /**
+ * Returns the base-10 logarithm of {@code x}, rounded according to the specified rounding mode.
+ *
+ * @throws IllegalArgumentException if {@code x <= 0}
+ * @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(long x, RoundingMode mode) {
+ checkPositive("x", x);
+ if (fitsInInt(x)) {
+ return IntMath.log10((int) x, mode);
+ }
+ int logFloor = log10Floor(x);
+ long floorPow = POWERS_OF_10[logFloor];
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(x == floorPow);
+ // fall through
+ case FLOOR:
+ case DOWN:
+ return logFloor;
+ case CEILING:
+ case UP:
+ return (x == floorPow) ? logFloor : logFloor + 1;
+ case HALF_DOWN:
+ case HALF_UP:
+ case HALF_EVEN:
+ // sqrt(10) is irrational, so log10(x)-logFloor is never exactly 0.5
+ 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 = MAX_LOG10_FOR_LEADING_ZEROS[Long.numberOfLeadingZeros(x)];
+ // y is the higher of the two possible values of floor(log10(x))
+
+ long sgn = (x - POWERS_OF_10[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;
+ }
+
+ // MAX_LOG10_FOR_LEADING_ZEROS[i] == floor(log10(2^(Long.SIZE - i)))
+ @VisibleForTesting static final byte[] MAX_LOG10_FOR_LEADING_ZEROS = {
+ 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[] POWERS_OF_10 = {
+ 1L,
+ 10L,
+ 100L,
+ 1000L,
+ 10000L,
+ 100000L,
+ 1000000L,
+ 10000000L,
+ 100000000L,
+ 1000000000L,
+ 10000000000L,
+ 100000000000L,
+ 1000000000000L,
+ 10000000000000L,
+ 100000000000000L,
+ 1000000000000000L,
+ 10000000000000000L,
+ 100000000000000000L,
+ 1000000000000000000L
+ };
+
+ // HALF_POWERS_OF_10[i] = largest long less than 10^(i + 0.5)
+ @GwtIncompatible("TODO")
+ @VisibleForTesting
+ static final long[] HALF_POWERS_OF_10 = {
+ 3L,
+ 31L,
+ 316L,
+ 3162L,
+ 31622L,
+ 316227L,
+ 3162277L,
+ 31622776L,
+ 316227766L,
+ 3162277660L,
+ 31622776601L,
+ 316227766016L,
+ 3162277660168L,
+ 31622776601683L,
+ 316227766016837L,
+ 3162277660168379L,
+ 31622776601683793L,
+ 316227766016837933L,
+ 3162277660168379331L
+ };
+
+ /**
+ * Returns {@code b} to the {@code k}th power. Even if the result overflows, it will be equal to
+ * {@code BigInteger.valueOf(b).pow(k).longValue()}. This implementation runs in {@code O(log k)}
+ * time.
+ *
+ * @throws IllegalArgumentException if {@code k < 0}
+ */
+ @GwtIncompatible("TODO")
+ public static long pow(long b, int k) {
+ checkNonNegative("exponent", k);
+ if (-2 <= b && b <= 2) {
+ switch ((int) b) {
+ case 0:
+ return (k == 0) ? 1 : 0;
+ case 1:
+ return 1;
+ case (-1):
+ return ((k & 1) == 0) ? 1 : -1;
+ case 2:
+ return (k < Long.SIZE) ? 1L << k : 0;
+ case (-2):
+ if (k < Long.SIZE) {
+ return ((k & 1) == 0) ? 1L << k : -(1L << k);
+ } else {
+ return 0;
+ }
+ }
+ }
+ for (long accum = 1;; k >>= 1) {
+ switch (k) {
+ case 0:
+ return accum;
+ case 1:
+ return accum * b;
+ default:
+ accum *= ((k & 1) == 0) ? 1 : b;
+ b *= b;
+ }
+ }
+ }
+
+ /**
+ * Returns the square root of {@code x}, rounded with the specified rounding mode.
+ *
+ * @throws IllegalArgumentException if {@code x < 0}
+ * @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);
+ if (fitsInInt(x)) {
+ return IntMath.sqrt((int) x, mode);
+ }
+ long sqrtFloor = sqrtFloor(x);
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(sqrtFloor * sqrtFloor == x); // fall through
+ case FLOOR:
+ case DOWN:
+ return sqrtFloor;
+ case CEILING:
+ case UP:
+ return (sqrtFloor * sqrtFloor == x) ? sqrtFloor : sqrtFloor + 1;
+ case HALF_DOWN:
+ case HALF_UP:
+ case HALF_EVEN:
+ long halfSquare = sqrtFloor * sqrtFloor + sqrtFloor;
+ /*
+ * We wish to test whether or not x <= (sqrtFloor + 0.5)^2 = halfSquare + 0.25. Since both
+ * x and halfSquare are integers, this is equivalent to testing whether or not x <=
+ * halfSquare. (We have to deal with overflow, though.)
+ */
+ return (halfSquare >= x | halfSquare < 0) ? sqrtFloor : sqrtFloor + 1;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ @GwtIncompatible("TODO")
+ private static long sqrtFloor(long x) {
+ // 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;
+ }
+ do {
+ sqrt0 = sqrt1;
+ sqrt1 = (sqrt0 + (x / sqrt0)) >> 1;
+ } while (sqrt1 < sqrt0);
+ return sqrt0;
+ }
+
+ /**
+ * Returns the result of dividing {@code p} by {@code q}, rounding using the specified
+ * {@code RoundingMode}.
+ *
+ * @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);
+ long div = p / q; // throws if q == 0
+ long rem = p - q * div; // equals p % q
+
+ if (rem == 0) {
+ return div;
+ }
+
+ /*
+ * Normal Java division rounds towards 0, consistently with RoundingMode.DOWN. We just have to
+ * deal with the cases where rounding towards 0 is wrong, which typically depends on the sign of
+ * p / q.
+ *
+ * signum is 1 if p and q are both nonnegative or both negative, and -1 otherwise.
+ */
+ int signum = 1 | (int) ((p ^ q) >> (Long.SIZE - 1));
+ boolean increment;
+ switch (mode) {
+ case UNNECESSARY:
+ checkRoundingUnnecessary(rem == 0);
+ // fall through
+ case DOWN:
+ increment = false;
+ break;
+ case UP:
+ increment = true;
+ break;
+ case CEILING:
+ increment = signum > 0;
+ break;
+ case FLOOR:
+ increment = signum < 0;
+ break;
+ case HALF_EVEN:
+ case HALF_DOWN:
+ case HALF_UP:
+ long absRem = abs(rem);
+ long cmpRemToHalfDivisor = absRem - (abs(q) - absRem);
+ // subtracting two nonnegative longs can't overflow
+ // cmpRemToHalfDivisor has the same sign as compare(abs(rem), abs(q) / 2).
+ if (cmpRemToHalfDivisor == 0) { // exactly on the half mark
+ increment = (mode == HALF_UP | (mode == HALF_EVEN & (div & 1) != 0));
+ } else {
+ increment = cmpRemToHalfDivisor > 0; // closer to the UP value
+ }
+ break;
+ default:
+ throw new AssertionError();
+ }
+ return increment ? div + signum : div;
+ }
+
+ /**
+ * Returns {@code x mod m}. This differs from {@code x % m} in that it always returns a
+ * non-negative result.
+ *
+ * <p>For example:
+ *
+ * <pre> {@code
+ *
+ * mod(7, 4) == 3
+ * mod(-7, 4) == 1
+ * mod(-1, 4) == 3
+ * mod(-8, 4) == 0
+ * mod(8, 4) == 0}</pre>
+ *
+ * @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);
+ }
+
+ /**
+ * Returns {@code x mod m}. This differs from {@code x % m} in that it always returns a
+ * non-negative result.
+ *
+ * <p>For example:
+ *
+ * <pre> {@code
+ *
+ * mod(7, 4) == 3
+ * mod(-7, 4) == 1
+ * mod(-1, 4) == 3
+ * mod(-8, 4) == 0
+ * mod(8, 4) == 0}</pre>
+ *
+ * @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");
+ }
+ long result = x % m;
+ return (result >= 0) ? result : result + m;
+ }
+
+ /**
+ * Returns the greatest common divisor of {@code a, b}. Returns {@code 0} if
+ * {@code a == 0 && b == 0}.
+ *
+ * @throws IllegalArgumentException if {@code a < 0} or {@code b < 0}
+ */
+ @GwtIncompatible("TODO")
+ public static long gcd(long a, long b) {
+ /*
+ * The reason we require both arguments to be >= 0 is because otherwise, what do you return on
+ * gcd(0, Long.MIN_VALUE)? BigInteger.gcd would return positive 2^63, but positive 2^63 isn't
+ * an int.
+ */
+ 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 >60% 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)
+ a >>= Long.numberOfTrailingZeros(a); // divide out all 2s, since 2 doesn't divide b
+ }
+ return a << min(aTwos, bTwos);
+ }
+
+ /**
+ * Returns the sum of {@code a} and {@code b}, provided it does not overflow.
+ *
+ * @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);
+ return result;
+ }
+
+ /**
+ * Returns the difference of {@code a} and {@code b}, provided it does not overflow.
+ *
+ * @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);
+ return result;
+ }
+
+ /**
+ * Returns the product of {@code a} and {@code b}, provided it does not overflow.
+ *
+ * @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)
+ + Long.numberOfLeadingZeros(b) + Long.numberOfLeadingZeros(~b);
+ /*
+ * If leadingZeros > Long.SIZE + 1 it's definitely fine, if it's < Long.SIZE it's definitely
+ * bad. We do the leadingZeros check to avoid the division below if at all possible.
+ *
+ * Otherwise, if b == Long.MIN_VALUE, then the only allowed values of a are 0 and 1. We take
+ * care of all a < 0 with their own check, because in particular, the case a == -1 will
+ * incorrectly pass the division check below.
+ *
+ * In all other cases, we check that either a is 0 or the result is consistent with division.
+ */
+ if (leadingZeros > Long.SIZE + 1) {
+ return a * b;
+ }
+ checkNoOverflow(leadingZeros >= Long.SIZE);
+ checkNoOverflow(a >= 0 | b != Long.MIN_VALUE);
+ long result = a * b;
+ checkNoOverflow(a == 0 || result / a == b);
+ return result;
+ }
+
+ /**
+ * Returns the {@code b} to the {@code k}th power, provided it does not overflow.
+ *
+ * @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) {
+ switch ((int) b) {
+ case 0:
+ return (k == 0) ? 1 : 0;
+ case 1:
+ return 1;
+ case (-1):
+ return ((k & 1) == 0) ? 1 : -1;
+ case 2:
+ checkNoOverflow(k < Long.SIZE - 1);
+ return 1L << k;
+ case (-2):
+ checkNoOverflow(k < Long.SIZE);
+ return ((k & 1) == 0) ? (1L << k) : (-1L << k);
+ }
+ }
+ long accum = 1;
+ while (true) {
+ switch (k) {
+ case 0:
+ return accum;
+ case 1:
+ return checkedMultiply(accum, b);
+ default:
+ if ((k & 1) != 0) {
+ accum = checkedMultiply(accum, b);
+ }
+ k >>= 1;
+ if (k > 0) {
+ checkNoOverflow(b <= FLOOR_SQRT_MAX_LONG);
+ b *= b;
+ }
+ }
+ }
+ }
+
+ @GwtIncompatible("TODO")
+ @VisibleForTesting static final long FLOOR_SQRT_MAX_LONG = 3037000499L;
+
+ /**
+ * Returns {@code n!}, that is, the product of the first {@code n} positive
+ * integers, {@code 1} if {@code n == 0}, or {@link Long#MAX_VALUE} if the
+ * result does not fit in a {@code long}.
+ *
+ * @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;
+ }
+
+ static final long[] FACTORIALS = {
+ 1L,
+ 1L,
+ 1L * 2,
+ 1L * 2 * 3,
+ 1L * 2 * 3 * 4,
+ 1L * 2 * 3 * 4 * 5,
+ 1L * 2 * 3 * 4 * 5 * 6,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19,
+ 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19 * 20
+ };
+
+ /**
+ * Returns {@code n} choose {@code k}, also known as the binomial coefficient of {@code n} and
+ * {@code k}, or {@link Long#MAX_VALUE} if the result does not fit in a {@code long}.
+ *
+ * @throws IllegalArgumentException if {@code n < 0}, {@code k < 0}, or {@code k > n}
+ */
+ public static long binomial(int n, int k) {
+ checkNonNegative("n", n);
+ checkNonNegative("k", k);
+ checkArgument(k <= n, "k (%s) > n (%s)", k, n);
+ if (k > (n >> 1)) {
+ k = n - k;
+ }
+ if (k >= BIGGEST_BINOMIALS.length || n > BIGGEST_BINOMIALS[k]) {
+ return Long.MAX_VALUE;
+ }
+ 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;
+ }
+ }
+ return result;
+ }
+
+ /*
+ * binomial(BIGGEST_BINOMIALS[k], k) fits in a long, but not
+ * binomial(BIGGEST_BINOMIALS[k] + 1, k).
+ */
+ 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(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[] 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;
+ }
+
+ private LongMath() {}
+}
diff --git a/guava/src/com/google/common/math/MathPreconditions.java b/guava/src/com/google/common/math/MathPreconditions.java
new file mode 100644
index 0000000..96835c6
--- /dev/null
+++ b/guava/src/com/google/common/math/MathPreconditions.java
@@ -0,0 +1,98 @@
+/*
+ * 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.math;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.math.BigInteger;
+
+/**
+ * A collection of preconditions for math functions.
+ *
+ * @author Louis Wasserman
+ */
+@GwtCompatible
+final class MathPreconditions {
+ static int checkPositive(String role, int x) {
+ if (x <= 0) {
+ throw new IllegalArgumentException(role + " (" + x + ") must be > 0");
+ }
+ return x;
+ }
+
+ static long checkPositive(String role, long x) {
+ if (x <= 0) {
+ throw new IllegalArgumentException(role + " (" + x + ") must be > 0");
+ }
+ return 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(String role, int x) {
+ if (x < 0) {
+ throw new IllegalArgumentException(role + " (" + x + ") must be >= 0");
+ }
+ return x;
+ }
+
+ static long checkNonNegative(String role, long x) {
+ if (x < 0) {
+ throw new IllegalArgumentException(role + " (" + x + ") must be >= 0");
+ }
+ return x;
+ }
+
+ static BigInteger checkNonNegative(String role, BigInteger x) {
+ if (checkNotNull(x).signum() < 0) {
+ throw new IllegalArgumentException(role + " (" + x + ") must be >= 0");
+ }
+ return x;
+ }
+
+ static double checkNonNegative(String role, double x) {
+ if (!(x >= 0)) {
+ throw new IllegalArgumentException(role + " (" + x + ") must be >= 0");
+ }
+ return x;
+ }
+
+ static void checkRoundingUnnecessary(boolean condition) {
+ if (!condition) {
+ throw new ArithmeticException("mode was UNNECESSARY, but rounding was necessary");
+ }
+ }
+
+ static void checkInRange(boolean condition) {
+ if (!condition) {
+ throw new ArithmeticException("not in range");
+ }
+ }
+
+ static void checkNoOverflow(boolean condition) {
+ if (!condition) {
+ throw new ArithmeticException("overflow");
+ }
+ }
+
+ private MathPreconditions() {}
+}
diff --git a/guava/src/com/google/common/math/package-info.java b/guava/src/com/google/common/math/package-info.java
new file mode 100644
index 0000000..bd17e52
--- /dev/null
+++ b/guava/src/com/google/common/math/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/**
+ * Arithmetic functions operating on primitive values and {@link java.math.BigInteger} instances.
+ *
+ * <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
new file mode 100644
index 0000000..76ede3f
--- /dev/null
+++ b/guava/src/com/google/common/net/HostAndPort.java
@@ -0,0 +1,268 @@
+/*
+ * 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.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.base.Objects;
+
+import java.io.Serializable;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * An immutable representation of a host and port.
+ *
+ * <p>Example usage:
+ * <pre>
+ * HostAndPort hp = HostAndPort.fromString("[2001:db8::1]")
+ * .withDefaultPort(80)
+ * .requireBracketsForIPv6();
+ * hp.getHostText(); // returns "2001:db8::1"
+ * hp.getPort(); // returns 80
+ * hp.toString(); // returns "[2001:db8::1]:80"
+ * </pre>
+ *
+ * <p>Here are some examples of recognized formats:
+ * <ul>
+ * <li>example.com
+ * <li>example.com:80
+ * <li>192.0.2.1
+ * <li>192.0.2.1:80
+ * <li>[2001:db8::1] - {@link #getHostText()} omits brackets
+ * <li>[2001:db8::1]:80 - {@link #getHostText()} omits brackets
+ * <li>2001:db8::1 - Use {@link #requireBracketsForIPv6()} to prohibit this
+ * </ul>
+ *
+ * <p>Note that this is not an exhaustive list, because these methods are only
+ * concerned with brackets, colons, and port numbers. Full validation of the
+ * host field (if desired) is the caller's responsibility.
+ *
+ * @author Paul Marks
+ * @since 10.0
+ */
+@Beta @Immutable
+public final class HostAndPort implements Serializable {
+ /** Magic value indicating the absence of a port number. */
+ private static final int NO_PORT = -1;
+
+ /** Hostname, IPv4/IPv6 literal, or unvalidated nonsense. */
+ private final String host;
+
+ /** Validated port number in the range [0..65535], or NO_PORT */
+ private final int port;
+
+ /** True if the parsed host has colons, but no surrounding brackets. */
+ private final boolean hasBracketlessColons;
+
+ private HostAndPort(String host, int port, boolean hasBracketlessColons) {
+ this.host = host;
+ this.port = port;
+ this.hasBracketlessColons = hasBracketlessColons;
+ }
+
+ /**
+ * Returns the portion of this {@code HostAndPort} instance that should
+ * represent the hostname or IPv4/IPv6 literal.
+ *
+ * A successful parse does not imply any degree of sanity in this field.
+ * For additional validation, see the {@link HostSpecifier} class.
+ */
+ public String getHostText() {
+ return host;
+ }
+
+ /** Return true if this instance has a defined port. */
+ public boolean hasPort() {
+ return port >= 0;
+ }
+
+ /**
+ * Get the current port number, failing if no port is defined.
+ *
+ * @return a validated port number, in the range [0..65535]
+ * @throws IllegalStateException if no port is defined. You can use
+ * {@link #withDefaultPort(int)} to prevent this from occurring.
+ */
+ public int getPort() {
+ checkState(hasPort());
+ return port;
+ }
+
+ /**
+ * Returns the current port number, with a default if no port is defined.
+ */
+ public int getPortOrDefault(int defaultPort) {
+ return hasPort() ? port : defaultPort;
+ }
+
+ /**
+ * Build a HostAndPort instance from separate host and port values.
+ *
+ * <p>Note: Non-bracketed IPv6 literals are allowed.
+ * Use {@link #requireBracketsForIPv6()} to prohibit these.
+ *
+ * @param host the host string to parse. Must not contain a port number.
+ * @param port a port number from [0..65535]
+ * @return if parsing was successful, a populated HostAndPort object.
+ * @throws IllegalArgumentException if {@code host} contains a port number,
+ * or {@code port} is out of range.
+ */
+ public static HostAndPort fromParts(String host, int port) {
+ checkArgument(isValidPort(port));
+ HostAndPort parsedHost = fromString(host);
+ checkArgument(!parsedHost.hasPort());
+ return new HostAndPort(parsedHost.host, port, parsedHost.hasBracketlessColons);
+ }
+
+ private static final Pattern BRACKET_PATTERN = Pattern.compile("^\\[(.*:.*)\\](?::(\\d*))?$");
+
+ /**
+ * Split a freeform string into a host and port, without strict validation.
+ *
+ * Note that the host-only formats will leave the port field undefined. You
+ * can use {@link #withDefaultPort(int)} to patch in a default value.
+ *
+ * @param hostPortString the input string to parse.
+ * @return if parsing was successful, a populated HostAndPort object.
+ * @throws IllegalArgumentException if nothing meaningful could be parsed.
+ */
+ public static HostAndPort fromString(String hostPortString) {
+ checkNotNull(hostPortString);
+ String host;
+ String portString = null;
+ boolean hasBracketlessColons = false;
+
+ if (hostPortString.startsWith("[")) {
+ // Parse a bracketed host, typically an IPv6 literal.
+ Matcher matcher = BRACKET_PATTERN.matcher(hostPortString);
+ checkArgument(matcher.matches(), "Invalid bracketed host/port: %s", hostPortString);
+ host = matcher.group(1);
+ portString = matcher.group(2); // could be null
+ } else {
+ int colonPos = hostPortString.indexOf(':');
+ if (colonPos >= 0 && hostPortString.indexOf(':', colonPos + 1) == -1) {
+ // Exactly 1 colon. Split into host:port.
+ host = hostPortString.substring(0, colonPos);
+ portString = hostPortString.substring(colonPos + 1);
+ } else {
+ // 0 or 2+ colons. Bare hostname or IPv6 literal.
+ host = hostPortString;
+ hasBracketlessColons = (colonPos >= 0);
+ }
+ }
+
+ int port = NO_PORT;
+ 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);
+ try {
+ port = Integer.parseInt(portString);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Unparseable port number: " + hostPortString);
+ }
+ checkArgument(isValidPort(port), "Port number out of range: %s", hostPortString);
+ }
+
+ return new HostAndPort(host, port, hasBracketlessColons);
+ }
+
+ /**
+ * Provide a default port if the parsed string contained only a host.
+ *
+ * You can chain this after {@link #fromString(String)} to include a port in
+ * case the port was omitted from the input string. If a port was already
+ * provided, then this method is a no-op.
+ *
+ * @param defaultPort a port number, from [0..65535]
+ * @return a HostAndPort instance, guaranteed to have a defined port.
+ */
+ public HostAndPort withDefaultPort(int defaultPort) {
+ checkArgument(isValidPort(defaultPort));
+ if (hasPort() || port == defaultPort) {
+ return this;
+ }
+ return new HostAndPort(host, defaultPort, hasBracketlessColons);
+ }
+
+ /**
+ * Generate an error if the host might be a non-bracketed IPv6 literal.
+ *
+ * <p>URI formatting requires that IPv6 literals be surrounded by brackets,
+ * like "[2001:db8::1]". Chain this call after {@link #fromString(String)}
+ * to increase the strictness of the parser, and disallow IPv6 literals
+ * that don't contain these brackets.
+ *
+ * <p>Note that this parser identifies IPv6 literals solely based on the
+ * presence of a colon. To perform actual validation of IP addresses, see
+ * the {@link InetAddresses#forString(String)} method.
+ *
+ * @return {@code this}, to enable chaining of calls.
+ * @throws IllegalArgumentException if bracketless IPv6 is detected.
+ */
+ public HostAndPort requireBracketsForIPv6() {
+ checkArgument(!hasBracketlessColons, "Possible bracketless IPv6 literal: %s", host);
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other instanceof HostAndPort) {
+ HostAndPort that = (HostAndPort) other;
+ return Objects.equal(this.host, that.host)
+ && this.port == that.port
+ && this.hasBracketlessColons == that.hasBracketlessColons;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(host, port, hasBracketlessColons);
+ }
+
+ /** Rebuild the host:port string, including brackets if necessary. */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder(host.length() + 7);
+ if (host.indexOf(':') >= 0) {
+ builder.append('[').append(host).append(']');
+ } else {
+ builder.append(host);
+ }
+ if (hasPort()) {
+ builder.append(':').append(port);
+ }
+ return builder.toString();
+ }
+
+ /** Return true for valid port numbers. */
+ 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/HostSpecifier.java b/guava/src/com/google/common/net/HostSpecifier.java
new file mode 100644
index 0000000..3c90985
--- /dev/null
+++ b/guava/src/com/google/common/net/HostSpecifier.java
@@ -0,0 +1,178 @@
+/*
+ * 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.net;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.net.InetAddress;
+import java.text.ParseException;
+
+import javax.annotation.Nullable;
+
+/**
+ * A syntactically valid host specifier, suitable for use in a URI.
+ * This may be either a numeric IP address in IPv4 or IPv6 notation, or a
+ * domain name.
+ *
+ * <p>Because this class is intended to represent host specifiers which can
+ * reasonably be used in a URI, the domain name case is further restricted to
+ * include only those domain names which end in a recognized public suffix; see
+ * {@link InternetDomainName#isPublicSuffix()} for details.
+ *
+ * <p>Note that no network lookups are performed by any {@code HostSpecifier}
+ * methods. No attempt is made to verify that a provided specifier corresponds
+ * to a real or accessible host. Only syntactic and pattern-based checks are
+ * performed.
+ *
+ * <p>If you know that a given string represents a numeric IP address, use
+ * {@link InetAddresses} to obtain and manipulate a
+ * {@link java.net.InetAddress} instance from it rather than using this class.
+ * Similarly, if you know that a given string represents a domain name, use
+ * {@link InternetDomainName} rather than this class.
+ *
+ * @author Craig Berry
+ * @since 5.0
+ */
+@Beta
+public final class HostSpecifier {
+
+ private final String canonicalForm;
+
+ private HostSpecifier(String canonicalForm) {
+ this.canonicalForm = canonicalForm;
+ }
+
+ /**
+ * Returns a {@code HostSpecifier} built from the provided {@code specifier},
+ * which is already known to be valid. If the {@code specifier} might be
+ * invalid, use {@link #from(String)} instead.
+ *
+ * <p>The specifier must be in one of these formats:
+ * <ul>
+ * <li>A domain name, like {@code google.com}
+ * <li>A IPv4 address string, like {@code 127.0.0.1}
+ * <li>An IPv6 address string with or without brackets, like
+ * {@code [2001:db8::1]} or {@code 2001:db8::1}
+ * </ul>
+ *
+ * @throws IllegalArgumentException if the specifier is not valid.
+ */
+ public static HostSpecifier fromValid(String specifier) {
+ // Verify that no port was specified, and strip optional brackets from
+ // IPv6 literals.
+ final HostAndPort parsedHost = HostAndPort.fromString(specifier);
+ Preconditions.checkArgument(!parsedHost.hasPort());
+ final String host = parsedHost.getHostText();
+
+ // Try to interpret the specifier as an IP address. Note we build
+ // the address rather than using the .is* methods because we want to
+ // use InetAddresses.toUriString to convert the result to a string in
+ // canonical form.
+ InetAddress addr = null;
+ try {
+ addr = InetAddresses.forString(host);
+ } catch (IllegalArgumentException e) {
+ // It is not an IPv4 or IPv6 literal
+ }
+
+ if (addr != null) {
+ return new HostSpecifier(InetAddresses.toUriString(addr));
+ }
+
+ // It is not any kind of IP address; must be a domain name or invalid.
+
+ // TODO(user): different versions of this for different factories?
+ final InternetDomainName domain = InternetDomainName.from(host);
+
+ if (domain.hasPublicSuffix()) {
+ return new HostSpecifier(domain.name());
+ }
+
+ throw new IllegalArgumentException(
+ "Domain name does not have a recognized public suffix: " + host);
+ }
+
+ /**
+ * Attempts to return a {@code HostSpecifier} for the given string, throwing
+ * an exception if parsing fails. Always use this method in preference to
+ * {@link #fromValid(String)} for a specifier that is not already known to be
+ * valid.
+ *
+ * @throws ParseException if the specifier is not valid.
+ */
+ public static HostSpecifier from(String specifier)
+ throws ParseException {
+ try {
+ return fromValid(specifier);
+ } catch (IllegalArgumentException e) {
+ // Since the IAE can originate at several different points inside
+ // fromValid(), we implement this method in terms of that one rather
+ // than the reverse.
+
+ ParseException parseException =
+ new ParseException("Invalid host specifier: " + specifier, 0);
+ parseException.initCause(e);
+ throw parseException;
+ }
+ }
+
+ /**
+ * Determines whether {@code specifier} represents a valid
+ * {@link HostSpecifier} as described in the documentation for
+ * {@link #fromValid(String)}.
+ */
+ public static boolean isValid(String specifier) {
+ try {
+ fromValid(specifier);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (this == other) {
+ return true;
+ }
+
+ if (other instanceof HostSpecifier) {
+ final HostSpecifier that = (HostSpecifier) other;
+ return this.canonicalForm.equals(that.canonicalForm);
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return canonicalForm.hashCode();
+ }
+
+ /**
+ * Returns a string representation of the host specifier suitable for
+ * inclusion in a URI. If the host specifier is a domain name, the
+ * string will be normalized to all lower case. If the specifier was
+ * an IPv6 address without brackets, brackets are added so that the
+ * result will be usable in the host part of a URI.
+ */
+ @Override
+ public String toString() {
+ return canonicalForm;
+ }
+}
diff --git a/guava/src/com/google/common/net/HttpHeaders.java b/guava/src/com/google/common/net/HttpHeaders.java
new file mode 100644
index 0000000..4bb6f9f
--- /dev/null
+++ b/guava/src/com/google/common/net/HttpHeaders.java
@@ -0,0 +1,200 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtCompatible;
+
+/**
+ * Contains constant definitions for the HTTP header field names. See:
+ * <ul>
+ * <li><a href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a>
+ * <li><a href="http://www.ietf.org/rfc/rfc2183.txt">RFC 2183</a>
+ * <li><a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>
+ * <li><a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>
+ * <li><a href="http://www.ietf.org/rfc/rfc5988.txt">RFC 5988</a>
+ * </ul>
+ *
+ * @author Kurt Alfred Kluever
+ * @since 11.0
+ */
+@Beta
+@GwtCompatible
+public final class HttpHeaders {
+ private HttpHeaders() {}
+
+ // HTTP Request and Response header fields
+
+ /** The HTTP Cache-Control header field name. */
+ public static final String CACHE_CONTROL = "Cache-Control";
+ /** The HTTP Content-Length header field name. */
+ public static final String CONTENT_LENGTH = "Content-Length";
+ /** The HTTP Content-Type header field name. */
+ public static final String CONTENT_TYPE = "Content-Type";
+ /** The HTTP Date header field name. */
+ public static final String DATE = "Date";
+ /** The HTTP Pragma header field name. */
+ public static final String PRAGMA = "Pragma";
+ /** The HTTP Via header field name. */
+ public static final String VIA = "Via";
+ /** The HTTP Warning header field name. */
+ public static final String WARNING = "Warning";
+
+ // HTTP Request header fields
+
+ /** The HTTP Accept header field name. */
+ public static final String ACCEPT = "Accept";
+ /** The HTTP Accept-Charset header field name. */
+ public static final String ACCEPT_CHARSET = "Accept-Charset";
+ /** The HTTP Accept-Encoding header field name. */
+ public static final String ACCEPT_ENCODING = "Accept-Encoding";
+ /** The HTTP Accept-Language header field name. */
+ public static final String ACCEPT_LANGUAGE = "Accept-Language";
+ /** The HTTP Access-Control-Request-Headers header field name. */
+ public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
+ /** The HTTP Access-Control-Request-Method header field name. */
+ public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
+ /** The HTTP Authorization header field name. */
+ public static final String AUTHORIZATION = "Authorization";
+ /** The HTTP Connection header field name. */
+ public static final String CONNECTION = "Connection";
+ /** The HTTP Cookie header field name. */
+ public static final String COOKIE = "Cookie";
+ /** The HTTP Expect header field name. */
+ public static final String EXPECT = "Expect";
+ /** The HTTP From header field name. */
+ public static final String FROM = "From";
+ /** The HTTP Host header field name. */
+ public static final String HOST = "Host";
+ /** The HTTP If-Match header field name. */
+ public static final String IF_MATCH = "If-Match";
+ /** The HTTP If-Modified-Since header field name. */
+ public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
+ /** The HTTP If-None-Match header field name. */
+ public static final String IF_NONE_MATCH = "If-None-Match";
+ /** The HTTP If-Range header field name. */
+ public static final String IF_RANGE = "If-Range";
+ /** The HTTP If-Unmodified-Since header field name. */
+ public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
+ /** The HTTP Last-Event-ID header field name. */
+ public static final String LAST_EVENT_ID = "Last-Event-ID";
+ /** The HTTP Max-Forwards header field name. */
+ public static final String MAX_FORWARDS = "Max-Forwards";
+ /** The HTTP Origin header field name. */
+ public static final String ORIGIN = "Origin";
+ /** The HTTP Proxy-Authorization header field name. */
+ public static final String PROXY_AUTHORIZATION = "Proxy-Authorization";
+ /** The HTTP Range header field name. */
+ public static final String RANGE = "Range";
+ /** The HTTP Referer header field name. */
+ public static final String REFERER = "Referer";
+ /** The HTTP TE header field name. */
+ public static final String TE = "TE";
+ /** The HTTP Upgrade header field name. */
+ public static final String UPGRADE = "Upgrade";
+ /** The HTTP User-Agent header field name. */
+ public static final String USER_AGENT = "User-Agent";
+
+ // HTTP Response header fields
+
+ /** The HTTP Accept-Ranges header field name. */
+ public static final String ACCEPT_RANGES = "Accept-Ranges";
+ /** The HTTP Access-Control-Allow-Headers header field name. */
+ public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
+ /** The HTTP Access-Control-Allow-Methods header field name. */
+ public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
+ /** The HTTP Access-Control-Allow-Origin header field name. */
+ public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
+ /** The HTTP Access-Control-Allow-Credentials header field name. */
+ public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
+ /** The HTTP Access-Control-Expose-Headers header field name. */
+ public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
+ /** The HTTP Access-Control-Max-Age header field name. */
+ public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
+ /** The HTTP Age header field name. */
+ public static final String AGE = "Age";
+ /** The HTTP Allow header field name. */
+ public static final String ALLOW = "Allow";
+ /** The HTTP Content-Disposition header field name. */
+ public static final String CONTENT_DISPOSITION = "Content-Disposition";
+ /** The HTTP Content-Encoding header field name. */
+ public static final String CONTENT_ENCODING = "Content-Encoding";
+ /** The HTTP Content-Language header field name. */
+ public static final String CONTENT_LANGUAGE = "Content-Language";
+ /** The HTTP Content-Location header field name. */
+ public static final String CONTENT_LOCATION = "Content-Location";
+ /** The HTTP Content-MD5 header field name. */
+ public static final String CONTENT_MD5 = "Content-MD5";
+ /** The HTTP Content-Range header field name. */
+ public static final String CONTENT_RANGE = "Content-Range";
+ /** The HTTP ETag header field name. */
+ public static final String ETAG = "ETag";
+ /** The HTTP Expires header field name. */
+ public static final String EXPIRES = "Expires";
+ /** The HTTP Last-Modified header field name. */
+ public static final String LAST_MODIFIED = "Last-Modified";
+ /** The HTTP Link header field name. */
+ public static final String LINK = "Link";
+ /** The HTTP Location header field name. */
+ public static final String LOCATION = "Location";
+ /** The HTTP P3P header field name. Limited browser support. */
+ public static final String P3P = "P3P";
+ /** The HTTP Proxy-Authenticate header field name. */
+ public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate";
+ /** The HTTP Refresh header field name. Non-standard header supported by most browsers. */
+ public static final String REFRESH = "Refresh";
+ /** The HTTP Retry-After header field name. */
+ public static final String RETRY_AFTER = "Retry-After";
+ /** The HTTP Server header field name. */
+ public static final String SERVER = "Server";
+ /** The HTTP Set-Cookie header field name. */
+ public static final String SET_COOKIE = "Set-Cookie";
+ /** The HTTP Set-Cookie2 header field name. */
+ public static final String SET_COOKIE2 = "Set-Cookie2";
+ /** The HTTP Trailer header field name. */
+ public static final String TRAILER = "Trailer";
+ /** The HTTP Transfer-Encoding header field name. */
+ public static final String TRANSFER_ENCODING = "Transfer-Encoding";
+ /** The HTTP Vary header field name. */
+ public static final String VARY = "Vary";
+ /** The HTTP WWW-Authenticate header field name. */
+ public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
+
+ // Common, non-standard HTTP header fields
+
+ /** The HTTP DNT header field name. */
+ public static final String DNT = "DNT";
+ /** The HTTP X-Content-Type-Options header field name. */
+ public static final String X_CONTENT_TYPE_OPTIONS = "X-Content-Type-Options";
+ /** The HTTP X-Do-Not-Track header field name. */
+ public static final String X_DO_NOT_TRACK = "X-Do-Not-Track";
+ /** The HTTP X-Forwarded-For header field name. */
+ public static final String X_FORWARDED_FOR = "X-Forwarded-For";
+ /** The HTTP X-Forwarded-Proto header field name. */
+ public static final String X_FORWARDED_PROTO = "X-Forwarded-Proto";
+ /** The HTTP X-Frame-Options header field name. */
+ public static final String X_FRAME_OPTIONS = "X-Frame-Options";
+ /** The HTTP X-Powered-By header field name. */
+ public static final String X_POWERED_BY = "X-Powered-By";
+ /** The HTTP X-Requested-With header field name. */
+ public static final String X_REQUESTED_WITH = "X-Requested-With";
+ /** The HTTP X-User-IP header field name. */
+ public static final String X_USER_IP = "X-User-IP";
+ /** The HTTP X-XSS-Protection header field name. */
+ public static final String X_XSS_PROTECTION = "X-XSS-Protection";
+
+}
diff --git a/guava/src/com/google/common/net/InetAddresses.java b/guava/src/com/google/common/net/InetAddresses.java
new file mode 100644
index 0000000..8eddd0d
--- /dev/null
+++ b/guava/src/com/google/common/net/InetAddresses.java
@@ -0,0 +1,1011 @@
+/*
+ * 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.Beta;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.hash.Hashing;
+import com.google.common.io.ByteStreams;
+import com.google.common.primitives.Ints;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import javax.annotation.Nullable;
+
+/**
+ * Static utility methods pertaining to {@link InetAddress} instances.
+ *
+ * <p><b>Important note:</b> Unlike {@code InetAddress.getByName()}, the
+ * methods of this class never cause DNS services to be accessed. For
+ * this reason, you should prefer these methods as much as possible over
+ * their JDK equivalents whenever you are expecting to handle only
+ * IP address string literals -- there is no blocking DNS penalty for a
+ * malformed string.
+ *
+ * <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
+ * in network byte order.
+ *
+ * <p>Examples of IP addresses and their byte representations:
+ * <ul>
+ * <li>The IPv4 loopback address, {@code "127.0.0.1"}.<br/>
+ * {@code 7f 00 00 01}
+ *
+ * <li>The IPv6 loopback address, {@code "::1"}.<br/>
+ * {@code 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01}
+ *
+ * <li>From the IPv6 reserved documentation prefix ({@code 2001:db8::/32}),
+ * {@code "2001:db8::1"}.<br/>
+ * {@code 20 01 0d b8 00 00 00 00 00 00 00 00 00 00 00 01}
+ *
+ * <li>An IPv6 "IPv4 compatible" (or "compat") address,
+ * {@code "::192.168.0.1"}.<br/>
+ * {@code 00 00 00 00 00 00 00 00 00 00 00 00 c0 a8 00 01}
+ *
+ * <li>An IPv6 "IPv4 mapped" address, {@code "::ffff:192.168.0.1"}.<br/>
+ * {@code 00 00 00 00 00 00 00 00 00 00 ff ff c0 a8 00 01}
+ * </ul>
+ *
+ * <p>A few notes about IPv6 "IPv4 mapped" addresses and their observed
+ * use in Java.
+ * <br><br>
+ * "IPv4 mapped" addresses were originally a representation of IPv4
+ * addresses for use on an IPv6 socket that could receive both IPv4
+ * and IPv6 connections (by disabling the {@code IPV6_V6ONLY} socket
+ * option on an IPv6 socket). Yes, it's confusing. Nevertheless,
+ * these "mapped" addresses were never supposed to be seen on the
+ * wire. That assumption was dropped, some say mistakenly, in later
+ * RFCs with the apparent aim of making IPv4-to-IPv6 transition simpler.
+ *
+ * <p>Technically one <i>can</i> create a 128bit IPv6 address with the wire
+ * format of a "mapped" address, as shown above, and transmit it in an
+ * IPv6 packet header. However, Java's InetAddress creation methods
+ * appear to adhere doggedly to the original intent of the "mapped"
+ * address: all "mapped" addresses return {@link Inet4Address} objects.
+ *
+ * <p>For added safety, it is common for IPv6 network operators to filter
+ * all packets where either the source or destination address appears to
+ * be a "compat" or "mapped" address. Filtering suggestions usually
+ * recommend discarding any packets with source or destination addresses
+ * in the invalid range {@code ::/3}, which includes both of these bizarre
+ * address formats. For more information on "bogons", including lists
+ * of IPv6 bogon space, see:
+ *
+ * <ul>
+ * <li><a target="_parent"
+ * href="http://en.wikipedia.org/wiki/Bogon_filtering"
+ * >http://en.wikipedia.org/wiki/Bogon_filtering</a>
+ * <li><a target="_parent"
+ * href="http://www.cymru.com/Bogons/ipv6.txt"
+ * >http://www.cymru.com/Bogons/ipv6.txt</a>
+ * <li><a target="_parent"
+ * href="http://www.cymru.com/Bogons/v6bogon.html"
+ * >http://www.cymru.com/Bogons/v6bogon.html</a>
+ * <li><a target="_parent"
+ * href="http://www.space.net/~gert/RIPE/ipv6-filters.html"
+ * >http://www.space.net/~gert/RIPE/ipv6-filters.html</a>
+ * </ul>
+ *
+ * @author Erik Kline
+ * @since 5.0
+ */
+@Beta
+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 InetAddresses() {}
+
+ /**
+ * 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
+ */
+ 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);
+ }
+
+ /**
+ * 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"}
+ * @return {@link InetAddress} representing the argument
+ * @throws IllegalArgumentException if the argument is not a valid IP string literal
+ */
+ public static InetAddress forString(String ipString) {
+ byte[] addr = ipStringToBytes(ipString);
+
+ // The argument was malformed, i.e. not an IP string literal.
+ if (addr == null) {
+ throw new IllegalArgumentException(
+ String.format("'%s' is not an IP string literal.", ipString));
+ }
+
+ return bytesToInetAddress(addr);
+ }
+
+ /**
+ * Returns {@code true} if the supplied string is a valid IP string
+ * literal, {@code false} otherwise.
+ *
+ * @param ipString {@code String} to evaluated as an IP string literal
+ * @return {@code true} if the argument is a valid IP string literal
+ */
+ public static boolean isInetAddress(String ipString) {
+ return ipStringToBytes(ipString) != null;
+ }
+
+ private static byte[] ipStringToBytes(String ipString) {
+ // Make a first pass to categorize the characters in this string.
+ boolean hasColon = false;
+ boolean hasDot = false;
+ for (int i = 0; i < ipString.length(); i++) {
+ char c = ipString.charAt(i);
+ if (c == '.') {
+ hasDot = true;
+ } else if (c == ':') {
+ if (hasDot) {
+ return null; // Colons must not appear after dots.
+ }
+ hasColon = true;
+ } else if (Character.digit(c, 16) == -1) {
+ return null; // Everything else must be a decimal or hex digit.
+ }
+ }
+
+ // Now decide which address family to parse.
+ if (hasColon) {
+ if (hasDot) {
+ ipString = convertDottedQuadToHex(ipString);
+ if (ipString == null) {
+ return null;
+ }
+ }
+ return textToNumericFormatV6(ipString);
+ } else if (hasDot) {
+ return textToNumericFormatV4(ipString);
+ }
+ return null;
+ }
+
+ private static byte[] textToNumericFormatV4(String ipString) {
+ String[] address = ipString.split("\\.", IPV4_PART_COUNT + 1);
+ if (address.length != IPV4_PART_COUNT) {
+ return null;
+ }
+
+ byte[] bytes = new byte[IPV4_PART_COUNT];
+ try {
+ for (int i = 0; i < bytes.length; i++) {
+ bytes[i] = parseOctet(address[i]);
+ }
+ } catch (NumberFormatException ex) {
+ return null;
+ }
+
+ return bytes;
+ }
+
+ private static byte[] textToNumericFormatV6(String ipString) {
+ // An address can have [2..8] colons, and N colons make N+1 parts.
+ String[] parts = ipString.split(":", IPV6_PART_COUNT + 2);
+ if (parts.length < 3 || parts.length > IPV6_PART_COUNT + 1) {
+ return null;
+ }
+
+ // Disregarding the endpoints, find "::" with nothing in between.
+ // This indicates that a run of zeroes has been skipped.
+ int skipIndex = -1;
+ for (int i = 1; i < parts.length - 1; i++) {
+ if (parts[i].length() == 0) {
+ if (skipIndex >= 0) {
+ return null; // Can't have more than one ::
+ }
+ skipIndex = i;
+ }
+ }
+
+ int partsHi; // Number of parts to copy from above/before the "::"
+ int partsLo; // Number of parts to copy from below/after the "::"
+ if (skipIndex >= 0) {
+ // If we found a "::", then check if it also covers the endpoints.
+ partsHi = skipIndex;
+ partsLo = parts.length - skipIndex - 1;
+ if (parts[0].length() == 0 && --partsHi != 0) {
+ return null; // ^: requires ^::
+ }
+ if (parts[parts.length - 1].length() == 0 && --partsLo != 0) {
+ return null; // :$ requires ::$
+ }
+ } else {
+ // Otherwise, allocate the entire address to partsHi. The endpoints
+ // could still be empty, but parseHextet() will check for that.
+ partsHi = parts.length;
+ partsLo = 0;
+ }
+
+ // If we found a ::, then we must have skipped at least one part.
+ // Otherwise, we must have exactly the right number of parts.
+ int partsSkipped = IPV6_PART_COUNT - (partsHi + partsLo);
+ if (!(skipIndex >= 0 ? partsSkipped >= 1 : partsSkipped == 0)) {
+ return null;
+ }
+
+ // Now parse the hextets into a byte array.
+ ByteBuffer rawBytes = ByteBuffer.allocate(2 * IPV6_PART_COUNT);
+ try {
+ for (int i = 0; i < partsHi; i++) {
+ rawBytes.putShort(parseHextet(parts[i]));
+ }
+ for (int i = 0; i < partsSkipped; i++) {
+ rawBytes.putShort((short) 0);
+ }
+ for (int i = partsLo; i > 0; i--) {
+ rawBytes.putShort(parseHextet(parts[parts.length - i]));
+ }
+ } catch (NumberFormatException ex) {
+ return null;
+ }
+ return rawBytes.array();
+ }
+
+ private static String convertDottedQuadToHex(String ipString) {
+ int lastColon = ipString.lastIndexOf(':');
+ String initialPart = ipString.substring(0, lastColon + 1);
+ String dottedQuad = ipString.substring(lastColon + 1);
+ byte[] quad = textToNumericFormatV4(dottedQuad);
+ if (quad == null) {
+ return null;
+ }
+ String penultimate = Integer.toHexString(((quad[0] & 0xff) << 8) | (quad[1] & 0xff));
+ String ultimate = Integer.toHexString(((quad[2] & 0xff) << 8) | (quad[3] & 0xff));
+ return initialPart + penultimate + ":" + ultimate;
+ }
+
+ private static byte parseOctet(String ipPart) {
+ // Note: we already verified that this string contains only hex digits.
+ int octet = Integer.parseInt(ipPart);
+ // Disallow leading zeroes, because no clear standard exists on
+ // whether these should be interpreted as decimal or octal.
+ if (octet > 255 || (ipPart.startsWith("0") && ipPart.length() > 1)) {
+ throw new NumberFormatException();
+ }
+ return (byte) octet;
+ }
+
+ private static short parseHextet(String ipPart) {
+ // Note: we already verified that this string contains only hex digits.
+ int hextet = Integer.parseInt(ipPart, 16);
+ if (hextet > 0xffff) {
+ throw new NumberFormatException();
+ }
+ return (short) hextet;
+ }
+
+ /**
+ * 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
+ * {@link InetAddress#getHostAddress()}, but for IPv6 addresses, the output
+ * follows <a href="http://tools.ietf.org/html/rfc5952">RFC 5952</a>
+ * section 4. The main difference is that this method uses "::" for zero
+ * compression, while Java's version uses the uncompressed form.
+ *
+ * <p>This method uses hexadecimal for all IPv6 addresses, including
+ * IPv4-mapped IPv6 addresses such as "::c000:201". The output does not
+ * include a Scope ID.
+ *
+ * @param ip {@link InetAddress} to be converted to an address string
+ * @return {@code String} containing the text-formatted IP address
+ * @since 10.0
+ */
+ public static String toAddrString(InetAddress ip) {
+ Preconditions.checkNotNull(ip);
+ if (ip instanceof Inet4Address) {
+ // For IPv4, Java's formatting is good enough.
+ return ip.getHostAddress();
+ }
+ Preconditions.checkArgument(ip instanceof Inet6Address);
+ byte[] bytes = ip.getAddress();
+ int[] hextets = new int[IPV6_PART_COUNT];
+ for (int i = 0; i < hextets.length; i++) {
+ hextets[i] = Ints.fromBytes(
+ (byte) 0, (byte) 0, bytes[2 * i], bytes[2 * i + 1]);
+ }
+ compressLongestRunOfZeroes(hextets);
+ return hextetsToIPv6String(hextets);
+ }
+
+ /**
+ * Identify and mark the longest run of zeroes in an IPv6 address.
+ *
+ * <p>Only runs of two or more hextets are considered. In case of a tie, the
+ * 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
+ */
+ private static void compressLongestRunOfZeroes(int[] hextets) {
+ int bestRunStart = -1;
+ int bestRunLength = -1;
+ int runStart = -1;
+ for (int i = 0; i < hextets.length + 1; i++) {
+ if (i < hextets.length && hextets[i] == 0) {
+ if (runStart < 0) {
+ runStart = i;
+ }
+ } else if (runStart >= 0) {
+ int runLength = i - runStart;
+ if (runLength > bestRunLength) {
+ bestRunStart = runStart;
+ bestRunLength = runLength;
+ }
+ runStart = -1;
+ }
+ }
+ if (bestRunLength >= 2) {
+ Arrays.fill(hextets, bestRunStart, bestRunStart + bestRunLength, -1);
+ }
+ }
+
+ /**
+ * 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
+ */
+ private static String hextetsToIPv6String(int[] hextets) {
+ /*
+ * While scanning the array, handle these state transitions:
+ * start->num => "num" start->gap => "::"
+ * num->num => ":num" num->gap => "::"
+ * gap->num => "num" gap->gap => ""
+ */
+ StringBuilder buf = new StringBuilder(39);
+ boolean lastWasNumber = false;
+ for (int i = 0; i < hextets.length; i++) {
+ boolean thisIsNumber = hextets[i] >= 0;
+ if (thisIsNumber) {
+ if (lastWasNumber) {
+ buf.append(':');
+ }
+ buf.append(Integer.toHexString(hextets[i]));
+ } else {
+ if (i == 0 || lastWasNumber) {
+ buf.append("::");
+ }
+ }
+ lastWasNumber = thisIsNumber;
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Returns the string representation of an {@link InetAddress} suitable
+ * for inclusion in a URI.
+ *
+ * <p>For IPv4 addresses, this is identical to
+ * {@link InetAddress#getHostAddress()}, but for IPv6 addresses it
+ * compresses zeroes and surrounds the text with square brackets; for example
+ * {@code "[2001:db8::1]"}.
+ *
+ * <p>Per section 3.2.2 of
+ * <a target="_parent"
+ * href="http://tools.ietf.org/html/rfc3986#section-3.2.2"
+ * >http://tools.ietf.org/html/rfc3986</a>,
+ * a URI containing an IPv6 string literal is of the form
+ * {@code "http://[2001:db8::1]:8888/index.html"}.
+ *
+ * <p>Use of either {@link InetAddresses#toAddrString},
+ * {@link InetAddress#getHostAddress()}, or this method is recommended over
+ * {@link InetAddress#toString()} when an IP address string literal is
+ * desired. This is because {@link InetAddress#toString()} prints the
+ * hostname and the IP address string joined by a "/".
+ *
+ * @param ip {@link InetAddress} to be converted to URI string literal
+ * @return {@code String} containing URI-safe string literal
+ */
+ public static String toUriString(InetAddress ip) {
+ if (ip instanceof Inet6Address) {
+ return "[" + toAddrString(ip) + "]";
+ }
+ return toAddrString(ip);
+ }
+
+ /**
+ * Returns an InetAddress representing the literal IPv4 or IPv6 host
+ * portion of a URL, encoded in the format specified by RFC 3986 section 3.2.2.
+ *
+ * <p>This function is similar to {@link InetAddresses#forString(String)},
+ * however, it requires that IPv6 addresses are surrounded by square brackets.
+ *
+ * <p>This function is the inverse of
+ * {@link InetAddresses#toUriString(java.net.InetAddress)}.
+ *
+ * @param hostAddr A RFC 3986 section 3.2.2 encoded IPv4 or IPv6 address
+ * @return an InetAddress representing the address in {@code hostAddr}
+ * @throws IllegalArgumentException if {@code hostAddr} is not a valid
+ * IPv4 address, or IPv6 address surrounded by square brackets
+ */
+ public static InetAddress forUriString(String hostAddr) {
+ Preconditions.checkNotNull(hostAddr);
+
+ // 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;
+ }
+
+ // 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));
+ }
+
+ return bytesToInetAddress(addr);
+ }
+
+ /**
+ * Returns {@code true} if the supplied string is a valid URI IP string
+ * literal, {@code false} otherwise.
+ *
+ * @param ipString {@code String} to evaluated as an IP URI host string literal
+ * @return {@code true} if the argument is a valid IP URI host
+ */
+ public static boolean isUriInetAddress(String ipString) {
+ try {
+ forUriString(ipString);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Evaluates whether the argument is an IPv6 "compat" address.
+ *
+ * <p>An "IPv4 compatible", or "compat", address is one with 96 leading
+ * bits of zero, with the remaining 32 bits interpreted as an
+ * IPv4 address. These are conventionally represented in string
+ * literals as {@code "::192.168.0.1"}, though {@code "::c0a8:1"} is
+ * also considered an IPv4 compatible address (and equivalent to
+ * {@code "::192.168.0.1"}).
+ *
+ * <p>For more on IPv4 compatible addresses see section 2.5.5.1 of
+ * <a target="_parent"
+ * href="http://tools.ietf.org/html/rfc4291#section-2.5.5.1"
+ * >http://tools.ietf.org/html/rfc4291</a>
+ *
+ * <p>NOTE: This method is different from
+ * {@link Inet6Address#isIPv4CompatibleAddress} in that it more
+ * correctly classifies {@code "::"} and {@code "::1"} as
+ * 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
+ * @return {@code true} if the argument is a valid "compat" address
+ */
+ public static boolean isCompatIPv4Address(Inet6Address ip) {
+ if (!ip.isIPv4CompatibleAddress()) {
+ return false;
+ }
+
+ byte[] bytes = ip.getAddress();
+ if ((bytes[12] == 0) && (bytes[13] == 0) && (bytes[14] == 0)
+ && ((bytes[15] == 0) || (bytes[15] == 1))) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the IPv4 address embedded in an IPv4 compatible 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
+ */
+ 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));
+ }
+
+ /**
+ * Evaluates whether the argument is a 6to4 address.
+ *
+ * <p>6to4 addresses begin with the {@code "2002::/16"} prefix.
+ * The next 32 bits are the IPv4 address of the host to which
+ * IPv6-in-IPv4 tunneled packets should be routed.
+ *
+ * <p>For more on 6to4 addresses see section 2 of
+ * <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
+ * @return {@code true} if the argument is a 6to4 address
+ */
+ public static boolean is6to4Address(Inet6Address ip) {
+ byte[] bytes = ip.getAddress();
+ return (bytes[0] == (byte) 0x20) && (bytes[1] == (byte) 0x02);
+ }
+
+ /**
+ * 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
+ */
+ 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));
+ }
+
+ /**
+ * A simple immutable 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
+ * of the IPv6 address as part of the protocol. More protocols details
+ * can be found at:
+ * <a target="_parent" href="http://en.wikipedia.org/wiki/Teredo_tunneling"
+ * >http://en.wikipedia.org/wiki/Teredo_tunneling</a>.
+ *
+ * <p>The RFC can be found here:
+ * <a target="_parent" href="http://tools.ietf.org/html/rfc4380"
+ * >http://tools.ietf.org/html/rfc4380</a>.
+ *
+ * @since 5.0
+ */
+ @Beta
+ public static final class TeredoInfo {
+ private final Inet4Address server;
+ private final Inet4Address client;
+ private final int port;
+ private final int flags;
+
+ /**
+ * Constructs a TeredoInfo instance.
+ *
+ * <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
+ */
+ // TODO: why is this public?
+ 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);
+ this.port = port;
+ this.flags = flags;
+ }
+
+ public Inet4Address getServer() {
+ return server;
+ }
+
+ public Inet4Address getClient() {
+ return client;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+ }
+
+ /**
+ * Evaluates whether the argument is a Teredo address.
+ *
+ * <p>Teredo addresses begin with the {@code "2001::/32"} prefix.
+ *
+ * @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) {
+ byte[] bytes = ip.getAddress();
+ return (bytes[0] == (byte) 0x20) && (bytes[1] == (byte) 0x01)
+ && (bytes[2] == 0) && (bytes[3] == 0);
+ }
+
+ /**
+ * Returns the Teredo information embedded in a Teredo address.
+ *
+ * @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
+ */
+ 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));
+
+ 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);
+ 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];
+ }
+ Inet4Address client = getInet4Address(clientBytes);
+
+ return new TeredoInfo(server, client, port, flags);
+ }
+
+ /**
+ * Evaluates whether the argument is an ISATAP address.
+ *
+ * <p>From RFC 5214: "ISATAP interface identifiers are constructed in
+ * Modified EUI-64 format [...] by concatenating the 24-bit IANA OUI
+ * (00-00-5E), the 8-bit hexadecimal value 0xFE, and a 32-bit IPv4
+ * address in network byte order [...]"
+ *
+ * <p>For more on ISATAP addresses see section 6.1 of
+ * <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
+ * @return {@code true} if the argument is an ISATAP address
+ */
+ public static boolean isIsatapAddress(Inet6Address ip) {
+
+ // If it's a Teredo address with the right port (41217, or 0xa101)
+ // which would be encoded as 0x5efe then it can't be an ISATAP address.
+ if (isTeredoAddress(ip)) {
+ return false;
+ }
+
+ byte[] bytes = ip.getAddress();
+
+ if ((bytes[8] | (byte) 0x03) != (byte) 0x03) {
+
+ // Verify that high byte of the 64 bit identifier is zero, modulo
+ // the U/L and G bits, with which we are not concerned.
+ return false;
+ }
+
+ return (bytes[9] == (byte) 0x00) && (bytes[10] == (byte) 0x5e)
+ && (bytes[11] == (byte) 0xfe);
+ }
+
+ /**
+ * Returns the IPv4 address embedded in an 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
+ */
+ 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));
+ }
+
+ /**
+ * Examines the Inet6Address to determine if it is an IPv6 address of one
+ * of the specified address types that contain an embedded IPv4 address.
+ *
+ * <p>NOTE: ISATAP addresses are explicitly excluded from this method
+ * 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
+ * @since 7.0
+ */
+ public static boolean hasEmbeddedIPv4ClientAddress(Inet6Address ip) {
+ return isCompatIPv4Address(ip) || is6to4Address(ip) || isTeredoAddress(ip);
+ }
+
+ /**
+ * Examines the Inet6Address to extract the embedded IPv4 client address
+ * if the InetAddress is an IPv6 address of one of the specified address
+ * types that contain an embedded IPv4 address.
+ *
+ * <p>NOTE: ISATAP addresses are explicitly excluded from this method
+ * 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
+ */
+ public static Inet4Address getEmbeddedIPv4ClientAddress(Inet6Address ip) {
+ if (isCompatIPv4Address(ip)) {
+ return getCompatIPv4Address(ip);
+ }
+
+ if (is6to4Address(ip)) {
+ return get6to4IPv4Address(ip);
+ }
+
+ if (isTeredoAddress(ip)) {
+ return getTeredoInfo(ip).getClient();
+ }
+
+ throw new IllegalArgumentException(
+ String.format("'%s' has no embedded IPv4 address.", toAddrString(ip)));
+ }
+
+ /**
+ * Evaluates whether the argument is an "IPv4 mapped" IPv6 address.
+ *
+ * <p>An "IPv4 mapped" address is anything in the range ::ffff:0:0/96
+ * (sometimes written as ::ffff:0.0.0.0/96), with the last 32 bits
+ * interpreted as an IPv4 address.
+ *
+ * <p>For more on IPv4 mapped addresses see section 2.5.5.2 of
+ * <a target="_parent"
+ * href="http://tools.ietf.org/html/rfc4291#section-2.5.5.2"
+ * >http://tools.ietf.org/html/rfc4291</a>
+ *
+ * <p>Note: This method takes a {@code String} argument because
+ * {@link InetAddress} automatically collapses mapped addresses to IPv4.
+ * (It is actually possible to avoid this using one of the obscure
+ * {@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
+ * @return {@code true} if the argument is a valid "mapped" address
+ * @since 10.0
+ */
+ public static boolean isMappedIPv4Address(String ipString) {
+ byte[] bytes = ipStringToBytes(ipString);
+ if (bytes != null && bytes.length == 16) {
+ for (int i = 0; i < 10; i++) {
+ if (bytes[i] != 0) {
+ return false;
+ }
+ }
+ for (int i = 10; i < 12; i++) {
+ if (bytes[i] != (byte) 0xff) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Coerces an IPv6 address into an IPv4 address.
+ *
+ * <p>HACK: As long as applications continue to use IPv4 addresses for
+ * indexing into tables, accounting, et cetera, it may be necessary to
+ * <b>coerce</b> IPv6 addresses into IPv4 addresses. This function does
+ * so by hashing the upper 64 bits into {@code 224.0.0.0/3}
+ * (64 bits into 29 bits).
+ *
+ * <p>A "coerced" IPv4 address is equivalent to itself.
+ *
+ * <p>NOTE: This function is failsafe for security purposes: ALL IPv6
+ * addresses (except localhost (::1)) are hashed to avoid the security
+ * risk associated with extracting an embedded IPv4 address that might
+ * permit elevated privileges.
+ *
+ * @param ip {@link InetAddress} to "coerce"
+ * @return {@link Inet4Address} represented "coerced" address
+ * @since 7.0
+ */
+ public static Inet4Address getCoercedIPv4Address(InetAddress ip) {
+ if (ip instanceof Inet4Address) {
+ return (Inet4Address) ip;
+ }
+
+ // Special cases:
+ byte[] bytes = ip.getAddress();
+ boolean leadingBytesOfZero = true;
+ for (int i = 0; i < 15; ++i) {
+ if (bytes[i] != 0) {
+ leadingBytesOfZero = false;
+ break;
+ }
+ }
+ if (leadingBytesOfZero && (bytes[15] == 1)) {
+ return LOOPBACK4; // ::1
+ } else if (leadingBytesOfZero && (bytes[15] == 0)) {
+ return ANY4; // ::0
+ }
+
+ Inet6Address ip6 = (Inet6Address) ip;
+ long addressAsLong = 0;
+ if (hasEmbeddedIPv4ClientAddress(ip6)) {
+ addressAsLong = getEmbeddedIPv4ClientAddress(ip6).hashCode();
+ } else {
+
+ // Just extract the high 64 bits (assuming the rest is user-modifiable).
+ addressAsLong = ByteBuffer.wrap(ip6.getAddress(), 0, 8).getLong();
+ }
+
+ // Many strategies for hashing are possible. This might suffice for now.
+ int coercedHash = Hashing.murmur3_32().hashLong(addressAsLong).asInt();
+
+ // Squash into 224/4 Multicast and 240/4 Reserved space (i.e. 224/3).
+ coercedHash |= 0xe0000000;
+
+ // Fixup to avoid some "illegal" values. Currently the only potential
+ // illegal value is 255.255.255.255.
+ if (coercedHash == 0xffffffff) {
+ coercedHash = 0xfffffffe;
+ }
+
+ return getInet4Address(Ints.toByteArray(coercedHash));
+ }
+
+ /**
+ * Returns an integer representing an IPv4 address regardless of
+ * whether the supplied argument is an IPv4 address or not.
+ *
+ * <p>IPv6 addresses are <b>coerced</b> to IPv4 addresses before being
+ * converted to integers.
+ *
+ * <p>As long as there are applications that assume that all IP addresses
+ * are IPv4 addresses and can therefore be converted safely to integers
+ * (for whatever purpose) this function can be used to handle IPv6
+ * addresses as well until the application is suitably fixed.
+ *
+ * <p>NOTE: an IPv6 address coerced to an IPv4 address can only be used
+ * for such purposes as rudimentary identification or indexing into a
+ * collection of real {@link InetAddress}es. They cannot be used as
+ * real addresses for the purposes of network communication.
+ *
+ * @param ip {@link InetAddress} to convert
+ * @return {@code int}, "coerced" if ip is not an IPv4 address
+ * @since 7.0
+ */
+ public static int coerceToInteger(InetAddress ip) {
+ return ByteStreams.newDataInput(getCoercedIPv4Address(ip).getAddress()).readInt();
+ }
+
+ /**
+ * Returns an Inet4Address having the integer value specified by
+ * the argument.
+ *
+ * @param address {@code int}, the 32bit integer address to be converted
+ * @return {@link Inet4Address} equivalent of the argument
+ */
+ public static Inet4Address fromInteger(int address) {
+ return getInet4Address(Ints.toByteArray(address));
+ }
+
+ /**
+ * Returns an address from a <b>little-endian ordered</b> byte array
+ * (the opposite of what {@link InetAddress#getByAddress} expects).
+ *
+ * <p>IPv4 address byte array must be 4 bytes long and IPv6 byte array
+ * must be 16 bytes long.
+ *
+ * @param addr the raw IP address in little-endian byte order
+ * @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 {
+ byte[] reversed = new byte[addr.length];
+ for (int i = 0; i < addr.length; i++) {
+ reversed[i] = addr[addr.length - i - 1];
+ }
+ return InetAddress.getByAddress(reversed);
+ }
+
+ /**
+ * Returns a new InetAddress that is one more than the passed in address.
+ * 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
+ * @since 10.0
+ */
+ public static InetAddress increment(InetAddress address) {
+ byte[] addr = address.getAddress();
+ int i = addr.length - 1;
+ while (i >= 0 && addr[i] == (byte) 0xff) {
+ addr[i] = 0;
+ i--;
+ }
+
+ Preconditions.checkArgument(i >= 0, "Incrementing %s would wrap.", address);
+
+ addr[i]++;
+ return bytesToInetAddress(addr);
+ }
+
+ /**
+ * Returns true if the InetAddress is either 255.255.255.255 for IPv4 or
+ * 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
+ * @since 10.0
+ */
+ public static boolean isMaximum(InetAddress address) {
+ byte[] addr = address.getAddress();
+ for (int i = 0; i < addr.length; i++) {
+ if (addr[i] != (byte) 0xff) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/guava/src/com/google/common/net/InternetDomainName.java b/guava/src/com/google/common/net/InternetDomainName.java
new file mode 100644
index 0000000..ace7cf2
--- /dev/null
+++ b/guava/src/com/google/common/net/InternetDomainName.java
@@ -0,0 +1,580 @@
+/*
+ * 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.net;
+
+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.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * An immutable well-formed internet domain name, such as {@code com} or {@code
+ * foo.co.uk}. Only syntactic analysis is performed; no DNS lookups or other
+ * network interactions take place. Thus there is no guarantee that the domain
+ * actually exists on the internet.
+ *
+ * <p>One common use of this class is to determine whether a given string is
+ * likely to represent an addressable domain on the web -- that is, for a
+ * candidate string {@code "xxx"}, might browsing to {@code "http://xxx/"}
+ * result in a webpage being displayed? In the past, this test was frequently
+ * done by determining whether the domain ended with a {@linkplain
+ * #isPublicSuffix() public suffix} but was not itself a public suffix. However,
+ * this test is no longer accurate. There are many domains which are both public
+ * suffixes and addressable as hosts; {@code "uk.com"} is one example. As a
+ * result, the only useful test to determine if a domain is a plausible web host
+ * is {@link #hasPublicSuffix()}. This will return {@code true} for many domains
+ * which (currently) are not hosts, such as {@code "com"}), but given that any
+ * public suffix may become a host without warning, it is better to err on the
+ * side of permissiveness and thus avoid spurious rejection of valid sites.
+ *
+ * <p>During construction, names are normalized in two ways:
+ * <ol>
+ * <li>ASCII uppercase characters are converted to lowercase.
+ * <li>Unicode dot separators other than the ASCII period ({@code '.'}) are
+ * converted to the ASCII period.
+ * </ol>
+ * The normalized values will be returned from {@link #name()} and
+ * {@link #parts()}, and will be reflected in the result of
+ * {@link #equals(Object)}.
+ *
+ * <p><a href="http://en.wikipedia.org/wiki/Internationalized_domain_name">
+ * internationalized domain names</a> such as {@code 网络.cn} are supported, as
+ * are the equivalent <a
+ * href="http://en.wikipedia.org/wiki/Internationalized_domain_name">IDNA
+ * Punycode-encoded</a> versions.
+ *
+ * @author Craig Berry
+ * @since 5.0
+ */
+@Beta
+@GwtCompatible(emulated = true)
+public final class InternetDomainName {
+
+ private static final CharMatcher DOTS_MATCHER =
+ CharMatcher.anyOf(".\u3002\uFF0E\uFF61");
+ private static final Splitter DOT_SPLITTER = Splitter.on('.');
+ private static final Joiner DOT_JOINER = Joiner.on('.');
+
+ /**
+ * Value of {@link #publicSuffixIndex} which indicates that no public suffix
+ * was found.
+ */
+ private static final int NO_PUBLIC_SUFFIX_FOUND = -1;
+
+ private static final String DOT_REGEX = "\\.";
+
+ /**
+ * Maximum parts (labels) in a domain name. This value arises from
+ * the 255-octet limit described in
+ * <a href="http://www.ietf.org/rfc/rfc2181.txt">RFC 2181</a> part 11 with
+ * the fact that the encoding of each part occupies at least two bytes
+ * (dot plus label externally, length byte plus label internally). Thus, if
+ * all labels have the minimum size of one byte, 127 of them will fit.
+ */
+ private static final int MAX_PARTS = 127;
+
+ /**
+ * Maximum length of a full domain name, including separators, and
+ * leaving room for the root label. See
+ * <a href="http://www.ietf.org/rfc/rfc2181.txt">RFC 2181</a> part 11.
+ */
+ private static final int MAX_LENGTH = 253;
+
+ /**
+ * Maximum size of a single part of a domain name. See
+ * <a href="http://www.ietf.org/rfc/rfc2181.txt">RFC 2181</a> part 11.
+ */
+ private static final int MAX_DOMAIN_PART_LENGTH = 63;
+
+ /**
+ * The full domain name, converted to lower case.
+ */
+ private final String name;
+
+ /**
+ * The parts of the domain name, converted to lower case.
+ */
+ private final ImmutableList<String> parts;
+
+ /**
+ * The index in the {@link #parts()} list at which the public suffix begins.
+ * For example, for the domain name {@code www.google.co.uk}, the value would
+ * be 2 (the index of the {@code co} part). The value is negative
+ * (specifically, {@link #NO_PUBLIC_SUFFIX_FOUND}) if no public suffix was
+ * found.
+ */
+ private final int publicSuffixIndex;
+
+ /**
+ * Constructor used to implement {@link #from(String)}, and from subclasses.
+ */
+ InternetDomainName(String name) {
+ // Normalize:
+ // * ASCII characters to lowercase
+ // * All dot-like characters to '.'
+ // * Strip trailing '.'
+
+ name = Ascii.toLowerCase(DOTS_MATCHER.replaceFrom(name, '.'));
+
+ if (name.endsWith(".")) {
+ name = name.substring(0, name.length() - 1);
+ }
+
+ 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(validateSyntax(parts), "Not a valid domain name: '%s'", name);
+
+ this.publicSuffixIndex = findPublicSuffix();
+ }
+
+ /**
+ * Returns the index of the leftmost part of the public suffix, or -1 if not
+ * found. Note that the value defined as the "public suffix" may not be a
+ * public suffix according to {@link #isPublicSuffix()} if the domain ends
+ * with an excluded domain pattern such as {@code "nhs.uk"}.
+ */
+ private int findPublicSuffix() {
+ final int partsSize = parts.size();
+
+ for (int i = 0; i < partsSize; i++) {
+ String ancestorName = DOT_JOINER.join(parts.subList(i, partsSize));
+
+ if (TldPatterns.EXACT.contains(ancestorName)) {
+ return i;
+ }
+
+ // Excluded domains (e.g. !nhs.uk) use the next highest
+ // domain as the effective public suffix (e.g. uk).
+
+ if (TldPatterns.EXCLUDED.contains(ancestorName)) {
+ return i + 1;
+ }
+
+ if (matchesWildcardPublicSuffix(ancestorName)) {
+ return i;
+ }
+ }
+
+ return NO_PUBLIC_SUFFIX_FOUND;
+ }
+
+ /**
+ * A deprecated synonym for {@link #from(String)}.
+ *
+ * @param domain A domain name (not IP address)
+ * @throws IllegalArgumentException if {@code name} is not syntactically valid
+ * according to {@link #isValidLenient}
+ * @since 8.0 (previously named {@code from})
+ * @deprecated Use {@link #from(String)}
+ */
+ @Deprecated
+ public static InternetDomainName fromLenient(String domain) {
+ return from(domain);
+ }
+
+ /**
+ * Returns an instance of {@link InternetDomainName} after lenient
+ * validation. Specifically, validation against <a
+ * href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>
+ * ("Internationalizing Domain Names in Applications") is skipped, while
+ * validation against <a
+ * href="http://www.ietf.org/rfc/rfc1035.txt">RFC 1035</a> is relaxed in
+ * the following ways:
+ * <ul>
+ * <li>Any part containing non-ASCII characters is considered valid.
+ * <li>Underscores ('_') are permitted wherever dashes ('-') are permitted.
+ * <li>Parts other than the final part may start with a digit.
+ * </ul>
+ *
+ *
+ * @param domain A domain name (not IP address)
+ * @throws IllegalArgumentException if {@code name} is not syntactically valid
+ * according to {@link #isValid}
+ * @since 10.0 (previously named {@code fromLenient})
+ */
+ public static InternetDomainName from(String domain) {
+ return new InternetDomainName(checkNotNull(domain));
+ }
+
+ /**
+ * Validation method used by {@from} to ensure that the domain name is
+ * syntactically valid according to RFC 1035.
+ *
+ * @return Is the domain name syntactically valid?
+ */
+ private static boolean validateSyntax(List<String> parts) {
+ final int lastIndex = parts.size() - 1;
+
+ // Validate the last part specially, as it has different syntax rules.
+
+ if (!validatePart(parts.get(lastIndex), true)) {
+ return false;
+ }
+
+ for (int i = 0; i < lastIndex; i++) {
+ String part = parts.get(i);
+ if (!validatePart(part, false)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static final CharMatcher DASH_MATCHER = CharMatcher.anyOf("-_");
+
+ private static final CharMatcher PART_CHAR_MATCHER =
+ CharMatcher.JAVA_LETTER_OR_DIGIT.or(DASH_MATCHER);
+
+ /**
+ * Helper method for {@link #validateSyntax(List)}. Validates that one part of
+ * a domain name is valid.
+ *
+ * @param part The domain name part to be validated
+ * @param isFinalPart Is this the final (rightmost) domain part?
+ * @return Whether the part is valid
+ */
+ private static boolean validatePart(String part, boolean isFinalPart) {
+
+ // These tests could be collapsed into one big boolean expression, but
+ // they have been left as independent tests for clarity.
+
+ if (part.length() < 1 || part.length() > MAX_DOMAIN_PART_LENGTH) {
+ return false;
+ }
+
+ /*
+ * GWT claims to support java.lang.Character's char-classification methods,
+ * but it actually only works for ASCII. So for now, assume any non-ASCII
+ * characters are valid. The only place this seems to be documented is here:
+ * http://osdir.com/ml/GoogleWebToolkitContributors/2010-03/msg00178.html
+ *
+ * <p>ASCII characters in the part are expected to be valid per RFC 1035,
+ * with underscore also being allowed due to widespread practice.
+ */
+
+ String asciiChars = CharMatcher.ASCII.retainFrom(part);
+
+ if (!PART_CHAR_MATCHER.matchesAllOf(asciiChars)) {
+ return false;
+ }
+
+ // No initial or final dashes or underscores.
+
+ if (DASH_MATCHER.matches(part.charAt(0))
+ || DASH_MATCHER.matches(part.charAt(part.length() - 1))) {
+ return false;
+ }
+
+ /*
+ * Note that we allow (in contravention of a strict interpretation of the
+ * relevant RFCs) domain parts other than the last may begin with a digit
+ * (for example, "3com.com"). It's important to disallow an initial digit in
+ * the last part; it's the only thing that stops an IPv4 numeric address
+ * like 127.0.0.1 from looking like a valid domain name.
+ */
+
+ if (isFinalPart && CharMatcher.DIGIT.matches(part.charAt(0))) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the domain name, normalized to all lower case.
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Returns the individual components of this domain name, normalized to all
+ * lower case. For example, for the domain name {@code mail.google.com}, this
+ * method returns the list {@code ["mail", "google", "com"]}.
+ */
+ public ImmutableList<String> parts() {
+ return parts;
+ }
+
+ /**
+ * Indicates whether this domain name represents a <i>public suffix</i>, as
+ * defined by the Mozilla Foundation's
+ * <a href="http://publicsuffix.org/">Public Suffix List</a> (PSL). A public
+ * suffix is one under which Internet users can directly register names, such
+ * as {@code com}, {@code co.uk} or {@code pvt.k12.wy.us}. Examples of domain
+ * names that are <i>not</i> public suffixes include {@code google}, {@code
+ * google.com} and {@code foo.co.uk}.
+ *
+ * @return {@code true} if this domain name appears exactly on the public
+ * suffix list
+ * @since 6.0
+ */
+ public boolean isPublicSuffix() {
+ return publicSuffixIndex == 0;
+ }
+
+ /**
+ * Indicates whether this domain name ends in a {@linkplain #isPublicSuffix()
+ * public suffix}, including if it is a public suffix itself. For example,
+ * returns {@code true} for {@code www.google.com}, {@code foo.co.uk} and
+ * {@code com}, but not for {@code google} or {@code google.foo}. This is
+ * the recommended method for determining whether a domain is potentially an
+ * addressable host.
+ *
+ * @since 6.0
+ */
+ public boolean hasPublicSuffix() {
+ return publicSuffixIndex != NO_PUBLIC_SUFFIX_FOUND;
+ }
+
+ /**
+ * Returns the {@linkplain #isPublicSuffix() public suffix} portion of the
+ * domain name, or {@code null} if no public suffix is present.
+ *
+ * @since 6.0
+ */
+ public InternetDomainName publicSuffix() {
+ return hasPublicSuffix() ? ancestor(publicSuffixIndex) : null;
+ }
+
+ /**
+ * Indicates whether this domain name ends in a {@linkplain #isPublicSuffix()
+ * public suffix}, while not being a public suffix itself. For example,
+ * returns {@code true} for {@code www.google.com}, {@code foo.co.uk} and
+ * {@code bar.ca.us}, but not for {@code google}, {@code com}, or {@code
+ * google.foo}.
+ *
+ * <p><b>Warning:</b> a {@code false} result from this method does not imply
+ * that the domain does not represent an addressable host, as many public
+ * suffixes are also addressable hosts. Use {@link #hasPublicSuffix()} for
+ * that test.
+ *
+ * <p>This method can be used to determine whether it will probably be
+ * possible to set cookies on the domain, though even that depends on
+ * individual browsers' implementations of cookie controls. See
+ * <a href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a> for details.
+ *
+ * @since 6.0
+ */
+ public boolean isUnderPublicSuffix() {
+ return publicSuffixIndex > 0;
+ }
+
+ /**
+ * Indicates whether this domain name is composed of exactly one subdomain
+ * component followed by a {@linkplain #isPublicSuffix() public suffix}. For
+ * example, returns {@code true} for {@code google.com} and {@code foo.co.uk},
+ * but not for {@code www.google.com} or {@code co.uk}.
+ *
+ * <p><b>Warning:</b> A {@code true} result from this method does not imply
+ * that the domain is at the highest level which is addressable as a host, as
+ * many public suffixes are also addressable hosts. For example, the domain
+ * {@code bar.uk.com} has a public suffix of {@code uk.com}, so it would
+ * return {@code true} from this method. But {@code uk.com} is itself an
+ * addressable host.
+ *
+ * <p>This method can be used to determine whether a domain is probably the
+ * highest level for which cookies may be set, though even that depends on
+ * individual browsers' implementations of cookie controls. See
+ * <a href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a> for details.
+ *
+ * @since 6.0
+ */
+ public boolean isTopPrivateDomain() {
+ return publicSuffixIndex == 1;
+ }
+
+ /**
+ * Returns the portion of this domain name that is one level beneath the
+ * public suffix. For example, for {@code x.adwords.google.co.uk} it returns
+ * {@code google.co.uk}, since {@code co.uk} is a public suffix.
+ *
+ * <p>If {@link #isTopPrivateDomain()} is true, the current domain name
+ * instance is returned.
+ *
+ * <p>This method should not be used to determine the topmost parent domain
+ * which is addressable as a host, as many public suffixes are also
+ * addressable hosts. For example, the domain {@code foo.bar.uk.com} has
+ * a public suffix of {@code uk.com}, so it would return {@code bar.uk.com}
+ * from this method. But {@code uk.com} is itself an addressable host.
+ *
+ * <p>This method can be used to determine the probable highest level parent
+ * domain for which cookies may be set, though even that depends on individual
+ * browsers' implementations of cookie controls.
+ *
+ * @throws IllegalStateException if this domain does not end with a
+ * public suffix
+ * @since 6.0
+ */
+ public InternetDomainName topPrivateDomain() {
+ if (isTopPrivateDomain()) {
+ return this;
+ }
+ checkState(isUnderPublicSuffix(), "Not under a public suffix: %s", name);
+ return ancestor(publicSuffixIndex - 1);
+ }
+
+ /**
+ * Indicates whether this domain is composed of two or more parts.
+ */
+ public boolean hasParent() {
+ return parts.size() > 1;
+ }
+
+ /**
+ * Returns an {@code InternetDomainName} that is the immediate ancestor of
+ * this one; that is, the current domain with the leftmost part removed. For
+ * example, the parent of {@code www.google.com} is {@code google.com}.
+ *
+ * @throws IllegalStateException if the domain has no parent, as determined
+ * by {@link #hasParent}
+ */
+ public InternetDomainName parent() {
+ checkState(hasParent(), "Domain '%s' has no parent", name);
+ return ancestor(1);
+ }
+
+ /**
+ * Returns the ancestor of the current domain at the given number of levels
+ * "higher" (rightward) in the subdomain list. The number of levels must be
+ * non-negative, and less than {@code N-1}, where {@code N} is the number of
+ * parts in the domain.
+ *
+ * <p>TODO: Reasonable candidate for addition to public API.
+ */
+ private InternetDomainName ancestor(int levels) {
+ return from(DOT_JOINER.join(parts.subList(levels, parts.size())));
+ }
+
+ /**
+ * Creates and returns a new {@code InternetDomainName} by prepending the
+ * argument and a dot to the current name. For example, {@code
+ * InternetDomainName.from("foo.com").child("www.bar")} returns a new
+ * {@code InternetDomainName} with the value {@code www.bar.foo.com}. Only
+ * lenient validation is performed, as described {@link #from(String) here}.
+ *
+ * @throws NullPointerException if leftParts is null
+ * @throws IllegalArgumentException if the resulting name is not valid
+ */
+ public InternetDomainName child(String leftParts) {
+ return from(checkNotNull(leftParts) + "." + name);
+ }
+
+ /**
+ * A deprecated synonym for {@link #isValid(String)}.
+ *
+ * @since 8.0 (previously named {@code isValid})
+ * @deprecated Use {@link #isValid(String)} instead
+ */
+ @Deprecated
+ public static boolean isValidLenient(String name) {
+ return isValid(name);
+ }
+
+ /**
+ * Indicates whether the argument is a syntactically valid domain name using
+ * lenient validation. Specifically, validation against <a
+ * href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>
+ * ("Internationalizing Domain Names in Applications") is skipped.
+ *
+ * <p>The following two code snippets are equivalent:
+ *
+ * <pre> {@code
+ *
+ * domainName = InternetDomainName.isValid(name)
+ * ? InternetDomainName.from(name)
+ * : DEFAULT_DOMAIN;
+ * }</pre>
+ *
+ * <pre> {@code
+ *
+ * try {
+ * domainName = InternetDomainName.from(name);
+ * } catch (IllegalArgumentException e) {
+ * domainName = DEFAULT_DOMAIN;
+ * }}</pre>
+ *
+ * @since 8.0 (previously named {@code isValidLenient})
+ */
+ public static boolean isValid(String name) {
+ try {
+ from(name);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Does the domain name match one of the "wildcard" patterns (e.g.
+ * {@code "*.ar"})?
+ */
+ private static boolean matchesWildcardPublicSuffix(String domain) {
+ final String[] pieces = domain.split(DOT_REGEX, 2);
+ return pieces.length == 2 && TldPatterns.UNDER.contains(pieces[1]);
+ }
+
+ // TODO: specify this to return the same as name(); remove name()
+ @Override
+ public String toString() {
+ return Objects.toStringHelper(this).add("name", name).toString();
+ }
+
+ /**
+ * Equality testing is based on the text supplied by the caller,
+ * after normalization as described in the class documentation. For
+ * example, a non-ASCII Unicode domain name and the Punycode version
+ * of the same domain name would not be considered equal.
+ *
+ */
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+
+ if (object instanceof InternetDomainName) {
+ InternetDomainName that = (InternetDomainName) object;
+ return this.name.equals(that.name);
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
diff --git a/guava/src/com/google/common/net/MediaType.java b/guava/src/com/google/common/net/MediaType.java
new file mode 100644
index 0000000..c804b88
--- /dev/null
+++ b/guava/src/com/google/common/net/MediaType.java
@@ -0,0 +1,667 @@
+/*
+ * 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");
+ 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 */
+ 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");
+ 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 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");
+ 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(ATOM_UTF_8, ATOM_UTF_8)
+ .put(BZIP2, BZIP2)
+ .put(FORM_DATA, FORM_DATA)
+ .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(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(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
new file mode 100644
index 0000000..6fc4545
--- /dev/null
+++ b/guava/src/com/google/common/net/TldPatterns.java
@@ -0,0 +1,4633 @@
+
+// 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;
+
+/**
+ * A generated static class containing public members which provide domain
+ * name patterns used in determining whether a given domain name is an
+ * effective top-level domain (TLD).
+ */
+@GwtCompatible
+final class TldPatterns {
+ private TldPatterns() {}
+
+ /**
+ * If a hostname is contained in this set, it is a TLD.
+ */
+ static final ImmutableSet<String> EXACT = ImmutableSet.of(
+ "ac",
+ "com.ac",
+ "edu.ac",
+ "gov.ac",
+ "net.ac",
+ "mil.ac",
+ "org.ac",
+ "ad",
+ "nom.ad",
+ "ae",
+ "co.ae",
+ "net.ae",
+ "org.ae",
+ "sch.ae",
+ "ac.ae",
+ "gov.ae",
+ "mil.ae",
+ "aero",
+ "accident-investigation.aero",
+ "accident-prevention.aero",
+ "aerobatic.aero",
+ "aeroclub.aero",
+ "aerodrome.aero",
+ "agents.aero",
+ "aircraft.aero",
+ "airline.aero",
+ "airport.aero",
+ "air-surveillance.aero",
+ "airtraffic.aero",
+ "air-traffic-control.aero",
+ "ambulance.aero",
+ "amusement.aero",
+ "association.aero",
+ "author.aero",
+ "ballooning.aero",
+ "broker.aero",
+ "caa.aero",
+ "cargo.aero",
+ "catering.aero",
+ "certification.aero",
+ "championship.aero",
+ "charter.aero",
+ "civilaviation.aero",
+ "club.aero",
+ "conference.aero",
+ "consultant.aero",
+ "consulting.aero",
+ "control.aero",
+ "council.aero",
+ "crew.aero",
+ "design.aero",
+ "dgca.aero",
+ "educator.aero",
+ "emergency.aero",
+ "engine.aero",
+ "engineer.aero",
+ "entertainment.aero",
+ "equipment.aero",
+ "exchange.aero",
+ "express.aero",
+ "federation.aero",
+ "flight.aero",
+ "freight.aero",
+ "fuel.aero",
+ "gliding.aero",
+ "government.aero",
+ "groundhandling.aero",
+ "group.aero",
+ "hanggliding.aero",
+ "homebuilt.aero",
+ "insurance.aero",
+ "journal.aero",
+ "journalist.aero",
+ "leasing.aero",
+ "logistics.aero",
+ "magazine.aero",
+ "maintenance.aero",
+ "marketplace.aero",
+ "media.aero",
+ "microlight.aero",
+ "modelling.aero",
+ "navigation.aero",
+ "parachuting.aero",
+ "paragliding.aero",
+ "passenger-association.aero",
+ "pilot.aero",
+ "press.aero",
+ "production.aero",
+ "recreation.aero",
+ "repbody.aero",
+ "res.aero",
+ "research.aero",
+ "rotorcraft.aero",
+ "safety.aero",
+ "scientist.aero",
+ "services.aero",
+ "show.aero",
+ "skydiving.aero",
+ "software.aero",
+ "student.aero",
+ "taxi.aero",
+ "trader.aero",
+ "trading.aero",
+ "trainer.aero",
+ "union.aero",
+ "workinggroup.aero",
+ "works.aero",
+ "af",
+ "gov.af",
+ "com.af",
+ "org.af",
+ "net.af",
+ "edu.af",
+ "ag",
+ "com.ag",
+ "org.ag",
+ "net.ag",
+ "co.ag",
+ "nom.ag",
+ "ai",
+ "off.ai",
+ "com.ai",
+ "net.ai",
+ "org.ai",
+ "al",
+ "com.al",
+ "edu.al",
+ "gov.al",
+ "mil.al",
+ "net.al",
+ "org.al",
+ "am",
+ "an",
+ "com.an",
+ "net.an",
+ "org.an",
+ "edu.an",
+ "ao",
+ "ed.ao",
+ "gv.ao",
+ "og.ao",
+ "co.ao",
+ "pb.ao",
+ "it.ao",
+ "aq",
+ "e164.arpa",
+ "in-addr.arpa",
+ "ip6.arpa",
+ "iris.arpa",
+ "uri.arpa",
+ "urn.arpa",
+ "as",
+ "gov.as",
+ "asia",
+ "at",
+ "ac.at",
+ "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",
+ "act.edu.au",
+ "nsw.edu.au",
+ "nt.edu.au",
+ "qld.edu.au",
+ "sa.edu.au",
+ "tas.edu.au",
+ "vic.edu.au",
+ "wa.edu.au",
+ "act.gov.au",
+ "nt.gov.au",
+ "qld.gov.au",
+ "sa.gov.au",
+ "tas.gov.au",
+ "vic.gov.au",
+ "wa.gov.au",
+ "aw",
+ "com.aw",
+ "ax",
+ "az",
+ "com.az",
+ "net.az",
+ "int.az",
+ "gov.az",
+ "org.az",
+ "edu.az",
+ "info.az",
+ "pp.az",
+ "mil.az",
+ "name.az",
+ "pro.az",
+ "biz.az",
+ "ba",
+ "org.ba",
+ "net.ba",
+ "edu.ba",
+ "gov.ba",
+ "mil.ba",
+ "unsa.ba",
+ "unbi.ba",
+ "co.ba",
+ "com.ba",
+ "rs.ba",
+ "bb",
+ "biz.bb",
+ "com.bb",
+ "edu.bb",
+ "gov.bb",
+ "info.bb",
+ "net.bb",
+ "org.bb",
+ "store.bb",
+ "be",
+ "ac.be",
+ "bf",
+ "gov.bf",
+ "bg",
+ "a.bg",
+ "b.bg",
+ "c.bg",
+ "d.bg",
+ "e.bg",
+ "f.bg",
+ "g.bg",
+ "h.bg",
+ "i.bg",
+ "j.bg",
+ "k.bg",
+ "l.bg",
+ "m.bg",
+ "n.bg",
+ "o.bg",
+ "p.bg",
+ "q.bg",
+ "r.bg",
+ "s.bg",
+ "t.bg",
+ "u.bg",
+ "v.bg",
+ "w.bg",
+ "x.bg",
+ "y.bg",
+ "z.bg",
+ "0.bg",
+ "1.bg",
+ "2.bg",
+ "3.bg",
+ "4.bg",
+ "5.bg",
+ "6.bg",
+ "7.bg",
+ "8.bg",
+ "9.bg",
+ "bh",
+ "com.bh",
+ "edu.bh",
+ "net.bh",
+ "org.bh",
+ "gov.bh",
+ "bi",
+ "co.bi",
+ "com.bi",
+ "edu.bi",
+ "or.bi",
+ "org.bi",
+ "biz",
+ "bj",
+ "asso.bj",
+ "barreau.bj",
+ "gouv.bj",
+ "bm",
+ "com.bm",
+ "edu.bm",
+ "gov.bm",
+ "net.bm",
+ "org.bm",
+ "bo",
+ "com.bo",
+ "edu.bo",
+ "gov.bo",
+ "gob.bo",
+ "int.bo",
+ "org.bo",
+ "net.bo",
+ "mil.bo",
+ "tv.bo",
+ "br",
+ "adm.br",
+ "adv.br",
+ "agr.br",
+ "am.br",
+ "arq.br",
+ "art.br",
+ "ato.br",
+ "b.br",
+ "bio.br",
+ "blog.br",
+ "bmd.br",
+ "can.br",
+ "cim.br",
+ "cng.br",
+ "cnt.br",
+ "com.br",
+ "coop.br",
+ "ecn.br",
+ "edu.br",
+ "emp.br",
+ "eng.br",
+ "esp.br",
+ "etc.br",
+ "eti.br",
+ "far.br",
+ "flog.br",
+ "fm.br",
+ "fnd.br",
+ "fot.br",
+ "fst.br",
+ "g12.br",
+ "ggf.br",
+ "gov.br",
+ "imb.br",
+ "ind.br",
+ "inf.br",
+ "jor.br",
+ "jus.br",
+ "lel.br",
+ "mat.br",
+ "med.br",
+ "mil.br",
+ "mus.br",
+ "net.br",
+ "nom.br",
+ "not.br",
+ "ntr.br",
+ "odo.br",
+ "org.br",
+ "ppg.br",
+ "pro.br",
+ "psc.br",
+ "psi.br",
+ "qsl.br",
+ "radio.br",
+ "rec.br",
+ "slg.br",
+ "srv.br",
+ "taxi.br",
+ "teo.br",
+ "tmp.br",
+ "trd.br",
+ "tur.br",
+ "tv.br",
+ "vet.br",
+ "vlog.br",
+ "wiki.br",
+ "zlg.br",
+ "bs",
+ "com.bs",
+ "net.bs",
+ "org.bs",
+ "edu.bs",
+ "gov.bs",
+ "bt",
+ "com.bt",
+ "edu.bt",
+ "gov.bt",
+ "net.bt",
+ "org.bt",
+ "bw",
+ "co.bw",
+ "org.bw",
+ "by",
+ "gov.by",
+ "mil.by",
+ "com.by",
+ "of.by",
+ "bz",
+ "com.bz",
+ "net.bz",
+ "org.bz",
+ "edu.bz",
+ "gov.bz",
+ "ca",
+ "ab.ca",
+ "bc.ca",
+ "mb.ca",
+ "nb.ca",
+ "nf.ca",
+ "nl.ca",
+ "ns.ca",
+ "nt.ca",
+ "nu.ca",
+ "on.ca",
+ "pe.ca",
+ "qc.ca",
+ "sk.ca",
+ "yk.ca",
+ "gc.ca",
+ "cat",
+ "cc",
+ "cd",
+ "gov.cd",
+ "cf",
+ "cg",
+ "ch",
+ "ci",
+ "org.ci",
+ "or.ci",
+ "com.ci",
+ "co.ci",
+ "edu.ci",
+ "ed.ci",
+ "ac.ci",
+ "net.ci",
+ "go.ci",
+ "asso.ci",
+ "a\u00e9roport.ci",
+ "xn--aroport-bya.ci",
+ "int.ci",
+ "presse.ci",
+ "md.ci",
+ "gouv.ci",
+ "cl",
+ "gov.cl",
+ "gob.cl",
+ "co.cl",
+ "mil.cl",
+ "cm",
+ "gov.cm",
+ "cn",
+ "ac.cn",
+ "com.cn",
+ "edu.cn",
+ "gov.cn",
+ "net.cn",
+ "org.cn",
+ "mil.cn",
+ "\u516c\u53f8.cn",
+ "xn--55qx5d.cn",
+ "\u7f51\u7edc.cn",
+ "xn--io0a7i.cn",
+ "\u7db2\u7d61.cn",
+ "xn--od0alg.cn",
+ "ah.cn",
+ "bj.cn",
+ "cq.cn",
+ "fj.cn",
+ "gd.cn",
+ "gs.cn",
+ "gz.cn",
+ "gx.cn",
+ "ha.cn",
+ "hb.cn",
+ "he.cn",
+ "hi.cn",
+ "hl.cn",
+ "hn.cn",
+ "jl.cn",
+ "js.cn",
+ "jx.cn",
+ "ln.cn",
+ "nm.cn",
+ "nx.cn",
+ "qh.cn",
+ "sc.cn",
+ "sd.cn",
+ "sh.cn",
+ "sn.cn",
+ "sx.cn",
+ "tj.cn",
+ "xj.cn",
+ "xz.cn",
+ "yn.cn",
+ "zj.cn",
+ "hk.cn",
+ "mo.cn",
+ "tw.cn",
+ "co",
+ "arts.co",
+ "com.co",
+ "edu.co",
+ "firm.co",
+ "gov.co",
+ "info.co",
+ "int.co",
+ "mil.co",
+ "net.co",
+ "nom.co",
+ "org.co",
+ "rec.co",
+ "web.co",
+ "com",
+ "coop",
+ "cr",
+ "ac.cr",
+ "co.cr",
+ "ed.cr",
+ "fi.cr",
+ "go.cr",
+ "or.cr",
+ "sa.cr",
+ "cu",
+ "com.cu",
+ "edu.cu",
+ "org.cu",
+ "net.cu",
+ "gov.cu",
+ "inf.cu",
+ "cv",
+ "cx",
+ "gov.cx",
+ "cz",
+ "de",
+ "dj",
+ "dk",
+ "dm",
+ "com.dm",
+ "net.dm",
+ "org.dm",
+ "edu.dm",
+ "gov.dm",
+ "do",
+ "art.do",
+ "com.do",
+ "edu.do",
+ "gob.do",
+ "gov.do",
+ "mil.do",
+ "net.do",
+ "org.do",
+ "sld.do",
+ "web.do",
+ "dz",
+ "com.dz",
+ "org.dz",
+ "net.dz",
+ "gov.dz",
+ "edu.dz",
+ "asso.dz",
+ "pol.dz",
+ "art.dz",
+ "ec",
+ "com.ec",
+ "info.ec",
+ "net.ec",
+ "fin.ec",
+ "k12.ec",
+ "med.ec",
+ "pro.ec",
+ "org.ec",
+ "edu.ec",
+ "gov.ec",
+ "gob.ec",
+ "mil.ec",
+ "edu",
+ "ee",
+ "edu.ee",
+ "gov.ee",
+ "riik.ee",
+ "lib.ee",
+ "med.ee",
+ "com.ee",
+ "pri.ee",
+ "aip.ee",
+ "org.ee",
+ "fie.ee",
+ "eg",
+ "com.eg",
+ "edu.eg",
+ "eun.eg",
+ "gov.eg",
+ "mil.eg",
+ "name.eg",
+ "net.eg",
+ "org.eg",
+ "sci.eg",
+ "es",
+ "com.es",
+ "nom.es",
+ "org.es",
+ "gob.es",
+ "edu.es",
+ "eu",
+ "fi",
+ "aland.fi",
+ "fm",
+ "fo",
+ "fr",
+ "com.fr",
+ "asso.fr",
+ "nom.fr",
+ "prd.fr",
+ "presse.fr",
+ "tm.fr",
+ "aeroport.fr",
+ "assedic.fr",
+ "avocat.fr",
+ "avoues.fr",
+ "cci.fr",
+ "chambagri.fr",
+ "chirurgiens-dentistes.fr",
+ "experts-comptables.fr",
+ "geometre-expert.fr",
+ "gouv.fr",
+ "greta.fr",
+ "huissier-justice.fr",
+ "medecin.fr",
+ "notaires.fr",
+ "pharmacien.fr",
+ "port.fr",
+ "veterinaire.fr",
+ "ga",
+ "gd",
+ "ge",
+ "com.ge",
+ "edu.ge",
+ "gov.ge",
+ "org.ge",
+ "mil.ge",
+ "net.ge",
+ "pvt.ge",
+ "gf",
+ "gg",
+ "co.gg",
+ "org.gg",
+ "net.gg",
+ "sch.gg",
+ "gov.gg",
+ "gh",
+ "com.gh",
+ "edu.gh",
+ "gov.gh",
+ "org.gh",
+ "mil.gh",
+ "gi",
+ "com.gi",
+ "ltd.gi",
+ "gov.gi",
+ "mod.gi",
+ "edu.gi",
+ "org.gi",
+ "gl",
+ "gm",
+ "ac.gn",
+ "com.gn",
+ "edu.gn",
+ "gov.gn",
+ "org.gn",
+ "net.gn",
+ "gov",
+ "gp",
+ "com.gp",
+ "net.gp",
+ "mobi.gp",
+ "edu.gp",
+ "org.gp",
+ "asso.gp",
+ "gq",
+ "gr",
+ "com.gr",
+ "edu.gr",
+ "net.gr",
+ "org.gr",
+ "gov.gr",
+ "gs",
+ "gw",
+ "gy",
+ "co.gy",
+ "com.gy",
+ "net.gy",
+ "hk",
+ "com.hk",
+ "edu.hk",
+ "gov.hk",
+ "idv.hk",
+ "net.hk",
+ "org.hk",
+ "\u516c\u53f8.hk",
+ "xn--55qx5d.hk",
+ "\u6559\u80b2.hk",
+ "xn--wcvs22d.hk",
+ "\u654e\u80b2.hk",
+ "xn--lcvr32d.hk",
+ "\u653f\u5e9c.hk",
+ "xn--mxtq1m.hk",
+ "\u500b\u4eba.hk",
+ "xn--gmqw5a.hk",
+ "\u4e2a\u4eba.hk",
+ "xn--ciqpn.hk",
+ "\u7b87\u4eba.hk",
+ "xn--gmq050i.hk",
+ "\u7db2\u7edc.hk",
+ "xn--zf0avx.hk",
+ "\u7f51\u7edc.hk",
+ "xn--io0a7i.hk",
+ "\u7ec4\u7e54.hk",
+ "xn--mk0axi.hk",
+ "\u7db2\u7d61.hk",
+ "xn--od0alg.hk",
+ "\u7f51\u7d61.hk",
+ "xn--od0aq3b.hk",
+ "\u7ec4\u7ec7.hk",
+ "xn--tn0ag.hk",
+ "\u7d44\u7e54.hk",
+ "xn--uc0atv.hk",
+ "\u7d44\u7ec7.hk",
+ "xn--uc0ay4a.hk",
+ "hm",
+ "hn",
+ "com.hn",
+ "edu.hn",
+ "org.hn",
+ "net.hn",
+ "mil.hn",
+ "gob.hn",
+ "hr",
+ "iz.hr",
+ "from.hr",
+ "name.hr",
+ "com.hr",
+ "ht",
+ "com.ht",
+ "shop.ht",
+ "firm.ht",
+ "info.ht",
+ "adult.ht",
+ "net.ht",
+ "pro.ht",
+ "org.ht",
+ "med.ht",
+ "art.ht",
+ "coop.ht",
+ "pol.ht",
+ "asso.ht",
+ "edu.ht",
+ "rel.ht",
+ "gouv.ht",
+ "perso.ht",
+ "hu",
+ "co.hu",
+ "info.hu",
+ "org.hu",
+ "priv.hu",
+ "sport.hu",
+ "tm.hu",
+ "2000.hu",
+ "agrar.hu",
+ "bolt.hu",
+ "casino.hu",
+ "city.hu",
+ "erotica.hu",
+ "erotika.hu",
+ "film.hu",
+ "forum.hu",
+ "games.hu",
+ "hotel.hu",
+ "ingatlan.hu",
+ "jogasz.hu",
+ "konyvelo.hu",
+ "lakas.hu",
+ "media.hu",
+ "news.hu",
+ "reklam.hu",
+ "sex.hu",
+ "shop.hu",
+ "suli.hu",
+ "szex.hu",
+ "tozsde.hu",
+ "utazas.hu",
+ "video.hu",
+ "id",
+ "ac.id",
+ "co.id",
+ "go.id",
+ "mil.id",
+ "net.id",
+ "or.id",
+ "sch.id",
+ "web.id",
+ "ie",
+ "gov.ie",
+ "im",
+ "co.im",
+ "ltd.co.im",
+ "plc.co.im",
+ "net.im",
+ "gov.im",
+ "org.im",
+ "nic.im",
+ "ac.im",
+ "in",
+ "co.in",
+ "firm.in",
+ "net.in",
+ "org.in",
+ "gen.in",
+ "ind.in",
+ "nic.in",
+ "ac.in",
+ "edu.in",
+ "res.in",
+ "gov.in",
+ "mil.in",
+ "info",
+ "int",
+ "eu.int",
+ "io",
+ "com.io",
+ "iq",
+ "gov.iq",
+ "edu.iq",
+ "mil.iq",
+ "com.iq",
+ "org.iq",
+ "net.iq",
+ "ir",
+ "ac.ir",
+ "co.ir",
+ "gov.ir",
+ "id.ir",
+ "net.ir",
+ "org.ir",
+ "sch.ir",
+ "\u0627\u06cc\u0631\u0627\u0646.ir",
+ "xn--mgba3a4f16a.ir",
+ "\u0627\u064a\u0631\u0627\u0646.ir",
+ "xn--mgba3a4fra.ir",
+ "is",
+ "net.is",
+ "com.is",
+ "edu.is",
+ "gov.is",
+ "org.is",
+ "int.is",
+ "it",
+ "gov.it",
+ "edu.it",
+ "agrigento.it",
+ "ag.it",
+ "alessandria.it",
+ "al.it",
+ "ancona.it",
+ "an.it",
+ "aosta.it",
+ "aoste.it",
+ "ao.it",
+ "arezzo.it",
+ "ar.it",
+ "ascoli-piceno.it",
+ "ascolipiceno.it",
+ "ap.it",
+ "asti.it",
+ "at.it",
+ "avellino.it",
+ "av.it",
+ "bari.it",
+ "ba.it",
+ "andria-barletta-trani.it",
+ "andriabarlettatrani.it",
+ "trani-barletta-andria.it",
+ "tranibarlettaandria.it",
+ "barletta-trani-andria.it",
+ "barlettatraniandria.it",
+ "andria-trani-barletta.it",
+ "andriatranibarletta.it",
+ "trani-andria-barletta.it",
+ "traniandriabarletta.it",
+ "bt.it",
+ "belluno.it",
+ "bl.it",
+ "benevento.it",
+ "bn.it",
+ "bergamo.it",
+ "bg.it",
+ "biella.it",
+ "bi.it",
+ "bologna.it",
+ "bo.it",
+ "bolzano.it",
+ "bozen.it",
+ "balsan.it",
+ "alto-adige.it",
+ "altoadige.it",
+ "suedtirol.it",
+ "bz.it",
+ "brescia.it",
+ "bs.it",
+ "brindisi.it",
+ "br.it",
+ "cagliari.it",
+ "ca.it",
+ "caltanissetta.it",
+ "cl.it",
+ "campobasso.it",
+ "cb.it",
+ "carboniaiglesias.it",
+ "carbonia-iglesias.it",
+ "iglesias-carbonia.it",
+ "iglesiascarbonia.it",
+ "ci.it",
+ "caserta.it",
+ "ce.it",
+ "catania.it",
+ "ct.it",
+ "catanzaro.it",
+ "cz.it",
+ "chieti.it",
+ "ch.it",
+ "como.it",
+ "co.it",
+ "cosenza.it",
+ "cs.it",
+ "cremona.it",
+ "cr.it",
+ "crotone.it",
+ "kr.it",
+ "cuneo.it",
+ "cn.it",
+ "dell-ogliastra.it",
+ "dellogliastra.it",
+ "ogliastra.it",
+ "og.it",
+ "enna.it",
+ "en.it",
+ "ferrara.it",
+ "fe.it",
+ "fermo.it",
+ "fm.it",
+ "firenze.it",
+ "florence.it",
+ "fi.it",
+ "foggia.it",
+ "fg.it",
+ "forli-cesena.it",
+ "forlicesena.it",
+ "cesena-forli.it",
+ "cesenaforli.it",
+ "fc.it",
+ "frosinone.it",
+ "fr.it",
+ "genova.it",
+ "genoa.it",
+ "ge.it",
+ "gorizia.it",
+ "go.it",
+ "grosseto.it",
+ "gr.it",
+ "imperia.it",
+ "im.it",
+ "isernia.it",
+ "is.it",
+ "laquila.it",
+ "aquila.it",
+ "aq.it",
+ "la-spezia.it",
+ "laspezia.it",
+ "sp.it",
+ "latina.it",
+ "lt.it",
+ "lecce.it",
+ "le.it",
+ "lecco.it",
+ "lc.it",
+ "livorno.it",
+ "li.it",
+ "lodi.it",
+ "lo.it",
+ "lucca.it",
+ "lu.it",
+ "macerata.it",
+ "mc.it",
+ "mantova.it",
+ "mn.it",
+ "massa-carrara.it",
+ "massacarrara.it",
+ "carrara-massa.it",
+ "carraramassa.it",
+ "ms.it",
+ "matera.it",
+ "mt.it",
+ "medio-campidano.it",
+ "mediocampidano.it",
+ "campidano-medio.it",
+ "campidanomedio.it",
+ "vs.it",
+ "messina.it",
+ "me.it",
+ "milano.it",
+ "milan.it",
+ "mi.it",
+ "modena.it",
+ "mo.it",
+ "monza.it",
+ "monza-brianza.it",
+ "monzabrianza.it",
+ "monzaebrianza.it",
+ "monzaedellabrianza.it",
+ "monza-e-della-brianza.it",
+ "mb.it",
+ "napoli.it",
+ "naples.it",
+ "na.it",
+ "novara.it",
+ "no.it",
+ "nuoro.it",
+ "nu.it",
+ "oristano.it",
+ "or.it",
+ "padova.it",
+ "padua.it",
+ "pd.it",
+ "palermo.it",
+ "pa.it",
+ "parma.it",
+ "pr.it",
+ "pavia.it",
+ "pv.it",
+ "perugia.it",
+ "pg.it",
+ "pescara.it",
+ "pe.it",
+ "pesaro-urbino.it",
+ "pesarourbino.it",
+ "urbino-pesaro.it",
+ "urbinopesaro.it",
+ "pu.it",
+ "piacenza.it",
+ "pc.it",
+ "pisa.it",
+ "pi.it",
+ "pistoia.it",
+ "pt.it",
+ "pordenone.it",
+ "pn.it",
+ "potenza.it",
+ "pz.it",
+ "prato.it",
+ "po.it",
+ "ragusa.it",
+ "rg.it",
+ "ravenna.it",
+ "ra.it",
+ "reggio-calabria.it",
+ "reggiocalabria.it",
+ "rc.it",
+ "reggio-emilia.it",
+ "reggioemilia.it",
+ "re.it",
+ "rieti.it",
+ "ri.it",
+ "rimini.it",
+ "rn.it",
+ "roma.it",
+ "rome.it",
+ "rm.it",
+ "rovigo.it",
+ "ro.it",
+ "salerno.it",
+ "sa.it",
+ "sassari.it",
+ "ss.it",
+ "savona.it",
+ "sv.it",
+ "siena.it",
+ "si.it",
+ "siracusa.it",
+ "sr.it",
+ "sondrio.it",
+ "so.it",
+ "taranto.it",
+ "ta.it",
+ "tempio-olbia.it",
+ "tempioolbia.it",
+ "olbia-tempio.it",
+ "olbiatempio.it",
+ "ot.it",
+ "teramo.it",
+ "te.it",
+ "terni.it",
+ "tr.it",
+ "torino.it",
+ "turin.it",
+ "to.it",
+ "trapani.it",
+ "tp.it",
+ "trento.it",
+ "trentino.it",
+ "tn.it",
+ "treviso.it",
+ "tv.it",
+ "trieste.it",
+ "ts.it",
+ "udine.it",
+ "ud.it",
+ "varese.it",
+ "va.it",
+ "venezia.it",
+ "venice.it",
+ "ve.it",
+ "verbania.it",
+ "vb.it",
+ "vercelli.it",
+ "vc.it",
+ "verona.it",
+ "vr.it",
+ "vibo-valentia.it",
+ "vibovalentia.it",
+ "vv.it",
+ "vicenza.it",
+ "vi.it",
+ "viterbo.it",
+ "vt.it",
+ "je",
+ "co.je",
+ "org.je",
+ "net.je",
+ "sch.je",
+ "gov.je",
+ "jo",
+ "com.jo",
+ "org.jo",
+ "net.jo",
+ "edu.jo",
+ "sch.jo",
+ "gov.jo",
+ "mil.jo",
+ "name.jo",
+ "jobs",
+ "jp",
+ "ac.jp",
+ "ad.jp",
+ "co.jp",
+ "ed.jp",
+ "go.jp",
+ "gr.jp",
+ "lg.jp",
+ "ne.jp",
+ "or.jp",
+ "kg",
+ "org.kg",
+ "net.kg",
+ "com.kg",
+ "edu.kg",
+ "gov.kg",
+ "mil.kg",
+ "ki",
+ "edu.ki",
+ "biz.ki",
+ "net.ki",
+ "org.ki",
+ "gov.ki",
+ "info.ki",
+ "com.ki",
+ "km",
+ "org.km",
+ "nom.km",
+ "gov.km",
+ "prd.km",
+ "tm.km",
+ "edu.km",
+ "mil.km",
+ "ass.km",
+ "com.km",
+ "coop.km",
+ "asso.km",
+ "presse.km",
+ "medecin.km",
+ "notaires.km",
+ "pharmaciens.km",
+ "veterinaire.km",
+ "gouv.km",
+ "kn",
+ "net.kn",
+ "org.kn",
+ "edu.kn",
+ "gov.kn",
+ "com.kp",
+ "edu.kp",
+ "gov.kp",
+ "org.kp",
+ "rep.kp",
+ "tra.kp",
+ "kr",
+ "ac.kr",
+ "co.kr",
+ "es.kr",
+ "go.kr",
+ "hs.kr",
+ "kg.kr",
+ "mil.kr",
+ "ms.kr",
+ "ne.kr",
+ "or.kr",
+ "pe.kr",
+ "re.kr",
+ "sc.kr",
+ "busan.kr",
+ "chungbuk.kr",
+ "chungnam.kr",
+ "daegu.kr",
+ "daejeon.kr",
+ "gangwon.kr",
+ "gwangju.kr",
+ "gyeongbuk.kr",
+ "gyeonggi.kr",
+ "gyeongnam.kr",
+ "incheon.kr",
+ "jeju.kr",
+ "jeonbuk.kr",
+ "jeonnam.kr",
+ "seoul.kr",
+ "ulsan.kr",
+ "ky",
+ "edu.ky",
+ "gov.ky",
+ "com.ky",
+ "org.ky",
+ "net.ky",
+ "kz",
+ "org.kz",
+ "edu.kz",
+ "net.kz",
+ "gov.kz",
+ "mil.kz",
+ "com.kz",
+ "la",
+ "int.la",
+ "net.la",
+ "info.la",
+ "edu.la",
+ "gov.la",
+ "per.la",
+ "com.la",
+ "org.la",
+ "com.lb",
+ "edu.lb",
+ "gov.lb",
+ "net.lb",
+ "org.lb",
+ "lc",
+ "com.lc",
+ "net.lc",
+ "co.lc",
+ "org.lc",
+ "edu.lc",
+ "gov.lc",
+ "li",
+ "lk",
+ "gov.lk",
+ "sch.lk",
+ "net.lk",
+ "int.lk",
+ "com.lk",
+ "org.lk",
+ "edu.lk",
+ "ngo.lk",
+ "soc.lk",
+ "web.lk",
+ "ltd.lk",
+ "assn.lk",
+ "grp.lk",
+ "hotel.lk",
+ "com.lr",
+ "edu.lr",
+ "gov.lr",
+ "org.lr",
+ "net.lr",
+ "ls",
+ "co.ls",
+ "org.ls",
+ "lt",
+ "gov.lt",
+ "lu",
+ "lv",
+ "com.lv",
+ "edu.lv",
+ "gov.lv",
+ "org.lv",
+ "mil.lv",
+ "id.lv",
+ "net.lv",
+ "asn.lv",
+ "conf.lv",
+ "ly",
+ "com.ly",
+ "net.ly",
+ "gov.ly",
+ "plc.ly",
+ "edu.ly",
+ "sch.ly",
+ "med.ly",
+ "org.ly",
+ "id.ly",
+ "ma",
+ "co.ma",
+ "net.ma",
+ "gov.ma",
+ "org.ma",
+ "ac.ma",
+ "press.ma",
+ "mc",
+ "tm.mc",
+ "asso.mc",
+ "md",
+ "me",
+ "co.me",
+ "net.me",
+ "org.me",
+ "edu.me",
+ "ac.me",
+ "gov.me",
+ "its.me",
+ "priv.me",
+ "mg",
+ "org.mg",
+ "nom.mg",
+ "gov.mg",
+ "prd.mg",
+ "tm.mg",
+ "edu.mg",
+ "mil.mg",
+ "com.mg",
+ "mh",
+ "mil",
+ "mk",
+ "com.mk",
+ "org.mk",
+ "net.mk",
+ "edu.mk",
+ "gov.mk",
+ "inf.mk",
+ "name.mk",
+ "ml",
+ "com.ml",
+ "edu.ml",
+ "gouv.ml",
+ "gov.ml",
+ "net.ml",
+ "org.ml",
+ "presse.ml",
+ "mn",
+ "gov.mn",
+ "edu.mn",
+ "org.mn",
+ "mo",
+ "com.mo",
+ "net.mo",
+ "org.mo",
+ "edu.mo",
+ "gov.mo",
+ "mobi",
+ "mp",
+ "mq",
+ "mr",
+ "gov.mr",
+ "ms",
+ "mu",
+ "com.mu",
+ "net.mu",
+ "org.mu",
+ "gov.mu",
+ "ac.mu",
+ "co.mu",
+ "or.mu",
+ "museum",
+ "academy.museum",
+ "agriculture.museum",
+ "air.museum",
+ "airguard.museum",
+ "alabama.museum",
+ "alaska.museum",
+ "amber.museum",
+ "ambulance.museum",
+ "american.museum",
+ "americana.museum",
+ "americanantiques.museum",
+ "americanart.museum",
+ "amsterdam.museum",
+ "and.museum",
+ "annefrank.museum",
+ "anthro.museum",
+ "anthropology.museum",
+ "antiques.museum",
+ "aquarium.museum",
+ "arboretum.museum",
+ "archaeological.museum",
+ "archaeology.museum",
+ "architecture.museum",
+ "art.museum",
+ "artanddesign.museum",
+ "artcenter.museum",
+ "artdeco.museum",
+ "arteducation.museum",
+ "artgallery.museum",
+ "arts.museum",
+ "artsandcrafts.museum",
+ "asmatart.museum",
+ "assassination.museum",
+ "assisi.museum",
+ "association.museum",
+ "astronomy.museum",
+ "atlanta.museum",
+ "austin.museum",
+ "australia.museum",
+ "automotive.museum",
+ "aviation.museum",
+ "axis.museum",
+ "badajoz.museum",
+ "baghdad.museum",
+ "bahn.museum",
+ "bale.museum",
+ "baltimore.museum",
+ "barcelona.museum",
+ "baseball.museum",
+ "basel.museum",
+ "baths.museum",
+ "bauern.museum",
+ "beauxarts.museum",
+ "beeldengeluid.museum",
+ "bellevue.museum",
+ "bergbau.museum",
+ "berkeley.museum",
+ "berlin.museum",
+ "bern.museum",
+ "bible.museum",
+ "bilbao.museum",
+ "bill.museum",
+ "birdart.museum",
+ "birthplace.museum",
+ "bonn.museum",
+ "boston.museum",
+ "botanical.museum",
+ "botanicalgarden.museum",
+ "botanicgarden.museum",
+ "botany.museum",
+ "brandywinevalley.museum",
+ "brasil.museum",
+ "bristol.museum",
+ "british.museum",
+ "britishcolumbia.museum",
+ "broadcast.museum",
+ "brunel.museum",
+ "brussel.museum",
+ "brussels.museum",
+ "bruxelles.museum",
+ "building.museum",
+ "burghof.museum",
+ "bus.museum",
+ "bushey.museum",
+ "cadaques.museum",
+ "california.museum",
+ "cambridge.museum",
+ "can.museum",
+ "canada.museum",
+ "capebreton.museum",
+ "carrier.museum",
+ "cartoonart.museum",
+ "casadelamoneda.museum",
+ "castle.museum",
+ "castres.museum",
+ "celtic.museum",
+ "center.museum",
+ "chattanooga.museum",
+ "cheltenham.museum",
+ "chesapeakebay.museum",
+ "chicago.museum",
+ "children.museum",
+ "childrens.museum",
+ "childrensgarden.museum",
+ "chiropractic.museum",
+ "chocolate.museum",
+ "christiansburg.museum",
+ "cincinnati.museum",
+ "cinema.museum",
+ "circus.museum",
+ "civilisation.museum",
+ "civilization.museum",
+ "civilwar.museum",
+ "clinton.museum",
+ "clock.museum",
+ "coal.museum",
+ "coastaldefence.museum",
+ "cody.museum",
+ "coldwar.museum",
+ "collection.museum",
+ "colonialwilliamsburg.museum",
+ "coloradoplateau.museum",
+ "columbia.museum",
+ "columbus.museum",
+ "communication.museum",
+ "communications.museum",
+ "community.museum",
+ "computer.museum",
+ "computerhistory.museum",
+ "comunica\u00e7\u00f5es.museum",
+ "xn--comunicaes-v6a2o.museum",
+ "contemporary.museum",
+ "contemporaryart.museum",
+ "convent.museum",
+ "copenhagen.museum",
+ "corporation.museum",
+ "correios-e-telecomunica\u00e7\u00f5es.museum",
+ "xn--correios-e-telecomunicaes-ghc29a.museum",
+ "corvette.museum",
+ "costume.museum",
+ "countryestate.museum",
+ "county.museum",
+ "crafts.museum",
+ "cranbrook.museum",
+ "creation.museum",
+ "cultural.museum",
+ "culturalcenter.museum",
+ "culture.museum",
+ "cyber.museum",
+ "cymru.museum",
+ "dali.museum",
+ "dallas.museum",
+ "database.museum",
+ "ddr.museum",
+ "decorativearts.museum",
+ "delaware.museum",
+ "delmenhorst.museum",
+ "denmark.museum",
+ "depot.museum",
+ "design.museum",
+ "detroit.museum",
+ "dinosaur.museum",
+ "discovery.museum",
+ "dolls.museum",
+ "donostia.museum",
+ "durham.museum",
+ "eastafrica.museum",
+ "eastcoast.museum",
+ "education.museum",
+ "educational.museum",
+ "egyptian.museum",
+ "eisenbahn.museum",
+ "elburg.museum",
+ "elvendrell.museum",
+ "embroidery.museum",
+ "encyclopedic.museum",
+ "england.museum",
+ "entomology.museum",
+ "environment.museum",
+ "environmentalconservation.museum",
+ "epilepsy.museum",
+ "essex.museum",
+ "estate.museum",
+ "ethnology.museum",
+ "exeter.museum",
+ "exhibition.museum",
+ "family.museum",
+ "farm.museum",
+ "farmequipment.museum",
+ "farmers.museum",
+ "farmstead.museum",
+ "field.museum",
+ "figueres.museum",
+ "filatelia.museum",
+ "film.museum",
+ "fineart.museum",
+ "finearts.museum",
+ "finland.museum",
+ "flanders.museum",
+ "florida.museum",
+ "force.museum",
+ "fortmissoula.museum",
+ "fortworth.museum",
+ "foundation.museum",
+ "francaise.museum",
+ "frankfurt.museum",
+ "franziskaner.museum",
+ "freemasonry.museum",
+ "freiburg.museum",
+ "fribourg.museum",
+ "frog.museum",
+ "fundacio.museum",
+ "furniture.museum",
+ "gallery.museum",
+ "garden.museum",
+ "gateway.museum",
+ "geelvinck.museum",
+ "gemological.museum",
+ "geology.museum",
+ "georgia.museum",
+ "giessen.museum",
+ "glas.museum",
+ "glass.museum",
+ "gorge.museum",
+ "grandrapids.museum",
+ "graz.museum",
+ "guernsey.museum",
+ "halloffame.museum",
+ "hamburg.museum",
+ "handson.museum",
+ "harvestcelebration.museum",
+ "hawaii.museum",
+ "health.museum",
+ "heimatunduhren.museum",
+ "hellas.museum",
+ "helsinki.museum",
+ "hembygdsforbund.museum",
+ "heritage.museum",
+ "histoire.museum",
+ "historical.museum",
+ "historicalsociety.museum",
+ "historichouses.museum",
+ "historisch.museum",
+ "historisches.museum",
+ "history.museum",
+ "historyofscience.museum",
+ "horology.museum",
+ "house.museum",
+ "humanities.museum",
+ "illustration.museum",
+ "imageandsound.museum",
+ "indian.museum",
+ "indiana.museum",
+ "indianapolis.museum",
+ "indianmarket.museum",
+ "intelligence.museum",
+ "interactive.museum",
+ "iraq.museum",
+ "iron.museum",
+ "isleofman.museum",
+ "jamison.museum",
+ "jefferson.museum",
+ "jerusalem.museum",
+ "jewelry.museum",
+ "jewish.museum",
+ "jewishart.museum",
+ "jfk.museum",
+ "journalism.museum",
+ "judaica.museum",
+ "judygarland.museum",
+ "juedisches.museum",
+ "juif.museum",
+ "karate.museum",
+ "karikatur.museum",
+ "kids.museum",
+ "koebenhavn.museum",
+ "koeln.museum",
+ "kunst.museum",
+ "kunstsammlung.museum",
+ "kunstunddesign.museum",
+ "labor.museum",
+ "labour.museum",
+ "lajolla.museum",
+ "lancashire.museum",
+ "landes.museum",
+ "lans.museum",
+ "l\u00e4ns.museum",
+ "xn--lns-qla.museum",
+ "larsson.museum",
+ "lewismiller.museum",
+ "lincoln.museum",
+ "linz.museum",
+ "living.museum",
+ "livinghistory.museum",
+ "localhistory.museum",
+ "london.museum",
+ "losangeles.museum",
+ "louvre.museum",
+ "loyalist.museum",
+ "lucerne.museum",
+ "luxembourg.museum",
+ "luzern.museum",
+ "mad.museum",
+ "madrid.museum",
+ "mallorca.museum",
+ "manchester.museum",
+ "mansion.museum",
+ "mansions.museum",
+ "manx.museum",
+ "marburg.museum",
+ "maritime.museum",
+ "maritimo.museum",
+ "maryland.museum",
+ "marylhurst.museum",
+ "media.museum",
+ "medical.museum",
+ "medizinhistorisches.museum",
+ "meeres.museum",
+ "memorial.museum",
+ "mesaverde.museum",
+ "michigan.museum",
+ "midatlantic.museum",
+ "military.museum",
+ "mill.museum",
+ "miners.museum",
+ "mining.museum",
+ "minnesota.museum",
+ "missile.museum",
+ "missoula.museum",
+ "modern.museum",
+ "moma.museum",
+ "money.museum",
+ "monmouth.museum",
+ "monticello.museum",
+ "montreal.museum",
+ "moscow.museum",
+ "motorcycle.museum",
+ "muenchen.museum",
+ "muenster.museum",
+ "mulhouse.museum",
+ "muncie.museum",
+ "museet.museum",
+ "museumcenter.museum",
+ "museumvereniging.museum",
+ "music.museum",
+ "national.museum",
+ "nationalfirearms.museum",
+ "nationalheritage.museum",
+ "nativeamerican.museum",
+ "naturalhistory.museum",
+ "naturalhistorymuseum.museum",
+ "naturalsciences.museum",
+ "nature.museum",
+ "naturhistorisches.museum",
+ "natuurwetenschappen.museum",
+ "naumburg.museum",
+ "naval.museum",
+ "nebraska.museum",
+ "neues.museum",
+ "newhampshire.museum",
+ "newjersey.museum",
+ "newmexico.museum",
+ "newport.museum",
+ "newspaper.museum",
+ "newyork.museum",
+ "niepce.museum",
+ "norfolk.museum",
+ "north.museum",
+ "nrw.museum",
+ "nuernberg.museum",
+ "nuremberg.museum",
+ "nyc.museum",
+ "nyny.museum",
+ "oceanographic.museum",
+ "oceanographique.museum",
+ "omaha.museum",
+ "online.museum",
+ "ontario.museum",
+ "openair.museum",
+ "oregon.museum",
+ "oregontrail.museum",
+ "otago.museum",
+ "oxford.museum",
+ "pacific.museum",
+ "paderborn.museum",
+ "palace.museum",
+ "paleo.museum",
+ "palmsprings.museum",
+ "panama.museum",
+ "paris.museum",
+ "pasadena.museum",
+ "pharmacy.museum",
+ "philadelphia.museum",
+ "philadelphiaarea.museum",
+ "philately.museum",
+ "phoenix.museum",
+ "photography.museum",
+ "pilots.museum",
+ "pittsburgh.museum",
+ "planetarium.museum",
+ "plantation.museum",
+ "plants.museum",
+ "plaza.museum",
+ "portal.museum",
+ "portland.museum",
+ "portlligat.museum",
+ "posts-and-telecommunications.museum",
+ "preservation.museum",
+ "presidio.museum",
+ "press.museum",
+ "project.museum",
+ "public.museum",
+ "pubol.museum",
+ "quebec.museum",
+ "railroad.museum",
+ "railway.museum",
+ "research.museum",
+ "resistance.museum",
+ "riodejaneiro.museum",
+ "rochester.museum",
+ "rockart.museum",
+ "roma.museum",
+ "russia.museum",
+ "saintlouis.museum",
+ "salem.museum",
+ "salvadordali.museum",
+ "salzburg.museum",
+ "sandiego.museum",
+ "sanfrancisco.museum",
+ "santabarbara.museum",
+ "santacruz.museum",
+ "santafe.museum",
+ "saskatchewan.museum",
+ "satx.museum",
+ "savannahga.museum",
+ "schlesisches.museum",
+ "schoenbrunn.museum",
+ "schokoladen.museum",
+ "school.museum",
+ "schweiz.museum",
+ "science.museum",
+ "scienceandhistory.museum",
+ "scienceandindustry.museum",
+ "sciencecenter.museum",
+ "sciencecenters.museum",
+ "science-fiction.museum",
+ "sciencehistory.museum",
+ "sciences.museum",
+ "sciencesnaturelles.museum",
+ "scotland.museum",
+ "seaport.museum",
+ "settlement.museum",
+ "settlers.museum",
+ "shell.museum",
+ "sherbrooke.museum",
+ "sibenik.museum",
+ "silk.museum",
+ "ski.museum",
+ "skole.museum",
+ "society.museum",
+ "sologne.museum",
+ "soundandvision.museum",
+ "southcarolina.museum",
+ "southwest.museum",
+ "space.museum",
+ "spy.museum",
+ "square.museum",
+ "stadt.museum",
+ "stalbans.museum",
+ "starnberg.museum",
+ "state.museum",
+ "stateofdelaware.museum",
+ "station.museum",
+ "steam.museum",
+ "steiermark.museum",
+ "stjohn.museum",
+ "stockholm.museum",
+ "stpetersburg.museum",
+ "stuttgart.museum",
+ "suisse.museum",
+ "surgeonshall.museum",
+ "surrey.museum",
+ "svizzera.museum",
+ "sweden.museum",
+ "sydney.museum",
+ "tank.museum",
+ "tcm.museum",
+ "technology.museum",
+ "telekommunikation.museum",
+ "television.museum",
+ "texas.museum",
+ "textile.museum",
+ "theater.museum",
+ "time.museum",
+ "timekeeping.museum",
+ "topology.museum",
+ "torino.museum",
+ "touch.museum",
+ "town.museum",
+ "transport.museum",
+ "tree.museum",
+ "trolley.museum",
+ "trust.museum",
+ "trustee.museum",
+ "uhren.museum",
+ "ulm.museum",
+ "undersea.museum",
+ "university.museum",
+ "usa.museum",
+ "usantiques.museum",
+ "usarts.museum",
+ "uscountryestate.museum",
+ "usculture.museum",
+ "usdecorativearts.museum",
+ "usgarden.museum",
+ "ushistory.museum",
+ "ushuaia.museum",
+ "uslivinghistory.museum",
+ "utah.museum",
+ "uvic.museum",
+ "valley.museum",
+ "vantaa.museum",
+ "versailles.museum",
+ "viking.museum",
+ "village.museum",
+ "virginia.museum",
+ "virtual.museum",
+ "virtuel.museum",
+ "vlaanderen.museum",
+ "volkenkunde.museum",
+ "wales.museum",
+ "wallonie.museum",
+ "war.museum",
+ "washingtondc.museum",
+ "watchandclock.museum",
+ "watch-and-clock.museum",
+ "western.museum",
+ "westfalen.museum",
+ "whaling.museum",
+ "wildlife.museum",
+ "williamsburg.museum",
+ "windmill.museum",
+ "workshop.museum",
+ "york.museum",
+ "yorkshire.museum",
+ "yosemite.museum",
+ "youth.museum",
+ "zoological.museum",
+ "zoology.museum",
+ "\u05d9\u05e8\u05d5\u05e9\u05dc\u05d9\u05dd.museum",
+ "xn--9dbhblg6di.museum",
+ "\u0438\u043a\u043e\u043c.museum",
+ "xn--h1aegh.museum",
+ "mv",
+ "aero.mv",
+ "biz.mv",
+ "com.mv",
+ "coop.mv",
+ "edu.mv",
+ "gov.mv",
+ "info.mv",
+ "int.mv",
+ "mil.mv",
+ "museum.mv",
+ "name.mv",
+ "net.mv",
+ "org.mv",
+ "pro.mv",
+ "mw",
+ "ac.mw",
+ "biz.mw",
+ "co.mw",
+ "com.mw",
+ "coop.mw",
+ "edu.mw",
+ "gov.mw",
+ "int.mw",
+ "museum.mw",
+ "net.mw",
+ "org.mw",
+ "mx",
+ "com.mx",
+ "org.mx",
+ "gob.mx",
+ "edu.mx",
+ "net.mx",
+ "my",
+ "com.my",
+ "net.my",
+ "org.my",
+ "gov.my",
+ "edu.my",
+ "mil.my",
+ "name.my",
+ "na",
+ "info.na",
+ "pro.na",
+ "name.na",
+ "school.na",
+ "or.na",
+ "dr.na",
+ "us.na",
+ "mx.na",
+ "ca.na",
+ "in.na",
+ "cc.na",
+ "tv.na",
+ "ws.na",
+ "mobi.na",
+ "co.na",
+ "com.na",
+ "org.na",
+ "name",
+ "nc",
+ "asso.nc",
+ "ne",
+ "net",
+ "nf",
+ "com.nf",
+ "net.nf",
+ "per.nf",
+ "rec.nf",
+ "web.nf",
+ "arts.nf",
+ "firm.nf",
+ "info.nf",
+ "other.nf",
+ "store.nf",
+ "ac.ng",
+ "com.ng",
+ "edu.ng",
+ "gov.ng",
+ "net.ng",
+ "org.ng",
+ "nl",
+ "bv.nl",
+ "no",
+ "fhs.no",
+ "vgs.no",
+ "fylkesbibl.no",
+ "folkebibl.no",
+ "museum.no",
+ "idrett.no",
+ "priv.no",
+ "mil.no",
+ "stat.no",
+ "dep.no",
+ "kommune.no",
+ "herad.no",
+ "aa.no",
+ "ah.no",
+ "bu.no",
+ "fm.no",
+ "hl.no",
+ "hm.no",
+ "jan-mayen.no",
+ "mr.no",
+ "nl.no",
+ "nt.no",
+ "of.no",
+ "ol.no",
+ "oslo.no",
+ "rl.no",
+ "sf.no",
+ "st.no",
+ "svalbard.no",
+ "tm.no",
+ "tr.no",
+ "va.no",
+ "vf.no",
+ "gs.aa.no",
+ "gs.ah.no",
+ "gs.bu.no",
+ "gs.fm.no",
+ "gs.hl.no",
+ "gs.hm.no",
+ "gs.jan-mayen.no",
+ "gs.mr.no",
+ "gs.nl.no",
+ "gs.nt.no",
+ "gs.of.no",
+ "gs.ol.no",
+ "gs.oslo.no",
+ "gs.rl.no",
+ "gs.sf.no",
+ "gs.st.no",
+ "gs.svalbard.no",
+ "gs.tm.no",
+ "gs.tr.no",
+ "gs.va.no",
+ "gs.vf.no",
+ "akrehamn.no",
+ "\u00e5krehamn.no",
+ "xn--krehamn-dxa.no",
+ "algard.no",
+ "\u00e5lg\u00e5rd.no",
+ "xn--lgrd-poac.no",
+ "arna.no",
+ "brumunddal.no",
+ "bryne.no",
+ "bronnoysund.no",
+ "br\u00f8nn\u00f8ysund.no",
+ "xn--brnnysund-m8ac.no",
+ "drobak.no",
+ "dr\u00f8bak.no",
+ "xn--drbak-wua.no",
+ "egersund.no",
+ "fetsund.no",
+ "floro.no",
+ "flor\u00f8.no",
+ "xn--flor-jra.no",
+ "fredrikstad.no",
+ "hokksund.no",
+ "honefoss.no",
+ "h\u00f8nefoss.no",
+ "xn--hnefoss-q1a.no",
+ "jessheim.no",
+ "jorpeland.no",
+ "j\u00f8rpeland.no",
+ "xn--jrpeland-54a.no",
+ "kirkenes.no",
+ "kopervik.no",
+ "krokstadelva.no",
+ "langevag.no",
+ "langev\u00e5g.no",
+ "xn--langevg-jxa.no",
+ "leirvik.no",
+ "mjondalen.no",
+ "mj\u00f8ndalen.no",
+ "xn--mjndalen-64a.no",
+ "mo-i-rana.no",
+ "mosjoen.no",
+ "mosj\u00f8en.no",
+ "xn--mosjen-eya.no",
+ "nesoddtangen.no",
+ "orkanger.no",
+ "osoyro.no",
+ "os\u00f8yro.no",
+ "xn--osyro-wua.no",
+ "raholt.no",
+ "r\u00e5holt.no",
+ "xn--rholt-mra.no",
+ "sandnessjoen.no",
+ "sandnessj\u00f8en.no",
+ "xn--sandnessjen-ogb.no",
+ "skedsmokorset.no",
+ "slattum.no",
+ "spjelkavik.no",
+ "stathelle.no",
+ "stavern.no",
+ "stjordalshalsen.no",
+ "stj\u00f8rdalshalsen.no",
+ "xn--stjrdalshalsen-sqb.no",
+ "tananger.no",
+ "tranby.no",
+ "vossevangen.no",
+ "afjord.no",
+ "\u00e5fjord.no",
+ "xn--fjord-lra.no",
+ "agdenes.no",
+ "al.no",
+ "\u00e5l.no",
+ "xn--l-1fa.no",
+ "alesund.no",
+ "\u00e5lesund.no",
+ "xn--lesund-hua.no",
+ "alstahaug.no",
+ "alta.no",
+ "\u00e1lt\u00e1.no",
+ "xn--lt-liac.no",
+ "alaheadju.no",
+ "\u00e1laheadju.no",
+ "xn--laheadju-7ya.no",
+ "alvdal.no",
+ "amli.no",
+ "\u00e5mli.no",
+ "xn--mli-tla.no",
+ "amot.no",
+ "\u00e5mot.no",
+ "xn--mot-tla.no",
+ "andebu.no",
+ "andoy.no",
+ "and\u00f8y.no",
+ "xn--andy-ira.no",
+ "andasuolo.no",
+ "ardal.no",
+ "\u00e5rdal.no",
+ "xn--rdal-poa.no",
+ "aremark.no",
+ "arendal.no",
+ "\u00e5s.no",
+ "xn--s-1fa.no",
+ "aseral.no",
+ "\u00e5seral.no",
+ "xn--seral-lra.no",
+ "asker.no",
+ "askim.no",
+ "askvoll.no",
+ "askoy.no",
+ "ask\u00f8y.no",
+ "xn--asky-ira.no",
+ "asnes.no",
+ "\u00e5snes.no",
+ "xn--snes-poa.no",
+ "audnedaln.no",
+ "aukra.no",
+ "aure.no",
+ "aurland.no",
+ "aurskog-holand.no",
+ "aurskog-h\u00f8land.no",
+ "xn--aurskog-hland-jnb.no",
+ "austevoll.no",
+ "austrheim.no",
+ "averoy.no",
+ "aver\u00f8y.no",
+ "xn--avery-yua.no",
+ "balestrand.no",
+ "ballangen.no",
+ "balat.no",
+ "b\u00e1l\u00e1t.no",
+ "xn--blt-elab.no",
+ "balsfjord.no",
+ "bahccavuotna.no",
+ "b\u00e1hccavuotna.no",
+ "xn--bhccavuotna-k7a.no",
+ "bamble.no",
+ "bardu.no",
+ "beardu.no",
+ "beiarn.no",
+ "bajddar.no",
+ "b\u00e1jddar.no",
+ "xn--bjddar-pta.no",
+ "baidar.no",
+ "b\u00e1id\u00e1r.no",
+ "xn--bidr-5nac.no",
+ "berg.no",
+ "bergen.no",
+ "berlevag.no",
+ "berlev\u00e5g.no",
+ "xn--berlevg-jxa.no",
+ "bearalvahki.no",
+ "bearalv\u00e1hki.no",
+ "xn--bearalvhki-y4a.no",
+ "bindal.no",
+ "birkenes.no",
+ "bjarkoy.no",
+ "bjark\u00f8y.no",
+ "xn--bjarky-fya.no",
+ "bjerkreim.no",
+ "bjugn.no",
+ "bodo.no",
+ "bod\u00f8.no",
+ "xn--bod-2na.no",
+ "badaddja.no",
+ "b\u00e5d\u00e5ddj\u00e5.no",
+ "xn--bdddj-mrabd.no",
+ "budejju.no",
+ "bokn.no",
+ "bremanger.no",
+ "bronnoy.no",
+ "br\u00f8nn\u00f8y.no",
+ "xn--brnny-wuac.no",
+ "bygland.no",
+ "bykle.no",
+ "barum.no",
+ "b\u00e6rum.no",
+ "xn--brum-voa.no",
+ "bo.telemark.no",
+ "b\u00f8.telemark.no",
+ "xn--b-5ga.telemark.no",
+ "bo.nordland.no",
+ "b\u00f8.nordland.no",
+ "xn--b-5ga.nordland.no",
+ "bievat.no",
+ "biev\u00e1t.no",
+ "xn--bievt-0qa.no",
+ "bomlo.no",
+ "b\u00f8mlo.no",
+ "xn--bmlo-gra.no",
+ "batsfjord.no",
+ "b\u00e5tsfjord.no",
+ "xn--btsfjord-9za.no",
+ "bahcavuotna.no",
+ "b\u00e1hcavuotna.no",
+ "xn--bhcavuotna-s4a.no",
+ "dovre.no",
+ "drammen.no",
+ "drangedal.no",
+ "dyroy.no",
+ "dyr\u00f8y.no",
+ "xn--dyry-ira.no",
+ "donna.no",
+ "d\u00f8nna.no",
+ "xn--dnna-gra.no",
+ "eid.no",
+ "eidfjord.no",
+ "eidsberg.no",
+ "eidskog.no",
+ "eidsvoll.no",
+ "eigersund.no",
+ "elverum.no",
+ "enebakk.no",
+ "engerdal.no",
+ "etne.no",
+ "etnedal.no",
+ "evenes.no",
+ "evenassi.no",
+ "even\u00e1\u0161\u0161i.no",
+ "xn--eveni-0qa01ga.no",
+ "evje-og-hornnes.no",
+ "farsund.no",
+ "fauske.no",
+ "fuossko.no",
+ "fuoisku.no",
+ "fedje.no",
+ "fet.no",
+ "finnoy.no",
+ "finn\u00f8y.no",
+ "xn--finny-yua.no",
+ "fitjar.no",
+ "fjaler.no",
+ "fjell.no",
+ "flakstad.no",
+ "flatanger.no",
+ "flekkefjord.no",
+ "flesberg.no",
+ "flora.no",
+ "fla.no",
+ "fl\u00e5.no",
+ "xn--fl-zia.no",
+ "folldal.no",
+ "forsand.no",
+ "fosnes.no",
+ "frei.no",
+ "frogn.no",
+ "froland.no",
+ "frosta.no",
+ "frana.no",
+ "fr\u00e6na.no",
+ "xn--frna-woa.no",
+ "froya.no",
+ "fr\u00f8ya.no",
+ "xn--frya-hra.no",
+ "fusa.no",
+ "fyresdal.no",
+ "forde.no",
+ "f\u00f8rde.no",
+ "xn--frde-gra.no",
+ "gamvik.no",
+ "gangaviika.no",
+ "g\u00e1\u014bgaviika.no",
+ "xn--ggaviika-8ya47h.no",
+ "gaular.no",
+ "gausdal.no",
+ "gildeskal.no",
+ "gildesk\u00e5l.no",
+ "xn--gildeskl-g0a.no",
+ "giske.no",
+ "gjemnes.no",
+ "gjerdrum.no",
+ "gjerstad.no",
+ "gjesdal.no",
+ "gjovik.no",
+ "gj\u00f8vik.no",
+ "xn--gjvik-wua.no",
+ "gloppen.no",
+ "gol.no",
+ "gran.no",
+ "grane.no",
+ "granvin.no",
+ "gratangen.no",
+ "grimstad.no",
+ "grong.no",
+ "kraanghke.no",
+ "kr\u00e5anghke.no",
+ "xn--kranghke-b0a.no",
+ "grue.no",
+ "gulen.no",
+ "hadsel.no",
+ "halden.no",
+ "halsa.no",
+ "hamar.no",
+ "hamaroy.no",
+ "habmer.no",
+ "h\u00e1bmer.no",
+ "xn--hbmer-xqa.no",
+ "hapmir.no",
+ "h\u00e1pmir.no",
+ "xn--hpmir-xqa.no",
+ "hammerfest.no",
+ "hammarfeasta.no",
+ "h\u00e1mm\u00e1rfeasta.no",
+ "xn--hmmrfeasta-s4ac.no",
+ "haram.no",
+ "hareid.no",
+ "harstad.no",
+ "hasvik.no",
+ "aknoluokta.no",
+ "\u00e1k\u014boluokta.no",
+ "xn--koluokta-7ya57h.no",
+ "hattfjelldal.no",
+ "aarborte.no",
+ "haugesund.no",
+ "hemne.no",
+ "hemnes.no",
+ "hemsedal.no",
+ "heroy.more-og-romsdal.no",
+ "her\u00f8y.m\u00f8re-og-romsdal.no",
+ "xn--hery-ira.xn--mre-og-romsdal-qqb.no",
+ "heroy.nordland.no",
+ "her\u00f8y.nordland.no",
+ "xn--hery-ira.nordland.no",
+ "hitra.no",
+ "hjartdal.no",
+ "hjelmeland.no",
+ "hobol.no",
+ "hob\u00f8l.no",
+ "xn--hobl-ira.no",
+ "hof.no",
+ "hol.no",
+ "hole.no",
+ "holmestrand.no",
+ "holtalen.no",
+ "holt\u00e5len.no",
+ "xn--holtlen-hxa.no",
+ "hornindal.no",
+ "horten.no",
+ "hurdal.no",
+ "hurum.no",
+ "hvaler.no",
+ "hyllestad.no",
+ "hagebostad.no",
+ "h\u00e6gebostad.no",
+ "xn--hgebostad-g3a.no",
+ "hoyanger.no",
+ "h\u00f8yanger.no",
+ "xn--hyanger-q1a.no",
+ "hoylandet.no",
+ "h\u00f8ylandet.no",
+ "xn--hylandet-54a.no",
+ "ha.no",
+ "h\u00e5.no",
+ "xn--h-2fa.no",
+ "ibestad.no",
+ "inderoy.no",
+ "inder\u00f8y.no",
+ "xn--indery-fya.no",
+ "iveland.no",
+ "jevnaker.no",
+ "jondal.no",
+ "jolster.no",
+ "j\u00f8lster.no",
+ "xn--jlster-bya.no",
+ "karasjok.no",
+ "karasjohka.no",
+ "k\u00e1r\u00e1\u0161johka.no",
+ "xn--krjohka-hwab49j.no",
+ "karlsoy.no",
+ "galsa.no",
+ "g\u00e1ls\u00e1.no",
+ "xn--gls-elac.no",
+ "karmoy.no",
+ "karm\u00f8y.no",
+ "xn--karmy-yua.no",
+ "kautokeino.no",
+ "guovdageaidnu.no",
+ "klepp.no",
+ "klabu.no",
+ "kl\u00e6bu.no",
+ "xn--klbu-woa.no",
+ "kongsberg.no",
+ "kongsvinger.no",
+ "kragero.no",
+ "krager\u00f8.no",
+ "xn--krager-gya.no",
+ "kristiansand.no",
+ "kristiansund.no",
+ "krodsherad.no",
+ "kr\u00f8dsherad.no",
+ "xn--krdsherad-m8a.no",
+ "kvalsund.no",
+ "rahkkeravju.no",
+ "r\u00e1hkker\u00e1vju.no",
+ "xn--rhkkervju-01af.no",
+ "kvam.no",
+ "kvinesdal.no",
+ "kvinnherad.no",
+ "kviteseid.no",
+ "kvitsoy.no",
+ "kvits\u00f8y.no",
+ "xn--kvitsy-fya.no",
+ "kvafjord.no",
+ "kv\u00e6fjord.no",
+ "xn--kvfjord-nxa.no",
+ "giehtavuoatna.no",
+ "kvanangen.no",
+ "kv\u00e6nangen.no",
+ "xn--kvnangen-k0a.no",
+ "navuotna.no",
+ "n\u00e1vuotna.no",
+ "xn--nvuotna-hwa.no",
+ "kafjord.no",
+ "k\u00e5fjord.no",
+ "xn--kfjord-iua.no",
+ "gaivuotna.no",
+ "g\u00e1ivuotna.no",
+ "xn--givuotna-8ya.no",
+ "larvik.no",
+ "lavangen.no",
+ "lavagis.no",
+ "loabat.no",
+ "loab\u00e1t.no",
+ "xn--loabt-0qa.no",
+ "lebesby.no",
+ "davvesiida.no",
+ "leikanger.no",
+ "leirfjord.no",
+ "leka.no",
+ "leksvik.no",
+ "lenvik.no",
+ "leangaviika.no",
+ "lea\u014bgaviika.no",
+ "xn--leagaviika-52b.no",
+ "lesja.no",
+ "levanger.no",
+ "lier.no",
+ "lierne.no",
+ "lillehammer.no",
+ "lillesand.no",
+ "lindesnes.no",
+ "lindas.no",
+ "lind\u00e5s.no",
+ "xn--linds-pra.no",
+ "lom.no",
+ "loppa.no",
+ "lahppi.no",
+ "l\u00e1hppi.no",
+ "xn--lhppi-xqa.no",
+ "lund.no",
+ "lunner.no",
+ "luroy.no",
+ "lur\u00f8y.no",
+ "xn--lury-ira.no",
+ "luster.no",
+ "lyngdal.no",
+ "lyngen.no",
+ "ivgu.no",
+ "lardal.no",
+ "lerdal.no",
+ "l\u00e6rdal.no",
+ "xn--lrdal-sra.no",
+ "lodingen.no",
+ "l\u00f8dingen.no",
+ "xn--ldingen-q1a.no",
+ "lorenskog.no",
+ "l\u00f8renskog.no",
+ "xn--lrenskog-54a.no",
+ "loten.no",
+ "l\u00f8ten.no",
+ "xn--lten-gra.no",
+ "malvik.no",
+ "masoy.no",
+ "m\u00e5s\u00f8y.no",
+ "xn--msy-ula0h.no",
+ "muosat.no",
+ "muos\u00e1t.no",
+ "xn--muost-0qa.no",
+ "mandal.no",
+ "marker.no",
+ "marnardal.no",
+ "masfjorden.no",
+ "meland.no",
+ "meldal.no",
+ "melhus.no",
+ "meloy.no",
+ "mel\u00f8y.no",
+ "xn--mely-ira.no",
+ "meraker.no",
+ "mer\u00e5ker.no",
+ "xn--merker-kua.no",
+ "moareke.no",
+ "mo\u00e5reke.no",
+ "xn--moreke-jua.no",
+ "midsund.no",
+ "midtre-gauldal.no",
+ "modalen.no",
+ "modum.no",
+ "molde.no",
+ "moskenes.no",
+ "moss.no",
+ "mosvik.no",
+ "malselv.no",
+ "m\u00e5lselv.no",
+ "xn--mlselv-iua.no",
+ "malatvuopmi.no",
+ "m\u00e1latvuopmi.no",
+ "xn--mlatvuopmi-s4a.no",
+ "namdalseid.no",
+ "aejrie.no",
+ "namsos.no",
+ "namsskogan.no",
+ "naamesjevuemie.no",
+ "n\u00e5\u00e5mesjevuemie.no",
+ "xn--nmesjevuemie-tcba.no",
+ "laakesvuemie.no",
+ "nannestad.no",
+ "narvik.no",
+ "narviika.no",
+ "naustdal.no",
+ "nedre-eiker.no",
+ "nes.akershus.no",
+ "nes.buskerud.no",
+ "nesna.no",
+ "nesodden.no",
+ "nesseby.no",
+ "unjarga.no",
+ "unj\u00e1rga.no",
+ "xn--unjrga-rta.no",
+ "nesset.no",
+ "nissedal.no",
+ "nittedal.no",
+ "nord-aurdal.no",
+ "nord-fron.no",
+ "nord-odal.no",
+ "norddal.no",
+ "nordkapp.no",
+ "davvenjarga.no",
+ "davvenj\u00e1rga.no",
+ "xn--davvenjrga-y4a.no",
+ "nordre-land.no",
+ "nordreisa.no",
+ "raisa.no",
+ "r\u00e1isa.no",
+ "xn--risa-5na.no",
+ "nore-og-uvdal.no",
+ "notodden.no",
+ "naroy.no",
+ "n\u00e6r\u00f8y.no",
+ "xn--nry-yla5g.no",
+ "notteroy.no",
+ "n\u00f8tter\u00f8y.no",
+ "xn--nttery-byae.no",
+ "odda.no",
+ "oksnes.no",
+ "\u00f8ksnes.no",
+ "xn--ksnes-uua.no",
+ "oppdal.no",
+ "oppegard.no",
+ "oppeg\u00e5rd.no",
+ "xn--oppegrd-ixa.no",
+ "orkdal.no",
+ "orland.no",
+ "\u00f8rland.no",
+ "xn--rland-uua.no",
+ "orskog.no",
+ "\u00f8rskog.no",
+ "xn--rskog-uua.no",
+ "orsta.no",
+ "\u00f8rsta.no",
+ "xn--rsta-fra.no",
+ "os.hedmark.no",
+ "os.hordaland.no",
+ "osen.no",
+ "osteroy.no",
+ "oster\u00f8y.no",
+ "xn--ostery-fya.no",
+ "ostre-toten.no",
+ "\u00f8stre-toten.no",
+ "xn--stre-toten-zcb.no",
+ "overhalla.no",
+ "ovre-eiker.no",
+ "\u00f8vre-eiker.no",
+ "xn--vre-eiker-k8a.no",
+ "oyer.no",
+ "\u00f8yer.no",
+ "xn--yer-zna.no",
+ "oygarden.no",
+ "\u00f8ygarden.no",
+ "xn--ygarden-p1a.no",
+ "oystre-slidre.no",
+ "\u00f8ystre-slidre.no",
+ "xn--ystre-slidre-ujb.no",
+ "porsanger.no",
+ "porsangu.no",
+ "pors\u00e1\u014bgu.no",
+ "xn--porsgu-sta26f.no",
+ "porsgrunn.no",
+ "radoy.no",
+ "rad\u00f8y.no",
+ "xn--rady-ira.no",
+ "rakkestad.no",
+ "rana.no",
+ "ruovat.no",
+ "randaberg.no",
+ "rauma.no",
+ "rendalen.no",
+ "rennebu.no",
+ "rennesoy.no",
+ "rennes\u00f8y.no",
+ "xn--rennesy-v1a.no",
+ "rindal.no",
+ "ringebu.no",
+ "ringerike.no",
+ "ringsaker.no",
+ "rissa.no",
+ "risor.no",
+ "ris\u00f8r.no",
+ "xn--risr-ira.no",
+ "roan.no",
+ "rollag.no",
+ "rygge.no",
+ "ralingen.no",
+ "r\u00e6lingen.no",
+ "xn--rlingen-mxa.no",
+ "rodoy.no",
+ "r\u00f8d\u00f8y.no",
+ "xn--rdy-0nab.no",
+ "romskog.no",
+ "r\u00f8mskog.no",
+ "xn--rmskog-bya.no",
+ "roros.no",
+ "r\u00f8ros.no",
+ "xn--rros-gra.no",
+ "rost.no",
+ "r\u00f8st.no",
+ "xn--rst-0na.no",
+ "royken.no",
+ "r\u00f8yken.no",
+ "xn--ryken-vua.no",
+ "royrvik.no",
+ "r\u00f8yrvik.no",
+ "xn--ryrvik-bya.no",
+ "rade.no",
+ "r\u00e5de.no",
+ "xn--rde-ula.no",
+ "salangen.no",
+ "siellak.no",
+ "saltdal.no",
+ "salat.no",
+ "s\u00e1l\u00e1t.no",
+ "xn--slt-elab.no",
+ "s\u00e1lat.no",
+ "xn--slat-5na.no",
+ "samnanger.no",
+ "sande.more-og-romsdal.no",
+ "sande.m\u00f8re-og-romsdal.no",
+ "sande.xn--mre-og-romsdal-qqb.no",
+ "sande.vestfold.no",
+ "sandefjord.no",
+ "sandnes.no",
+ "sandoy.no",
+ "sand\u00f8y.no",
+ "xn--sandy-yua.no",
+ "sarpsborg.no",
+ "sauda.no",
+ "sauherad.no",
+ "sel.no",
+ "selbu.no",
+ "selje.no",
+ "seljord.no",
+ "sigdal.no",
+ "siljan.no",
+ "sirdal.no",
+ "skaun.no",
+ "skedsmo.no",
+ "ski.no",
+ "skien.no",
+ "skiptvet.no",
+ "skjervoy.no",
+ "skjerv\u00f8y.no",
+ "xn--skjervy-v1a.no",
+ "skierva.no",
+ "skierv\u00e1.no",
+ "xn--skierv-uta.no",
+ "skjak.no",
+ "skj\u00e5k.no",
+ "xn--skjk-soa.no",
+ "skodje.no",
+ "skanland.no",
+ "sk\u00e5nland.no",
+ "xn--sknland-fxa.no",
+ "skanit.no",
+ "sk\u00e1nit.no",
+ "xn--sknit-yqa.no",
+ "smola.no",
+ "sm\u00f8la.no",
+ "xn--smla-hra.no",
+ "snillfjord.no",
+ "snasa.no",
+ "sn\u00e5sa.no",
+ "xn--snsa-roa.no",
+ "snoasa.no",
+ "snaase.no",
+ "sn\u00e5ase.no",
+ "xn--snase-nra.no",
+ "sogndal.no",
+ "sokndal.no",
+ "sola.no",
+ "solund.no",
+ "songdalen.no",
+ "sortland.no",
+ "spydeberg.no",
+ "stange.no",
+ "stavanger.no",
+ "steigen.no",
+ "steinkjer.no",
+ "stjordal.no",
+ "stj\u00f8rdal.no",
+ "xn--stjrdal-s1a.no",
+ "stokke.no",
+ "stor-elvdal.no",
+ "stord.no",
+ "stordal.no",
+ "storfjord.no",
+ "omasvuotna.no",
+ "strand.no",
+ "stranda.no",
+ "stryn.no",
+ "sula.no",
+ "suldal.no",
+ "sund.no",
+ "sunndal.no",
+ "surnadal.no",
+ "sveio.no",
+ "svelvik.no",
+ "sykkylven.no",
+ "sogne.no",
+ "s\u00f8gne.no",
+ "xn--sgne-gra.no",
+ "somna.no",
+ "s\u00f8mna.no",
+ "xn--smna-gra.no",
+ "sondre-land.no",
+ "s\u00f8ndre-land.no",
+ "xn--sndre-land-0cb.no",
+ "sor-aurdal.no",
+ "s\u00f8r-aurdal.no",
+ "xn--sr-aurdal-l8a.no",
+ "sor-fron.no",
+ "s\u00f8r-fron.no",
+ "xn--sr-fron-q1a.no",
+ "sor-odal.no",
+ "s\u00f8r-odal.no",
+ "xn--sr-odal-q1a.no",
+ "sor-varanger.no",
+ "s\u00f8r-varanger.no",
+ "xn--sr-varanger-ggb.no",
+ "matta-varjjat.no",
+ "m\u00e1tta-v\u00e1rjjat.no",
+ "xn--mtta-vrjjat-k7af.no",
+ "sorfold.no",
+ "s\u00f8rfold.no",
+ "xn--srfold-bya.no",
+ "sorreisa.no",
+ "s\u00f8rreisa.no",
+ "xn--srreisa-q1a.no",
+ "sorum.no",
+ "s\u00f8rum.no",
+ "xn--srum-gra.no",
+ "tana.no",
+ "deatnu.no",
+ "time.no",
+ "tingvoll.no",
+ "tinn.no",
+ "tjeldsund.no",
+ "dielddanuorri.no",
+ "tjome.no",
+ "tj\u00f8me.no",
+ "xn--tjme-hra.no",
+ "tokke.no",
+ "tolga.no",
+ "torsken.no",
+ "tranoy.no",
+ "tran\u00f8y.no",
+ "xn--trany-yua.no",
+ "tromso.no",
+ "troms\u00f8.no",
+ "xn--troms-zua.no",
+ "tromsa.no",
+ "romsa.no",
+ "trondheim.no",
+ "troandin.no",
+ "trysil.no",
+ "trana.no",
+ "tr\u00e6na.no",
+ "xn--trna-woa.no",
+ "trogstad.no",
+ "tr\u00f8gstad.no",
+ "xn--trgstad-r1a.no",
+ "tvedestrand.no",
+ "tydal.no",
+ "tynset.no",
+ "tysfjord.no",
+ "divtasvuodna.no",
+ "divttasvuotna.no",
+ "tysnes.no",
+ "tysvar.no",
+ "tysv\u00e6r.no",
+ "xn--tysvr-vra.no",
+ "tonsberg.no",
+ "t\u00f8nsberg.no",
+ "xn--tnsberg-q1a.no",
+ "ullensaker.no",
+ "ullensvang.no",
+ "ulvik.no",
+ "utsira.no",
+ "vadso.no",
+ "vads\u00f8.no",
+ "xn--vads-jra.no",
+ "cahcesuolo.no",
+ "\u010d\u00e1hcesuolo.no",
+ "xn--hcesuolo-7ya35b.no",
+ "vaksdal.no",
+ "valle.no",
+ "vang.no",
+ "vanylven.no",
+ "vardo.no",
+ "vard\u00f8.no",
+ "xn--vard-jra.no",
+ "varggat.no",
+ "v\u00e1rgg\u00e1t.no",
+ "xn--vrggt-xqad.no",
+ "vefsn.no",
+ "vaapste.no",
+ "vega.no",
+ "vegarshei.no",
+ "veg\u00e5rshei.no",
+ "xn--vegrshei-c0a.no",
+ "vennesla.no",
+ "verdal.no",
+ "verran.no",
+ "vestby.no",
+ "vestnes.no",
+ "vestre-slidre.no",
+ "vestre-toten.no",
+ "vestvagoy.no",
+ "vestv\u00e5g\u00f8y.no",
+ "xn--vestvgy-ixa6o.no",
+ "vevelstad.no",
+ "vik.no",
+ "vikna.no",
+ "vindafjord.no",
+ "volda.no",
+ "voss.no",
+ "varoy.no",
+ "v\u00e6r\u00f8y.no",
+ "xn--vry-yla5g.no",
+ "vagan.no",
+ "v\u00e5gan.no",
+ "xn--vgan-qoa.no",
+ "voagat.no",
+ "vagsoy.no",
+ "v\u00e5gs\u00f8y.no",
+ "xn--vgsy-qoa0j.no",
+ "vaga.no",
+ "v\u00e5g\u00e5.no",
+ "xn--vg-yiab.no",
+ "valer.ostfold.no",
+ "v\u00e5ler.\u00f8stfold.no",
+ "xn--vler-qoa.xn--stfold-9xa.no",
+ "valer.hedmark.no",
+ "v\u00e5ler.hedmark.no",
+ "xn--vler-qoa.hedmark.no",
+ "nr",
+ "biz.nr",
+ "info.nr",
+ "gov.nr",
+ "edu.nr",
+ "org.nr",
+ "net.nr",
+ "com.nr",
+ "nu",
+ "org",
+ "pa",
+ "ac.pa",
+ "gob.pa",
+ "com.pa",
+ "org.pa",
+ "sld.pa",
+ "edu.pa",
+ "net.pa",
+ "ing.pa",
+ "abo.pa",
+ "med.pa",
+ "nom.pa",
+ "pe",
+ "edu.pe",
+ "gob.pe",
+ "nom.pe",
+ "mil.pe",
+ "org.pe",
+ "com.pe",
+ "net.pe",
+ "pf",
+ "com.pf",
+ "org.pf",
+ "edu.pf",
+ "ph",
+ "com.ph",
+ "net.ph",
+ "org.ph",
+ "gov.ph",
+ "edu.ph",
+ "ngo.ph",
+ "mil.ph",
+ "i.ph",
+ "pk",
+ "com.pk",
+ "net.pk",
+ "edu.pk",
+ "org.pk",
+ "fam.pk",
+ "biz.pk",
+ "web.pk",
+ "gov.pk",
+ "gob.pk",
+ "gok.pk",
+ "gon.pk",
+ "gop.pk",
+ "gos.pk",
+ "info.pk",
+ "pl",
+ "aid.pl",
+ "agro.pl",
+ "atm.pl",
+ "auto.pl",
+ "biz.pl",
+ "com.pl",
+ "edu.pl",
+ "gmina.pl",
+ "gsm.pl",
+ "info.pl",
+ "mail.pl",
+ "miasta.pl",
+ "media.pl",
+ "mil.pl",
+ "net.pl",
+ "nieruchomosci.pl",
+ "nom.pl",
+ "org.pl",
+ "pc.pl",
+ "powiat.pl",
+ "priv.pl",
+ "realestate.pl",
+ "rel.pl",
+ "sex.pl",
+ "shop.pl",
+ "sklep.pl",
+ "sos.pl",
+ "szkola.pl",
+ "targi.pl",
+ "tm.pl",
+ "tourism.pl",
+ "travel.pl",
+ "turystyka.pl",
+ "6bone.pl",
+ "art.pl",
+ "mbone.pl",
+ "gov.pl",
+ "uw.gov.pl",
+ "um.gov.pl",
+ "ug.gov.pl",
+ "upow.gov.pl",
+ "starostwo.gov.pl",
+ "so.gov.pl",
+ "sr.gov.pl",
+ "po.gov.pl",
+ "pa.gov.pl",
+ "ngo.pl",
+ "irc.pl",
+ "usenet.pl",
+ "augustow.pl",
+ "babia-gora.pl",
+ "bedzin.pl",
+ "beskidy.pl",
+ "bialowieza.pl",
+ "bialystok.pl",
+ "bielawa.pl",
+ "bieszczady.pl",
+ "boleslawiec.pl",
+ "bydgoszcz.pl",
+ "bytom.pl",
+ "cieszyn.pl",
+ "czeladz.pl",
+ "czest.pl",
+ "dlugoleka.pl",
+ "elblag.pl",
+ "elk.pl",
+ "glogow.pl",
+ "gniezno.pl",
+ "gorlice.pl",
+ "grajewo.pl",
+ "ilawa.pl",
+ "jaworzno.pl",
+ "jelenia-gora.pl",
+ "jgora.pl",
+ "kalisz.pl",
+ "kazimierz-dolny.pl",
+ "karpacz.pl",
+ "kartuzy.pl",
+ "kaszuby.pl",
+ "katowice.pl",
+ "kepno.pl",
+ "ketrzyn.pl",
+ "klodzko.pl",
+ "kobierzyce.pl",
+ "kolobrzeg.pl",
+ "konin.pl",
+ "konskowola.pl",
+ "kutno.pl",
+ "lapy.pl",
+ "lebork.pl",
+ "legnica.pl",
+ "lezajsk.pl",
+ "limanowa.pl",
+ "lomza.pl",
+ "lowicz.pl",
+ "lubin.pl",
+ "lukow.pl",
+ "malbork.pl",
+ "malopolska.pl",
+ "mazowsze.pl",
+ "mazury.pl",
+ "mielec.pl",
+ "mielno.pl",
+ "mragowo.pl",
+ "naklo.pl",
+ "nowaruda.pl",
+ "nysa.pl",
+ "olawa.pl",
+ "olecko.pl",
+ "olkusz.pl",
+ "olsztyn.pl",
+ "opoczno.pl",
+ "opole.pl",
+ "ostroda.pl",
+ "ostroleka.pl",
+ "ostrowiec.pl",
+ "ostrowwlkp.pl",
+ "pila.pl",
+ "pisz.pl",
+ "podhale.pl",
+ "podlasie.pl",
+ "polkowice.pl",
+ "pomorze.pl",
+ "pomorskie.pl",
+ "prochowice.pl",
+ "pruszkow.pl",
+ "przeworsk.pl",
+ "pulawy.pl",
+ "radom.pl",
+ "rawa-maz.pl",
+ "rybnik.pl",
+ "rzeszow.pl",
+ "sanok.pl",
+ "sejny.pl",
+ "siedlce.pl",
+ "slask.pl",
+ "slupsk.pl",
+ "sosnowiec.pl",
+ "stalowa-wola.pl",
+ "skoczow.pl",
+ "starachowice.pl",
+ "stargard.pl",
+ "suwalki.pl",
+ "swidnica.pl",
+ "swiebodzin.pl",
+ "swinoujscie.pl",
+ "szczecin.pl",
+ "szczytno.pl",
+ "tarnobrzeg.pl",
+ "tgory.pl",
+ "turek.pl",
+ "tychy.pl",
+ "ustka.pl",
+ "walbrzych.pl",
+ "warmia.pl",
+ "warszawa.pl",
+ "waw.pl",
+ "wegrow.pl",
+ "wielun.pl",
+ "wlocl.pl",
+ "wloclawek.pl",
+ "wodzislaw.pl",
+ "wolomin.pl",
+ "wroclaw.pl",
+ "zachpomor.pl",
+ "zagan.pl",
+ "zarow.pl",
+ "zgora.pl",
+ "zgorzelec.pl",
+ "gda.pl",
+ "gdansk.pl",
+ "gdynia.pl",
+ "med.pl",
+ "sopot.pl",
+ "gliwice.pl",
+ "krakow.pl",
+ "poznan.pl",
+ "wroc.pl",
+ "zakopane.pl",
+ "pm",
+ "pn",
+ "gov.pn",
+ "co.pn",
+ "org.pn",
+ "edu.pn",
+ "net.pn",
+ "pr",
+ "com.pr",
+ "net.pr",
+ "org.pr",
+ "gov.pr",
+ "edu.pr",
+ "isla.pr",
+ "pro.pr",
+ "biz.pr",
+ "info.pr",
+ "name.pr",
+ "est.pr",
+ "prof.pr",
+ "ac.pr",
+ "pro",
+ "aca.pro",
+ "bar.pro",
+ "cpa.pro",
+ "jur.pro",
+ "law.pro",
+ "med.pro",
+ "eng.pro",
+ "ps",
+ "edu.ps",
+ "gov.ps",
+ "sec.ps",
+ "plo.ps",
+ "com.ps",
+ "org.ps",
+ "net.ps",
+ "pt",
+ "net.pt",
+ "gov.pt",
+ "org.pt",
+ "edu.pt",
+ "int.pt",
+ "publ.pt",
+ "com.pt",
+ "nome.pt",
+ "pw",
+ "co.pw",
+ "ne.pw",
+ "or.pw",
+ "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",
+ "nom.re",
+ "ro",
+ "com.ro",
+ "org.ro",
+ "tm.ro",
+ "nt.ro",
+ "nom.ro",
+ "info.ro",
+ "rec.ro",
+ "arts.ro",
+ "firm.ro",
+ "store.ro",
+ "www.ro",
+ "rs",
+ "co.rs",
+ "org.rs",
+ "edu.rs",
+ "ac.rs",
+ "gov.rs",
+ "in.rs",
+ "ru",
+ "ac.ru",
+ "com.ru",
+ "edu.ru",
+ "int.ru",
+ "net.ru",
+ "org.ru",
+ "pp.ru",
+ "adygeya.ru",
+ "altai.ru",
+ "amur.ru",
+ "arkhangelsk.ru",
+ "astrakhan.ru",
+ "bashkiria.ru",
+ "belgorod.ru",
+ "bir.ru",
+ "bryansk.ru",
+ "buryatia.ru",
+ "cbg.ru",
+ "chel.ru",
+ "chelyabinsk.ru",
+ "chita.ru",
+ "chukotka.ru",
+ "chuvashia.ru",
+ "dagestan.ru",
+ "dudinka.ru",
+ "e-burg.ru",
+ "grozny.ru",
+ "irkutsk.ru",
+ "ivanovo.ru",
+ "izhevsk.ru",
+ "jar.ru",
+ "joshkar-ola.ru",
+ "kalmykia.ru",
+ "kaluga.ru",
+ "kamchatka.ru",
+ "karelia.ru",
+ "kazan.ru",
+ "kchr.ru",
+ "kemerovo.ru",
+ "khabarovsk.ru",
+ "khakassia.ru",
+ "khv.ru",
+ "kirov.ru",
+ "koenig.ru",
+ "komi.ru",
+ "kostroma.ru",
+ "krasnoyarsk.ru",
+ "kuban.ru",
+ "kurgan.ru",
+ "kursk.ru",
+ "lipetsk.ru",
+ "magadan.ru",
+ "mari.ru",
+ "mari-el.ru",
+ "marine.ru",
+ "mordovia.ru",
+ "mosreg.ru",
+ "msk.ru",
+ "murmansk.ru",
+ "nalchik.ru",
+ "nnov.ru",
+ "nov.ru",
+ "novosibirsk.ru",
+ "nsk.ru",
+ "omsk.ru",
+ "orenburg.ru",
+ "oryol.ru",
+ "palana.ru",
+ "penza.ru",
+ "perm.ru",
+ "pskov.ru",
+ "ptz.ru",
+ "rnd.ru",
+ "ryazan.ru",
+ "sakhalin.ru",
+ "samara.ru",
+ "saratov.ru",
+ "simbirsk.ru",
+ "smolensk.ru",
+ "spb.ru",
+ "stavropol.ru",
+ "stv.ru",
+ "surgut.ru",
+ "tambov.ru",
+ "tatarstan.ru",
+ "tom.ru",
+ "tomsk.ru",
+ "tsaritsyn.ru",
+ "tsk.ru",
+ "tula.ru",
+ "tuva.ru",
+ "tver.ru",
+ "tyumen.ru",
+ "udm.ru",
+ "udmurtia.ru",
+ "ulan-ude.ru",
+ "vladikavkaz.ru",
+ "vladimir.ru",
+ "vladivostok.ru",
+ "volgograd.ru",
+ "vologda.ru",
+ "voronezh.ru",
+ "vrn.ru",
+ "vyatka.ru",
+ "yakutia.ru",
+ "yamal.ru",
+ "yaroslavl.ru",
+ "yekaterinburg.ru",
+ "yuzhno-sakhalinsk.ru",
+ "amursk.ru",
+ "baikal.ru",
+ "cmw.ru",
+ "fareast.ru",
+ "jamal.ru",
+ "kms.ru",
+ "k-uralsk.ru",
+ "kustanai.ru",
+ "kuzbass.ru",
+ "magnitka.ru",
+ "mytis.ru",
+ "nakhodka.ru",
+ "nkz.ru",
+ "norilsk.ru",
+ "oskol.ru",
+ "pyatigorsk.ru",
+ "rubtsovsk.ru",
+ "snz.ru",
+ "syzran.ru",
+ "vdonsk.ru",
+ "zgrad.ru",
+ "gov.ru",
+ "mil.ru",
+ "test.ru",
+ "rw",
+ "gov.rw",
+ "net.rw",
+ "edu.rw",
+ "ac.rw",
+ "com.rw",
+ "co.rw",
+ "int.rw",
+ "mil.rw",
+ "gouv.rw",
+ "sa",
+ "com.sa",
+ "net.sa",
+ "org.sa",
+ "gov.sa",
+ "med.sa",
+ "pub.sa",
+ "edu.sa",
+ "sch.sa",
+ "sb",
+ "com.sb",
+ "edu.sb",
+ "gov.sb",
+ "net.sb",
+ "org.sb",
+ "sc",
+ "com.sc",
+ "gov.sc",
+ "net.sc",
+ "org.sc",
+ "edu.sc",
+ "sd",
+ "com.sd",
+ "net.sd",
+ "org.sd",
+ "edu.sd",
+ "med.sd",
+ "tv.sd",
+ "gov.sd",
+ "info.sd",
+ "se",
+ "a.se",
+ "ac.se",
+ "b.se",
+ "bd.se",
+ "brand.se",
+ "c.se",
+ "d.se",
+ "e.se",
+ "f.se",
+ "fh.se",
+ "fhsk.se",
+ "fhv.se",
+ "g.se",
+ "h.se",
+ "i.se",
+ "k.se",
+ "komforb.se",
+ "kommunalforbund.se",
+ "komvux.se",
+ "l.se",
+ "lanbib.se",
+ "m.se",
+ "n.se",
+ "naturbruksgymn.se",
+ "o.se",
+ "org.se",
+ "p.se",
+ "parti.se",
+ "pp.se",
+ "press.se",
+ "r.se",
+ "s.se",
+ "sshn.se",
+ "t.se",
+ "tm.se",
+ "u.se",
+ "w.se",
+ "x.se",
+ "y.se",
+ "z.se",
+ "sg",
+ "com.sg",
+ "net.sg",
+ "org.sg",
+ "gov.sg",
+ "edu.sg",
+ "per.sg",
+ "sh",
+ "si",
+ "sk",
+ "sl",
+ "com.sl",
+ "net.sl",
+ "edu.sl",
+ "gov.sl",
+ "org.sl",
+ "sm",
+ "sn",
+ "art.sn",
+ "com.sn",
+ "edu.sn",
+ "gouv.sn",
+ "org.sn",
+ "perso.sn",
+ "univ.sn",
+ "so",
+ "com.so",
+ "net.so",
+ "org.so",
+ "sr",
+ "st",
+ "co.st",
+ "com.st",
+ "consulado.st",
+ "edu.st",
+ "embaixada.st",
+ "gov.st",
+ "mil.st",
+ "net.st",
+ "org.st",
+ "principe.st",
+ "saotome.st",
+ "store.st",
+ "su",
+ "sx",
+ "gov.sx",
+ "sy",
+ "edu.sy",
+ "gov.sy",
+ "net.sy",
+ "mil.sy",
+ "com.sy",
+ "org.sy",
+ "sz",
+ "co.sz",
+ "ac.sz",
+ "org.sz",
+ "tc",
+ "td",
+ "tel",
+ "tf",
+ "tg",
+ "th",
+ "ac.th",
+ "co.th",
+ "go.th",
+ "in.th",
+ "mi.th",
+ "net.th",
+ "or.th",
+ "tj",
+ "ac.tj",
+ "biz.tj",
+ "co.tj",
+ "com.tj",
+ "edu.tj",
+ "go.tj",
+ "gov.tj",
+ "int.tj",
+ "mil.tj",
+ "name.tj",
+ "net.tj",
+ "nic.tj",
+ "org.tj",
+ "test.tj",
+ "web.tj",
+ "tk",
+ "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",
+ "fin.tn",
+ "gov.tn",
+ "ind.tn",
+ "intl.tn",
+ "nat.tn",
+ "net.tn",
+ "org.tn",
+ "info.tn",
+ "perso.tn",
+ "tourism.tn",
+ "edunet.tn",
+ "rnrt.tn",
+ "rns.tn",
+ "rnu.tn",
+ "mincom.tn",
+ "agrinet.tn",
+ "defense.tn",
+ "turen.tn",
+ "to",
+ "com.to",
+ "gov.to",
+ "net.to",
+ "org.to",
+ "edu.to",
+ "mil.to",
+ "gov.nc.tr",
+ "travel",
+ "tt",
+ "co.tt",
+ "com.tt",
+ "org.tt",
+ "net.tt",
+ "biz.tt",
+ "info.tt",
+ "pro.tt",
+ "int.tt",
+ "coop.tt",
+ "jobs.tt",
+ "mobi.tt",
+ "travel.tt",
+ "museum.tt",
+ "aero.tt",
+ "name.tt",
+ "gov.tt",
+ "edu.tt",
+ "tv",
+ "tw",
+ "edu.tw",
+ "gov.tw",
+ "mil.tw",
+ "com.tw",
+ "net.tw",
+ "org.tw",
+ "idv.tw",
+ "game.tw",
+ "ebiz.tw",
+ "club.tw",
+ "\u7db2\u8def.tw",
+ "xn--zf0ao64a.tw",
+ "\u7d44\u7e54.tw",
+ "xn--uc0atv.tw",
+ "\u5546\u696d.tw",
+ "xn--czrw28b.tw",
+ "ac.tz",
+ "co.tz",
+ "go.tz",
+ "mil.tz",
+ "ne.tz",
+ "or.tz",
+ "sc.tz",
+ "ua",
+ "com.ua",
+ "edu.ua",
+ "gov.ua",
+ "in.ua",
+ "net.ua",
+ "org.ua",
+ "cherkassy.ua",
+ "chernigov.ua",
+ "chernovtsy.ua",
+ "ck.ua",
+ "cn.ua",
+ "crimea.ua",
+ "cv.ua",
+ "dn.ua",
+ "dnepropetrovsk.ua",
+ "donetsk.ua",
+ "dp.ua",
+ "if.ua",
+ "ivano-frankivsk.ua",
+ "kh.ua",
+ "kharkov.ua",
+ "kherson.ua",
+ "khmelnitskiy.ua",
+ "kiev.ua",
+ "kirovograd.ua",
+ "km.ua",
+ "kr.ua",
+ "ks.ua",
+ "kv.ua",
+ "lg.ua",
+ "lugansk.ua",
+ "lutsk.ua",
+ "lviv.ua",
+ "mk.ua",
+ "nikolaev.ua",
+ "od.ua",
+ "odessa.ua",
+ "pl.ua",
+ "poltava.ua",
+ "rovno.ua",
+ "rv.ua",
+ "sebastopol.ua",
+ "sumy.ua",
+ "te.ua",
+ "ternopil.ua",
+ "uzhgorod.ua",
+ "vinnica.ua",
+ "vn.ua",
+ "zaporizhzhe.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",
+ "us",
+ "dni.us",
+ "fed.us",
+ "isa.us",
+ "kids.us",
+ "nsn.us",
+ "ak.us",
+ "al.us",
+ "ar.us",
+ "as.us",
+ "az.us",
+ "ca.us",
+ "co.us",
+ "ct.us",
+ "dc.us",
+ "de.us",
+ "fl.us",
+ "ga.us",
+ "gu.us",
+ "hi.us",
+ "ia.us",
+ "id.us",
+ "il.us",
+ "in.us",
+ "ks.us",
+ "ky.us",
+ "la.us",
+ "ma.us",
+ "md.us",
+ "me.us",
+ "mi.us",
+ "mn.us",
+ "mo.us",
+ "ms.us",
+ "mt.us",
+ "nc.us",
+ "nd.us",
+ "ne.us",
+ "nh.us",
+ "nj.us",
+ "nm.us",
+ "nv.us",
+ "ny.us",
+ "oh.us",
+ "ok.us",
+ "or.us",
+ "pa.us",
+ "pr.us",
+ "ri.us",
+ "sc.us",
+ "sd.us",
+ "tn.us",
+ "tx.us",
+ "ut.us",
+ "vi.us",
+ "vt.us",
+ "va.us",
+ "wa.us",
+ "wi.us",
+ "wv.us",
+ "wy.us",
+ "k12.ak.us",
+ "k12.al.us",
+ "k12.ar.us",
+ "k12.as.us",
+ "k12.az.us",
+ "k12.ca.us",
+ "k12.co.us",
+ "k12.ct.us",
+ "k12.dc.us",
+ "k12.de.us",
+ "k12.fl.us",
+ "k12.ga.us",
+ "k12.gu.us",
+ "k12.ia.us",
+ "k12.id.us",
+ "k12.il.us",
+ "k12.in.us",
+ "k12.ks.us",
+ "k12.ky.us",
+ "k12.la.us",
+ "k12.ma.us",
+ "k12.md.us",
+ "k12.me.us",
+ "k12.mi.us",
+ "k12.mn.us",
+ "k12.mo.us",
+ "k12.ms.us",
+ "k12.mt.us",
+ "k12.nc.us",
+ "k12.nd.us",
+ "k12.ne.us",
+ "k12.nh.us",
+ "k12.nj.us",
+ "k12.nm.us",
+ "k12.nv.us",
+ "k12.ny.us",
+ "k12.oh.us",
+ "k12.ok.us",
+ "k12.or.us",
+ "k12.pa.us",
+ "k12.pr.us",
+ "k12.ri.us",
+ "k12.sc.us",
+ "k12.sd.us",
+ "k12.tn.us",
+ "k12.tx.us",
+ "k12.ut.us",
+ "k12.vi.us",
+ "k12.vt.us",
+ "k12.va.us",
+ "k12.wa.us",
+ "k12.wi.us",
+ "k12.wv.us",
+ "k12.wy.us",
+ "cc.ak.us",
+ "cc.al.us",
+ "cc.ar.us",
+ "cc.as.us",
+ "cc.az.us",
+ "cc.ca.us",
+ "cc.co.us",
+ "cc.ct.us",
+ "cc.dc.us",
+ "cc.de.us",
+ "cc.fl.us",
+ "cc.ga.us",
+ "cc.gu.us",
+ "cc.hi.us",
+ "cc.ia.us",
+ "cc.id.us",
+ "cc.il.us",
+ "cc.in.us",
+ "cc.ks.us",
+ "cc.ky.us",
+ "cc.la.us",
+ "cc.ma.us",
+ "cc.md.us",
+ "cc.me.us",
+ "cc.mi.us",
+ "cc.mn.us",
+ "cc.mo.us",
+ "cc.ms.us",
+ "cc.mt.us",
+ "cc.nc.us",
+ "cc.nd.us",
+ "cc.ne.us",
+ "cc.nh.us",
+ "cc.nj.us",
+ "cc.nm.us",
+ "cc.nv.us",
+ "cc.ny.us",
+ "cc.oh.us",
+ "cc.ok.us",
+ "cc.or.us",
+ "cc.pa.us",
+ "cc.pr.us",
+ "cc.ri.us",
+ "cc.sc.us",
+ "cc.sd.us",
+ "cc.tn.us",
+ "cc.tx.us",
+ "cc.ut.us",
+ "cc.vi.us",
+ "cc.vt.us",
+ "cc.va.us",
+ "cc.wa.us",
+ "cc.wi.us",
+ "cc.wv.us",
+ "cc.wy.us",
+ "lib.ak.us",
+ "lib.al.us",
+ "lib.ar.us",
+ "lib.as.us",
+ "lib.az.us",
+ "lib.ca.us",
+ "lib.co.us",
+ "lib.ct.us",
+ "lib.dc.us",
+ "lib.de.us",
+ "lib.fl.us",
+ "lib.ga.us",
+ "lib.gu.us",
+ "lib.hi.us",
+ "lib.ia.us",
+ "lib.id.us",
+ "lib.il.us",
+ "lib.in.us",
+ "lib.ks.us",
+ "lib.ky.us",
+ "lib.la.us",
+ "lib.ma.us",
+ "lib.md.us",
+ "lib.me.us",
+ "lib.mi.us",
+ "lib.mn.us",
+ "lib.mo.us",
+ "lib.ms.us",
+ "lib.mt.us",
+ "lib.nc.us",
+ "lib.nd.us",
+ "lib.ne.us",
+ "lib.nh.us",
+ "lib.nj.us",
+ "lib.nm.us",
+ "lib.nv.us",
+ "lib.ny.us",
+ "lib.oh.us",
+ "lib.ok.us",
+ "lib.or.us",
+ "lib.pa.us",
+ "lib.pr.us",
+ "lib.ri.us",
+ "lib.sc.us",
+ "lib.sd.us",
+ "lib.tn.us",
+ "lib.tx.us",
+ "lib.ut.us",
+ "lib.vi.us",
+ "lib.vt.us",
+ "lib.va.us",
+ "lib.wa.us",
+ "lib.wi.us",
+ "lib.wv.us",
+ "lib.wy.us",
+ "pvt.k12.ma.us",
+ "chtr.k12.ma.us",
+ "paroch.k12.ma.us",
+ "uz",
+ "co.uz",
+ "com.uz",
+ "net.uz",
+ "org.uz",
+ "va",
+ "vc",
+ "com.vc",
+ "net.vc",
+ "org.vc",
+ "gov.vc",
+ "mil.vc",
+ "edu.vc",
+ "vg",
+ "vi",
+ "co.vi",
+ "com.vi",
+ "k12.vi",
+ "net.vi",
+ "org.vi",
+ "vn",
+ "com.vn",
+ "net.vn",
+ "org.vn",
+ "edu.vn",
+ "gov.vn",
+ "int.vn",
+ "ac.vn",
+ "biz.vn",
+ "info.vn",
+ "name.vn",
+ "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",
+ "xn--54b7fta0cc",
+ "\u4e2d\u56fd",
+ "xn--fiqs8s",
+ "\u4e2d\u570b",
+ "xn--fiqz9s",
+ "\u0627\u0644\u062c\u0632\u0627\u0626\u0631",
+ "xn--lgbbat1ad8j",
+ "\u0645\u0635\u0631",
+ "xn--wgbh1c",
+ "\u10d2\u10d4",
+ "xn--node",
+ "\u9999\u6e2f",
+ "xn--j6w193g",
+ "\u092d\u093e\u0930\u0924",
+ "xn--h2brj9c",
+ "\u0628\u06be\u0627\u0631\u062a",
+ "xn--mgbbh1a71e",
+ "\u0c2d\u0c3e\u0c30\u0c24\u0c4d",
+ "xn--fpcrj9c3d",
+ "\u0aad\u0abe\u0ab0\u0aa4",
+ "xn--gecrj9c",
+ "\u0a2d\u0a3e\u0a30\u0a24",
+ "xn--s9brj9c",
+ "\u09ad\u09be\u09b0\u09a4",
+ "xn--45brj9c",
+ "\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe",
+ "xn--xkc2dl3a5ee0h",
+ "\u0627\u06cc\u0631\u0627\u0646",
+ "xn--mgba3a4f16a",
+ "\u0627\u064a\u0631\u0627\u0646",
+ "xn--mgba3a4fra",
+ "\u0627\u0644\u0627\u0631\u062f\u0646",
+ "xn--mgbayh7gpa",
+ "\ud55c\uad6d",
+ "xn--3e0b707e",
+ "\u0dbd\u0d82\u0d9a\u0dcf",
+ "xn--fzc2c9e2c",
+ "\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8",
+ "xn--xkc2al3hye2a",
+ "\u0627\u0644\u0645\u063a\u0631\u0628",
+ "xn--mgbc0a9azcg",
+ "\u0639\u0645\u0627\u0646",
+ "xn--mgb9awbf",
+ "\u0641\u0644\u0633\u0637\u064a\u0646",
+ "xn--ygbi2ammx",
+ "\u0441\u0440\u0431",
+ "xn--90a3ac",
+ "\u0440\u0444",
+ "xn--p1ai",
+ "\u0642\u0637\u0631",
+ "xn--wgbl6a",
+ "\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629",
+ "xn--mgberp4a5d4ar",
+ "\u0627\u0644\u0633\u0639\u0648\u062f\u06cc\u0629",
+ "xn--mgberp4a5d4a87g",
+ "\u0627\u0644\u0633\u0639\u0648\u062f\u06cc\u06c3",
+ "xn--mgbqly7c0a67fbc",
+ "\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0647",
+ "xn--mgbqly7cvafr",
+ "\u0633\u0648\u0631\u064a\u0629",
+ "xn--ogbpf8fl",
+ "\u0633\u0648\u0631\u064a\u0627",
+ "xn--mgbtf8fl",
+ "\u65b0\u52a0\u5761",
+ "xn--yfro4i67o",
+ "\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd",
+ "xn--clchc0ea0b2g2a9gcd",
+ "\u0e44\u0e17\u0e22",
+ "xn--o3cw4h",
+ "\u062a\u0648\u0646\u0633",
+ "xn--pgbs0dh",
+ "\u53f0\u7063",
+ "xn--kpry57d",
+ "\u53f0\u6e7e",
+ "xn--kprw13d",
+ "\u81fa\u7063",
+ "xn--nnx388a",
+ "\u0443\u043a\u0440",
+ "xn--j1amh",
+ "\u0627\u0644\u064a\u0645\u0646",
+ "xn--mgb2ddes",
+ "xxx",
+ "biz.at",
+ "info.at",
+ "priv.at",
+ "co.ca",
+ "ar.com",
+ "br.com",
+ "cn.com",
+ "de.com",
+ "eu.com",
+ "gb.com",
+ "gr.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",
+ "gb.net",
+ "jp.net",
+ "se.net",
+ "uk.net",
+ "ae.org",
+ "us.org",
+ "com.de",
+ "operaunite.com",
+ "appspot.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"
+ );
+
+ /**
+ * If a hostname is not in the EXCLUDE set, and if removing its
+ * leftmost component results in a name which is contained in this
+ * set, it is a TLD.
+ */
+ static final ImmutableSet<String> UNDER = ImmutableSet.of(
+ "ar",
+ "bd",
+ "bn",
+ "ck",
+ "cy",
+ "er",
+ "et",
+ "fj",
+ "fk",
+ "gt",
+ "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",
+ "kw",
+ "mm",
+ "mt",
+ "mz",
+ "ni",
+ "np",
+ "nz",
+ "om",
+ "pg",
+ "py",
+ "sv",
+ "tr",
+ "uk",
+ "sch.uk",
+ "uy",
+ "ve",
+ "ye",
+ "za",
+ "zm",
+ "zw"
+ );
+
+ /**
+ * 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(
+ "congresodelalengua3.ar",
+ "educ.ar",
+ "gobiernoelectronico.ar",
+ "mecon.ar",
+ "nacion.ar",
+ "nic.ar",
+ "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",
+ "nawras.om",
+ "omanmobile.om",
+ "omanpost.om",
+ "omantel.om",
+ "rakpetroleum.om",
+ "siemens.om",
+ "songfest.om",
+ "statecouncil.om",
+ "nic.tr",
+ "bl.uk",
+ "british-library.uk",
+ "icnet.uk",
+ "jet.uk",
+ "mod.uk",
+ "nel.uk",
+ "nhs.uk",
+ "nic.uk",
+ "nls.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
new file mode 100644
index 0000000..090a231
--- /dev/null
+++ b/guava/src/com/google/common/net/package-info.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains utility methods and classes for working with net
+ * addresses (numeric IP and domain names).
+ *
+ * <p>This package is a part of the open-source
+ * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
+ *
+ * @author Craig Berry
+ */
+@ParametersAreNonnullByDefault
+package com.google.common.net;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/guava/src/com/google/common/primitives/AndroidInteger.java b/guava/src/com/google/common/primitives/AndroidInteger.java
new file mode 100644
index 0000000..7fa8abd
--- /dev/null
+++ b/guava/src/com/google/common/primitives/AndroidInteger.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.checkNotNull;
+
+import javax.annotation.CheckForNull;
+
+/**
+ * Static utility methods derived from Android's {@code Integer.java}.
+ */
+final class AndroidInteger {
+ /**
+ * See {@link Ints#tryParse(String)} for the public interface.
+ */
+ @CheckForNull
+ static Integer tryParse(String string) {
+ return tryParse(string, 10);
+ }
+
+ /**
+ * See {@link Ints#tryParse(String, int)} for the public interface.
+ */
+ @CheckForNull
+ static Integer tryParse(String string, int radix) {
+ checkNotNull(string);
+ checkArgument(radix >= Character.MIN_RADIX,
+ "Invalid radix %s, min radix is %s", radix, Character.MIN_RADIX);
+ checkArgument(radix <= Character.MAX_RADIX,
+ "Invalid radix %s, max radix is %s", radix, Character.MAX_RADIX);
+ int length = string.length(), i = 0;
+ if (length == 0) {
+ return null;
+ }
+ boolean negative = string.charAt(i) == '-';
+ if (negative && ++i == length) {
+ return null;
+ }
+ return tryParse(string, i, radix, negative);
+ }
+
+ @CheckForNull
+ private static Integer tryParse(String string, int offset, int radix,
+ boolean negative) {
+ int max = Integer.MIN_VALUE / radix;
+ int result = 0, length = string.length();
+ while (offset < length) {
+ int digit = Character.digit(string.charAt(offset++), radix);
+ if (digit == -1) {
+ return null;
+ }
+ if (max > result) {
+ return null;
+ }
+ int next = result * radix - digit;
+ if (next > result) {
+ return null;
+ }
+ result = next;
+ }
+ if (!negative) {
+ result = -result;
+ if (result < 0) {
+ return null;
+ }
+ }
+ // For GWT where ints do not overflow
+ if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
+ return null;
+ }
+ return result;
+ }
+
+ private AndroidInteger() {}
+}
diff --git a/guava/src/com/google/common/primitives/Booleans.java b/guava/src/com/google/common/primitives/Booleans.java
new file mode 100644
index 0000000..3601a8a
--- /dev/null
+++ b/guava/src/com/google/common/primitives/Booleans.java
@@ -0,0 +1,471 @@
+/*
+ * 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 java.io.Serializable;
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.BitSet;
+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 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
+ */
+@GwtCompatible
+public final class Booleans {
+ private Booleans() {}
+
+ /**
+ * Returns a hash code for {@code value}; equal to the result of invoking
+ * {@code ((Boolean) value).hashCode()}.
+ *
+ * @param value a primitive {@code boolean} value
+ * @return a hash code for the value
+ */
+ public static int hashCode(boolean value) {
+ return value ? 1231 : 1237;
+ }
+
+ /**
+ * Compares the two specified {@code boolean} values in the standard way
+ * ({@code false} is considered less than {@code true}). The sign of the
+ * value returned is the same as that of {@code ((Boolean) a).compareTo(b)}.
+ *
+ * @param a the first {@code boolean} to compare
+ * @param b the second {@code boolean} to compare
+ * @return a positive number if only {@code a} is {@code true}, a negative
+ * number if only {@code b} is true, or zero if {@code a == b}
+ */
+ public static int compare(boolean a, boolean b) {
+ return (a == b) ? 0 : (a ? 1 : -1);
+ }
+
+ /**
+ * Returns {@code true} if {@code target} is present as an element anywhere in
+ * {@code array}.
+ *
+ * <p><b>Note:</b> consider representing the array as a {@link
+ * BitSet} instead, replacing {@code Booleans.contains(array, true)}
+ * with {@code !bitSet.isEmpty()} and {@code Booleans.contains(array, false)}
+ * with {@code bitSet.nextClearBit(0) == sizeOfBitSet}.
+ *
+ * @param array an array of {@code boolean} values, possibly empty
+ * @param target a primitive {@code boolean} value
+ * @return {@code true} if {@code array[i] == target} for some value of {@code
+ * i}
+ */
+ public static boolean contains(boolean[] array, boolean target) {
+ for (boolean value : array) {
+ if (value == target) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the index of the first appearance of the value {@code target} in
+ * {@code array}.
+ *
+ * <p><b>Note:</b> consider representing the array as a {@link BitSet}
+ * instead, and using {@link BitSet#nextSetBit(int)} or {@link
+ * BitSet#nextClearBit(int)}.
+ *
+ * @param array an array of {@code boolean} values, possibly empty
+ * @param target a primitive {@code boolean} 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(boolean[] array, boolean target) {
+ return indexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int indexOf(
+ boolean[] array, boolean 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(boolean[] array, boolean[] 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 boolean} values, possibly empty
+ * @param target a primitive {@code boolean} 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(boolean[] array, boolean target) {
+ return lastIndexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int lastIndexOf(
+ boolean[] array, boolean target, int start, int end) {
+ for (int i = end - 1; i >= start; i--) {
+ if (array[i] == target) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the values from each provided array combined into a single array.
+ * For example, {@code concat(new boolean[] {a, b}, new boolean[] {}, new
+ * boolean[] {c}} returns the array {@code {a, b, c}}.
+ *
+ * @param arrays zero or more {@code boolean} arrays
+ * @return a single array containing all the values from the source arrays, in
+ * order
+ */
+ public static boolean[] concat(boolean[]... arrays) {
+ int length = 0;
+ for (boolean[] array : arrays) {
+ length += array.length;
+ }
+ boolean[] result = new boolean[length];
+ int pos = 0;
+ for (boolean[] array : arrays) {
+ System.arraycopy(array, 0, result, pos, array.length);
+ pos += array.length;
+ }
+ return result;
+ }
+
+ /**
+ * 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 boolean[] ensureCapacity(
+ boolean[] 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 boolean[] copyOf(boolean[] original, int length) {
+ boolean[] copy = new boolean[length];
+ System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
+ return copy;
+ }
+
+ /**
+ * Returns a string containing the supplied {@code boolean} values separated
+ * by {@code separator}. For example, {@code join("-", false, true, false)}
+ * returns the string {@code "false-true-false"}.
+ *
+ * @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 boolean} values, possibly empty
+ */
+ public static String join(String separator, boolean... 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 * 7);
+ 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 boolean} arrays
+ * lexicographically. That is, it compares, using {@link
+ * #compare(boolean, boolean)}), 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 [] < [false] < [false, true] < [true]}.
+ *
+ * <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(boolean[], boolean[])}.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
+ * Lexicographical order article at Wikipedia</a>
+ * @since 2.0
+ */
+ public static Comparator<boolean[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ private enum LexicographicalComparator implements Comparator<boolean[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(boolean[] left, boolean[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = Booleans.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * Copies a collection of {@code Boolean} instances into a new array of
+ * primitive {@code boolean} 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.
+ *
+ * <p><b>Note:</b> consider representing the collection as a {@link
+ * BitSet} instead.
+ *
+ * @param collection a collection of {@code Boolean} 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 boolean[] toArray(Collection<Boolean> collection) {
+ if (collection instanceof BooleanArrayAsList) {
+ return ((BooleanArrayAsList) collection).toBooleanArray();
+ }
+
+ Object[] boxedArray = collection.toArray();
+ int len = boxedArray.length;
+ boolean[] array = new boolean[len];
+ for (int i = 0; i < len; i++) {
+ // checkNotNull for GWT (do not optimize)
+ array[i] = (Boolean) 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 Boolean} 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<Boolean> asList(boolean... backingArray) {
+ if (backingArray.length == 0) {
+ return Collections.emptyList();
+ }
+ return new BooleanArrayAsList(backingArray);
+ }
+
+ @GwtCompatible
+ private static class BooleanArrayAsList extends AbstractList<Boolean>
+ implements RandomAccess, Serializable {
+ final boolean[] array;
+ final int start;
+ final int end;
+
+ BooleanArrayAsList(boolean[] array) {
+ this(array, 0, array.length);
+ }
+
+ BooleanArrayAsList(boolean[] 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 Boolean 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 Boolean)
+ && Booleans.indexOf(array, (Boolean) target, start, end) != -1;
+ }
+
+ @Override public int indexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof Boolean) {
+ int i = Booleans.indexOf(array, (Boolean) 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 Boolean) {
+ int i = Booleans.lastIndexOf(array, (Boolean) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @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);
+ return oldValue;
+ }
+
+ @Override public List<Boolean> subList(int fromIndex, int toIndex) {
+ int size = size();
+ checkPositionIndexes(fromIndex, toIndex, size);
+ if (fromIndex == toIndex) {
+ return Collections.emptyList();
+ }
+ return new BooleanArrayAsList(array, start + fromIndex, start + toIndex);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof BooleanArrayAsList) {
+ BooleanArrayAsList that = (BooleanArrayAsList) 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 + Booleans.hashCode(array[i]);
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder(size() * 7);
+ builder.append(array[start] ? "[true" : "[false");
+ for (int i = start + 1; i < end; i++) {
+ builder.append(array[i] ? ", true" : ", false");
+ }
+ return builder.append(']').toString();
+ }
+
+ boolean[] toBooleanArray() {
+ // Arrays.copyOfRange() is not available under GWT
+ int size = size();
+ boolean[] result = new boolean[size];
+ System.arraycopy(array, start, result, 0, size);
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/guava/src/com/google/common/primitives/Bytes.java b/guava/src/com/google/common/primitives/Bytes.java
new file mode 100644
index 0000000..d9c5e1f
--- /dev/null
+++ b/guava/src/com/google/common/primitives/Bytes.java
@@ -0,0 +1,389 @@
+/*
+ * 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 java.io.Serializable;
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.RandomAccess;
+
+/**
+ * Static utility methods pertaining to {@code byte} primitives, that are not
+ * already found in either {@link Byte} or {@link Arrays}, <i>and interpret
+ * bytes as neither signed nor unsigned</i>. The methods which specifically
+ * 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
+ */
+// TODO(kevinb): how to prevent warning on UnsignedBytes when building GWT
+// javadoc?
+@GwtCompatible
+public final class Bytes {
+ private Bytes() {}
+
+ /**
+ * Returns a hash code for {@code value}; equal to the result of invoking
+ * {@code ((Byte) value).hashCode()}.
+ *
+ * @param value a primitive {@code byte} value
+ * @return a hash code for the value
+ */
+ public static int hashCode(byte value) {
+ return value;
+ }
+
+ /**
+ * Returns {@code true} if {@code target} is present as an element anywhere in
+ * {@code array}.
+ *
+ * @param array an array of {@code byte} values, possibly empty
+ * @param target a primitive {@code byte} value
+ * @return {@code true} if {@code array[i] == target} for some value of {@code
+ * i}
+ */
+ public static boolean contains(byte[] array, byte target) {
+ for (byte 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 byte} values, possibly empty
+ * @param target a primitive {@code byte} 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(byte[] array, byte target) {
+ return indexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int indexOf(
+ byte[] array, byte 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(byte[] array, byte[] 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 byte} values, possibly empty
+ * @param target a primitive {@code byte} 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(byte[] array, byte target) {
+ return lastIndexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int lastIndexOf(
+ byte[] array, byte target, int start, int end) {
+ for (int i = end - 1; i >= start; i--) {
+ if (array[i] == target) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the values from each provided array combined into a single array.
+ * For example, {@code concat(new byte[] {a, b}, new byte[] {}, new
+ * byte[] {c}} returns the array {@code {a, b, c}}.
+ *
+ * @param arrays zero or more {@code byte} arrays
+ * @return a single array containing all the values from the source arrays, in
+ * order
+ */
+ public static byte[] concat(byte[]... arrays) {
+ int length = 0;
+ for (byte[] array : arrays) {
+ length += array.length;
+ }
+ byte[] result = new byte[length];
+ int pos = 0;
+ for (byte[] array : arrays) {
+ System.arraycopy(array, 0, result, pos, array.length);
+ pos += array.length;
+ }
+ return result;
+ }
+
+ /**
+ * 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 byte[] ensureCapacity(
+ byte[] 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 byte[] copyOf(byte[] original, int length) {
+ byte[] copy = new byte[length];
+ System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
+ return copy;
+ }
+
+ /**
+ * Returns an array containing each value of {@code collection}, converted to
+ * a {@code byte} value in the manner of {@link Number#byteValue}.
+ *
+ * <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
+ * @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) {
+ if (collection instanceof ByteArrayAsList) {
+ return ((ByteArrayAsList) collection).toByteArray();
+ }
+
+ Object[] boxedArray = collection.toArray();
+ int len = boxedArray.length;
+ 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();
+ }
+ 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 Byte} 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<Byte> asList(byte... backingArray) {
+ if (backingArray.length == 0) {
+ return Collections.emptyList();
+ }
+ return new ByteArrayAsList(backingArray);
+ }
+
+ @GwtCompatible
+ private static class ByteArrayAsList extends AbstractList<Byte>
+ implements RandomAccess, Serializable {
+ final byte[] array;
+ final int start;
+ final int end;
+
+ ByteArrayAsList(byte[] array) {
+ this(array, 0, array.length);
+ }
+
+ ByteArrayAsList(byte[] 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 Byte 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 Byte)
+ && Bytes.indexOf(array, (Byte) target, start, end) != -1;
+ }
+
+ @Override public int indexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof Byte) {
+ int i = Bytes.indexOf(array, (Byte) 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 Byte) {
+ int i = Bytes.lastIndexOf(array, (Byte) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @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);
+ return oldValue;
+ }
+
+ @Override public List<Byte> subList(int fromIndex, int toIndex) {
+ int size = size();
+ checkPositionIndexes(fromIndex, toIndex, size);
+ if (fromIndex == toIndex) {
+ return Collections.emptyList();
+ }
+ return new ByteArrayAsList(array, start + fromIndex, start + toIndex);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof ByteArrayAsList) {
+ ByteArrayAsList that = (ByteArrayAsList) 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 + Bytes.hashCode(array[i]);
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder(size() * 5);
+ builder.append('[').append(array[start]);
+ for (int i = start + 1; i < end; i++) {
+ builder.append(", ").append(array[i]);
+ }
+ return builder.append(']').toString();
+ }
+
+ byte[] toByteArray() {
+ // Arrays.copyOfRange() is not available under GWT
+ int size = size();
+ byte[] result = new byte[size];
+ System.arraycopy(array, start, result, 0, size);
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/guava/src/com/google/common/primitives/Chars.java b/guava/src/com/google/common/primitives/Chars.java
new file mode 100644
index 0000000..241814a
--- /dev/null
+++ b/guava/src/com/google/common/primitives/Chars.java
@@ -0,0 +1,587 @@
+/*
+ * 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 char} primitives, that are not
+ * already found in either {@link Character} or {@link Arrays}.
+ *
+ * <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
+ */
+@GwtCompatible(emulated = true)
+public final class Chars {
+ private Chars() {}
+
+ /**
+ * The number of bytes required to represent a primitive {@code char}
+ * value.
+ */
+ public static final int BYTES = Character.SIZE / Byte.SIZE;
+
+ /**
+ * Returns a hash code for {@code value}; equal to the result of invoking
+ * {@code ((Character) value).hashCode()}.
+ *
+ * @param value a primitive {@code char} value
+ * @return a hash code for the value
+ */
+ public static int hashCode(char value) {
+ return value;
+ }
+
+ /**
+ * Returns the {@code char} value that is equal to {@code value}, if possible.
+ *
+ * @param value any value in the range of the {@code char} type
+ * @return the {@code char} value that equals {@code value}
+ * @throws IllegalArgumentException if {@code value} is greater than {@link
+ * Character#MAX_VALUE} or less than {@link Character#MIN_VALUE}
+ */
+ public static char checkedCast(long value) {
+ char result = (char) value;
+ checkArgument(result == value, "Out of range: %s", value);
+ return result;
+ }
+
+ /**
+ * Returns the {@code char} nearest in value to {@code value}.
+ *
+ * @param value any {@code long} value
+ * @return the same value cast to {@code char} if it is in the range of the
+ * {@code char} type, {@link Character#MAX_VALUE} if it is too large,
+ * or {@link Character#MIN_VALUE} if it is too small
+ */
+ public static char saturatedCast(long value) {
+ if (value > Character.MAX_VALUE) {
+ return Character.MAX_VALUE;
+ }
+ if (value < Character.MIN_VALUE) {
+ return Character.MIN_VALUE;
+ }
+ return (char) value;
+ }
+
+ /**
+ * Compares the two specified {@code char} values. The sign of the value
+ * returned is the same as that of {@code ((Character) a).compareTo(b)}.
+ *
+ * @param a the first {@code char} to compare
+ * @param b the second {@code char} 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(char a, char b) {
+ return a - b; // safe due to restricted range
+ }
+
+ /**
+ * Returns {@code true} if {@code target} is present as an element anywhere in
+ * {@code array}.
+ *
+ * @param array an array of {@code char} values, possibly empty
+ * @param target a primitive {@code char} value
+ * @return {@code true} if {@code array[i] == target} for some value of {@code
+ * i}
+ */
+ public static boolean contains(char[] array, char target) {
+ for (char 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 char} values, possibly empty
+ * @param target a primitive {@code char} 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(char[] array, char target) {
+ return indexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int indexOf(
+ char[] array, char 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(char[] array, char[] 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 char} values, possibly empty
+ * @param target a primitive {@code char} 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(char[] array, char target) {
+ return lastIndexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int lastIndexOf(
+ char[] array, char 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 char} 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 char min(char... array) {
+ checkArgument(array.length > 0);
+ char 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 char} 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 char max(char... array) {
+ checkArgument(array.length > 0);
+ char 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 char[] {a, b}, new char[] {}, new
+ * char[] {c}} returns the array {@code {a, b, c}}.
+ *
+ * @param arrays zero or more {@code char} arrays
+ * @return a single array containing all the values from the source arrays, in
+ * order
+ */
+ public static char[] concat(char[]... arrays) {
+ int length = 0;
+ for (char[] array : arrays) {
+ length += array.length;
+ }
+ char[] result = new char[length];
+ int pos = 0;
+ for (char[] 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 2-element byte
+ * array; equivalent to {@code
+ * ByteBuffer.allocate(2).putChar(value).array()}. For example, the input
+ * value {@code '\\u5432'} would yield the byte array {@code {0x54, 0x32}}.
+ *
+ * <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(char value) {
+ return new byte[] {
+ (byte) (value >> 8),
+ (byte) value};
+ }
+
+ /**
+ * Returns the {@code char} value whose big-endian representation is
+ * stored in the first 2 bytes of {@code bytes}; equivalent to {@code
+ * ByteBuffer.wrap(bytes).getChar()}. For example, the input byte array
+ * {@code {0x54, 0x32}} would yield the {@code char} value {@code '\\u5432'}.
+ *
+ * <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 2
+ * elements
+ */
+ @GwtIncompatible("doesn't work")
+ public static char fromByteArray(byte[] bytes) {
+ checkArgument(bytes.length >= BYTES,
+ "array too small: %s < %s", bytes.length, BYTES);
+ return fromBytes(bytes[0], bytes[1]);
+ }
+
+ /**
+ * Returns the {@code char} value whose byte representation is the given 2
+ * bytes, in big-endian order; equivalent to {@code Chars.fromByteArray(new
+ * byte[] {b1, b2})}.
+ *
+ * @since 7.0
+ */
+ @GwtIncompatible("doesn't work")
+ public static char fromBytes(byte b1, byte b2) {
+ return (char) ((b1 << 8) | (b2 & 0xFF));
+ }
+
+ /**
+ * 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 char[] ensureCapacity(
+ char[] 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 char[] copyOf(char[] original, int length) {
+ char[] copy = new char[length];
+ System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
+ return copy;
+ }
+
+ /**
+ * Returns a string containing the supplied {@code char} 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 char} values, possibly empty
+ */
+ public static String join(String separator, char... array) {
+ checkNotNull(separator);
+ int len = array.length;
+ if (len == 0) {
+ return "";
+ }
+
+ StringBuilder builder
+ = new StringBuilder(len + separator.length() * (len - 1));
+ builder.append(array[0]);
+ for (int i = 1; i < len; i++) {
+ builder.append(separator).append(array[i]);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns a comparator that compares two {@code char} arrays
+ * lexicographically. That is, it compares, using {@link
+ * #compare(char, char)}), 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 [] < ['a'] < ['a', 'b'] < ['b']}.
+ *
+ * <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(char[], char[])}.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
+ * Lexicographical order article at Wikipedia</a>
+ * @since 2.0
+ */
+ public static Comparator<char[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ private enum LexicographicalComparator implements Comparator<char[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(char[] left, char[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = Chars.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * Copies a collection of {@code Character} instances into a new array of
+ * primitive {@code char} 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 Character} 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 char[] toArray(Collection<Character> collection) {
+ if (collection instanceof CharArrayAsList) {
+ return ((CharArrayAsList) collection).toCharArray();
+ }
+
+ Object[] boxedArray = collection.toArray();
+ int len = boxedArray.length;
+ char[] array = new char[len];
+ for (int i = 0; i < len; i++) {
+ // checkNotNull for GWT (do not optimize)
+ array[i] = (Character) 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 Character} 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<Character> asList(char... backingArray) {
+ if (backingArray.length == 0) {
+ return Collections.emptyList();
+ }
+ return new CharArrayAsList(backingArray);
+ }
+
+ @GwtCompatible
+ private static class CharArrayAsList extends AbstractList<Character>
+ implements RandomAccess, Serializable {
+ final char[] array;
+ final int start;
+ final int end;
+
+ CharArrayAsList(char[] array) {
+ this(array, 0, array.length);
+ }
+
+ CharArrayAsList(char[] 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 Character 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 Character)
+ && Chars.indexOf(array, (Character) target, start, end) != -1;
+ }
+
+ @Override public int indexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof Character) {
+ int i = Chars.indexOf(array, (Character) 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 Character) {
+ int i = Chars.lastIndexOf(array, (Character) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @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);
+ return oldValue;
+ }
+
+ @Override public List<Character> subList(int fromIndex, int toIndex) {
+ int size = size();
+ checkPositionIndexes(fromIndex, toIndex, size);
+ if (fromIndex == toIndex) {
+ return Collections.emptyList();
+ }
+ return new CharArrayAsList(array, start + fromIndex, start + toIndex);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof CharArrayAsList) {
+ CharArrayAsList that = (CharArrayAsList) 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 + Chars.hashCode(array[i]);
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder(size() * 3);
+ builder.append('[').append(array[start]);
+ for (int i = start + 1; i < end; i++) {
+ builder.append(", ").append(array[i]);
+ }
+ return builder.append(']').toString();
+ }
+
+ char[] toCharArray() {
+ // Arrays.copyOfRange() is not available under GWT
+ int size = size();
+ char[] result = new char[size];
+ System.arraycopy(array, start, result, 0, size);
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/guava/src/com/google/common/primitives/Doubles.java b/guava/src/com/google/common/primitives/Doubles.java
new file mode 100644
index 0000000..f108357
--- /dev/null
+++ b/guava/src/com/google/common/primitives/Doubles.java
@@ -0,0 +1,534 @@
+/*
+ * 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 static java.lang.Double.NEGATIVE_INFINITY;
+import static java.lang.Double.POSITIVE_INFINITY;
+
+import com.google.common.annotations.GwtCompatible;
+
+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 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
+public final class Doubles {
+ private Doubles() {}
+
+ /**
+ * The number of bytes required to represent a primitive {@code double}
+ * value.
+ *
+ * @since 10.0
+ */
+ public static final int BYTES = Double.SIZE / Byte.SIZE;
+
+ /**
+ * Returns a hash code for {@code value}; equal to the result of invoking
+ * {@code ((Double) value).hashCode()}.
+ *
+ * @param value a primitive {@code double} value
+ * @return a hash code for the value
+ */
+ public static int hashCode(double value) {
+ return ((Double) value).hashCode();
+ // TODO(kevinb): do it this way when we can (GWT problem):
+ // long bits = Double.doubleToLongBits(value);
+ // return (int)(bits ^ (bits >>> 32));
+ }
+
+ /**
+ * Compares the two specified {@code double} values. The sign of the value
+ * returned is the same as that of <code>((Double) a).{@linkplain
+ * Double#compareTo compareTo}(b)</code>. As with that method, {@code NaN} is
+ * treated as greater than all other values, and {@code 0.0 > -0.0}.
+ *
+ * @param a the first {@code double} to compare
+ * @param b the second {@code double} 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(double a, double b) {
+ return Double.compare(a, b);
+ }
+
+ /**
+ * Returns {@code true} if {@code value} represents a real number. This is
+ * equivalent to, but not necessarily implemented as,
+ * {@code !(Double.isInfinite(value) || Double.isNaN(value))}.
+ *
+ * @since 10.0
+ */
+ public static boolean isFinite(double value) {
+ return NEGATIVE_INFINITY < value & value < POSITIVE_INFINITY;
+ }
+
+ /**
+ * Returns {@code true} if {@code target} is present as an element anywhere in
+ * {@code array}. Note that this always returns {@code false} when {@code
+ * target} is {@code NaN}.
+ *
+ * @param array an array of {@code double} values, possibly empty
+ * @param target a primitive {@code double} value
+ * @return {@code true} if {@code array[i] == target} for some value of {@code
+ * i}
+ */
+ public static boolean contains(double[] array, double target) {
+ for (double value : array) {
+ if (value == target) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the index of the first appearance of the value {@code target} in
+ * {@code array}. Note that this always returns {@code -1} when {@code target}
+ * is {@code NaN}.
+ *
+ * @param array an array of {@code double} values, possibly empty
+ * @param target a primitive {@code double} 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(double[] array, double target) {
+ return indexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int indexOf(
+ double[] array, double 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}.
+ *
+ * <p>Note that this always returns {@code -1} when {@code target} contains
+ * {@code NaN}.
+ *
+ * @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(double[] array, double[] 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}. Note that this always returns {@code -1} when {@code target}
+ * is {@code NaN}.
+ *
+ * @param array an array of {@code double} values, possibly empty
+ * @param target a primitive {@code double} 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(double[] array, double target) {
+ return lastIndexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int lastIndexOf(
+ double[] array, double 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}, using the same rules of
+ * comparison as {@link Math#min(double, double)}.
+ *
+ * @param array a <i>nonempty</i> array of {@code double} 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 double min(double... array) {
+ checkArgument(array.length > 0);
+ double min = array[0];
+ for (int i = 1; i < array.length; i++) {
+ min = Math.min(min, array[i]);
+ }
+ return min;
+ }
+
+ /**
+ * Returns the greatest value present in {@code array}, using the same rules
+ * of comparison as {@link Math#max(double, double)}.
+ *
+ * @param array a <i>nonempty</i> array of {@code double} 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 double max(double... array) {
+ checkArgument(array.length > 0);
+ double max = array[0];
+ for (int i = 1; i < array.length; i++) {
+ max = Math.max(max, array[i]);
+ }
+ return max;
+ }
+
+ /**
+ * Returns the values from each provided array combined into a single array.
+ * For example, {@code concat(new double[] {a, b}, new double[] {}, new
+ * double[] {c}} returns the array {@code {a, b, c}}.
+ *
+ * @param arrays zero or more {@code double} arrays
+ * @return a single array containing all the values from the source arrays, in
+ * order
+ */
+ public static double[] concat(double[]... arrays) {
+ int length = 0;
+ for (double[] array : arrays) {
+ length += array.length;
+ }
+ double[] result = new double[length];
+ int pos = 0;
+ for (double[] array : arrays) {
+ System.arraycopy(array, 0, result, pos, array.length);
+ pos += array.length;
+ }
+ return result;
+ }
+
+ /**
+ * 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 double[] ensureCapacity(
+ double[] 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 double[] copyOf(double[] original, int length) {
+ double[] copy = new double[length];
+ System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
+ return copy;
+ }
+
+ /**
+ * Returns a string containing the supplied {@code double} values, converted
+ * to strings as specified by {@link Double#toString(double)}, and separated
+ * by {@code separator}. For example, {@code join("-", 1.0, 2.0, 3.0)} returns
+ * 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"}.
+ *
+ * @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 double} values, possibly empty
+ */
+ public static String join(String separator, double... 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 * 12);
+ 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 double} arrays
+ * lexicographically. That is, it compares, using {@link
+ * #compare(double, double)}), 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.0] < [1.0, 2.0] < [2.0]}.
+ *
+ * <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(double[], double[])}.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
+ * Lexicographical order article at Wikipedia</a>
+ * @since 2.0
+ */
+ public static Comparator<double[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ private enum LexicographicalComparator implements Comparator<double[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(double[] left, double[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = Doubles.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * Returns an array containing each value of {@code collection}, converted to
+ * a {@code double} value in the manner of {@link Number#doubleValue}.
+ *
+ * <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
+ * @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) {
+ if (collection instanceof DoubleArrayAsList) {
+ return ((DoubleArrayAsList) collection).toDoubleArray();
+ }
+
+ Object[] boxedArray = collection.toArray();
+ int len = boxedArray.length;
+ 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();
+ }
+ 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 Double} 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.
+ *
+ * <p>The returned list may have unexpected behavior if it contains {@code
+ * NaN}, or if {@code NaN} is used as a parameter to any of its methods.
+ *
+ * @param backingArray the array to back the list
+ * @return a list view of the array
+ */
+ public static List<Double> asList(double... backingArray) {
+ if (backingArray.length == 0) {
+ return Collections.emptyList();
+ }
+ return new DoubleArrayAsList(backingArray);
+ }
+
+ @GwtCompatible
+ private static class DoubleArrayAsList extends AbstractList<Double>
+ implements RandomAccess, Serializable {
+ final double[] array;
+ final int start;
+ final int end;
+
+ DoubleArrayAsList(double[] array) {
+ this(array, 0, array.length);
+ }
+
+ DoubleArrayAsList(double[] 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 Double 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 Double)
+ && Doubles.indexOf(array, (Double) target, start, end) != -1;
+ }
+
+ @Override public int indexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof Double) {
+ int i = Doubles.indexOf(array, (Double) 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 Double) {
+ int i = Doubles.lastIndexOf(array, (Double) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @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);
+ return oldValue;
+ }
+
+ @Override public List<Double> subList(int fromIndex, int toIndex) {
+ int size = size();
+ checkPositionIndexes(fromIndex, toIndex, size);
+ if (fromIndex == toIndex) {
+ return Collections.emptyList();
+ }
+ return new DoubleArrayAsList(array, start + fromIndex, start + toIndex);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof DoubleArrayAsList) {
+ DoubleArrayAsList that = (DoubleArrayAsList) 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 + Doubles.hashCode(array[i]);
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder(size() * 12);
+ builder.append('[').append(array[start]);
+ for (int i = start + 1; i < end; i++) {
+ builder.append(", ").append(array[i]);
+ }
+ return builder.append(']').toString();
+ }
+
+ double[] toDoubleArray() {
+ // Arrays.copyOfRange() is not available under GWT
+ int size = size();
+ double[] result = new double[size];
+ System.arraycopy(array, start, result, 0, size);
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/guava/src/com/google/common/primitives/Floats.java b/guava/src/com/google/common/primitives/Floats.java
new file mode 100644
index 0000000..6d6cec4
--- /dev/null
+++ b/guava/src/com/google/common/primitives/Floats.java
@@ -0,0 +1,531 @@
+/*
+ * 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 static java.lang.Float.NEGATIVE_INFINITY;
+import static java.lang.Float.POSITIVE_INFINITY;
+
+import com.google.common.annotations.GwtCompatible;
+
+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 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
+public final class Floats {
+ private Floats() {}
+
+ /**
+ * The number of bytes required to represent a primitive {@code float}
+ * value.
+ *
+ * @since 10.0
+ */
+ public static final int BYTES = Float.SIZE / Byte.SIZE;
+
+ /**
+ * Returns a hash code for {@code value}; equal to the result of invoking
+ * {@code ((Float) value).hashCode()}.
+ *
+ * @param value a primitive {@code float} value
+ * @return a hash code for the value
+ */
+ public static int hashCode(float value) {
+ // TODO(kevinb): is there a better way, that's still gwt-safe?
+ return ((Float) value).hashCode();
+ }
+
+ /**
+ * Compares the two specified {@code float} values using {@link
+ * Float#compare(float, float)}. You may prefer to invoke that method
+ * directly; this method exists only for consistency with the other utilities
+ * in this package.
+ *
+ * @param a the first {@code float} to compare
+ * @param b the second {@code float} to compare
+ * @return the result of invoking {@link Float#compare(float, float)}
+ */
+ public static int compare(float a, float b) {
+ return Float.compare(a, b);
+ }
+
+ /**
+ * Returns {@code true} if {@code value} represents a real number. This is
+ * equivalent to, but not necessarily implemented as,
+ * {@code !(Float.isInfinite(value) || Float.isNaN(value))}.
+ *
+ * @since 10.0
+ */
+ public static boolean isFinite(float value) {
+ return NEGATIVE_INFINITY < value & value < POSITIVE_INFINITY;
+ }
+
+ /**
+ * Returns {@code true} if {@code target} is present as an element anywhere in
+ * {@code array}. Note that this always returns {@code false} when {@code
+ * target} is {@code NaN}.
+ *
+ * @param array an array of {@code float} values, possibly empty
+ * @param target a primitive {@code float} value
+ * @return {@code true} if {@code array[i] == target} for some value of {@code
+ * i}
+ */
+ public static boolean contains(float[] array, float target) {
+ for (float value : array) {
+ if (value == target) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the index of the first appearance of the value {@code target} in
+ * {@code array}. Note that this always returns {@code -1} when {@code target}
+ * is {@code NaN}.
+ *
+ * @param array an array of {@code float} values, possibly empty
+ * @param target a primitive {@code float} 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(float[] array, float target) {
+ return indexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int indexOf(
+ float[] array, float 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}.
+ *
+ * <p>Note that this always returns {@code -1} when {@code target} contains
+ * {@code NaN}.
+ *
+ * @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(float[] array, float[] 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}. Note that this always returns {@code -1} when {@code target}
+ * is {@code NaN}.
+ *
+ * @param array an array of {@code float} values, possibly empty
+ * @param target a primitive {@code float} 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(float[] array, float target) {
+ return lastIndexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int lastIndexOf(
+ float[] array, float 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}, using the same rules of
+ * comparison as {@link Math#min(float, float)}.
+ *
+ * @param array a <i>nonempty</i> array of {@code float} 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 float min(float... array) {
+ checkArgument(array.length > 0);
+ float min = array[0];
+ for (int i = 1; i < array.length; i++) {
+ min = Math.min(min, array[i]);
+ }
+ return min;
+ }
+
+ /**
+ * Returns the greatest value present in {@code array}, using the same rules
+ * of comparison as {@link Math#min(float, float)}.
+ *
+ * @param array a <i>nonempty</i> array of {@code float} 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 float max(float... array) {
+ checkArgument(array.length > 0);
+ float max = array[0];
+ for (int i = 1; i < array.length; i++) {
+ max = Math.max(max, array[i]);
+ }
+ return max;
+ }
+
+ /**
+ * Returns the values from each provided array combined into a single array.
+ * For example, {@code concat(new float[] {a, b}, new float[] {}, new
+ * float[] {c}} returns the array {@code {a, b, c}}.
+ *
+ * @param arrays zero or more {@code float} arrays
+ * @return a single array containing all the values from the source arrays, in
+ * order
+ */
+ public static float[] concat(float[]... arrays) {
+ int length = 0;
+ for (float[] array : arrays) {
+ length += array.length;
+ }
+ float[] result = new float[length];
+ int pos = 0;
+ for (float[] array : arrays) {
+ System.arraycopy(array, 0, result, pos, array.length);
+ pos += array.length;
+ }
+ return result;
+ }
+
+ /**
+ * 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 float[] ensureCapacity(
+ float[] 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 float[] copyOf(float[] original, int length) {
+ float[] copy = new float[length];
+ System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
+ return copy;
+ }
+
+ /**
+ * Returns a string containing the supplied {@code float} values, converted
+ * to strings as specified by {@link Float#toString(float)}, and separated by
+ * {@code separator}. For example, {@code join("-", 1.0f, 2.0f, 3.0f)}
+ * returns the string {@code "1.0-2.0-3.0"}.
+ *
+ * <p>Note that {@link Float#toString(float)} formats {@code float}
+ * differently in GWT. 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)
+ * @param array an array of {@code float} values, possibly empty
+ */
+ public static String join(String separator, float... 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 * 12);
+ 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 float} arrays
+ * lexicographically. That is, it compares, using {@link
+ * #compare(float, float)}), 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.0f] < [1.0f, 2.0f]
+ * < [2.0f]}.
+ *
+ * <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(float[], float[])}.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
+ * Lexicographical order article at Wikipedia</a>
+ * @since 2.0
+ */
+ public static Comparator<float[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ private enum LexicographicalComparator implements Comparator<float[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(float[] left, float[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = Floats.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * Returns an array containing each value of {@code collection}, converted to
+ * a {@code float} value in the manner of {@link Number#floatValue}.
+ *
+ * <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
+ * @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) {
+ if (collection instanceof FloatArrayAsList) {
+ return ((FloatArrayAsList) collection).toFloatArray();
+ }
+
+ Object[] boxedArray = collection.toArray();
+ int len = boxedArray.length;
+ 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();
+ }
+ 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 Float} 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.
+ *
+ * <p>The returned list may have unexpected behavior if it contains {@code
+ * NaN}, or if {@code NaN} is used as a parameter to any of its methods.
+ *
+ * @param backingArray the array to back the list
+ * @return a list view of the array
+ */
+ public static List<Float> asList(float... backingArray) {
+ if (backingArray.length == 0) {
+ return Collections.emptyList();
+ }
+ return new FloatArrayAsList(backingArray);
+ }
+
+ @GwtCompatible
+ private static class FloatArrayAsList extends AbstractList<Float>
+ implements RandomAccess, Serializable {
+ final float[] array;
+ final int start;
+ final int end;
+
+ FloatArrayAsList(float[] array) {
+ this(array, 0, array.length);
+ }
+
+ FloatArrayAsList(float[] 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 Float 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 Float)
+ && Floats.indexOf(array, (Float) target, start, end) != -1;
+ }
+
+ @Override public int indexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof Float) {
+ int i = Floats.indexOf(array, (Float) 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 Float) {
+ int i = Floats.lastIndexOf(array, (Float) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @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);
+ return oldValue;
+ }
+
+ @Override public List<Float> subList(int fromIndex, int toIndex) {
+ int size = size();
+ checkPositionIndexes(fromIndex, toIndex, size);
+ if (fromIndex == toIndex) {
+ return Collections.emptyList();
+ }
+ return new FloatArrayAsList(array, start + fromIndex, start + toIndex);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof FloatArrayAsList) {
+ FloatArrayAsList that = (FloatArrayAsList) 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 + Floats.hashCode(array[i]);
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder(size() * 12);
+ builder.append('[').append(array[start]);
+ for (int i = start + 1; i < end; i++) {
+ builder.append(", ").append(array[i]);
+ }
+ return builder.append(']').toString();
+ }
+
+ float[] toFloatArray() {
+ // Arrays.copyOfRange() is not available under GWT
+ int size = size();
+ float[] result = new float[size];
+ System.arraycopy(array, start, result, 0, size);
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/guava/src/com/google/common/primitives/Ints.java b/guava/src/com/google/common/primitives/Ints.java
new file mode 100644
index 0000000..966066d
--- /dev/null
+++ b/guava/src/com/google/common/primitives/Ints.java
@@ -0,0 +1,620 @@
+/*
+ * 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.Beta;
+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;
+
+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
+ */
+@GwtCompatible(emulated = true)
+public final class Ints {
+ private Ints() {}
+
+ /**
+ * The number of bytes required to represent a primitive {@code int}
+ * value.
+ */
+ public static final int BYTES = Integer.SIZE / Byte.SIZE;
+
+ /**
+ * The largest power of two that can be represented as an {@code int}.
+ *
+ * @since 10.0
+ */
+ public static final int MAX_POWER_OF_TWO = 1 << (Integer.SIZE - 2);
+
+ /**
+ * Returns a hash code for {@code value}; equal to the result of invoking
+ * {@code ((Integer) value).hashCode()}.
+ *
+ * @param value a primitive {@code int} value
+ * @return a hash code for the value
+ */
+ public static int hashCode(int value) {
+ return value;
+ }
+
+ /**
+ * Returns the {@code int} value that is equal to {@code value}, if possible.
+ *
+ * @param value any value in the range of the {@code int} type
+ * @return the {@code int} value that equals {@code value}
+ * @throws IllegalArgumentException if {@code value} is greater than {@link
+ * Integer#MAX_VALUE} or less than {@link Integer#MIN_VALUE}
+ */
+ public static int checkedCast(long value) {
+ int result = (int) value;
+ checkArgument(result == value, "Out of range: %s", value);
+ return result;
+ }
+
+ /**
+ * Returns the {@code int} nearest in value to {@code value}.
+ *
+ * @param value any {@code long} value
+ * @return the same value cast to {@code int} if it is in the range of the
+ * {@code int} type, {@link Integer#MAX_VALUE} if it is too large,
+ * or {@link Integer#MIN_VALUE} if it is too small
+ */
+ public static int saturatedCast(long value) {
+ if (value > Integer.MAX_VALUE) {
+ return Integer.MAX_VALUE;
+ }
+ if (value < Integer.MIN_VALUE) {
+ return Integer.MIN_VALUE;
+ }
+ return (int) value;
+ }
+
+ /**
+ * Compares the two specified {@code int} values. The sign of the value
+ * returned is the same as that of {@code ((Integer) a).compareTo(b)}.
+ *
+ * @param a the first {@code int} to compare
+ * @param b the second {@code int} 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(int a, int 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 int} values, possibly empty
+ * @param target a primitive {@code int} value
+ * @return {@code true} if {@code array[i] == target} for some value of {@code
+ * i}
+ */
+ public static boolean contains(int[] array, int target) {
+ for (int 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 int} values, possibly empty
+ * @param target a primitive {@code int} 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(int[] array, int target) {
+ return indexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int indexOf(
+ int[] array, int 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(int[] array, int[] 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 int} values, possibly empty
+ * @param target a primitive {@code int} 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(int[] array, int target) {
+ return lastIndexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int lastIndexOf(
+ int[] array, int 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 int} 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 int min(int... array) {
+ checkArgument(array.length > 0);
+ int 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 int} 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 int max(int... array) {
+ checkArgument(array.length > 0);
+ int 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 int[] {a, b}, new int[] {}, new
+ * int[] {c}} returns the array {@code {a, b, c}}.
+ *
+ * @param arrays zero or more {@code int} arrays
+ * @return a single array containing all the values from the source arrays, in
+ * order
+ */
+ public static int[] concat(int[]... arrays) {
+ int length = 0;
+ for (int[] array : arrays) {
+ length += array.length;
+ }
+ int[] result = new int[length];
+ int pos = 0;
+ for (int[] 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 4-element byte
+ * array; equivalent to {@code ByteBuffer.allocate(4).putInt(value).array()}.
+ * For example, the input value {@code 0x12131415} would yield the byte array
+ * {@code {0x12, 0x13, 0x14, 0x15}}.
+ *
+ * <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(int value) {
+ return new byte[] {
+ (byte) (value >> 24),
+ (byte) (value >> 16),
+ (byte) (value >> 8),
+ (byte) value};
+ }
+
+ /**
+ * Returns the {@code int} value whose big-endian representation is stored in
+ * the first 4 bytes of {@code bytes}; equivalent to {@code
+ * ByteBuffer.wrap(bytes).getInt()}. For example, the input byte array {@code
+ * {0x12, 0x13, 0x14, 0x15, 0x33}} would yield the {@code int} value {@code
+ * 0x12131415}.
+ *
+ * <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 4 elements
+ */
+ @GwtIncompatible("doesn't work")
+ public static int 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 int} value whose byte representation is the given 4
+ * bytes, in big-endian order; equivalent to {@code Ints.fromByteArray(new
+ * byte[] {b1, b2, b3, b4})}.
+ *
+ * @since 7.0
+ */
+ @GwtIncompatible("doesn't work")
+ public static int fromBytes(byte b1, byte b2, byte b3, byte b4) {
+ return b1 << 24 | (b2 & 0xFF) << 16 | (b3 & 0xFF) << 8 | (b4 & 0xFF);
+ }
+
+ /**
+ * 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 int[] ensureCapacity(
+ int[] 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 int[] copyOf(int[] original, int length) {
+ int[] copy = new int[length];
+ System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
+ return copy;
+ }
+
+ /**
+ * Returns a string containing the supplied {@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 {@code int} values, possibly empty
+ */
+ public static String join(String separator, int... 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 * 5);
+ 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 int} arrays
+ * lexicographically. 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]}.
+ *
+ * <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>
+ * @since 2.0
+ */
+ public static Comparator<int[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ private enum LexicographicalComparator implements Comparator<int[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(int[] left, int[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = Ints.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * Returns an array containing each value of {@code collection}, converted to
+ * a {@code int} value in the manner of {@link Number#intValue}.
+ *
+ * <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
+ * @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) {
+ if (collection instanceof IntArrayAsList) {
+ return ((IntArrayAsList) collection).toIntArray();
+ }
+
+ Object[] boxedArray = collection.toArray();
+ int len = boxedArray.length;
+ 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();
+ }
+ 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 Integer} 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<Integer> asList(int... backingArray) {
+ if (backingArray.length == 0) {
+ return Collections.emptyList();
+ }
+ return new IntArrayAsList(backingArray);
+ }
+
+ @GwtCompatible
+ private static class IntArrayAsList extends AbstractList<Integer>
+ implements RandomAccess, Serializable {
+ final int[] array;
+ final int start;
+ final int end;
+
+ IntArrayAsList(int[] array) {
+ this(array, 0, array.length);
+ }
+
+ IntArrayAsList(int[] 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 Integer 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 Integer)
+ && Ints.indexOf(array, (Integer) target, start, end) != -1;
+ }
+
+ @Override public int indexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof Integer) {
+ int i = Ints.indexOf(array, (Integer) 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 Integer) {
+ int i = Ints.lastIndexOf(array, (Integer) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @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);
+ return oldValue;
+ }
+
+ @Override public List<Integer> subList(int fromIndex, int toIndex) {
+ int size = size();
+ checkPositionIndexes(fromIndex, toIndex, size);
+ if (fromIndex == toIndex) {
+ return Collections.emptyList();
+ }
+ return new IntArrayAsList(array, start + fromIndex, start + toIndex);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof IntArrayAsList) {
+ IntArrayAsList that = (IntArrayAsList) 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 + Ints.hashCode(array[i]);
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder(size() * 5);
+ builder.append('[').append(array[start]);
+ for (int i = start + 1; i < end; i++) {
+ builder.append(", ").append(array[i]);
+ }
+ return builder.append(']').toString();
+ }
+
+ int[] toIntArray() {
+ // Arrays.copyOfRange() is not available under GWT
+ int size = size();
+ int[] result = new int[size];
+ System.arraycopy(array, start, result, 0, size);
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Parses the specified string as a signed decimal integer value. The ASCII
+ * character {@code '-'} (<code>'&#92;u002D'</code>) is recognized as the
+ * minus sign.
+ *
+ * <p>Unlike {@link Integer#parseInt(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 Integer#parseInt(String)} for
+ * that version.
+ *
+ * @param string the string representation of an integer value
+ * @return the integer value represented by {@code string}, or {@code null} if
+ * {@code string} has a length of zero or cannot be parsed as an integer
+ * value
+ * @since 11.0
+ */
+ @Beta
+ @CheckForNull
+ @GwtIncompatible("TODO")
+ public static Integer tryParse(String string) {
+ return AndroidInteger.tryParse(string, 10);
+ }
+}
diff --git a/guava/src/com/google/common/primitives/Longs.java b/guava/src/com/google/common/primitives/Longs.java
new file mode 100644
index 0000000..fd04178
--- /dev/null
+++ b/guava/src/com/google/common/primitives/Longs.java
@@ -0,0 +1,575 @@
+/*
+ * 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 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 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
+public final class Longs {
+ private Longs() {}
+
+ /**
+ * The number of bytes required to represent a primitive {@code long}
+ * value.
+ */
+ public static final int BYTES = Long.SIZE / Byte.SIZE;
+
+ /**
+ * The largest power of two that can be represented as a {@code long}.
+ *
+ * @since 10.0
+ */
+ public static final long MAX_POWER_OF_TWO = 1L << (Long.SIZE - 2);
+
+ /**
+ * Returns a hash code for {@code value}; equal to the result of invoking
+ * {@code ((Long) value).hashCode()}.
+ *
+ * <p>This method always return the value specified by {@link
+ * Long#hashCode()} in java, which might be different from
+ * {@code ((Long) value).hashCode()} in GWT because {@link Long#hashCode()}
+ * in GWT does not obey the JRE contract.
+ *
+ * @param value a primitive {@code long} value
+ * @return a hash code for the value
+ */
+ public static int hashCode(long value) {
+ return (int) (value ^ (value >>> 32));
+ }
+
+ /**
+ * Compares the two specified {@code long} values. The sign of the value
+ * returned is the same as that of {@code ((Long) a).compareTo(b)}.
+ *
+ * @param a the first {@code long} to compare
+ * @param b the second {@code long} 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(long a, long 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 long} values, possibly empty
+ * @param target a primitive {@code long} value
+ * @return {@code true} if {@code array[i] == target} for some value of {@code
+ * i}
+ */
+ public static boolean contains(long[] array, long target) {
+ for (long 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 long} values, possibly empty
+ * @param target a primitive {@code long} 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(long[] array, long target) {
+ return indexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int indexOf(
+ long[] array, long 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(long[] array, long[] 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 long} values, possibly empty
+ * @param target a primitive {@code long} 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(long[] array, long target) {
+ return lastIndexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int lastIndexOf(
+ long[] array, long 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 long} 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 long min(long... array) {
+ checkArgument(array.length > 0);
+ long 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 long} 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 long max(long... array) {
+ checkArgument(array.length > 0);
+ long 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 long[] {a, b}, new long[] {}, new
+ * long[] {c}} returns the array {@code {a, b, c}}.
+ *
+ * @param arrays zero or more {@code long} arrays
+ * @return a single array containing all the values from the source arrays, in
+ * order
+ */
+ public static long[] concat(long[]... arrays) {
+ int length = 0;
+ for (long[] array : arrays) {
+ length += array.length;
+ }
+ long[] result = new long[length];
+ int pos = 0;
+ for (long[] array : arrays) {
+ System.arraycopy(array, 0, result, pos, array.length);
+ pos += array.length;
+ }
+ return result;
+ }
+
+ /**
+ * Returns a big-endian representation of {@code value} in an 8-element byte
+ * array; equivalent to {@code ByteBuffer.allocate(8).putLong(value).array()}.
+ * For example, the input value {@code 0x1213141516171819L} would yield the
+ * byte array {@code {0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}}.
+ *
+ * <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.
+ */
+ 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;
+ }
+
+ /**
+ * Returns the {@code long} value whose big-endian representation is
+ * stored in the first 8 bytes of {@code bytes}; equivalent to {@code
+ * ByteBuffer.wrap(bytes).getLong()}. For example, the input byte array
+ * {@code {0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}} would yield the
+ * {@code long} value {@code 0x1213141516171819L}.
+ *
+ * <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 8
+ * elements
+ */
+ public static long 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],
+ bytes[4], bytes[5], bytes[6], bytes[7]) ;
+ }
+
+ /**
+ * Returns the {@code long} value whose byte representation is the given 8
+ * bytes, in big-endian order; equivalent to {@code Longs.fromByteArray(new
+ * byte[] {b1, b2, b3, b4, b5, b6, b7, b8})}.
+ *
+ * @since 7.0
+ */
+ public static long fromBytes(byte b1, byte b2, byte b3, byte b4,
+ byte b5, byte b6, byte b7, byte b8) {
+ return (b1 & 0xFFL) << 56
+ | (b2 & 0xFFL) << 48
+ | (b3 & 0xFFL) << 40
+ | (b4 & 0xFFL) << 32
+ | (b5 & 0xFFL) << 24
+ | (b6 & 0xFFL) << 16
+ | (b7 & 0xFFL) << 8
+ | (b8 & 0xFFL);
+ }
+
+ /**
+ * 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 long[] ensureCapacity(
+ long[] 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 long[] copyOf(long[] original, int length) {
+ long[] copy = new long[length];
+ System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
+ return copy;
+ }
+
+ /**
+ * Returns a string containing the supplied {@code long} values separated
+ * by {@code separator}. For example, {@code join("-", 1L, 2L, 3L)} 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 long} values, possibly empty
+ */
+ public static String join(String separator, long... 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 * 10);
+ 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 long} arrays
+ * 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]}.
+ *
+ * <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>
+ * @since 2.0
+ */
+ public static Comparator<long[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ private enum LexicographicalComparator implements Comparator<long[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(long[] left, long[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = Longs.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * Returns an array containing each value of {@code collection}, converted to
+ * a {@code long} value in the manner of {@link Number#longValue}.
+ *
+ * <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
+ * @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) {
+ if (collection instanceof LongArrayAsList) {
+ return ((LongArrayAsList) collection).toLongArray();
+ }
+
+ Object[] boxedArray = collection.toArray();
+ int len = boxedArray.length;
+ 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();
+ }
+ 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 Long} 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<Long> asList(long... backingArray) {
+ if (backingArray.length == 0) {
+ return Collections.emptyList();
+ }
+ return new LongArrayAsList(backingArray);
+ }
+
+ @GwtCompatible
+ private static class LongArrayAsList extends AbstractList<Long>
+ implements RandomAccess, Serializable {
+ final long[] array;
+ final int start;
+ final int end;
+
+ LongArrayAsList(long[] array) {
+ this(array, 0, array.length);
+ }
+
+ LongArrayAsList(long[] 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 Long 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 Long)
+ && Longs.indexOf(array, (Long) target, start, end) != -1;
+ }
+
+ @Override public int indexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof Long) {
+ int i = Longs.indexOf(array, (Long) 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 Long) {
+ int i = Longs.lastIndexOf(array, (Long) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @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);
+ return oldValue;
+ }
+
+ @Override public List<Long> subList(int fromIndex, int toIndex) {
+ int size = size();
+ checkPositionIndexes(fromIndex, toIndex, size);
+ if (fromIndex == toIndex) {
+ return Collections.emptyList();
+ }
+ return new LongArrayAsList(array, start + fromIndex, start + toIndex);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof LongArrayAsList) {
+ LongArrayAsList that = (LongArrayAsList) 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 + Longs.hashCode(array[i]);
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder(size() * 10);
+ builder.append('[').append(array[start]);
+ for (int i = start + 1; i < end; i++) {
+ builder.append(", ").append(array[i]);
+ }
+ return builder.append(']').toString();
+ }
+
+ long[] toLongArray() {
+ // Arrays.copyOfRange() is not available under GWT
+ int size = size();
+ long[] result = new long[size];
+ System.arraycopy(array, start, result, 0, size);
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/guava/src/com/google/common/primitives/ParseRequest.java b/guava/src/com/google/common/primitives/ParseRequest.java
new file mode 100644
index 0000000..98f29b4
--- /dev/null
+++ b/guava/src/com/google/common/primitives/ParseRequest.java
@@ -0,0 +1,57 @@
+/*
+ * 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/Primitives.java b/guava/src/com/google/common/primitives/Primitives.java
new file mode 100644
index 0000000..08c6f31
--- /dev/null
+++ b/guava/src/com/google/common/primitives/Primitives.java
@@ -0,0 +1,134 @@
+/*
+ * 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.primitives;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Contains static utility methods pertaining to primitive types and their
+ * corresponding wrapper types.
+ *
+ * @author Kevin Bourrillion
+ * @since 1.0
+ */
+public final class Primitives {
+ private Primitives() {}
+
+ /** A map from primitive types to their corresponding wrapper types. */
+ private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE;
+
+ /** A map from wrapper types to their corresponding primitive types. */
+ private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPE;
+
+ // Sad that we can't use a BiMap. :(
+
+ static {
+ Map<Class<?>, Class<?>> primToWrap = new HashMap<Class<?>, Class<?>>(16);
+ Map<Class<?>, Class<?>> wrapToPrim = new HashMap<Class<?>, Class<?>>(16);
+
+ add(primToWrap, wrapToPrim, boolean.class, Boolean.class);
+ add(primToWrap, wrapToPrim, byte.class, Byte.class);
+ add(primToWrap, wrapToPrim, char.class, Character.class);
+ add(primToWrap, wrapToPrim, double.class, Double.class);
+ add(primToWrap, wrapToPrim, float.class, Float.class);
+ add(primToWrap, wrapToPrim, int.class, Integer.class);
+ add(primToWrap, wrapToPrim, long.class, Long.class);
+ add(primToWrap, wrapToPrim, short.class, Short.class);
+ add(primToWrap, wrapToPrim, void.class, Void.class);
+
+ PRIMITIVE_TO_WRAPPER_TYPE = Collections.unmodifiableMap(primToWrap);
+ WRAPPER_TO_PRIMITIVE_TYPE = Collections.unmodifiableMap(wrapToPrim);
+ }
+
+ private static void add(Map<Class<?>, Class<?>> forward,
+ Map<Class<?>, Class<?>> backward, Class<?> key, Class<?> value) {
+ forward.put(key, value);
+ backward.put(value, key);
+ }
+
+ /**
+ * Returns an immutable set of all nine primitive types (including {@code
+ * void}). Note that a simpler way to test whether a {@code Class} instance
+ * is a member of this set is to call {@link Class#isPrimitive}.
+ *
+ * @since 3.0
+ */
+ public static Set<Class<?>> allPrimitiveTypes() {
+ return PRIMITIVE_TO_WRAPPER_TYPE.keySet();
+ }
+
+ /**
+ * Returns an immutable set of all nine primitive-wrapper types (including
+ * {@link Void}).
+ *
+ * @since 3.0
+ */
+ public static Set<Class<?>> allWrapperTypes() {
+ return WRAPPER_TO_PRIMITIVE_TYPE.keySet();
+ }
+
+ /**
+ * Returns {@code true} if {@code type} is one of the nine
+ * primitive-wrapper types, such as {@link Integer}.
+ *
+ * @see Class#isPrimitive
+ */
+ public static boolean isWrapperType(Class<?> type) {
+ return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(checkNotNull(type));
+ }
+
+ /**
+ * Returns the corresponding wrapper type of {@code type} if it is a primitive
+ * type; otherwise returns {@code type} itself. Idempotent.
+ * <pre>
+ * wrap(int.class) == Integer.class
+ * wrap(Integer.class) == Integer.class
+ * wrap(String.class) == String.class
+ * </pre>
+ */
+ public static <T> Class<T> wrap(Class<T> type) {
+ checkNotNull(type);
+
+ // cast is safe: long.class and Long.class are both of type Class<Long>
+ @SuppressWarnings("unchecked")
+ Class<T> wrapped = (Class<T>) PRIMITIVE_TO_WRAPPER_TYPE.get(type);
+ return (wrapped == null) ? type : wrapped;
+ }
+
+ /**
+ * Returns the corresponding primitive type of {@code type} if it is a
+ * wrapper type; otherwise returns {@code type} itself. Idempotent.
+ * <pre>
+ * unwrap(Integer.class) == int.class
+ * unwrap(int.class) == int.class
+ * unwrap(String.class) == String.class
+ * </pre>
+ */
+ public static <T> Class<T> unwrap(Class<T> type) {
+ checkNotNull(type);
+
+ // cast is safe: long.class and Long.class are both of type Class<Long>
+ @SuppressWarnings("unchecked")
+ Class<T> unwrapped = (Class<T>) WRAPPER_TO_PRIMITIVE_TYPE.get(type);
+ return (unwrapped == null) ? type : unwrapped;
+ }
+}
diff --git a/guava/src/com/google/common/primitives/Shorts.java b/guava/src/com/google/common/primitives/Shorts.java
new file mode 100644
index 0000000..db3d206
--- /dev/null
+++ b/guava/src/com/google/common/primitives/Shorts.java
@@ -0,0 +1,593 @@
+/*
+ * 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 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
+ */
+@GwtCompatible(emulated = true)
+public final class Shorts {
+ private Shorts() {}
+
+ /**
+ * The number of bytes required to represent a primitive {@code short}
+ * value.
+ */
+ public static final int BYTES = Short.SIZE / Byte.SIZE;
+
+ /**
+ * The largest power of two that can be represented as a {@code short}.
+ *
+ * @since 10.0
+ */
+ public static final short MAX_POWER_OF_TWO = 1 << (Short.SIZE - 2);
+
+ /**
+ * Returns a hash code for {@code value}; equal to the result of invoking
+ * {@code ((Short) value).hashCode()}.
+ *
+ * @param value a primitive {@code short} value
+ * @return a hash code for the value
+ */
+ public static int hashCode(short value) {
+ return value;
+ }
+
+ /**
+ * Returns the {@code short} value that is equal to {@code value}, if
+ * possible.
+ *
+ * @param value any value in the range of the {@code short} type
+ * @return the {@code short} value that equals {@code value}
+ * @throws IllegalArgumentException if {@code value} is greater than {@link
+ * Short#MAX_VALUE} or less than {@link Short#MIN_VALUE}
+ */
+ public static short checkedCast(long value) {
+ short result = (short) value;
+ checkArgument(result == value, "Out of range: %s", value);
+ return result;
+ }
+
+ /**
+ * Returns the {@code short} nearest in value to {@code value}.
+ *
+ * @param value any {@code long} value
+ * @return the same value cast to {@code short} if it is in the range of the
+ * {@code short} type, {@link Short#MAX_VALUE} if it is too large,
+ * or {@link Short#MIN_VALUE} if it is too small
+ */
+ public static short saturatedCast(long value) {
+ if (value > Short.MAX_VALUE) {
+ return Short.MAX_VALUE;
+ }
+ if (value < Short.MIN_VALUE) {
+ return Short.MIN_VALUE;
+ }
+ return (short) value;
+ }
+
+ /**
+ * Compares the two specified {@code short} values. The sign of the value
+ * returned is the same as that of {@code ((Short) a).compareTo(b)}.
+ *
+ * @param a the first {@code short} to compare
+ * @param b the second {@code short} 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(short a, short b) {
+ return a - b; // safe due to restricted range
+ }
+
+ /**
+ * Returns {@code true} if {@code target} is present as an element anywhere in
+ * {@code array}.
+ *
+ * @param array an array of {@code short} values, possibly empty
+ * @param target a primitive {@code short} value
+ * @return {@code true} if {@code array[i] == target} for some value of {@code
+ * i}
+ */
+ public static boolean contains(short[] array, short target) {
+ for (short 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 short} values, possibly empty
+ * @param target a primitive {@code short} 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(short[] array, short target) {
+ return indexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int indexOf(
+ short[] array, short 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(short[] array, short[] 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 short} values, possibly empty
+ * @param target a primitive {@code short} 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(short[] array, short target) {
+ return lastIndexOf(array, target, 0, array.length);
+ }
+
+ // TODO(kevinb): consider making this public
+ private static int lastIndexOf(
+ short[] array, short 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 short} 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 short min(short... array) {
+ checkArgument(array.length > 0);
+ short 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 short} 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 short max(short... array) {
+ checkArgument(array.length > 0);
+ short 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 short[] {a, b}, new short[] {}, new
+ * short[] {c}} returns the array {@code {a, b, c}}.
+ *
+ * @param arrays zero or more {@code short} arrays
+ * @return a single array containing all the values from the source arrays, in
+ * order
+ */
+ public static short[] concat(short[]... arrays) {
+ int length = 0;
+ for (short[] array : arrays) {
+ length += array.length;
+ }
+ short[] result = new short[length];
+ int pos = 0;
+ for (short[] 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 2-element byte
+ * array; equivalent to {@code
+ * ByteBuffer.allocate(2).putShort(value).array()}. For example, the input
+ * value {@code (short) 0x1234} would yield the byte array {@code {0x12,
+ * 0x34}}.
+ *
+ * <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(short value) {
+ return new byte[] {
+ (byte) (value >> 8),
+ (byte) value};
+ }
+
+ /**
+ * Returns the {@code short} value whose big-endian representation is
+ * stored in the first 2 bytes of {@code bytes}; equivalent to {@code
+ * ByteBuffer.wrap(bytes).getShort()}. For example, the input byte array
+ * {@code {0x54, 0x32}} would yield the {@code short} value {@code 0x5432}.
+ *
+ * <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 2
+ * elements
+ */
+ @GwtIncompatible("doesn't work")
+ public static short fromByteArray(byte[] bytes) {
+ checkArgument(bytes.length >= BYTES,
+ "array too small: %s < %s", bytes.length, BYTES);
+ return fromBytes(bytes[0], bytes[1]);
+ }
+
+ /**
+ * Returns the {@code short} value whose byte representation is the given 2
+ * bytes, in big-endian order; equivalent to {@code Shorts.fromByteArray(new
+ * byte[] {b1, b2})}.
+ *
+ * @since 7.0
+ */
+ @GwtIncompatible("doesn't work")
+ public static short fromBytes(byte b1, byte b2) {
+ return (short) ((b1 << 8) | (b2 & 0xFF));
+ }
+
+ /**
+ * 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 short[] ensureCapacity(
+ short[] 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 short[] copyOf(short[] original, int length) {
+ short[] copy = new short[length];
+ System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
+ return copy;
+ }
+
+ /**
+ * Returns a string containing the supplied {@code short} values separated
+ * by {@code separator}. For example, {@code join("-", (short) 1, (short) 2,
+ * (short) 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 short} values, possibly empty
+ */
+ public static String join(String separator, short... 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 * 6);
+ 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 short} arrays
+ * lexicographically. That is, it compares, using {@link
+ * #compare(short, short)}), 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 [] < [(short) 1] <
+ * [(short) 1, (short) 2] < [(short) 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(short[], short[])}.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
+ * Lexicographical order article at Wikipedia</a>
+ * @since 2.0
+ */
+ public static Comparator<short[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ private enum LexicographicalComparator implements Comparator<short[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(short[] left, short[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = Shorts.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * Returns an array containing each value of {@code collection}, converted to
+ * a {@code short} value in the manner of {@link Number#shortValue}.
+ *
+ * <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
+ * @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) {
+ if (collection instanceof ShortArrayAsList) {
+ return ((ShortArrayAsList) collection).toShortArray();
+ }
+
+ Object[] boxedArray = collection.toArray();
+ int len = boxedArray.length;
+ 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();
+ }
+ 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 Short} 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<Short> asList(short... backingArray) {
+ if (backingArray.length == 0) {
+ return Collections.emptyList();
+ }
+ return new ShortArrayAsList(backingArray);
+ }
+
+ @GwtCompatible
+ private static class ShortArrayAsList extends AbstractList<Short>
+ implements RandomAccess, Serializable {
+ final short[] array;
+ final int start;
+ final int end;
+
+ ShortArrayAsList(short[] array) {
+ this(array, 0, array.length);
+ }
+
+ ShortArrayAsList(short[] 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 Short 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 Short)
+ && Shorts.indexOf(array, (Short) target, start, end) != -1;
+ }
+
+ @Override public int indexOf(Object target) {
+ // Overridden to prevent a ton of boxing
+ if (target instanceof Short) {
+ int i = Shorts.indexOf(array, (Short) 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 Short) {
+ int i = Shorts.lastIndexOf(array, (Short) target, start, end);
+ if (i >= 0) {
+ return i - start;
+ }
+ }
+ return -1;
+ }
+
+ @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);
+ return oldValue;
+ }
+
+ @Override public List<Short> subList(int fromIndex, int toIndex) {
+ int size = size();
+ checkPositionIndexes(fromIndex, toIndex, size);
+ if (fromIndex == toIndex) {
+ return Collections.emptyList();
+ }
+ return new ShortArrayAsList(array, start + fromIndex, start + toIndex);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof ShortArrayAsList) {
+ ShortArrayAsList that = (ShortArrayAsList) 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 + Shorts.hashCode(array[i]);
+ }
+ return result;
+ }
+
+ @Override public String toString() {
+ StringBuilder builder = new StringBuilder(size() * 6);
+ builder.append('[').append(array[start]);
+ for (int i = start + 1; i < end; i++) {
+ builder.append(", ").append(array[i]);
+ }
+ return builder.append(']').toString();
+ }
+
+ short[] toShortArray() {
+ // Arrays.copyOfRange() is not available under GWT
+ int size = size();
+ short[] result = new short[size];
+ System.arraycopy(array, start, result, 0, size);
+ return result;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/guava/src/com/google/common/primitives/SignedBytes.java b/guava/src/com/google/common/primitives/SignedBytes.java
new file mode 100644
index 0000000..07e3bda
--- /dev/null
+++ b/guava/src/com/google/common/primitives/SignedBytes.java
@@ -0,0 +1,194 @@
+/*
+ * 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.primitives;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.GwtCompatible;
+
+import java.util.Comparator;
+
+/**
+ * Static utility methods pertaining to {@code byte} primitives that
+ * 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
+ */
+// TODO(kevinb): how to prevent warning on UnsignedBytes when building GWT
+// javadoc?
+@GwtCompatible
+public final class SignedBytes {
+ private SignedBytes() {}
+
+ /**
+ * The largest power of two that can be represented as a signed {@code byte}.
+ *
+ * @since 10.0
+ */
+ public static final byte MAX_POWER_OF_TWO = 1 << 6;
+
+ /**
+ * Returns the {@code byte} value that is equal to {@code value}, if possible.
+ *
+ * @param value any value in the range of the {@code byte} type
+ * @return the {@code byte} value that equals {@code value}
+ * @throws IllegalArgumentException if {@code value} is greater than {@link
+ * Byte#MAX_VALUE} or less than {@link Byte#MIN_VALUE}
+ */
+ public static byte checkedCast(long value) {
+ byte result = (byte) value;
+ checkArgument(result == value, "Out of range: %s", value);
+ return result;
+ }
+
+ /**
+ * Returns the {@code byte} nearest in value to {@code value}.
+ *
+ * @param value any {@code long} value
+ * @return the same value cast to {@code byte} if it is in the range of the
+ * {@code byte} type, {@link Byte#MAX_VALUE} if it is too large,
+ * or {@link Byte#MIN_VALUE} if it is too small
+ */
+ public static byte saturatedCast(long value) {
+ if (value > Byte.MAX_VALUE) {
+ return Byte.MAX_VALUE;
+ }
+ if (value < Byte.MIN_VALUE) {
+ return Byte.MIN_VALUE;
+ }
+ return (byte) value;
+ }
+
+ /**
+ * Compares the two specified {@code byte} values. The sign of the value
+ * returned is the same as that of {@code ((Byte) a).compareTo(b)}.
+ *
+ * @param a the first {@code byte} to compare
+ * @param b the second {@code byte} 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(byte a, byte b) {
+ return a - b; // safe due to restricted range
+ }
+
+ /**
+ * Returns the least value present in {@code array}.
+ *
+ * @param array a <i>nonempty</i> array of {@code byte} 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 byte min(byte... array) {
+ checkArgument(array.length > 0);
+ byte 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 byte} 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 byte max(byte... array) {
+ checkArgument(array.length > 0);
+ byte max = array[0];
+ for (int i = 1; i < array.length; i++) {
+ if (array[i] > max) {
+ max = array[i];
+ }
+ }
+ return max;
+ }
+
+ /**
+ * Returns a string containing the supplied {@code byte} values separated
+ * by {@code separator}. For example, {@code join(":", 0x01, 0x02, -0x01)}
+ * returns the string {@code "1:2:-1"}.
+ *
+ * @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 byte} values, possibly empty
+ */
+ public static String join(String separator, byte... 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 * 5);
+ 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 byte} arrays
+ * lexicographically. That is, it compares, using {@link
+ * #compare(byte, byte)}), 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 [] < [0x01] < [0x01, 0x80] <
+ * [0x01, 0x7F] < [0x02]}. Values are treated as signed.
+ *
+ * <p>The returned comparator is inconsistent with {@link
+ * Object#equals(Object)} (since arrays support only identity equality), but
+ * it is consistent with {@link java.util.Arrays#equals(byte[], byte[])}.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
+ * Lexicographical order article at Wikipedia</a>
+ * @since 2.0
+ */
+ public static Comparator<byte[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ private enum LexicographicalComparator implements Comparator<byte[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(byte[] left, byte[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = SignedBytes.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/primitives/UnsignedBytes.java b/guava/src/com/google/common/primitives/UnsignedBytes.java
new file mode 100644
index 0000000..f82895b
--- /dev/null
+++ b/guava/src/com/google/common/primitives/UnsignedBytes.java
@@ -0,0 +1,438 @@
+/*
+ * 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.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;
+
+import java.lang.reflect.Field;
+import java.nio.ByteOrder;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Comparator;
+
+/**
+ * Static utility methods pertaining to {@code byte} primitives that interpret
+ * values as <i>unsigned</i> (that is, any negative value {@code b} is treated
+ * as the positive value {@code 256 + b}). The corresponding methods that treat
+ * 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}.
+ *
+ * @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;
+
+ /**
+ * Returns the value of the given byte as an integer, when treated as
+ * unsigned. That is, returns {@code value + 256} if {@code value} is
+ * negative; {@code value} itself otherwise.
+ *
+ * @since 6.0
+ */
+ public static int toInt(byte value) {
+ return value & UNSIGNED_MASK;
+ }
+
+ /**
+ * Returns the {@code byte} value that, when treated as unsigned, is equal to
+ * {@code value}, if possible.
+ *
+ * @param value a value between 0 and 255 inclusive
+ * @return the {@code byte} value that, when treated as unsigned, equals
+ * {@code value}
+ * @throws IllegalArgumentException if {@code value} is negative or greater
+ * than 255
+ */
+ public static byte checkedCast(long value) {
+ checkArgument(value >> Byte.SIZE == 0, "out of range: %s", value);
+ return (byte) value;
+ }
+
+ /**
+ * Returns the {@code byte} value that, when treated as unsigned, is nearest
+ * in value to {@code value}.
+ *
+ * @param value any {@code long} value
+ * @return {@code (byte) 255} if {@code value >= 255}, {@code (byte) 0} if
+ * {@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 < 0) {
+ return (byte) 0;
+ }
+ return (byte) value;
+ }
+
+ /**
+ * Compares the two specified {@code byte} values, treating them as unsigned
+ * values between 0 and 255 inclusive. For example, {@code (byte) -127} is
+ * considered greater than {@code (byte) 127} because it is seen as having
+ * the value of positive {@code 129}.
+ *
+ * @param a the first {@code byte} to compare
+ * @param b the second {@code byte} 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(byte a, byte b) {
+ return toInt(a) - toInt(b);
+ }
+
+ /**
+ * Returns the least value present in {@code array}.
+ *
+ * @param array a <i>nonempty</i> array of {@code byte} 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 byte min(byte... array) {
+ checkArgument(array.length > 0);
+ int min = toInt(array[0]);
+ for (int i = 1; i < array.length; i++) {
+ int next = toInt(array[i]);
+ if (next < min) {
+ min = next;
+ }
+ }
+ return (byte) min;
+ }
+
+ /**
+ * Returns the greatest value present in {@code array}.
+ *
+ * @param array a <i>nonempty</i> array of {@code byte} 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 byte max(byte... array) {
+ checkArgument(array.length > 0);
+ int max = toInt(array[0]);
+ for (int i = 1; i < array.length; i++) {
+ int next = toInt(array[i]);
+ if (next > max) {
+ max = next;
+ }
+ }
+ return (byte) max;
+ }
+
+ /**
+ * 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 long}
+ * value
+ * @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}.
+ * @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"}.
+ *
+ * @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 byte} values, possibly empty
+ */
+ public static String join(String separator, byte... 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 * (3 + separator.length()));
+ builder.append(toInt(array[0]));
+ for (int i = 1; i < array.length; i++) {
+ builder.append(separator).append(toString(array[i]));
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns a comparator that compares two {@code byte} arrays
+ * lexicographically. That is, it compares, using {@link
+ * #compare(byte, byte)}), 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 [] < [0x01] < [0x01, 0x7F] <
+ * [0x01, 0x80] < [0x02]}. Values are treated as unsigned.
+ *
+ * <p>The returned comparator is inconsistent with {@link
+ * Object#equals(Object)} (since arrays support only identity equality), but
+ * it is consistent with {@link java.util.Arrays#equals(byte[], byte[])}.
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
+ * Lexicographical order article at Wikipedia</a>
+ * @since 2.0
+ */
+ public static Comparator<byte[]> lexicographicalComparator() {
+ return LexicographicalComparatorHolder.BEST_COMPARATOR;
+ }
+
+ @VisibleForTesting
+ static Comparator<byte[]> lexicographicalComparatorJavaImpl() {
+ return LexicographicalComparatorHolder.PureJavaComparator.INSTANCE;
+ }
+
+ /**
+ * Provides a lexicographical comparator implementation; either a Java
+ * implementation or a faster implementation based on {@link Unsafe}.
+ *
+ * <p>Uses reflection to gracefully fall back to the Java implementation if
+ * {@code Unsafe} isn't available.
+ */
+ @VisibleForTesting
+ static class LexicographicalComparatorHolder {
+ 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 = (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) & 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;
+ }
+ }
+
+ enum PureJavaComparator implements Comparator<byte[]> {
+ INSTANCE;
+
+ @Override public int compare(byte[] left, byte[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ int result = UnsignedBytes.compare(left[i], right[i]);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * 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();
+ }
+ }
+ }
+}
diff --git a/guava/src/com/google/common/primitives/UnsignedInteger.java b/guava/src/com/google/common/primitives/UnsignedInteger.java
new file mode 100644
index 0000000..a0df3a9
--- /dev/null
+++ b/guava/src/com/google/common/primitives/UnsignedInteger.java
@@ -0,0 +1,240 @@
+/*
+ * 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 static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+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.Nullable;
+
+/**
+ * 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);
+ public static final UnsignedInteger ONE = asUnsigned(1);
+ public static final UnsignedInteger MAX_VALUE = asUnsigned(-1);
+
+ private final int value;
+
+ private UnsignedInteger(int value) {
+ this.value = value & 0xffffffff;
+ }
+
+ /**
+ * Returns an {@code UnsignedInteger} that, when treated as signed, is
+ * equal to {@code value}.
+ */
+ public static UnsignedInteger asUnsigned(int value) {
+ return new UnsignedInteger(value);
+ }
+
+ /**
+ * Returns an {@code UnsignedInteger} that is equal to {@code value},
+ * if possible. The inverse operation of {@link #longValue()}.
+ */
+ public static UnsignedInteger valueOf(long value) {
+ checkArgument((value & INT_MASK) == value,
+ "value (%s) is outside the range for an unsigned integer value", 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 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
+ */
+ public static UnsignedInteger valueOf(String string) {
+ return valueOf(string, 10);
+ }
+
+ /**
+ * 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 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.
+ */
+ public UnsignedInteger add(UnsignedInteger val) {
+ 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.
+ */
+ public UnsignedInteger subtract(UnsignedInteger val) {
+ 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.
+ */
+ @GwtIncompatible("Does not truncate correctly")
+ public UnsignedInteger multiply(UnsignedInteger val) {
+ checkNotNull(val);
+ return asUnsigned(value * val.value);
+ }
+
+ /**
+ * Returns the result of dividing this by {@code val}.
+ */
+ public UnsignedInteger divide(UnsignedInteger val) {
+ checkNotNull(val);
+ return asUnsigned(UnsignedInts.divide(value, val.value));
+ }
+
+ /**
+ * Returns the remainder of dividing this by {@code val}.
+ */
+ public UnsignedInteger remainder(UnsignedInteger val) {
+ 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 #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}.
+ */
+ @Override
+ public int intValue() {
+ return value;
+ }
+
+ /**
+ * Returns the value of this {@code UnsignedInteger} as a {@code long}.
+ */
+ @Override
+ public long longValue() {
+ return toLong(value);
+ }
+
+ /**
+ * Returns the value of this {@code UnsignedInteger} as a {@code float}, analogous to a widening
+ * primitive conversion from {@code int} to {@code float}, and correctly rounded.
+ */
+ @Override
+ public float floatValue() {
+ return longValue();
+ }
+
+ /**
+ * Returns the value of this {@code UnsignedInteger} as a {@code float}, analogous to a widening
+ * primitive conversion from {@code int} to {@code double}, and correctly rounded.
+ */
+ @Override
+ public double doubleValue() {
+ return longValue();
+ }
+
+ /**
+ * Returns the value of this {@code UnsignedInteger} as a {@link BigInteger}.
+ */
+ public BigInteger bigIntegerValue() {
+ return BigInteger.valueOf(longValue());
+ }
+
+ /**
+ * Compares this unsigned integer to another unsigned integer.
+ * Returns {@code 0} if they are equal, a negative number if {@code this < other},
+ * and a positive number if {@code this > other}.
+ */
+ @Override
+ public int compareTo(UnsignedInteger other) {
+ checkNotNull(other);
+ return compare(value, other.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (obj instanceof UnsignedInteger) {
+ UnsignedInteger other = (UnsignedInteger) obj;
+ return value == other.value;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a string representation of the {@code UnsignedInteger} value, in base 10.
+ */
+ @Override
+ public String toString() {
+ return toString(10);
+ }
+
+ /**
+ * Returns a string representation of the {@code UnsignedInteger} value, in base {@code radix}.
+ * If {@code radix < Character.MIN_RADIX} or {@code radix > Character.MAX_RADIX}, the radix
+ * {@code 10} is used.
+ */
+ public String toString(int radix) {
+ return UnsignedInts.toString(value, radix);
+ }
+}
diff --git a/guava/src/com/google/common/primitives/UnsignedInts.java b/guava/src/com/google/common/primitives/UnsignedInts.java
new file mode 100644
index 0000000..93ec66e
--- /dev/null
+++ b/guava/src/com/google/common/primitives/UnsignedInts.java
@@ -0,0 +1,275 @@
+/*
+ * 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 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;
+
+/**
+ * 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
+ */
+@Beta
+@GwtCompatible
+public final class UnsignedInts {
+ static final long INT_MASK = 0xffffffffL;
+
+ private UnsignedInts() {}
+
+ static int flip(int value) {
+ return value ^ Integer.MIN_VALUE;
+ }
+
+ /**
+ * 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
+ * greater than {@code b}; or zero if they are equal
+ */
+ public static int compare(int a, int b) {
+ return Ints.compare(flip(a), flip(b));
+ }
+
+ /**
+ * Returns the value of the given {@code int} as a {@code long}, when treated as unsigned.
+ */
+ public static long toLong(int value) {
+ return value & INT_MASK;
+ }
+
+ /**
+ * 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}
+ * @throws IllegalArgumentException if {@code array} is empty
+ */
+ public static int min(int... array) {
+ checkArgument(array.length > 0);
+ int min = flip(array[0]);
+ for (int i = 1; i < array.length; i++) {
+ int next = flip(array[i]);
+ if (next < min) {
+ min = next;
+ }
+ }
+ return flip(min);
+ }
+
+ /**
+ * 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}
+ * @throws IllegalArgumentException if {@code array} is empty
+ */
+ public static int max(int... array) {
+ checkArgument(array.length > 0);
+ int max = flip(array[0]);
+ for (int i = 1; i < array.length; i++) {
+ int next = flip(array[i]);
+ if (next > max) {
+ max = next;
+ }
+ }
+ return flip(max);
+ }
+
+ /**
+ * 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
+ */
+ public static String join(String separator, int... 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 * 5);
+ builder.append(toString(array[0]));
+ for (int i = 1; i < array.length; i++) {
+ builder.append(separator).append(toString(array[i]));
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns a comparator that compares two arrays of unsigned {@code int} values lexicographically.
+ * 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>
+ */
+ public static Comparator<int[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ enum LexicographicalComparator implements Comparator<int[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(int[] left, int[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ if (left[i] != right[i]) {
+ return UnsignedInts.compare(left[i], right[i]);
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * 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
+ */
+ public static int divide(int dividend, int divisor) {
+ return (int) (toLong(dividend) / toLong(divisor));
+ }
+
+ /**
+ * 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
+ */
+ public static int remainder(int dividend, int divisor) {
+ return (int) (toLong(dividend) % toLong(divisor));
+ }
+
+ /**
+ * 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 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);
+ }
+
+ /**
+ * 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.
+ */
+ public static int parseUnsignedInt(String string, int radix) {
+ checkNotNull(string);
+ long result = Long.parseLong(string, radix);
+ if ((result & INT_MASK) != result) {
+ throw new NumberFormatException("Input " + string + " in base " + radix
+ + " is not in the range of an unsigned integer");
+ }
+ return (int) result;
+ }
+
+ /**
+ * Returns a string representation of x, where x is treated as unsigned.
+ */
+ public static String toString(int 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}.
+ */
+ public static String toString(int x, int radix) {
+ long asLong = x & INT_MASK;
+ return Long.toString(asLong, radix);
+ }
+}
diff --git a/guava/src/com/google/common/primitives/UnsignedLong.java b/guava/src/com/google/common/primitives/UnsignedLong.java
new file mode 100644
index 0000000..1562497
--- /dev/null
+++ b/guava/src/com/google/common/primitives/UnsignedLong.java
@@ -0,0 +1,243 @@
+/*
+ * 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 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.Nullable;
+
+/**
+ * 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>.
+ *
+ * @author Louis Wasserman
+ * @author Colin Evans
+ * @since 11.0
+ */
+@Beta
+@GwtCompatible(serializable = true)
+public final class UnsignedLong extends Number implements Comparable<UnsignedLong>, Serializable {
+
+ private static final long UNSIGNED_MASK = 0x7fffffffffffffffL;
+
+ public static final UnsignedLong ZERO = new UnsignedLong(0);
+ public static final UnsignedLong ONE = new UnsignedLong(1);
+ public static final UnsignedLong MAX_VALUE = new UnsignedLong(-1L);
+
+ private final long value;
+
+ private UnsignedLong(long value) {
+ this.value = value;
+ }
+
+ /**
+ * Returns an {@code UnsignedLong} that, when treated as signed, is equal to {@code value}. The
+ * inverse operation is {@link #longValue()}.
+ *
+ * <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}.
+ */
+ public static UnsignedLong asUnsigned(long value) {
+ return new UnsignedLong(value);
+ }
+
+ /**
+ * 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}
+ */
+ public static UnsignedLong valueOf(BigInteger value) {
+ checkNotNull(value);
+ checkArgument(value.signum() >= 0 && value.bitLength() <= Long.SIZE,
+ "value (%s) is outside the range for an unsigned long value", value);
+ return asUnsigned(value.longValue());
+ }
+
+ /**
+ * Returns an {@code UnsignedLong} holding the value of the specified {@code String}, parsed as
+ * an unsigned {@code long} value.
+ *
+ * @throws NumberFormatException if the string does not contain a parsable unsigned {@code long}
+ * value
+ */
+ public static UnsignedLong valueOf(String string) {
+ return valueOf(string, 10);
+ }
+
+ /**
+ * Returns an {@code UnsignedLong} holding the value of the specified {@code String}, parsed as
+ * an unsigned {@code long} value in the specified radix.
+ *
+ * @throws NumberFormatException if the string does not contain a parsable unsigned {@code long}
+ * value, or {@code radix} is not between {@link Character#MIN_RADIX} and
+ * {@link Character#MAX_RADIX}
+ */
+ public static UnsignedLong valueOf(String string, int 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.
+ */
+ public UnsignedLong add(UnsignedLong val) {
+ 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.
+ */
+ public UnsignedLong subtract(UnsignedLong val) {
+ 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.
+ */
+ public UnsignedLong multiply(UnsignedLong val) {
+ checkNotNull(val);
+ return asUnsigned(value * val.value);
+ }
+
+ /**
+ * Returns the result of dividing this by {@code val}.
+ */
+ public UnsignedLong divide(UnsignedLong val) {
+ checkNotNull(val);
+ return asUnsigned(UnsignedLongs.divide(value, val.value));
+ }
+
+ /**
+ * Returns the remainder of dividing this by {@code val}.
+ */
+ public UnsignedLong remainder(UnsignedLong val) {
+ checkNotNull(val);
+ return asUnsigned(UnsignedLongs.remainder(value, val.value));
+ }
+
+ /**
+ * Returns the value of this {@code UnsignedLong} as an {@code int}.
+ */
+ @Override
+ public int intValue() {
+ return (int) value;
+ }
+
+ /**
+ * Returns the value of this {@code UnsignedLong} as a {@code long}. This is an inverse operation
+ * to {@link #asUnsigned}.
+ *
+ * <p>Note that if this {@code UnsignedLong} holds a value {@code >= 2^63}, the returned value
+ * will be equal to {@code this - 2^64}.
+ */
+ @Override
+ public long longValue() {
+ return value;
+ }
+
+ /**
+ * Returns the value of this {@code UnsignedLong} as a {@code float}, analogous to a widening
+ * primitive conversion from {@code long} to {@code float}, and correctly rounded.
+ */
+ @Override
+ public float floatValue() {
+ @SuppressWarnings("cast")
+ float fValue = (float) (value & UNSIGNED_MASK);
+ if (value < 0) {
+ fValue += 0x1.0p63f;
+ }
+ return fValue;
+ }
+
+ /**
+ * Returns the value of this {@code UnsignedLong} as a {@code double}, analogous to a widening
+ * primitive conversion from {@code long} to {@code double}, and correctly rounded.
+ */
+ @Override
+ public double doubleValue() {
+ @SuppressWarnings("cast")
+ double dValue = (double) (value & UNSIGNED_MASK);
+ if (value < 0) {
+ dValue += 0x1.0p63;
+ }
+ return dValue;
+ }
+
+ /**
+ * Returns the value of this {@code UnsignedLong} as a {@link BigInteger}.
+ */
+ public BigInteger bigIntegerValue() {
+ BigInteger bigInt = BigInteger.valueOf(value & UNSIGNED_MASK);
+ if (value < 0) {
+ bigInt = bigInt.setBit(Long.SIZE - 1);
+ }
+ return bigInt;
+ }
+
+ @Override
+ public int compareTo(UnsignedLong o) {
+ checkNotNull(o);
+ return UnsignedLongs.compare(value, o.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Longs.hashCode(value);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (obj instanceof UnsignedLong) {
+ UnsignedLong other = (UnsignedLong) obj;
+ return value == other.value;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a string representation of the {@code UnsignedLong} value, in base 10.
+ */
+ @Override
+ public String toString() {
+ return UnsignedLongs.toString(value);
+ }
+
+ /**
+ * Returns a string representation of the {@code UnsignedLong} value, in base {@code radix}. If
+ * {@code radix < Character.MIN_RADIX} or {@code radix > Character.MAX_RADIX}, the radix
+ * {@code 10} is used.
+ */
+ public String toString(int radix) {
+ return UnsignedLongs.toString(value, radix);
+ }
+}
diff --git a/guava/src/com/google/common/primitives/UnsignedLongs.java b/guava/src/com/google/common/primitives/UnsignedLongs.java
new file mode 100644
index 0000000..83f732f
--- /dev/null
+++ b/guava/src/com/google/common/primitives/UnsignedLongs.java
@@ -0,0 +1,391 @@
+/*
+ * 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 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;
+
+/**
+ * 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
+ * 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
+ * @since 10.0
+ */
+@Beta
+@GwtCompatible
+public final class UnsignedLongs {
+ private UnsignedLongs() {}
+
+ public static final long MAX_VALUE = -1L; // Equivalent to 2^64 - 1
+
+ /**
+ * 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)}
+ * as signed longs.
+ */
+ private static long flip(long a) {
+ return a ^ Long.MIN_VALUE;
+ }
+
+ /**
+ * 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
+ * greater than {@code b}; or zero if they are equal
+ */
+ public static int compare(long a, long b) {
+ return Longs.compare(flip(a), flip(b));
+ }
+
+ /**
+ * 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}
+ * @throws IllegalArgumentException if {@code array} is empty
+ */
+ public static long min(long... array) {
+ checkArgument(array.length > 0);
+ long min = flip(array[0]);
+ for (int i = 1; i < array.length; i++) {
+ long next = flip(array[i]);
+ if (next < min) {
+ min = next;
+ }
+ }
+ return flip(min);
+ }
+
+ /**
+ * 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}
+ * @throws IllegalArgumentException if {@code array} is empty
+ */
+ public static long max(long... array) {
+ checkArgument(array.length > 0);
+ long max = flip(array[0]);
+ for (int i = 1; i < array.length; i++) {
+ long next = flip(array[i]);
+ if (next > max) {
+ max = next;
+ }
+ }
+ return flip(max);
+ }
+
+ /**
+ * 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
+ */
+ public static String join(String separator, long... 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 * 5);
+ builder.append(toString(array[0]));
+ for (int i = 1; i < array.length; i++) {
+ builder.append(separator).append(toString(array[i]));
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns a comparator that compares two arrays of unsigned {@code long} values
+ * 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>
+ */
+ public static Comparator<long[]> lexicographicalComparator() {
+ return LexicographicalComparator.INSTANCE;
+ }
+
+ enum LexicographicalComparator implements Comparator<long[]> {
+ INSTANCE;
+
+ @Override
+ public int compare(long[] left, long[] right) {
+ int minLength = Math.min(left.length, right.length);
+ for (int i = 0; i < minLength; i++) {
+ if (left[i] != right[i]) {
+ return UnsignedLongs.compare(left[i], right[i]);
+ }
+ }
+ return left.length - right.length;
+ }
+ }
+
+ /**
+ * 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
+ */
+ public static long divide(long dividend, long divisor) {
+ if (divisor < 0) { // i.e., divisor >= 2^63:
+ if (compare(dividend, divisor) < 0) {
+ return 0; // dividend < divisor
+ } else {
+ return 1; // dividend >= divisor
+ }
+ }
+
+ // Optimization - use signed division if dividend < 2^63
+ if (dividend >= 0) {
+ return dividend / divisor;
+ }
+
+ /*
+ * Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
+ * guaranteed to be either exact or one less than the correct value. This follows from fact
+ * that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is not
+ * quite trivial.
+ */
+ long quotient = ((dividend >>> 1) / divisor) << 1;
+ long rem = dividend - quotient * divisor;
+ return quotient + (compare(rem, divisor) >= 0 ? 1 : 0);
+ }
+
+ /**
+ * 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
+ * @since 11.0
+ */
+ public static long remainder(long dividend, long divisor) {
+ if (divisor < 0) { // i.e., divisor >= 2^63:
+ if (compare(dividend, divisor) < 0) {
+ return dividend; // dividend < divisor
+ } else {
+ return dividend - divisor; // dividend >= divisor
+ }
+ }
+
+ // Optimization - use signed modulus if dividend < 2^63
+ if (dividend >= 0) {
+ return dividend % divisor;
+ }
+
+ /*
+ * Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
+ * guaranteed to be either exact or one less than the correct value. This follows from fact
+ * that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is not
+ * quite trivial.
+ */
+ long quotient = ((dividend >>> 1) / divisor) << 1;
+ long rem = dividend - quotient * divisor;
+ return rem - (compare(rem, divisor) >= 0 ? divisor : 0);
+ }
+
+ /**
+ * 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
+ */
+ 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}.
+ */
+ public static long parseUnsignedLong(String s, int radix) {
+ checkNotNull(s);
+ if (s.length() == 0) {
+ throw new NumberFormatException("empty string");
+ }
+ if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
+ throw new NumberFormatException("illegal radix: " + radix);
+ }
+
+ int max_safe_pos = maxSafeDigits[radix] - 1;
+ long value = 0;
+ for (int pos = 0; pos < s.length(); pos++) {
+ int digit = Character.digit(s.charAt(pos), radix);
+ if (digit == -1) {
+ throw new NumberFormatException(s);
+ }
+ if (pos > max_safe_pos && overflowInParse(value, digit, radix)) {
+ throw new NumberFormatException("Too large for unsigned long: " + s);
+ }
+ value = (value * radix) + digit;
+ }
+
+ return value;
+ }
+
+ /**
+ * Returns true if (current * radix) + digit is a number too large to be represented by an
+ * unsigned long. This is useful for detecting overflow while parsing a string representation of
+ * a number. Does not verify whether supplied radix is valid, passing an invalid radix will give
+ * undefined results or an ArrayIndexOutOfBoundsException.
+ */
+ private static boolean overflowInParse(long current, int digit, int radix) {
+ if (current >= 0) {
+ if (current < maxValueDivs[radix]) {
+ return false;
+ }
+ if (current > maxValueDivs[radix]) {
+ return true;
+ }
+ // current == maxValueDivs[radix]
+ return (digit > maxValueMods[radix]);
+ }
+
+ // current < 0: high bit is set
+ return true;
+ }
+
+ /**
+ * Returns a string representation of x, where x is treated as unsigned.
+ */
+ public static String toString(long 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}.
+ */
+ public static String toString(long 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);
+ if (x == 0) {
+ // Simply return "0"
+ return "0";
+ } else {
+ 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;
+ }
+ // Generate string
+ return new String(buf, i, buf.length - i);
+ }
+ }
+
+ // calculated as 0xffffffffffffffff / radix
+ private static final long[] maxValueDivs = new long[Character.MAX_RADIX + 1];
+ private static final int[] maxValueMods = new int[Character.MAX_RADIX + 1];
+ private static final int[] maxSafeDigits = new int[Character.MAX_RADIX + 1];
+ static {
+ BigInteger overflow = new BigInteger("10000000000000000", 16);
+ for (int i = Character.MIN_RADIX; i <= Character.MAX_RADIX; i++) {
+ maxValueDivs[i] = divide(MAX_VALUE, i);
+ maxValueMods[i] = (int) remainder(MAX_VALUE, i);
+ maxSafeDigits[i] = overflow.toString(i).length() - 1;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/primitives/package-info.java b/guava/src/com/google/common/primitives/package-info.java
new file mode 100644
index 0000000..205183f
--- /dev/null
+++ b/guava/src/com/google/common/primitives/package-info.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+/**
+ * Static utilities for working with the eight primitive types and {@code void},
+ * and value types for treating them as unsigned.
+ *
+ * <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>
+ *
+ * <h3>General static utilities</h3>
+ *
+ * <ul>
+ * <li>{@link com.google.common.primitives.Primitives}
+ * </ul>
+ *
+ * <h3>Per-type static utilities</h3>
+ *
+ * <ul>
+ * <li>{@link com.google.common.primitives.Booleans}
+ * <li>{@link com.google.common.primitives.Bytes}
+ * <ul>
+ * <li>{@link com.google.common.primitives.SignedBytes}
+ * <li>{@link com.google.common.primitives.UnsignedBytes}
+ * </ul>
+ * <li>{@link com.google.common.primitives.Chars}
+ * <li>{@link com.google.common.primitives.Doubles}
+ * <li>{@link com.google.common.primitives.Floats}
+ * <li>{@link com.google.common.primitives.Ints}
+ * <ul>
+ * <li>{@link com.google.common.primitives.UnsignedInts}
+ * </ul>
+ * <li>{@link com.google.common.primitives.Longs}
+ * <ul>
+ * <li>{@link com.google.common.primitives.UnsignedLongs}
+ * </ul>
+ * <li>{@link com.google.common.primitives.Shorts}
+ * </ul>
+ *
+ * <h3>Value types</h3>
+ * <ul>
+ * <li>{@link com.google.common.primitives.UnsignedInteger}
+ * <li>{@link com.google.common.primitives.UnsignedLong}
+ * </ul>
+ */
+@ParametersAreNonnullByDefault
+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
new file mode 100644
index 0000000..8453b7c
--- /dev/null
+++ b/guava/src/com/google/common/reflect/AbstractInvocationHandler.java
@@ -0,0 +1,82 @@
+/*
+ * 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 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>{@link Object#equals}, {@link Object#hashCode} are implemented according to referential
+ * equality (the default behavior of {@link Object}). {@link Object#toString} delegates to
+ * {@link #toString} that can be overridden by subclasses.
+ */
+ @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 System.identityHashCode(proxy);
+ }
+ if (args.length == 1
+ && method.getName().equals("equals")
+ && method.getParameterTypes()[0] == Object.class) {
+ return proxy == args[0];
+ }
+ 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;
+
+ /**
+ * The dynamic proxies' {@link Object#toString} will delegate to this method. Subclasses can
+ * override this to provide custom string representation of the proxies.
+ */
+ @Override public String toString() {
+ return super.toString();
+ }
+}
diff --git a/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java b/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java
new file mode 100644
index 0000000..43e5e1e
--- /dev/null
+++ b/guava/src/com/google/common/reflect/ImmutableTypeToInstanceMap.java
@@ -0,0 +1,138 @@
+/*
+ * 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/MutableTypeToInstanceMap.java b/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java
new file mode 100644
index 0000000..5f1249d
--- /dev/null
+++ b/guava/src/com/google/common/reflect/MutableTypeToInstanceMap.java
@@ -0,0 +1,89 @@
+/*
+ * 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/Reflection.java b/guava/src/com/google/common/reflect/Reflection.java
new file mode 100644
index 0000000..6b25f01
--- /dev/null
+++ b/guava/src/com/google/common/reflect/Reflection.java
@@ -0,0 +1,103 @@
+/*
+ * 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 cls} 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<?> cls) {
+ return getPackageName(cls.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('.');
+ if (lastDot < 0) {
+ return "";
+ } else {
+ return 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(interfaceType);
+ checkNotNull(handler);
+ checkArgument(interfaceType.isInterface());
+ 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
new file mode 100644
index 0000000..c686661
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeCapture.java
@@ -0,0 +1,38 @@
+/*
+ * 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
new file mode 100644
index 0000000..a6a46bc
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeParameter.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.google.common.annotations.Beta;
+
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+
+/**
+ * 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;
+
+ private TypeParameter(TypeVariable<?> typeVariable) {
+ this.typeVariable = checkNotNull(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(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
new file mode 100644
index 0000000..0c42ef5
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeResolver.java
@@ -0,0 +1,389 @@
+/*
+ * 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, formal, 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) {
+ 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) {
+ 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
new file mode 100644
index 0000000..3b00820
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeToInstanceMap.java
@@ -0,0 +1,92 @@
+/*
+ * 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
new file mode 100644
index 0000000..08a2440
--- /dev/null
+++ b/guava/src/com/google/common/reflect/TypeToken.java
@@ -0,0 +1,1086 @@
+/*
+ * 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.GenericArrayType;
+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 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);
+ }
+
+ /**
+ * 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)
+ .toImmutableSet());
+ } 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)
+ .toImmutableSet());
+ } 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();
+ }
+ })
+ .toImmutableSet();
+ }
+
+ @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)
+ .toImmutableSet());
+ } 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<?>
+ 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
new file mode 100644
index 0000000..19264d3
--- /dev/null
+++ b/guava/src/com/google/common/reflect/Types.java
@@ -0,0 +1,518 @@
+/*
+ * 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);
+ }
+ }
+ }
+
+ static IllegalArgumentException buildUnexpectedTypeException(
+ Type type, Class<?>... expected) {
+ // Build exception message
+ StringBuilder exceptionMessage =
+ new StringBuilder("Unexpected type. Expected one of: ");
+ for (Class<?> clazz : expected) {
+ exceptionMessage.append(clazz.getName()).append(", ");
+ }
+ exceptionMessage.append("but got: ").append(type.getClass().getName())
+ .append(", for type: ").append(toString(type)).append('.');
+
+ return new IllegalArgumentException(exceptionMessage.toString());
+ }
+
+ /** 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
new file mode 100644
index 0000000..e8ac02a
--- /dev/null
+++ b/guava/src/com/google/common/reflect/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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/AbstractCheckedFuture.java b/guava/src/com/google/common/util/concurrent/AbstractCheckedFuture.java
new file mode 100644
index 0000000..dfaf343
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AbstractCheckedFuture.java
@@ -0,0 +1,117 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A delegating wrapper around a {@link ListenableFuture} that adds support for
+ * the {@link #checkedGet()} and {@link #checkedGet(long, TimeUnit)} methods.
+ *
+ * @author Sven Mawson
+ * @since 1.0
+ */
+@Beta
+public abstract class AbstractCheckedFuture<V, X extends Exception>
+ extends ForwardingListenableFuture.SimpleForwardingListenableFuture<V>
+ implements CheckedFuture<V, X> {
+ /**
+ * Constructs an {@code AbstractCheckedFuture} that wraps a delegate.
+ */
+ protected AbstractCheckedFuture(ListenableFuture<V> delegate) {
+ super(delegate);
+ }
+
+ /**
+ * Translates from an {@link InterruptedException},
+ * {@link CancellationException} or {@link ExecutionException} thrown by
+ * {@code get} to an exception of type {@code X} to be thrown by
+ * {@code checkedGet}. Subclasses must implement this method.
+ *
+ * <p>If {@code e} is an {@code InterruptedException}, the calling
+ * {@code checkedGet} method has already restored the interrupt after catching
+ * the exception. If an implementation of {@link #mapException(Exception)}
+ * wishes to swallow the interrupt, it can do so by calling
+ * {@link Thread#interrupted()}.
+ *
+ * <p>Subclasses may choose to throw, rather than return, a subclass of
+ * {@code RuntimeException} to allow creating a CheckedFuture that throws
+ * both checked and unchecked exceptions.
+ */
+ protected abstract X mapException(Exception e);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation calls {@link #get()} and maps that method's standard
+ * exceptions to instances of type {@code X} using {@link #mapException}.
+ *
+ * <p>In addition, if {@code get} throws an {@link InterruptedException}, this
+ * implementation will set the current thread's interrupt status before
+ * calling {@code mapException}.
+ *
+ * @throws X if {@link #get()} throws an {@link InterruptedException},
+ * {@link CancellationException}, or {@link ExecutionException}
+ */
+ @Override
+ public V checkedGet() throws X {
+ try {
+ return get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw mapException(e);
+ } catch (CancellationException e) {
+ throw mapException(e);
+ } catch (ExecutionException e) {
+ throw mapException(e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation calls {@link #get(long, TimeUnit)} and maps that
+ * method's standard exceptions (excluding {@link TimeoutException}, which is
+ * propagated) to instances of type {@code X} using {@link #mapException}.
+ *
+ * <p>In addition, if {@code get} throws an {@link InterruptedException}, this
+ * implementation will set the current thread's interrupt status before
+ * calling {@code mapException}.
+ *
+ * @throws X if {@link #get()} throws an {@link InterruptedException},
+ * {@link CancellationException}, or {@link ExecutionException}
+ * @throws TimeoutException {@inheritDoc}
+ */
+ @Override
+ public V checkedGet(long timeout, TimeUnit unit) throws TimeoutException, X {
+ try {
+ return get(timeout, unit);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw mapException(e);
+ } catch (CancellationException e) {
+ throw mapException(e);
+ } catch (ExecutionException e) {
+ throw mapException(e);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java b/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
new file mode 100644
index 0000000..6926c85
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AbstractExecutionThreadService.java
@@ -0,0 +1,188 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Throwables;
+
+import java.util.concurrent.Executor;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Base class for services that can implement {@link #startUp}, {@link #run} and
+ * {@link #shutDown} methods. This class uses a single thread to execute the
+ * service; consider {@link AbstractService} if you would like to manage any
+ * threading manually.
+ *
+ * @author Jesse Wilson
+ * @since 1.0
+ */
+@Beta
+public abstract class AbstractExecutionThreadService implements Service {
+ private static final Logger logger = Logger.getLogger(
+ AbstractExecutionThreadService.class.getName());
+
+ /* use AbstractService for state management */
+ private final Service delegate = new AbstractService() {
+ @Override protected final void doStart() {
+ executor().execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ startUp();
+ notifyStarted();
+
+ if (isRunning()) {
+ try {
+ AbstractExecutionThreadService.this.run();
+ } catch (Throwable t) {
+ try {
+ shutDown();
+ } catch (Exception ignored) {
+ logger.log(Level.WARNING,
+ "Error while attempting to shut down the service"
+ + " after failure.", ignored);
+ }
+ throw t;
+ }
+ }
+
+ shutDown();
+ notifyStopped();
+ } catch (Throwable t) {
+ notifyFailed(t);
+ throw Throwables.propagate(t);
+ }
+ }
+ });
+ }
+
+ @Override protected void doStop() {
+ triggerShutdown();
+ }
+ };
+
+ /**
+ * 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 {}
+
+ /**
+ * Run the service. This method is invoked on the execution thread.
+ * Implementations must respond to stop requests. You could poll for lifecycle
+ * changes in a work loop:
+ * <pre>
+ * public void run() {
+ * while ({@link #isRunning()}) {
+ * // perform a unit of work
+ * }
+ * }
+ * </pre>
+ * ...or you could respond to stop requests by implementing {@link
+ * #triggerShutdown()}, which should cause {@link #run()} to return.
+ */
+ protected abstract void run() throws Exception;
+
+ /**
+ * 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() {}
+
+ /**
+ * Returns the {@link Executor} that will be used to run this service.
+ * Subclasses may override this method to use a custom {@link Executor}, which
+ * may configure its worker thread with a specific name, thread group or
+ * priority. The returned executor's {@link Executor#execute(Runnable)
+ * execute()} method is called when this service is started, and should return
+ * promptly.
+ *
+ * <p>The default implementation returns a new {@link Executor} that sets the
+ * name of its threads to the string returned by {@link #getServiceName}
+ */
+ protected Executor executor() {
+ return new Executor() {
+ @Override
+ public void execute(Runnable command) {
+ new Thread(command, getServiceName()).start();
+ }
+ };
+ }
+
+ @Override public String toString() {
+ return getServiceName() + " [" + state() + "]";
+ }
+
+ // We override instead of using ForwardingService so that these can be final.
+
+ @Override public final ListenableFuture<State> start() {
+ return delegate.start();
+ }
+
+ @Override public final State startAndWait() {
+ return delegate.startAndWait();
+ }
+
+ @Override public final boolean isRunning() {
+ return delegate.isRunning();
+ }
+
+ @Override public final State state() {
+ return delegate.state();
+ }
+
+ @Override public final ListenableFuture<State> stop() {
+ return delegate.stop();
+ }
+
+ @Override public final State stopAndWait() {
+ return delegate.stopAndWait();
+ }
+
+ @Override public final void addListener(Listener listener, Executor executor) {
+ delegate.addListener(listener, executor);
+ }
+
+ /**
+ * Returns the name of this service. {@link AbstractExecutionThreadService}
+ * may include the name in debugging output.
+ *
+ * <p>Subclasses may override this method.
+ *
+ * @since 10.0
+ */
+ 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
new file mode 100644
index 0000000..28b2cc0
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AbstractFuture.java
@@ -0,0 +1,371 @@
+/*
+ * 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.util.concurrent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.concurrent.CancellationException;
+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.AbstractQueuedSynchronizer;
+
+import javax.annotation.Nullable;
+
+/**
+ * An abstract implementation of the {@link ListenableFuture} interface. This
+ * class is preferable to {@link java.util.concurrent.FutureTask} for two
+ * reasons: It implements {@code ListenableFuture}, and it does not implement
+ * {@code Runnable}. (If you want a {@code Runnable} implementation of {@code
+ * ListenableFuture}, create a {@link ListenableFutureTask}, or submit your
+ * tasks to a {@link ListeningExecutorService}.)
+ *
+ * <p>This class implements all methods in {@code ListenableFuture}.
+ * Subclasses should provide a way to set the result of the computation through
+ * the protected methods {@link #set(Object)} and
+ * {@link #setException(Throwable)}. Subclasses may also override {@link
+ * #interruptTask()}, which will be invoked automatically if a call to {@link
+ * #cancel(boolean) cancel(true)} succeeds in canceling the future.
+ *
+ * <p>{@code AbstractFuture} uses an {@link AbstractQueuedSynchronizer} to deal
+ * with concurrency issues and guarantee thread safety.
+ *
+ * <p>The state changing methods all return a boolean indicating success or
+ * failure in changing the future's state. Valid states are running,
+ * completed, failed, or cancelled.
+ *
+ * <p>This class uses an {@link ExecutionList} to guarantee that all registered
+ * listeners will be executed, either when the future finishes or, for listeners
+ * that are added after the future completes, immediately.
+ * {@code Runnable}-{@code Executor} pairs are stored in the execution list but
+ * are not necessarily executed in the order in which they were added. (If a
+ * listener is added after the Future is complete, it will be executed
+ * immediately, even if earlier listeners have not been executed. Additionally,
+ * executors need not guarantee FIFO execution, or different listeners may run
+ * in different executors.)
+ *
+ * @author Sven Mawson
+ * @since 1.0
+ */
+public abstract class AbstractFuture<V> implements ListenableFuture<V> {
+
+ /** Synchronization control for AbstractFutures. */
+ private final Sync<V> sync = new Sync<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.
+ */
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default {@link AbstractFuture} implementation throws {@code
+ * InterruptedException} if the current thread is interrupted before or during
+ * the call, even if the value is already available.
+ *
+ * @throws InterruptedException if the current thread was interrupted before
+ * or during the call (optional but recommended).
+ * @throws CancellationException {@inheritDoc}
+ */
+ @Override
+ public V get(long timeout, TimeUnit unit) throws InterruptedException,
+ TimeoutException, ExecutionException {
+ return sync.get(unit.toNanos(timeout));
+ }
+
+ /*
+ * Improve the documentation of when InterruptedException is thrown. Our
+ * behavior matches the JDK's, but the JDK's documentation is misleading.
+ */
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The default {@link AbstractFuture} implementation throws {@code
+ * InterruptedException} if the current thread is interrupted before or during
+ * the call, even if the value is already available.
+ *
+ * @throws InterruptedException if the current thread was interrupted before
+ * or during the call (optional but recommended).
+ * @throws CancellationException {@inheritDoc}
+ */
+ @Override
+ public V get() throws InterruptedException, ExecutionException {
+ return sync.get();
+ }
+
+ @Override
+ public boolean isDone() {
+ return sync.isDone();
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return sync.isCancelled();
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ if (!sync.cancel()) {
+ return false;
+ }
+ executionList.execute();
+ if (mayInterruptIfRunning) {
+ interruptTask();
+ }
+ return true;
+ }
+
+ /**
+ * Subclasses can override this method to implement interruption of the
+ * future's computation. The method is invoked automatically by a successful
+ * call to {@link #cancel(boolean) cancel(true)}.
+ *
+ * <p>The default implementation does nothing.
+ *
+ * @since 10.0
+ */
+ protected void interruptTask() {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 10.0
+ */
+ @Override
+ public void addListener(Runnable listener, Executor exec) {
+ executionList.add(listener, exec);
+ }
+
+ /**
+ * Subclasses should invoke this method to set the result of the computation
+ * to {@code value}. This will set the state of the future to
+ * {@link AbstractFuture.Sync#COMPLETED} and invoke the listeners if the
+ * state was successfully changed.
+ *
+ * @param value the value that was the result of the task.
+ * @return true if the state was successfully changed.
+ */
+ protected boolean set(@Nullable V value) {
+ boolean result = sync.set(value);
+ if (result) {
+ executionList.execute();
+ }
+ return result;
+ }
+
+ /**
+ * Subclasses should invoke this method to set the result of the computation
+ * to an error, {@code throwable}. This will set the state of the future to
+ * {@link AbstractFuture.Sync#COMPLETED} and invoke the listeners if the
+ * state was successfully changed.
+ *
+ * @param throwable the exception that the task failed with.
+ * @return true if the state was successfully changed.
+ * @throws Error if the throwable was an {@link Error}.
+ */
+ protected boolean setException(Throwable throwable) {
+ boolean result = sync.setException(checkNotNull(throwable));
+ if (result) {
+ executionList.execute();
+ }
+
+ // If it's an Error, we want to make sure it reaches the top of the
+ // call stack, so we rethrow it.
+ if (throwable instanceof Error) {
+ throw (Error) throwable;
+ }
+ return result;
+ }
+
+ /**
+ * <p>Following the contract of {@link AbstractQueuedSynchronizer} we create a
+ * 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 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 or CANCELLED.
+ *
+ * <p>We don't use the integer argument passed between acquire methods so we
+ * pass around a -1 everywhere.
+ */
+ static final class Sync<V> extends AbstractQueuedSynchronizer {
+
+ private static final long serialVersionUID = 0L;
+
+ /* Valid states. */
+ static final int RUNNING = 0;
+ static final int COMPLETING = 1;
+ static final int COMPLETED = 2;
+ static final int CANCELLED = 4;
+
+ private V value;
+ private Throwable exception;
+
+ /*
+ * Acquisition succeeds if the future is done, otherwise it fails.
+ */
+ @Override
+ protected int tryAcquireShared(int ignored) {
+ if (isDone()) {
+ return 1;
+ }
+ return -1;
+ }
+
+ /*
+ * We always allow a release to go through, this means the state has been
+ * successfully changed and the result is available.
+ */
+ @Override
+ protected boolean tryReleaseShared(int finalState) {
+ setState(finalState);
+ return true;
+ }
+
+ /**
+ * Blocks until the task is complete or the timeout expires. Throws a
+ * {@link TimeoutException} if the timer expires, otherwise behaves like
+ * {@link #get()}.
+ */
+ V get(long nanos) throws TimeoutException, CancellationException,
+ ExecutionException, InterruptedException {
+
+ // Attempt to acquire the shared lock with a timeout.
+ if (!tryAcquireSharedNanos(-1, nanos)) {
+ throw new TimeoutException("Timeout waiting for task.");
+ }
+
+ return getValue();
+ }
+
+ /**
+ * Blocks until {@link #complete(Object, Throwable, int)} has been
+ * successfully called. Throws a {@link CancellationException} if the task
+ * was cancelled, or a {@link ExecutionException} if the task completed with
+ * an error.
+ */
+ V get() throws CancellationException, ExecutionException,
+ InterruptedException {
+
+ // Acquire the shared lock allowing interruption.
+ acquireSharedInterruptibly(-1);
+ return getValue();
+ }
+
+ /**
+ * Implementation of the actual value retrieval. Will return the value
+ * on success, an exception on failure, a cancellation on cancellation, or
+ * an illegal state if the synchronizer is in an invalid state.
+ */
+ private V getValue() throws CancellationException, ExecutionException {
+ int state = getState();
+ switch (state) {
+ case COMPLETED:
+ if (exception != null) {
+ throw new ExecutionException(exception);
+ } else {
+ return value;
+ }
+
+ case CANCELLED:
+ throw new CancellationException("Task was cancelled.");
+
+ default:
+ throw new IllegalStateException(
+ "Error, synchronizer in invalid state: " + state);
+ }
+ }
+
+ /**
+ * Checks if the state is {@link #COMPLETED} or {@link #CANCELLED}.
+ */
+ boolean isDone() {
+ return (getState() & (COMPLETED | CANCELLED)) != 0;
+ }
+
+ /**
+ * Checks if the state is {@link #CANCELLED}.
+ */
+ boolean isCancelled() {
+ return getState() == CANCELLED;
+ }
+
+ /**
+ * Transition to the COMPLETED state and set the value.
+ */
+ boolean set(@Nullable V v) {
+ return complete(v, null, COMPLETED);
+ }
+
+ /**
+ * Transition to the COMPLETED state and set the exception.
+ */
+ boolean setException(Throwable t) {
+ return complete(null, t, COMPLETED);
+ }
+
+ /**
+ * Transition to the CANCELLED state.
+ */
+ boolean cancel() {
+ return complete(null, null, CANCELLED);
+ }
+
+ /**
+ * Implementation of completing a task. Either {@code v} or {@code t} will
+ * 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} 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.
+ * @param finalState the state to transition to.
+ */
+ private boolean complete(@Nullable V v, @Nullable Throwable t,
+ int finalState) {
+ boolean doCompletion = compareAndSetState(RUNNING, COMPLETING);
+ if (doCompletion) {
+ // If this thread successfully transitioned to COMPLETING, set the value
+ // and exception and then release to the final state.
+ this.value = v;
+ this.exception = t;
+ releaseShared(finalState);
+ } else if (getState() == COMPLETING) {
+ // If some other thread is currently completing the future, block until
+ // they are done so we can guarantee completion.
+ acquireShared(-1);
+ }
+ return doCompletion;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/AbstractIdleService.java b/guava/src/com/google/common/util/concurrent/AbstractIdleService.java
new file mode 100644
index 0000000..6d49ddd
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AbstractIdleService.java
@@ -0,0 +1,132 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Throwables;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Base class for services that do not need a thread while "running"
+ * but may need one during startup and shutdown. Subclasses can
+ * implement {@link #startUp} and {@link #shutDown} methods, each
+ * which run in a executor which by default uses a separate thread
+ * for each method.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public abstract class AbstractIdleService implements Service {
+
+ /* use AbstractService for state management */
+ private final Service delegate = new AbstractService() {
+ @Override protected final void doStart() {
+ executor(State.STARTING).execute(new Runnable() {
+ @Override public void run() {
+ try {
+ startUp();
+ notifyStarted();
+ } catch (Throwable t) {
+ notifyFailed(t);
+ throw Throwables.propagate(t);
+ }
+ }
+ });
+ }
+
+ @Override protected final void doStop() {
+ executor(State.STOPPING).execute(new Runnable() {
+ @Override public void run() {
+ try {
+ shutDown();
+ notifyStopped();
+ } catch (Throwable t) {
+ notifyFailed(t);
+ throw Throwables.propagate(t);
+ }
+ }
+ });
+ }
+ };
+
+ /** Start the service. */
+ protected abstract void startUp() throws Exception;
+
+ /** Stop the service. */
+ protected abstract void shutDown() throws Exception;
+
+ /**
+ * Returns the {@link Executor} that will be used to run this service.
+ * Subclasses may override this method to use a custom {@link Executor}, which
+ * may configure its worker thread with a specific name, thread group or
+ * 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) {
+ return new Executor() {
+ @Override
+ public void execute(Runnable command) {
+ new Thread(command, getServiceName() + " " + state).start();
+ }
+ };
+ }
+
+ @Override public String toString() {
+ return getServiceName() + " [" + state() + "]";
+ }
+
+ // We override instead of using ForwardingService so that these can be final.
+
+ @Override public final ListenableFuture<State> start() {
+ return delegate.start();
+ }
+
+ @Override public final State startAndWait() {
+ return delegate.startAndWait();
+ }
+
+ @Override public final boolean isRunning() {
+ return delegate.isRunning();
+ }
+
+ @Override public final State state() {
+ return delegate.state();
+ }
+
+ @Override public final ListenableFuture<State> stop() {
+ return delegate.stop();
+ }
+
+ @Override public final State stopAndWait() {
+ return delegate.stopAndWait();
+ }
+
+ @Override public final void addListener(Listener listener, Executor executor) {
+ delegate.addListener(listener, executor);
+ }
+
+ 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
new file mode 100644
index 0000000..4e867a6
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AbstractListeningExecutorService.java
@@ -0,0 +1,163 @@
+/*
+ * This file is a modified version of
+ * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/AbstractExecutorService.java?revision=1.35
+ * 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/
+ *
+ * Rationale for copying:
+ * Guava targets JDK5, whose AbstractExecutorService class lacks the newTaskFor protected
+ * customization methods needed by MoreExecutors.listeningDecorator. This class is a copy of
+ * AbstractExecutorService from the JSR166 CVS repository. It contains the desired methods.
+ */
+
+package com.google.common.util.concurrent;
+
+import static com.google.common.util.concurrent.MoreExecutors.invokeAnyImpl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Implements {@link ListeningExecutorService} execution methods atop the abstract {@link #execute}
+ * method. More concretely, the {@code submit}, {@code invokeAny} and {@code invokeAll} methods
+ * create {@link ListenableFutureTask} instances and pass them to {@link #execute}.
+ *
+ * <p>In addition to {@link #execute}, subclasses must implement all methods related to shutdown and
+ * termination.
+ *
+ * @author Doug Lea
+ */
+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, T result) {
+ ListenableFutureTask<T> ftask = ListenableFutureTask.create(task, result);
+ execute(ftask);
+ return ftask;
+ }
+
+ @Override public <T> ListenableFuture<T> submit(Callable<T> task) {
+ ListenableFutureTask<T> ftask = ListenableFutureTask.create(task);
+ execute(ftask);
+ return ftask;
+ }
+
+ @Override public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException, ExecutionException {
+ try {
+ return invokeAnyImpl(this, tasks, false, 0);
+ } catch (TimeoutException cannotHappen) {
+ throw new AssertionError();
+ }
+ }
+
+ @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));
+ }
+
+ @Override public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException {
+ if (tasks == null) {
+ throw new NullPointerException();
+ }
+ List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
+ boolean done = false;
+ try {
+ for (Callable<T> t : tasks) {
+ ListenableFutureTask<T> f = ListenableFutureTask.create(t);
+ futures.add(f);
+ execute(f);
+ }
+ for (Future<T> f : futures) {
+ if (!f.isDone()) {
+ try {
+ f.get();
+ } catch (CancellationException ignore) {
+ } catch (ExecutionException ignore) {
+ }
+ }
+ }
+ done = true;
+ return futures;
+ } finally {
+ if (!done) {
+ for (Future<T> f : futures) {
+ f.cancel(true);
+ }
+ }
+ }
+ }
+
+ @Override public <T> List<Future<T>> invokeAll(
+ Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ if (tasks == null || unit == null) {
+ throw new NullPointerException();
+ }
+ long nanos = unit.toNanos(timeout);
+ List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
+ boolean done = false;
+ try {
+ for (Callable<T> t : tasks) {
+ futures.add(ListenableFutureTask.create(t));
+ }
+
+ long lastTime = System.nanoTime();
+
+ // Interleave time checks and calls to execute in case
+ // executor doesn't have any/much parallelism.
+ Iterator<Future<T>> it = futures.iterator();
+ while (it.hasNext()) {
+ execute((Runnable) (it.next()));
+ long now = System.nanoTime();
+ nanos -= now - lastTime;
+ lastTime = now;
+ if (nanos <= 0) {
+ return futures;
+ }
+ }
+
+ for (Future<T> f : futures) {
+ if (!f.isDone()) {
+ if (nanos <= 0) {
+ return futures;
+ }
+ try {
+ f.get(nanos, TimeUnit.NANOSECONDS);
+ } catch (CancellationException ignore) {
+ } catch (ExecutionException ignore) {
+ } catch (TimeoutException toe) {
+ return futures;
+ }
+ long now = System.nanoTime();
+ nanos -= now - lastTime;
+ lastTime = now;
+ }
+ }
+ done = true;
+ return futures;
+ } finally {
+ if (!done) {
+ for (Future<T> f : futures) {
+ f.cancel(true);
+ }
+ }
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
new file mode 100644
index 0000000..cfc7475
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AbstractScheduledService.java
@@ -0,0 +1,446 @@
+/*
+ * 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.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.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.annotation.concurrent.GuardedBy;
+
+/**
+ * Base class for services that can implement {@link #startUp} and {@link #shutDown} but while in
+ * the "running" state need to perform a periodic task. Subclasses can implement {@link #startUp},
+ * {@link #shutDown} and also a {@link #runOneIteration} method that will be executed periodically.
+ *
+ * <p>This class uses the {@link ScheduledExecutorService} returned from {@link #executor} to run
+ * the {@link #startUp} and {@link #shutDown} methods and also uses that service to schedule the
+ * {@link #runOneIteration} that will be executed periodically as specified by its
+ * {@link Scheduler}. When this service is asked to stop via {@link #stop} or {@link #stopAndWait},
+ * it will cancel the periodic task (but not interrupt it) and wait for it to stop before running
+ * the {@link #shutDown} method.
+ *
+ * <p>Subclasses are guaranteed that the life cycle methods ({@link #runOneIteration}, {@link
+ * #startUp} and {@link #shutDown}) will never run concurrently. Notably, if any execution of {@link
+ * #runOneIteration} takes longer than its schedule defines, then subsequent executions may start
+ * late. Also, all life cycle methods are executed with a lock held, so subclasses can safely
+ * modify shared state without additional synchronization necessary for visibility to later
+ * executions of the life cycle methods.
+ *
+ * <h3>Usage Example</h3>
+ *
+ * Here is a sketch of a service which crawls a website and uses the scheduling capabilities to
+ * rate limit itself. <pre> {@code
+ * class CrawlingService extends AbstractScheduledService {
+ * private Set<Uri> visited;
+ * private Queue<Uri> toCrawl;
+ * protected void startUp() throws Exception {
+ * toCrawl = readStartingUris();
+ * }
+ *
+ * protected void runOneIteration() throws Exception {
+ * Uri uri = toCrawl.remove();
+ * Collection<Uri> newUris = crawl(uri);
+ * visited.add(uri);
+ * for (Uri newUri : newUris) {
+ * if (!visited.contains(newUri)) { toCrawl.add(newUri); }
+ * }
+ * }
+ *
+ * protected void shutDown() throws Exception {
+ * saveUris(toCrawl);
+ * }
+ *
+ * protected Scheduler scheduler() {
+ * return Scheduler.newFixedRateSchedule(0, 1, TimeUnit.SECONDS);
+ * }
+ * }}</pre>
+ *
+ * This class uses the life cycle methods to read in a list of starting URIs and save the set of
+ * outstanding URIs when shutting down. Also, it takes advantage of the scheduling functionality to
+ * rate limit the number of queries we perform.
+ *
+ * @author Luke Sandberg
+ * @since 11.0
+ */
+@Beta
+public abstract class AbstractScheduledService implements Service {
+ private static final Logger logger = Logger.getLogger(AbstractScheduledService.class.getName());
+
+ /**
+ * A scheduler defines the policy for how the {@link AbstractScheduledService} should run its
+ * task.
+ *
+ * <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 the
+ * {@link CustomScheduler} abstract class in preference to creating your own {@link Scheduler}
+ * implementation.
+ *
+ * @author Luke Sandberg
+ * @since 11.0
+ */
+ public abstract static class Scheduler {
+ /**
+ * Returns a {@link Scheduler} that schedules the task using the
+ * {@link ScheduledExecutorService#scheduleWithFixedDelay} method.
+ *
+ * @param initialDelay the time to delay first execution
+ * @param delay the delay between the termination of one execution and the commencement of the
+ * next
+ * @param unit the time unit of the initialDelay and delay parameters
+ */
+ public static Scheduler newFixedDelaySchedule(final long initialDelay, final long delay,
+ final TimeUnit unit) {
+ return new Scheduler() {
+ @Override
+ public Future<?> schedule(AbstractService service, ScheduledExecutorService executor,
+ Runnable task) {
+ return executor.scheduleWithFixedDelay(task, initialDelay, delay, unit);
+ }
+ };
+ }
+
+ /**
+ * Returns a {@link Scheduler} that schedules the task using the
+ * {@link ScheduledExecutorService#scheduleAtFixedRate} method.
+ *
+ * @param initialDelay the time to delay first execution
+ * @param period the period between successive executions of the task
+ * @param unit the time unit of the initialDelay and period parameters
+ */
+ public static Scheduler newFixedRateSchedule(final long initialDelay, final long period,
+ final TimeUnit unit) {
+ return new Scheduler() {
+ @Override
+ public Future<?> schedule(AbstractService service, ScheduledExecutorService executor,
+ Runnable task) {
+ return executor.scheduleAtFixedRate(task, initialDelay, period, unit);
+ }
+ };
+ }
+
+ /** Schedules the task to run on the provided executor on behalf of the service. */
+ abstract Future<?> schedule(AbstractService service, ScheduledExecutorService executor,
+ Runnable runnable);
+
+ private Scheduler() {}
+ }
+
+ /* use AbstractService for state management */
+ private final AbstractService delegate = new AbstractService() {
+
+ // A handle to the running task so that we can stop it when a shutdown has been requested.
+ // These two fields are volatile because their values will be accessed from multiple threads.
+ private volatile Future<?> runningTask;
+ private volatile ScheduledExecutorService executorService;
+
+ // This lock protects the task so we can ensure that none of the template methods (startUp,
+ // shutDown or runOneIteration) run concurrently with one another.
+ private final ReentrantLock lock = new ReentrantLock();
+
+ private final Runnable task = new Runnable() {
+ @Override public void run() {
+ lock.lock();
+ try {
+ AbstractScheduledService.this.runOneIteration();
+ } catch (Throwable t) {
+ try {
+ shutDown();
+ } catch (Exception ignored) {
+ logger.log(Level.WARNING,
+ "Error while attempting to shut down the service after failure.", ignored);
+ }
+ notifyFailed(t);
+ throw Throwables.propagate(t);
+ } finally {
+ lock.unlock();
+ }
+ }
+ };
+
+ @Override protected final void doStart() {
+ executorService = executor();
+ executorService.execute(new Runnable() {
+ @Override public void run() {
+ lock.lock();
+ try {
+ startUp();
+ runningTask = scheduler().schedule(delegate, executorService, task);
+ notifyStarted();
+ } catch (Throwable t) {
+ notifyFailed(t);
+ throw Throwables.propagate(t);
+ } finally {
+ lock.unlock();
+ }
+ }
+ });
+ }
+
+ @Override protected final void doStop() {
+ runningTask.cancel(false);
+ executorService.execute(new Runnable() {
+ @Override public void run() {
+ try {
+ lock.lock();
+ try {
+ if (state() != State.STOPPING) {
+ // This means that the state has changed since we were scheduled. This implies that
+ // an execution of runOneIteration has thrown an exception and we have transitioned
+ // to a failed state, also this means that shutDown has already been called, so we
+ // do not want to call it again.
+ return;
+ }
+ shutDown();
+ } finally {
+ lock.unlock();
+ }
+ notifyStopped();
+ } catch (Throwable t) {
+ notifyFailed(t);
+ throw Throwables.propagate(t);
+ }
+ }
+ });
+ }
+ };
+
+ /**
+ * 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
+ * longer be called.
+ */
+ protected abstract void runOneIteration() throws Exception;
+
+ /**
+ * Start the service.
+ *
+ * <p>By default this method does nothing.
+ */
+ protected 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 {}
+
+ /**
+ * Returns the {@link Scheduler} object used to configure this service. This method will only be
+ * called once.
+ */
+ protected abstract Scheduler scheduler();
+
+ /**
+ * Returns the {@link ScheduledExecutorService} that will be used to execute the {@link #startUp},
+ * {@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. This method will only be called once.
+ */
+ protected ScheduledExecutorService executor() {
+ return Executors.newSingleThreadScheduledExecutor();
+ }
+
+ @Override public String toString() {
+ return getClass().getSimpleName() + " [" + state() + "]";
+ }
+
+ // We override instead of using ForwardingService so that these can be final.
+
+ @Override public final ListenableFuture<State> start() {
+ return delegate.start();
+ }
+
+ @Override public final State startAndWait() {
+ return delegate.startAndWait();
+ }
+
+ @Override public final boolean isRunning() {
+ return delegate.isRunning();
+ }
+
+ @Override public final State state() {
+ return delegate.state();
+ }
+
+ @Override public final ListenableFuture<State> stop() {
+ return delegate.stop();
+ }
+
+ @Override public final State stopAndWait() {
+ return delegate.stopAndWait();
+ }
+
+ @Override public final void addListener(Listener listener, Executor executor) {
+ delegate.addListener(listener, executor);
+ }
+
+ /**
+ * 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.
+ *
+ * @author Luke Sandberg
+ * @since 11.0
+ */
+ @Beta
+ public abstract static class CustomScheduler extends Scheduler {
+
+ /**
+ * A callable class that can reschedule itself using a {@link CustomScheduler}.
+ */
+ private class ReschedulableCallable extends ForwardingFuture<Void> implements Callable<Void> {
+
+ /** The underlying task. */
+ private final Runnable wrappedRunnable;
+
+ /** The executor on which this Callable will be scheduled. */
+ private final ScheduledExecutorService executor;
+
+ /**
+ * The service that is managing this callable. This is used so that failure can be
+ * reported properly.
+ */
+ private final AbstractService service;
+
+ /**
+ * This lock is used to ensure safe and correct cancellation, it ensures that a new task is
+ * not scheduled while a cancel is ongoing. Also it protects the currentFuture variable to
+ * ensure that it is assigned atomically with being scheduled.
+ */
+ private final ReentrantLock lock = new ReentrantLock();
+
+ /** The future that represents the next execution of this task.*/
+ @GuardedBy("lock")
+ private Future<Void> currentFuture;
+
+ ReschedulableCallable(AbstractService service, ScheduledExecutorService executor,
+ Runnable runnable) {
+ this.wrappedRunnable = runnable;
+ this.executor = executor;
+ this.service = service;
+ }
+
+ @Override
+ public Void call() throws Exception {
+ wrappedRunnable.run();
+ reschedule();
+ return null;
+ }
+
+ /**
+ * Atomically reschedules this task and assigns the new future to {@link #currentFuture}.
+ */
+ public void reschedule() {
+ // We reschedule ourselves with a lock held for two reasons. 1. we want to make sure that
+ // cancel calls cancel on the correct future. 2. we want to make sure that the assignment
+ // to currentFuture doesn't race with itself so that currentFuture is assigned in the
+ // correct order.
+ lock.lock();
+ try {
+ if (currentFuture == null || !currentFuture.isCancelled()) {
+ final Schedule schedule = CustomScheduler.this.getNextSchedule();
+ currentFuture = executor.schedule(this, schedule.delay, schedule.unit);
+ }
+ } catch (Throwable e) {
+ // If an exception is thrown by the subclass then we need to make sure that the service
+ // notices and transitions to the FAILED state. We do it by calling notifyFailed directly
+ // because the service does not monitor the state of the future so if the exception is not
+ // caught and forwarded to the service the task would stop executing but the service would
+ // have no idea.
+ service.notifyFailed(e);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ // N.B. Only protect cancel and isCancelled because those are the only methods that are
+ // invoked by the AbstractScheduledService.
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ // Ensure that a task cannot be rescheduled while a cancel is ongoing.
+ lock.lock();
+ try {
+ return currentFuture.cancel(mayInterruptIfRunning);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ protected Future<Void> delegate() {
+ throw new UnsupportedOperationException("Only cancel is supported by this future");
+ }
+ }
+
+ @Override
+ final Future<?> schedule(AbstractService service, ScheduledExecutorService executor,
+ Runnable runnable) {
+ ReschedulableCallable task = new ReschedulableCallable(service, executor, runnable);
+ task.reschedule();
+ return task;
+ }
+
+ /**
+ * A value object that represents an absolute delay until a task should be invoked.
+ *
+ * @author Luke Sandberg
+ * @since 11.0
+ */
+ @Beta
+ protected static final class Schedule {
+
+ private final long delay;
+ private final TimeUnit unit;
+
+ /**
+ * @param delay the time from now to delay execution
+ * @param unit the time unit of the delay parameter
+ */
+ public Schedule(long delay, TimeUnit unit) {
+ this.delay = delay;
+ this.unit = Preconditions.checkNotNull(unit);
+ }
+ }
+
+ /**
+ * Calculates the time at which to next invoke the task.
+ *
+ * <p>This is guaranteed to be called immediately after the task has completed an iteration and
+ * on the same thread as the previous execution of {@link
+ * AbstractScheduledService#runOneIteration}.
+ *
+ * @return a schedule that defines the delay before the next execution.
+ */
+ protected abstract Schedule getNextSchedule() throws Exception;
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/AbstractService.java b/guava/src/com/google/common/util/concurrent/AbstractService.java
new file mode 100644
index 0000000..a2e14fe
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AbstractService.java
@@ -0,0 +1,536 @@
+/*
+ * 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.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.
+ *
+ * @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.
+ */
+ @GuardedBy("queuedListeners")
+ private final Queue<Runnable> queuedListeners = Queues.newConcurrentLinkedQueue();
+
+ /**
+ * 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.
+ */
+ @GuardedBy("lock")
+ private volatile StateSnapshot snapshot = new StateSnapshot(State.NEW);
+
+ 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.
+ *
+ * <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.
+ *
+ * <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();
+
+ @Override
+ public final ListenableFuture<State> start() {
+ lock.lock();
+ try {
+ if (snapshot.state == State.NEW) {
+ snapshot = new StateSnapshot(State.STARTING);
+ starting();
+ doStart();
+ }
+ } catch (Throwable startupFailure) {
+ notifyFailed(startupFailure);
+ } finally {
+ lock.unlock();
+ executeListeners();
+ }
+
+ return startup;
+ }
+
+ @Override
+ 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);
+ }
+ } catch (Throwable shutdownFailure) {
+ notifyFailed(shutdownFailure);
+ } finally {
+ lock.unlock();
+ executeListeners();
+ }
+
+ return shutdown;
+ }
+
+ @Override
+ public State startAndWait() {
+ return Futures.getUnchecked(start());
+ }
+
+ @Override
+ public State stopAndWait() {
+ return Futures.getUnchecked(stop());
+ }
+
+ /**
+ * 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}.
+ */
+ protected final void notifyStarted() {
+ lock.lock();
+ try {
+ if (snapshot.state != State.STARTING) {
+ IllegalStateException failure = new IllegalStateException(
+ "Cannot notifyStarted() when the service is " + snapshot.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();
+ } else {
+ snapshot = new StateSnapshot(State.RUNNING);
+ 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}.
+ *
+ * @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) {
+ IllegalStateException failure = new IllegalStateException(
+ "Cannot notifyStopped() when the service is " + snapshot.state);
+ notifyFailed(failure);
+ throw failure;
+ }
+ State previous = snapshot.state;
+ snapshot = new StateSnapshot(State.TERMINATED);
+ terminated(previous);
+ } 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.
+ */
+ 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);
+ }
+ } finally {
+ lock.unlock();
+ executeListeners();
+ }
+ }
+
+ @Override
+ public final boolean isRunning() {
+ return state() == State.RUNNING;
+ }
+
+ @Override
+ public final State state() {
+ return snapshot.externalState();
+ }
+
+ @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));
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override public String toString() {
+ return getClass().getSimpleName() + " [" + state() + "]";
+ }
+
+ /**
+ * A change from one service state to another, plus the result of the change.
+ */
+ private class Transition extends AbstractFuture<State> {
+ @Override
+ public State get(long timeout, TimeUnit unit)
+ throws InterruptedException, TimeoutException, ExecutionException {
+ try {
+ return super.get(timeout, unit);
+ } catch (TimeoutException e) {
+ throw new TimeoutException(AbstractService.this.toString());
+ }
+ }
+ }
+
+ /**
+ * 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, 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
new file mode 100644
index 0000000..441c029
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AsyncFunction.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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.Future;
+
+/**
+ * Transforms a value, possibly asynchronously. For an example usage and more
+ * information, see {@link Futures#transform(ListenableFuture, AsyncFunction)}.
+ *
+ * @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
+ * input}. The output {@code Future} need not be {@linkplain Future#isDone
+ * done}, making {@code AsyncFunction} suitable for asynchronous derivations.
+ *
+ * <p>Throwing an exception from this method is equivalent to returning a
+ * failing {@code Future}.
+ */
+ ListenableFuture<O> apply(I input) throws Exception;
+}
diff --git a/guava/src/com/google/common/util/concurrent/AtomicDouble.java b/guava/src/com/google/common/util/concurrent/AtomicDouble.java
new file mode 100644
index 0000000..615d7a9
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AtomicDouble.java
@@ -0,0 +1,257 @@
+/*
+ * Written by Doug Lea and Martin Buchholz 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/extra/AtomicDouble.java?revision=1.13
+ * (Modified to adapt to guava coding conventions and
+ * to use AtomicLongFieldUpdater instead of sun.misc.Unsafe)
+ */
+
+package com.google.common.util.concurrent;
+
+import static java.lang.Double.doubleToRawLongBits;
+import static java.lang.Double.longBitsToDouble;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+
+/**
+ * A {@code double} value that may be updated atomically. See the
+ * {@link java.util.concurrent.atomic} package specification for
+ * description of the properties of atomic variables. An {@code
+ * AtomicDouble} is used in applications such as atomic accumulation,
+ * and cannot be used as a replacement for a {@link Double}. However,
+ * this class does extend {@code Number} to allow uniform access by
+ * tools and utilities that deal with numerically-based classes.
+ *
+ * <p><a name="bitEquals">This class compares primitive {@code double}
+ * values in methods such as {@link #compareAndSet} by comparing their
+ * bitwise representation using {@link Double#doubleToRawLongBits},
+ * which differs from both the primitive double {@code ==} operator
+ * and from {@link Double#equals}, as if implemented by:
+ * <pre> {@code
+ * static boolean bitEquals(double x, double y) {
+ * long xBits = Double.doubleToRawLongBits(x);
+ * long yBits = Double.doubleToRawLongBits(y);
+ * return xBits == yBits;
+ * }}</pre>
+ *
+ * <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>
+ * and
+ * <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;
+
+ private transient volatile long value;
+
+ private static final AtomicLongFieldUpdater<AtomicDouble> updater =
+ AtomicLongFieldUpdater.newUpdater(AtomicDouble.class, "value");
+
+ /**
+ * Creates a new {@code AtomicDouble} with the given initial value.
+ *
+ * @param initialValue the initial value
+ */
+ public AtomicDouble(double initialValue) {
+ value = doubleToRawLongBits(initialValue);
+ }
+
+ /**
+ * Creates a new {@code AtomicDouble} with initial value {@code 0.0}.
+ */
+ public AtomicDouble() {
+ // assert doubleToRawLongBits(0.0) == 0L;
+ }
+
+ /**
+ * Gets the current value.
+ *
+ * @return the current value
+ */
+ public final double get() {
+ return longBitsToDouble(value);
+ }
+
+ /**
+ * Sets to the given value.
+ *
+ * @param newValue the new value
+ */
+ public final void set(double newValue) {
+ long next = doubleToRawLongBits(newValue);
+ value = next;
+ }
+
+ /**
+ * Eventually sets to the given value.
+ *
+ * @param newValue the new value
+ */
+ public final void lazySet(double newValue) {
+ set(newValue);
+ // TODO(user): replace with code below when jdk5 support is dropped.
+ // long next = doubleToRawLongBits(newValue);
+ // updater.lazySet(this, next);
+ }
+
+ /**
+ * Atomically sets to the given value and returns the old value.
+ *
+ * @param newValue the new value
+ * @return the previous value
+ */
+ public final double getAndSet(double newValue) {
+ long next = doubleToRawLongBits(newValue);
+ return longBitsToDouble(updater.getAndSet(this, next));
+ }
+
+ /**
+ * Atomically sets the value to the given updated value
+ * if the current value is <a href="#bitEquals">bitwise equal</a>
+ * to the expected value.
+ *
+ * @param expect the expected value
+ * @param update the new value
+ * @return {@code true} if successful. False return indicates that
+ * the actual value was not bitwise equal to the expected value.
+ */
+ public final boolean compareAndSet(double expect, double update) {
+ return updater.compareAndSet(this,
+ doubleToRawLongBits(expect),
+ doubleToRawLongBits(update));
+ }
+
+ /**
+ * Atomically sets the value to the given updated value
+ * if the current value is <a href="#bitEquals">bitwise equal</a>
+ * to the expected value.
+ *
+ * <p>May <a
+ * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
+ * fail spuriously</a>
+ * and does not provide ordering guarantees, so is only rarely an
+ * appropriate alternative to {@code compareAndSet}.
+ *
+ * @param expect the expected value
+ * @param update the new value
+ * @return {@code true} if successful
+ */
+ public final boolean weakCompareAndSet(double expect, double update) {
+ return updater.weakCompareAndSet(this,
+ doubleToRawLongBits(expect),
+ doubleToRawLongBits(update));
+ }
+
+ /**
+ * Atomically adds the given value to the current value.
+ *
+ * @param delta the value to add
+ * @return the previous value
+ */
+ public final double getAndAdd(double delta) {
+ while (true) {
+ long current = value;
+ double currentVal = longBitsToDouble(current);
+ double nextVal = currentVal + delta;
+ long next = doubleToRawLongBits(nextVal);
+ if (updater.compareAndSet(this, current, next)) {
+ return currentVal;
+ }
+ }
+ }
+
+ /**
+ * Atomically adds the given value to the current value.
+ *
+ * @param delta the value to add
+ * @return the updated value
+ */
+ public final double addAndGet(double delta) {
+ while (true) {
+ long current = value;
+ double currentVal = longBitsToDouble(current);
+ double nextVal = currentVal + delta;
+ long next = doubleToRawLongBits(nextVal);
+ if (updater.compareAndSet(this, current, next)) {
+ return nextVal;
+ }
+ }
+ }
+
+ /**
+ * Returns the String representation of the current value.
+ * @return the String representation of the current value
+ */
+ public String toString() {
+ return Double.toString(get());
+ }
+
+ /**
+ * Returns the value of this {@code AtomicDouble} as an {@code int}
+ * after a narrowing primitive conversion.
+ */
+ public int intValue() {
+ return (int) get();
+ }
+
+ /**
+ * Returns the value of this {@code AtomicDouble} as a {@code long}
+ * after a narrowing primitive conversion.
+ */
+ public long longValue() {
+ return (long) get();
+ }
+
+ /**
+ * Returns the value of this {@code AtomicDouble} as a {@code float}
+ * after a narrowing primitive conversion.
+ */
+ public float floatValue() {
+ return (float) get();
+ }
+
+ /**
+ * Returns the value of this {@code AtomicDouble} as a {@code double}.
+ */
+ public double doubleValue() {
+ return get();
+ }
+
+ /**
+ * Saves the state to a stream (that is, serializes it).
+ *
+ * @serialData The current value is emitted (a {@code double}).
+ */
+ private void writeObject(java.io.ObjectOutputStream s)
+ throws java.io.IOException {
+ s.defaultWriteObject();
+
+ s.writeDouble(get());
+ }
+
+ /**
+ * Reconstitutes the instance from a stream (that is, deserializes it).
+ */
+ private void readObject(java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException {
+ s.defaultReadObject();
+
+ set(s.readDouble());
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/AtomicDoubleArray.java b/guava/src/com/google/common/util/concurrent/AtomicDoubleArray.java
new file mode 100644
index 0000000..8da0195
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AtomicDoubleArray.java
@@ -0,0 +1,271 @@
+/*
+ * 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/extra/AtomicDoubleArray.java?revision=1.5
+ * (Modified to adapt to guava coding conventions and
+ * to use AtomicLongArray instead of sun.misc.Unsafe)
+ */
+
+package com.google.common.util.concurrent;
+
+import static java.lang.Double.doubleToRawLongBits;
+import static java.lang.Double.longBitsToDouble;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.atomic.AtomicLongArray;
+
+/**
+ * A {@code double} array in which elements may be updated atomically.
+ * See the {@link java.util.concurrent.atomic} package specification
+ * for description of the properties of atomic variables.
+ *
+ * <p><a name="bitEquals">This class compares primitive {@code double}
+ * values in methods such as {@link #compareAndSet} by comparing their
+ * bitwise representation using {@link Double#doubleToRawLongBits},
+ * which differs from both the primitive double {@code ==} operator
+ * and from {@link Double#equals}, as if implemented by:
+ * <pre> {@code
+ * static boolean bitEquals(double x, double y) {
+ * long xBits = Double.doubleToRawLongBits(x);
+ * long yBits = Double.doubleToRawLongBits(y);
+ * return xBits == yBits;
+ * }}</pre>
+ *
+ * @author Doug Lea
+ * @author Martin Buchholz
+ * @since 11.0
+ */
+@Beta
+public class AtomicDoubleArray implements java.io.Serializable {
+ private static final long serialVersionUID = 0L;
+
+ // Making this non-final is the lesser evil according to Effective
+ // Java 2nd Edition Item 76: Write readObject methods defensively.
+ private transient AtomicLongArray longs;
+
+ /**
+ * Creates a new {@code AtomicDoubleArray} of the given length,
+ * with all elements initially zero.
+ *
+ * @param length the length of the array
+ */
+ public AtomicDoubleArray(int length) {
+ this.longs = new AtomicLongArray(length);
+ }
+
+ /**
+ * Creates a new {@code AtomicDoubleArray} with the same length
+ * as, and all elements copied from, the given array.
+ *
+ * @param array the array to copy elements from
+ * @throws NullPointerException if array is null
+ */
+ public AtomicDoubleArray(double[] array) {
+ final int len = array.length;
+ long[] longArray = new long[len];
+ for (int i = 0; i < len; i++) {
+ longArray[i] = doubleToRawLongBits(array[i]);
+ }
+ this.longs = new AtomicLongArray(longArray);
+ }
+
+ /**
+ * Returns the length of the array.
+ *
+ * @return the length of the array
+ */
+ public final int length() {
+ return longs.length();
+ }
+
+ /**
+ * Gets the current value at position {@code i}.
+ *
+ * @param i the index
+ * @return the current value
+ */
+ public final double get(int i) {
+ return longBitsToDouble(longs.get(i));
+ }
+
+ /**
+ * Sets the element at position {@code i} to the given value.
+ *
+ * @param i the index
+ * @param newValue the new value
+ */
+ public final void set(int i, double newValue) {
+ long next = doubleToRawLongBits(newValue);
+ longs.set(i, next);
+ }
+
+ /**
+ * Eventually sets the element at position {@code i} to the given value.
+ *
+ * @param i the index
+ * @param newValue the new value
+ */
+ public final void lazySet(int i, double newValue) {
+ set(i, newValue);
+ // TODO(user): replace with code below when jdk5 support is dropped.
+ // long next = doubleToRawLongBits(newValue);
+ // longs.lazySet(i, next);
+ }
+
+ /**
+ * Atomically sets the element at position {@code i} to the given value
+ * and returns the old value.
+ *
+ * @param i the index
+ * @param newValue the new value
+ * @return the previous value
+ */
+ public final double getAndSet(int i, double newValue) {
+ long next = doubleToRawLongBits(newValue);
+ return longBitsToDouble(longs.getAndSet(i, next));
+ }
+
+ /**
+ * Atomically sets the element at position {@code i} to the given
+ * updated value
+ * if the current value is <a href="#bitEquals">bitwise equal</a>
+ * to the expected value.
+ *
+ * @param i the index
+ * @param expect the expected value
+ * @param update the new value
+ * @return true if successful. False return indicates that
+ * the actual value was not equal to the expected value.
+ */
+ public final boolean compareAndSet(int i, double expect, double update) {
+ return longs.compareAndSet(i,
+ doubleToRawLongBits(expect),
+ doubleToRawLongBits(update));
+ }
+
+ /**
+ * Atomically sets the element at position {@code i} to the given
+ * updated value
+ * if the current value is <a href="#bitEquals">bitwise equal</a>
+ * to the expected value.
+ *
+ * <p>May <a
+ * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
+ * fail spuriously</a>
+ * and does not provide ordering guarantees, so is only rarely an
+ * appropriate alternative to {@code compareAndSet}.
+ *
+ * @param i the index
+ * @param expect the expected value
+ * @param update the new value
+ * @return true if successful
+ */
+ public final boolean weakCompareAndSet(int i, double expect, double update) {
+ return longs.weakCompareAndSet(i,
+ doubleToRawLongBits(expect),
+ doubleToRawLongBits(update));
+ }
+
+ /**
+ * Atomically adds the given value to the element at index {@code i}.
+ *
+ * @param i the index
+ * @param delta the value to add
+ * @return the previous value
+ */
+ public final double getAndAdd(int i, double delta) {
+ while (true) {
+ long current = longs.get(i);
+ double currentVal = longBitsToDouble(current);
+ double nextVal = currentVal + delta;
+ long next = doubleToRawLongBits(nextVal);
+ if (longs.compareAndSet(i, current, next)) {
+ return currentVal;
+ }
+ }
+ }
+
+ /**
+ * Atomically adds the given value to the element at index {@code i}.
+ *
+ * @param i the index
+ * @param delta the value to add
+ * @return the updated value
+ */
+ public double addAndGet(int i, double delta) {
+ while (true) {
+ long current = longs.get(i);
+ double currentVal = longBitsToDouble(current);
+ double nextVal = currentVal + delta;
+ long next = doubleToRawLongBits(nextVal);
+ if (longs.compareAndSet(i, current, next)) {
+ return nextVal;
+ }
+ }
+ }
+
+ /**
+ * Returns the String representation of the current values of array.
+ * @return the String representation of the current values of array
+ */
+ public String toString() {
+ int iMax = length() - 1;
+ if (iMax == -1) {
+ return "[]";
+ }
+
+ // Double.toString(Math.PI).length() == 17
+ StringBuilder b = new StringBuilder((17 + 2) * (iMax + 1));
+ b.append('[');
+ for (int i = 0;; i++) {
+ b.append(longBitsToDouble(longs.get(i)));
+ if (i == iMax) {
+ return b.append(']').toString();
+ }
+ b.append(',').append(' ');
+ }
+ }
+
+ /**
+ * Saves the state to a stream (that is, serializes it).
+ *
+ * @serialData The length of the array is emitted (int), followed by all
+ * of its elements (each a {@code double}) in the proper order.
+ */
+ private void writeObject(java.io.ObjectOutputStream s)
+ throws java.io.IOException {
+ s.defaultWriteObject();
+
+ // Write out array length
+ int length = length();
+ s.writeInt(length);
+
+ // Write out all elements in the proper order.
+ for (int i = 0; i < length; i++) {
+ s.writeDouble(get(i));
+ }
+ }
+
+ /**
+ * Reconstitutes the instance from a stream (that is, deserializes it).
+ */
+ private void readObject(java.io.ObjectInputStream s)
+ throws java.io.IOException, ClassNotFoundException {
+ s.defaultReadObject();
+
+ // Read in array length and allocate array
+ int length = s.readInt();
+ this.longs = new AtomicLongArray(length);
+
+ // Read in all elements in the proper order.
+ for (int i = 0; i < length; i++) {
+ set(i, s.readDouble());
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/AtomicLongMap.java b/guava/src/com/google/common/util/concurrent/AtomicLongMap.java
new file mode 100644
index 0000000..f5aafd0
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/AtomicLongMap.java
@@ -0,0 +1,434 @@
+/*
+ * 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.GwtCompatible;
+import com.google.common.base.Function;
+import com.google.common.collect.Maps;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A map containing {@code long} values that can be atomically updated. While writes to a
+ * traditional {@code Map} rely on {@code put(K, V)}, the typical mechanism for writing to this map
+ * is {@code addAndGet(K, long)}, which adds a {@code long} to the value currently associated with
+ * {@code K}. If a key has not yet been associated with a value, its implicit value is zero.
+ *
+ * <p>Most methods in this class treat absent values and zero values identically, as individually
+ * documented. Exceptions to this are {@link #containsKey}, {@link #size}, {@link #isEmpty},
+ * {@link #asMap}, and {@link #toString}.
+ *
+ * <p>Instances of this class may be used by multiple threads concurrently. All operations are
+ * atomic unless otherwise noted.
+ *
+ * <p><b>Note:</b> If your values are always positive and less than 2^31, you may wish to use a
+ * {@link com.google.common.collect.Multiset} such as
+ * {@link com.google.common.collect.ConcurrentHashMultiset} instead.
+ *
+ * <b>Warning:</b> Unlike {@code Multiset}, entries whose values are zero are not automatically
+ * removed from the map. Instead they must be removed manually with {@link #removeAllZeros}.
+ *
+ * @author Charles Fry
+ * @since 11.0
+ */
+@Beta
+@GwtCompatible
+public final class AtomicLongMap<K> {
+ private final ConcurrentHashMap<K, AtomicLong> map;
+
+ private AtomicLongMap(ConcurrentHashMap<K, AtomicLong> map) {
+ this.map = checkNotNull(map);
+ }
+
+ /**
+ * Creates an {@code AtomicLongMap}.
+ */
+ public static <K> AtomicLongMap<K> create() {
+ return new AtomicLongMap<K>(new ConcurrentHashMap<K, AtomicLong>());
+ }
+
+ /**
+ * Creates an {@code AtomicLongMap} with the same mappings as the specified {@code Map}.
+ */
+ public static <K> AtomicLongMap<K> create(Map<? extends K, ? extends Long> m) {
+ AtomicLongMap<K> result = create();
+ result.putAll(m);
+ return result;
+ }
+
+ /**
+ * Returns the value associated with {@code key}, or zero if there is no value associated with
+ * {@code key}.
+ */
+ public long get(K key) {
+ AtomicLong atomic = map.get(key);
+ return atomic == null ? 0L : atomic.get();
+ }
+
+ /**
+ * Increments by one the value currently associated with {@code key}, and returns the new value.
+ */
+ public long incrementAndGet(K key) {
+ return addAndGet(key, 1);
+ }
+
+ /**
+ * Decrements by one the value currently associated with {@code key}, and returns the new value.
+ */
+ public long decrementAndGet(K key) {
+ return addAndGet(key, -1);
+ }
+
+ /**
+ * Adds {@code delta} to the value currently associated with {@code key}, and returns the new
+ * value.
+ */
+ public long addAndGet(K key, long delta) {
+ outer: for (;;) {
+ AtomicLong atomic = map.get(key);
+ if (atomic == null) {
+ atomic = map.putIfAbsent(key, new AtomicLong(delta));
+ if (atomic == null) {
+ return delta;
+ }
+ // atomic is now non-null; fall through
+ }
+
+ for (;;) {
+ long oldValue = atomic.get();
+ if (oldValue == 0L) {
+ // don't compareAndSet a zero
+ if (map.replace(key, atomic, new AtomicLong(delta))) {
+ return delta;
+ }
+ // atomic replaced
+ continue outer;
+ }
+
+ long newValue = oldValue + delta;
+ if (atomic.compareAndSet(oldValue, newValue)) {
+ return newValue;
+ }
+ // value changed
+ }
+ }
+ }
+
+ /**
+ * Increments by one the value currently associated with {@code key}, and returns the old value.
+ */
+ public long getAndIncrement(K key) {
+ return getAndAdd(key, 1);
+ }
+
+ /**
+ * Decrements by one the value currently associated with {@code key}, and returns the old value.
+ */
+ public long getAndDecrement(K key) {
+ return getAndAdd(key, -1);
+ }
+
+ /**
+ * Adds {@code delta} to the value currently associated with {@code key}, and returns the old
+ * value.
+ */
+ public long getAndAdd(K key, long delta) {
+ outer: for (;;) {
+ AtomicLong atomic = map.get(key);
+ if (atomic == null) {
+ atomic = map.putIfAbsent(key, new AtomicLong(delta));
+ if (atomic == null) {
+ return 0L;
+ }
+ // atomic is now non-null; fall through
+ }
+
+ for (;;) {
+ long oldValue = atomic.get();
+ if (oldValue == 0L) {
+ // don't compareAndSet a zero
+ if (map.replace(key, atomic, new AtomicLong(delta))) {
+ return 0L;
+ }
+ // atomic replaced
+ continue outer;
+ }
+
+ long newValue = oldValue + delta;
+ if (atomic.compareAndSet(oldValue, newValue)) {
+ return oldValue;
+ }
+ // value changed
+ }
+ }
+ }
+
+ /**
+ * Associates {@code newValue} with {@code key} in this map, and returns the value previously
+ * associated with {@code key}, or zero if there was no such value.
+ */
+ public long put(K key, long newValue) {
+ outer: for (;;) {
+ AtomicLong atomic = map.get(key);
+ if (atomic == null) {
+ atomic = map.putIfAbsent(key, new AtomicLong(newValue));
+ if (atomic == null) {
+ return 0L;
+ }
+ // atomic is now non-null; fall through
+ }
+
+ for (;;) {
+ long oldValue = atomic.get();
+ if (oldValue == 0L) {
+ // don't compareAndSet a zero
+ if (map.replace(key, atomic, new AtomicLong(newValue))) {
+ return 0L;
+ }
+ // atomic replaced
+ continue outer;
+ }
+
+ if (atomic.compareAndSet(oldValue, newValue)) {
+ return oldValue;
+ }
+ // value changed
+ }
+ }
+ }
+
+ /**
+ * Copies all of the mappings from the specified map to this map. 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.
+ */
+ public void putAll(Map<? extends K, ? extends Long> m) {
+ for (Map.Entry<? extends K, ? extends Long> entry : m.entrySet()) {
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Removes and returns the value associated with {@code key}. If {@code key} is not
+ * in the map, this method has no effect and returns zero.
+ */
+ public long remove(K key) {
+ AtomicLong atomic = map.get(key);
+ if (atomic == null) {
+ return 0L;
+ }
+
+ for (;;) {
+ long oldValue = atomic.get();
+ if (oldValue == 0L || atomic.compareAndSet(oldValue, 0L)) {
+ // only remove after setting to zero, to avoid concurrent updates
+ map.remove(key, atomic);
+ // succeed even if the remove fails, since the value was already adjusted
+ return oldValue;
+ }
+ }
+ }
+
+ /**
+ * Removes all mappings from this map whose values are zero.
+ *
+ * <p>This method is not atomic: the map may be visible in intermediate states, where some
+ * of the zero values have been removed and others have not.
+ */
+ public void removeAllZeros() {
+ for (K key : map.keySet()) {
+ AtomicLong atomic = map.get(key);
+ if (atomic != null && atomic.get() == 0L) {
+ map.remove(key, atomic);
+ }
+ }
+ }
+
+ /**
+ * Returns the sum of all values in this map.
+ *
+ * <p>This method is not atomic: the sum may or may not include other concurrent operations.
+ */
+ public long sum() {
+ long sum = 0L;
+ for (AtomicLong value : map.values()) {
+ sum = sum + value.get();
+ }
+ return sum;
+ }
+
+ private transient Map<K, Long> asMap;
+
+ /**
+ * Returns a live, read-only view of the map backing this {@code AtomicLongMap}.
+ */
+ public Map<K, Long> asMap() {
+ Map<K, Long> result = asMap;
+ return (result == null) ? asMap = createAsMap() : result;
+ }
+
+ private Map<K, Long> createAsMap() {
+ return Collections.unmodifiableMap(
+ Maps.transformValues(map, new Function<AtomicLong, Long>() {
+ @Override
+ public Long apply(AtomicLong atomic) {
+ return atomic.get();
+ }
+ }));
+ }
+
+ /**
+ * Returns true if this map contains a mapping for the specified key.
+ */
+ public boolean containsKey(Object key) {
+ return map.containsKey(key);
+ }
+
+ /**
+ * Returns the number of key-value mappings in this map. If the map contains more than
+ * {@code Integer.MAX_VALUE} elements, returns {@code Integer.MAX_VALUE}.
+ */
+ public int size() {
+ return map.size();
+ }
+
+ /**
+ * Returns {@code true} if this map contains no key-value mappings.
+ */
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * Removes all of the mappings from this map. The map will be empty after this call returns.
+ *
+ * <p>This method is not atomic: the map may not be empty after returning if there were concurrent
+ * writes.
+ */
+ public void clear() {
+ map.clear();
+ }
+
+ @Override
+ public String toString() {
+ return map.toString();
+ }
+
+ /*
+ * ConcurrentMap operations which we may eventually add.
+ *
+ * The problem with these is that remove(K, long) has to be done in two phases by definition ---
+ * first decrementing to zero, and then removing. putIfAbsent or replace could observe the
+ * intermediate zero-state. Ways we could deal with this are:
+ *
+ * - Don't define any of the ConcurrentMap operations. This is the current state of affairs.
+ *
+ * - Define putIfAbsent and replace as treating zero and absent identically (as currently
+ * implemented below). This is a bit surprising with putIfAbsent, which really becomes
+ * putIfZero.
+ *
+ * - Allow putIfAbsent and replace to distinguish between zero and absent, but don't implement
+ * remove(K, long). Without any two-phase operations it becomes feasible for all remaining
+ * operations to distinguish between zero and absent. If we do this, then perhaps we should add
+ * replace(key, long).
+ *
+ * - Introduce a special-value private static final AtomicLong that would have the meaning of
+ * removal-in-progress, and rework all operations to properly distinguish between zero and
+ * absent.
+ */
+
+ /**
+ * If {@code key} is not already associated with a value or if {@code key} is associated with
+ * zero, associate it with {@code newValue}. Returns the previous value associated with
+ * {@code key}, or zero if there was no mapping for {@code key}.
+ */
+ long putIfAbsent(K key, long newValue) {
+ for (;;) {
+ AtomicLong atomic = map.get(key);
+ if (atomic == null) {
+ atomic = map.putIfAbsent(key, new AtomicLong(newValue));
+ if (atomic == null) {
+ return 0L;
+ }
+ // atomic is now non-null; fall through
+ }
+
+ long oldValue = atomic.get();
+ if (oldValue == 0L) {
+ // don't compareAndSet a zero
+ if (map.replace(key, atomic, new AtomicLong(newValue))) {
+ return 0L;
+ }
+ // atomic replaced
+ continue;
+ }
+
+ return oldValue;
+ }
+ }
+
+ /**
+ * If {@code (key, expectedOldValue)} is currently in the map, this method replaces
+ * {@code expectedOldValue} with {@code newValue} and returns true; otherwise, this method
+ * returns false.
+ *
+ * <p>If {@code expectedOldValue} is zero, this method will succeed if {@code (key, zero)}
+ * is currently in the map, or if {@code key} is not in the map at all.
+ */
+ boolean replace(K key, long expectedOldValue, long newValue) {
+ if (expectedOldValue == 0L) {
+ return putIfAbsent(key, newValue) == 0L;
+ } else {
+ AtomicLong atomic = map.get(key);
+ return (atomic == null) ? false : atomic.compareAndSet(expectedOldValue, newValue);
+ }
+ }
+
+ /**
+ * If {@code (key, value)} is currently in the map, this method removes it and returns
+ * true; otherwise, this method returns false.
+ */
+ boolean remove(K key, long value) {
+ AtomicLong atomic = map.get(key);
+ if (atomic == null) {
+ return false;
+ }
+
+ long oldValue = atomic.get();
+ if (oldValue != value) {
+ return false;
+ }
+
+ if (oldValue == 0L || atomic.compareAndSet(oldValue, 0L)) {
+ // only remove after setting to zero, to avoid concurrent updates
+ map.remove(key, atomic);
+ // succeed even if the remove fails, since the value was already adjusted
+ return true;
+ }
+
+ // value changed
+ return false;
+ }
+
+}
diff --git a/guava/src/com/google/common/util/concurrent/Atomics.java b/guava/src/com/google/common/util/concurrent/Atomics.java
new file mode 100644
index 0000000..fece83d
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/Atomics.java
@@ -0,0 +1,76 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+import javax.annotation.Nullable;
+
+/**
+ * Static utility methods pertaining to classes in the
+ * {@code java.util.concurrent.atomic} package.
+ *
+ * @author Kurt Alfred Kluever
+ * @since 10.0
+ */
+@Beta
+public final class Atomics {
+ private Atomics() {}
+
+ /**
+ * Creates an {@code AtomicReference} instance with no initial value.
+ *
+ * @return a new {@code AtomicReference} with no initial value
+ */
+ public static <V> AtomicReference<V> newReference() {
+ return new AtomicReference<V>();
+ }
+
+ /**
+ * Creates an {@code AtomicReference} instance with the given initial value.
+ *
+ * @param initialValue the initial value
+ * @return a new {@code AtomicReference} with the given initial value
+ */
+ public static <V> AtomicReference<V> newReference(@Nullable V initialValue) {
+ return new AtomicReference<V>(initialValue);
+ }
+
+ /**
+ * Creates an {@code AtomicReferenceArray} instance of given length.
+ *
+ * @param length the length of the array
+ * @return a new {@code AtomicReferenceArray} with the given length
+ */
+ public static <E> AtomicReferenceArray<E> newReferenceArray(int length) {
+ return new AtomicReferenceArray<E>(length);
+ }
+
+ /**
+ * Creates an {@code AtomicReferenceArray} instance with the same length as,
+ * and all elements copied from, the given array.
+ *
+ * @param array the array to copy elements from
+ * @return a new {@code AtomicReferenceArray} copied from the given array
+ */
+ public static <E> AtomicReferenceArray<E> newReferenceArray(E[] array) {
+ return new AtomicReferenceArray<E>(array);
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/Callables.java b/guava/src/com/google/common/util/concurrent/Callables.java
new file mode 100644
index 0000000..f970f42
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/Callables.java
@@ -0,0 +1,43 @@
+/*
+ * 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.util.concurrent;
+
+import java.util.concurrent.Callable;
+
+import javax.annotation.Nullable;
+
+/**
+ * Static utility methods pertaining to the {@link Callable} interface.
+ *
+ * @author Isaac Shum
+ * @since 1.0
+ */
+public final class Callables {
+ private Callables() {}
+
+ /**
+ * Creates a {@code Callable} which immediately returns a preset value each
+ * time it is called.
+ */
+ public static <T> Callable<T> returning(final @Nullable T value) {
+ return new Callable<T>() {
+ @Override public T call() {
+ return value;
+ }
+ };
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/CheckedFuture.java b/guava/src/com/google/common/util/concurrent/CheckedFuture.java
new file mode 100644
index 0000000..31504e2
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/CheckedFuture.java
@@ -0,0 +1,76 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A {@code CheckedFuture} is a {@link ListenableFuture} that includes versions
+ * of the {@code get} methods that can throw a checked exception. This makes it
+ * easier to create a future that executes logic which can throw an exception.
+ *
+ * <p>A common implementation is {@link Futures#immediateCheckedFuture}.
+ *
+ * <p>Implementations of this interface must adapt the exceptions thrown by
+ * {@code Future#get()}: {@link CancellationException},
+ * {@link ExecutionException} and {@link InterruptedException} into the type
+ * specified by the {@code E} type parameter.
+ *
+ * <p>This interface also extends the ListenableFuture interface to allow
+ * listeners to be added. This allows the future to be used as a normal
+ * {@link Future} or as an asynchronous callback mechanism as needed. This
+ * allows multiple callbacks to be registered for a particular task, and the
+ * future will guarantee execution of all listeners when the task completes.
+ *
+ * <p>For a simpler alternative to CheckedFuture, consider accessing Future
+ * values with {@link Futures#get(Future, Class) Futures.get()}.
+ *
+ * @author Sven Mawson
+ * @since 1.0
+ */
+@Beta
+public interface CheckedFuture<V, X extends Exception>
+ extends ListenableFuture<V> {
+
+ /**
+ * Exception checking version of {@link Future#get()} that will translate
+ * {@link InterruptedException}, {@link CancellationException} and
+ * {@link ExecutionException} into application-specific exceptions.
+ *
+ * @return the result of executing the future.
+ * @throws X on interruption, cancellation or execution exceptions.
+ */
+ V checkedGet() throws X;
+
+ /**
+ * Exception checking version of {@link Future#get(long, TimeUnit)} that will
+ * translate {@link InterruptedException}, {@link CancellationException} and
+ * {@link ExecutionException} into application-specific exceptions. On
+ * timeout this method throws a normal {@link TimeoutException}.
+ *
+ * @return the result of executing the future.
+ * @throws TimeoutException if retrieving the result timed out.
+ * @throws X on interruption, cancellation or execution exceptions.
+ */
+ V checkedGet(long timeout, TimeUnit unit) throws TimeoutException, X;
+}
diff --git a/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java
new file mode 100644
index 0000000..53d19d0
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/CycleDetectingLockFactory.java
@@ -0,0 +1,1034 @@
+/*
+ * 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.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}s and
+ * {@link ReentrantReadWriteLock}s 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}s have different properties and can form cycles
+ * without potential deadlock, this class treats {@code ReadWriteLock}s 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.
+ @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 = 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}s 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
new file mode 100644
index 0000000..1a2edac
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ExecutionError.java
@@ -0,0 +1,64 @@
+/*
+ * 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.annotations.GwtCompatible;
+
+/**
+ * {@link Error} variant of {@link java.util.concurrent.ExecutionException}. As
+ * with {@code ExecutionException}, the error's {@linkplain #getCause() cause}
+ * comes from a failed task, possibly run in another thread. That cause should
+ * itself be an {@code Error}; if not, use {@code ExecutionException} or {@link
+ * UncheckedExecutionException}. This allows the client code to continue to
+ * distinguish between exceptions and errors, even when they come from other
+ * threads.
+ *
+ * @author Chris Povirk
+ * @since 10.0
+ */
+@Beta
+@GwtCompatible
+public class ExecutionError extends Error {
+ /**
+ * Creates a new instance with {@code null} as its detail message.
+ */
+ protected ExecutionError() {}
+
+ /**
+ * Creates a new instance with the given detail message.
+ */
+ protected ExecutionError(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new instance with the given detail message and cause.
+ */
+ public ExecutionError(String message, Error cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new instance with the given cause.
+ */
+ public ExecutionError(Error cause) {
+ super(cause);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/util/concurrent/ExecutionList.java b/guava/src/com/google/common/util/concurrent/ExecutionList.java
new file mode 100644
index 0000000..d1b78f5
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ExecutionList.java
@@ -0,0 +1,159 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+
+import java.util.Queue;
+import java.util.concurrent.Executor;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * <p>A list of listeners, each with an associated {@code Executor}, that
+ * guarantees that every {@code Runnable} that is {@linkplain #add added} will
+ * be executed after {@link #execute()} is called. Any {@code Runnable} added
+ * after the call to {@code execute} is still guaranteed to execute. There is no
+ * guarantee, however, that listeners will be executed in the order that they
+ * are added.
+ *
+ * <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.
+ *
+ * @author Nishant Thakkar
+ * @author Sven Mawson
+ * @since 1.0
+ */
+public final class ExecutionList {
+
+ // Logger to log exceptions caught when running runnables.
+ private static final Logger log =
+ Logger.getLogger(ExecutionList.class.getName());
+
+ // The runnable,executor pairs to execute.
+ private final Queue<RunnableExecutorPair> runnables = Lists.newLinkedList();
+
+ // Boolean we use mark when execution has started. Only accessed from within
+ // synchronized blocks.
+ private boolean executed = false;
+
+ /** Creates a new, empty {@link ExecutionList}. */
+ public ExecutionList() {
+ }
+
+ /**
+ * Adds the {@code Runnable} and accompanying {@code Executor} to the list of
+ * listeners to execute. If execution has already begun, the listener is
+ * executed immediately.
+ *
+ * <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: First, the
+ * thread that the listener runs in depends on whether the {@code
+ * ExecutionList} has been executed at the time it is added. In particular,
+ * listeners may run in the thread that calls {@code add}. Second, the thread
+ * that calls {@link #execute} may be an internal implementation thread, such
+ * as an RPC network thread, and {@code sameThreadExecutor()} listeners may
+ * run in this 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.
+ */
+ public void add(Runnable runnable, Executor executor) {
+ // Fail fast on a null. We throw NPE here because the contract of
+ // Executor states that it throws NPE on null listener, so we propagate
+ // that contract up into the add method as well.
+ Preconditions.checkNotNull(runnable, "Runnable was null.");
+ Preconditions.checkNotNull(executor, "Executor was null.");
+
+ boolean executeImmediate = false;
+
+ // Lock while we check state. We must maintain the lock while adding the
+ // new pair so that another thread can't run the list out from under us.
+ // We only add to the list if we have not yet started execution.
+ synchronized (runnables) {
+ if (!executed) {
+ runnables.add(new RunnableExecutorPair(runnable, executor));
+ } else {
+ executeImmediate = true;
+ }
+ }
+
+ // Execute the runnable immediately. Because of scheduling this may end up
+ // getting called before some of the previously added runnables, but we're
+ // OK with that. If we want to change the contract to guarantee ordering
+ // among runnables we'd have to modify the logic here to allow it.
+ if (executeImmediate) {
+ new RunnableExecutorPair(runnable, executor).execute();
+ }
+ }
+
+ /**
+ * Runs this execution list, executing all existing pairs in the order they
+ * were added. However, note that listeners added after this point may be
+ * executed before those previously added, and note that the execution order
+ * of all listeners is ultimately chosen by the implementations of the
+ * supplied executors.
+ *
+ * <p>This method is idempotent. Calling it several times in parallel is
+ * semantically equivalent to calling it exactly once.
+ *
+ * @since 10.0 (present in 1.0 as {@code run})
+ */
+ public void execute() {
+ // Lock while we update our state so the add method above will finish adding
+ // any listeners before we start to run them.
+ synchronized (runnables) {
+ if (executed) {
+ return;
+ }
+ executed = true;
+ }
+
+ // At this point the runnables will never be modified by another
+ // thread, so we are safe using it outside of the synchronized block.
+ while (!runnables.isEmpty()) {
+ runnables.poll().execute();
+ }
+ }
+
+ private static class RunnableExecutorPair {
+ final Runnable runnable;
+ final Executor executor;
+
+ RunnableExecutorPair(Runnable runnable, Executor executor) {
+ this.runnable = runnable;
+ this.executor = executor;
+ }
+
+ void execute() {
+ try {
+ executor.execute(runnable);
+ } catch (RuntimeException e) {
+ // Log it and keep going, bad runnable and/or executor. Don't
+ // punish the other runnables if we're given a bad one. We only
+ // catch RuntimeException because we want Errors to propagate up.
+ log.log(Level.SEVERE, "RuntimeException while executing runnable "
+ + runnable + " with executor " + executor, e);
+ }
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java b/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java
new file mode 100644
index 0000000..890479d
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/FakeTimeLimiter.java
@@ -0,0 +1,47 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A TimeLimiter implementation which actually does not attempt to limit time
+ * at all. This may be desirable to use in some unit tests. More importantly,
+ * attempting to debug a call which is time-limited would be extremely annoying,
+ * so this gives you a time-limiter you can easily swap in for your real
+ * time-limiter while you're debugging.
+ *
+ * @author Kevin Bourrillion
+ * @since 1.0
+ */
+@Beta
+public final class FakeTimeLimiter implements TimeLimiter {
+ @Override
+ public <T> T newProxy(T target, Class<T> interfaceType, long timeoutDuration,
+ TimeUnit timeoutUnit) {
+ return target; // ha ha
+ }
+
+ @Override
+ public <T> T callWithTimeout(Callable<T> callable, long timeoutDuration,
+ TimeUnit timeoutUnit, boolean amInterruptible) throws Exception {
+ return callable.call(); // fooled you
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ForwardingBlockingQueue.java b/guava/src/com/google/common/util/concurrent/ForwardingBlockingQueue.java
new file mode 100644
index 0000000..f7257a2
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ForwardingBlockingQueue.java
@@ -0,0 +1,74 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.collect.ForwardingQueue;
+
+import java.util.Collection;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link BlockingQueue} which forwards all its method calls to another
+ * {@link BlockingQueue}. Subclasses should override one or more methods to
+ * modify the behavior of the backing collection as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Raimundo Mirisola
+ *
+ * @param <E> the type of elements held in this collection
+ * @since 4.0
+ */
+public abstract class ForwardingBlockingQueue<E> extends ForwardingQueue<E>
+ implements BlockingQueue<E> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingBlockingQueue() {}
+
+ @Override protected abstract BlockingQueue<E> delegate();
+
+ @Override public int drainTo(
+ Collection<? super E> c, int maxElements) {
+ return delegate().drainTo(c, maxElements);
+ }
+
+ @Override public int drainTo(Collection<? super E> c) {
+ return delegate().drainTo(c);
+ }
+
+ @Override public boolean offer(E e, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return delegate().offer(e, timeout, unit);
+ }
+
+ @Override public E poll(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return delegate().poll(timeout, unit);
+ }
+
+ @Override public void put(E e) throws InterruptedException {
+ delegate().put(e);
+ }
+
+ @Override public int remainingCapacity() {
+ return delegate().remainingCapacity();
+ }
+
+ @Override public E take() throws InterruptedException {
+ return delegate().take();
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ForwardingCheckedFuture.java b/guava/src/com/google/common/util/concurrent/ForwardingCheckedFuture.java
new file mode 100644
index 0000000..1dee47a
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ForwardingCheckedFuture.java
@@ -0,0 +1,78 @@
+/*
+ * 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.Preconditions;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A future which forwards all its method calls to another future. Subclasses
+ * should override one or more methods to modify the behavior of the backing
+ * future as desired per the <a href=
+ * "http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p>Most subclasses can simply extend {@link SimpleForwardingCheckedFuture}.
+ *
+ * @param <V> The result type returned by this Future's {@code get} method
+ * @param <X> The type of the Exception thrown by the Future's
+ * {@code checkedGet} method
+ *
+ * @author Anthony Zana
+ * @since 9.0
+ */
+@Beta
+public abstract class ForwardingCheckedFuture<V, X extends Exception>
+ extends ForwardingListenableFuture<V> implements CheckedFuture<V, X> {
+
+ @Override
+ public V checkedGet() throws X {
+ return delegate().checkedGet();
+ }
+
+ @Override
+ public V checkedGet(long timeout, TimeUnit unit) throws TimeoutException, X {
+ return delegate().checkedGet(timeout, unit);
+ }
+
+ @Override
+ protected abstract CheckedFuture<V, X> delegate();
+
+ // TODO(cpovirk): Use Standard Javadoc form for SimpleForwarding*
+ /**
+ * A simplified version of {@link ForwardingCheckedFuture} where subclasses
+ * can pass in an already constructed {@link CheckedFuture} as the delegate.
+ *
+ * @since 9.0
+ */
+ @Beta
+ public abstract static class SimpleForwardingCheckedFuture<
+ V, X extends Exception> extends ForwardingCheckedFuture<V, X> {
+ private final CheckedFuture<V, X> delegate;
+
+ protected SimpleForwardingCheckedFuture(CheckedFuture<V, X> delegate) {
+ this.delegate = Preconditions.checkNotNull(delegate);
+ }
+
+ @Override
+ protected final CheckedFuture<V, X> delegate() {
+ return delegate;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ForwardingExecutorService.java b/guava/src/com/google/common/util/concurrent/ForwardingExecutorService.java
new file mode 100644
index 0000000..9c09af0
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ForwardingExecutorService.java
@@ -0,0 +1,117 @@
+/*
+ * 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.collect.ForwardingObject;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * An executor service which forwards all its method calls to another executor
+ * service. Subclasses should override one or more methods to modify the
+ * behavior of the backing executor service as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Kurt Alfred Kluever
+ * @since 10.0
+ */
+public abstract class ForwardingExecutorService extends ForwardingObject
+ implements ExecutorService {
+ /** Constructor for use by subclasses. */
+ protected ForwardingExecutorService() {}
+
+ @Override
+ protected abstract ExecutorService delegate();
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return delegate().awaitTermination(timeout, unit);
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(
+ Collection<? extends Callable<T>> tasks) throws InterruptedException {
+ return delegate().invokeAll(tasks);
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(
+ Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return delegate().invokeAll(tasks, timeout, unit);
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException, ExecutionException {
+ return delegate().invokeAny(tasks);
+ }
+
+ @Override
+ public <T> T invokeAny(
+ Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return delegate().invokeAny(tasks, timeout, unit);
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return delegate().isShutdown();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return delegate().isTerminated();
+ }
+
+ @Override
+ public void shutdown() {
+ delegate().shutdown();
+ }
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ return delegate().shutdownNow();
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ delegate().execute(command);
+ }
+
+ public <T> Future<T> submit(Callable<T> task) {
+ return delegate().submit(task);
+ }
+
+ @Override
+ public Future<?> submit(Runnable task) {
+ return delegate().submit(task);
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable task, T result) {
+ return delegate().submit(task, result);
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ForwardingFuture.java b/guava/src/com/google/common/util/concurrent/ForwardingFuture.java
new file mode 100644
index 0000000..9fcd119
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ForwardingFuture.java
@@ -0,0 +1,96 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ForwardingObject;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A {@link Future} which forwards all its method calls to another future.
+ * Subclasses should override one or more methods to modify the behavior of
+ * the backing future as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p>Most subclasses can just use {@link SimpleForwardingFuture}.
+ *
+ * @author Sven Mawson
+ * @since 1.0
+ */
+public abstract class ForwardingFuture<V> extends ForwardingObject
+ implements Future<V> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingFuture() {}
+
+ @Override protected abstract Future<V> delegate();
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return delegate().cancel(mayInterruptIfRunning);
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return delegate().isCancelled();
+ }
+
+ @Override
+ public boolean isDone() {
+ return delegate().isDone();
+ }
+
+ @Override
+ public V get() throws InterruptedException, ExecutionException {
+ return delegate().get();
+ }
+
+ @Override
+ public V get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return delegate().get(timeout, unit);
+ }
+
+ /*
+ * TODO(cpovirk): Use standard Javadoc form for SimpleForwarding* class and
+ * constructor
+ */
+ /**
+ * A simplified version of {@link ForwardingFuture} where subclasses
+ * can pass in an already constructed {@link Future} as the delegate.
+ *
+ * @since 9.0
+ */
+ public abstract static class SimpleForwardingFuture<V>
+ extends ForwardingFuture<V> {
+ private final Future<V> delegate;
+
+ protected SimpleForwardingFuture(Future<V> delegate) {
+ this.delegate = Preconditions.checkNotNull(delegate);
+ }
+
+ @Override
+ protected final Future<V> delegate() {
+ return delegate;
+ }
+
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ForwardingListenableFuture.java b/guava/src/com/google/common/util/concurrent/ForwardingListenableFuture.java
new file mode 100644
index 0000000..79f6d53
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ForwardingListenableFuture.java
@@ -0,0 +1,74 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.base.Preconditions;
+
+import java.util.concurrent.Executor;
+
+/**
+ * A {@link ListenableFuture} which forwards all its method calls to another
+ * future. Subclasses should override one or more methods to modify the behavior
+ * of the backing future as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * <p>Most subclasses can just use {@link SimpleForwardingListenableFuture}.
+ *
+ * @param <V> The result type returned by this Future's {@code get} method
+ *
+ * @author Shardul Deo
+ * @since 4.0
+ */
+public abstract class ForwardingListenableFuture<V> extends ForwardingFuture<V>
+ implements ListenableFuture<V> {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingListenableFuture() {}
+
+ @Override
+ protected abstract ListenableFuture<V> delegate();
+
+ @Override
+ public void addListener(Runnable listener, Executor exec) {
+ delegate().addListener(listener, exec);
+ }
+
+ /*
+ * TODO(cpovirk): Use standard Javadoc form for SimpleForwarding* class and
+ * constructor
+ */
+ /**
+ * A simplified version of {@link ForwardingListenableFuture} where subclasses
+ * can pass in an already constructed {@link ListenableFuture}
+ * as the delegate.
+ *
+ * @since 9.0
+ */
+ public abstract static class SimpleForwardingListenableFuture<V>
+ extends ForwardingListenableFuture<V> {
+ private final ListenableFuture<V> delegate;
+
+ protected SimpleForwardingListenableFuture(ListenableFuture<V> delegate) {
+ this.delegate = Preconditions.checkNotNull(delegate);
+ }
+
+ @Override
+ protected final ListenableFuture<V> delegate() {
+ return delegate;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ForwardingListeningExecutorService.java b/guava/src/com/google/common/util/concurrent/ForwardingListeningExecutorService.java
new file mode 100644
index 0000000..27e44de
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ForwardingListeningExecutorService.java
@@ -0,0 +1,52 @@
+/*
+ * 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 java.util.concurrent.Callable;
+
+/**
+ * A listening executor service which forwards all its method calls to another
+ * listening executor service. Subclasses should override one or more methods to
+ * modify the behavior of the backing executor service as desired per the <a
+ * href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
+ *
+ * @author Isaac Shum
+ * @since 10.0
+ */
+public abstract class ForwardingListeningExecutorService
+ extends ForwardingExecutorService implements ListeningExecutorService {
+ /** Constructor for use by subclasses. */
+ protected ForwardingListeningExecutorService() {}
+
+ @Override
+ protected abstract ListeningExecutorService delegate();
+
+ @Override
+ public <T> ListenableFuture<T> submit(Callable<T> task) {
+ return delegate().submit(task);
+ }
+
+ @Override
+ public ListenableFuture<?> submit(Runnable task) {
+ return delegate().submit(task);
+ }
+
+ @Override
+ public <T> ListenableFuture<T> submit(Runnable task, T result) {
+ return delegate().submit(task, result);
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ForwardingService.java b/guava/src/com/google/common/util/concurrent/ForwardingService.java
new file mode 100644
index 0000000..0fff279
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ForwardingService.java
@@ -0,0 +1,86 @@
+/*
+ * 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.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.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public abstract class ForwardingService extends ForwardingObject
+ implements Service {
+
+ /** Constructor for use by subclasses. */
+ protected ForwardingService() {}
+
+ @Override protected abstract Service delegate();
+
+ @Override public ListenableFuture<State> start() {
+ return delegate().start();
+ }
+
+ @Override public State state() {
+ return delegate().state();
+ }
+
+ @Override public ListenableFuture<State> stop() {
+ return delegate().stop();
+ }
+
+ @Override public State startAndWait() {
+ return delegate().startAndWait();
+ }
+
+ @Override public State stopAndWait() {
+ return delegate().stopAndWait();
+ }
+
+ @Override public boolean isRunning() {
+ return delegate().isRunning();
+ }
+
+ @Override public void addListener(Listener listener, Executor executor) {
+ delegate().addListener(listener, executor);
+ }
+
+ /**
+ * A sensible default implementation of {@link #startAndWait()}, in terms of
+ * {@link #start}. If you override {@link #start}, you may wish to override
+ * {@link #startAndWait()} to forward to this implementation.
+ * @since 9.0
+ */
+ protected State standardStartAndWait() {
+ return Futures.getUnchecked(start());
+ }
+
+ /**
+ * A sensible default implementation of {@link #stopAndWait()}, in terms of
+ * {@link #stop}. If you override {@link #stop}, you may wish to override
+ * {@link #stopAndWait()} to forward to this implementation.
+ * @since 9.0
+ */
+ protected State standardStopAndWait() {
+ return Futures.getUnchecked(stop());
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/FutureCallback.java b/guava/src/com/google/common/util/concurrent/FutureCallback.java
new file mode 100644
index 0000000..7b39d4a
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/FutureCallback.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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+/**
+ * A callback for accepting the results of a {@link java.util.concurrent.Future}
+ * computation asynchronously.
+ *
+ * <p>To attach to a {@link ListenableFuture} use {@link Futures#addCallback}.
+ *
+ * @author Anthony Zana
+ * @since 10.0
+ */
+@Beta
+public interface FutureCallback<V> {
+ /**
+ * Invoked with the result of the {@code Future} computation when it is
+ * successful.
+ */
+ void onSuccess(V result);
+
+ /**
+ * Invoked when a {@code Future} computation fails or is canceled.
+ *
+ * <p>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.
+ */
+ void onFailure(Throwable t);
+}
diff --git a/guava/src/com/google/common/util/concurrent/Futures.java b/guava/src/com/google/common/util/concurrent/Futures.java
new file mode 100644
index 0000000..0ff8e8a
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/Futures.java
@@ -0,0 +1,1249 @@
+/*
+ * 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.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 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 com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+
+import java.lang.reflect.Constructor;
+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 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
+ * @since 1.0
+ */
+@Beta
+public final class Futures {
+ private Futures() {}
+
+ /**
+ * Creates a {@link CheckedFuture} out of a normal {@link ListenableFuture}
+ * and a {@link Function} that maps from {@link Exception} instances into the
+ * appropriate checked type.
+ *
+ * <p>The given mapping function will be applied to an
+ * {@link InterruptedException}, a {@link CancellationException}, or an
+ * {@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)
+ */
+ public static <V, X extends Exception> CheckedFuture<V, X> makeChecked(
+ ListenableFuture<V> future, Function<Exception, X> mapper) {
+ return new MappingCheckedFuture<V, X>(checkNotNull(future), mapper);
+ }
+
+ /**
+ * Creates a {@code ListenableFuture} which has its value set immediately upon
+ * construction. The getters just return the value. This {@code Future} can't
+ * be canceled or timed out and its {@code isDone()} method always returns
+ * {@code true}.
+ */
+ public static <V> ListenableFuture<V> immediateFuture(@Nullable V value) {
+ SettableFuture<V> future = SettableFuture.create();
+ future.set(value);
+ return future;
+ }
+
+ /**
+ * Returns a {@code CheckedFuture} which has its value set immediately upon
+ * construction.
+ *
+ * <p>The returned {@code Future} can't be cancelled, and its {@code isDone()}
+ * method always returns {@code true}. Calling {@code get()} or {@code
+ * checkedGet()} will immediately return the provided value.
+ */
+ public static <V, X extends Exception> CheckedFuture<V, X>
+ immediateCheckedFuture(@Nullable V 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");
+ }
+ });
+ }
+
+ /**
+ * Returns a {@code ListenableFuture} which has an exception set immediately
+ * upon construction.
+ *
+ * <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 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);
+ SettableFuture<V> future = SettableFuture.create();
+ future.setException(throwable);
+ return future;
+ }
+
+ /**
+ * Returns a {@code CheckedFuture} which has an exception set immediately upon
+ * construction.
+ *
+ * <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 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(final X exception) {
+ checkNotNull(exception);
+ return makeChecked(Futures.<V>immediateFailedFuture(exception),
+ new Function<Exception, X>() {
+ @Override
+ public X apply(Exception e) {
+ return exception;
+ }
+ });
+ }
+
+ /**
+ * 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 AsyncFunction} to the result of the original
+ * {@code Future}. Example:
+ *
+ * <pre> {@code
+ * ListenableFuture<RowKey> rowKeyFuture = indexService.lookUp(query);
+ * AsyncFunction<RowKey, QueryResult> queryFunction =
+ * new AsyncFunction<RowKey, QueryResult>() {
+ * public ListenableFuture<QueryResult> apply(RowKey rowKey) {
+ * return dataService.read(rowKey);
+ * }
+ * };
+ * ListenableFuture<QueryResult> queryFuture =
+ * 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>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
+ * 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 future to transform
+ * @param function A function to transform the result of the input future
+ * to the result of the output future
+ * @return A future that holds result of the function (if the input succeeded)
+ * or the original input's failure (if not)
+ * @since 11.0
+ */
+ public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> input,
+ AsyncFunction<? super I, ? extends O> function) {
+ return transform(input, function, MoreExecutors.sameThreadExecutor());
+ }
+
+ /**
+ * 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 AsyncFunction} to the result of the original
+ * {@code Future}. Example:
+ *
+ * <pre> {@code
+ * ListenableFuture<RowKey> rowKeyFuture = indexService.lookUp(query);
+ * AsyncFunction<RowKey, QueryResult> queryFunction =
+ * new AsyncFunction<RowKey, QueryResult>() {
+ * public ListenableFuture<QueryResult> apply(RowKey rowKey) {
+ * return dataService.read(rowKey);
+ * }
+ * };
+ * ListenableFuture<QueryResult> queryFuture =
+ * transform(rowKeyFuture, queryFunction, executor);
+ * }</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.
+ *
+ * <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.
+ *
+ * @param input The future to transform
+ * @param function A function to transform the result of the input future
+ * to the result of the output future
+ * @param executor Executor to run the function in.
+ * @return A future that holds result of the function (if the input succeeded)
+ * or the original input's failure (if not)
+ * @since 11.0
+ */
+ public static <I, O> ListenableFuture<O> transform(ListenableFuture<I> input,
+ AsyncFunction<? super I, ? extends O> function,
+ Executor executor) {
+ ChainingListenableFuture<I, O> output =
+ new ChainingListenableFuture<I, O>(function, input);
+ input.addListener(output, executor);
+ return output;
+ }
+
+ /**
+ * Returns a new {@code ListenableFuture} whose result is the product of
+ * applying the given {@code Function} to the result of the given {@code
+ * Future}. Example:
+ *
+ * <pre> {@code
+ * ListenableFuture<QueryResult> queryFuture = ...;
+ * Function<QueryResult, List<Row>> rowsFunction =
+ * new Function<QueryResult, List<Row>>() {
+ * public List<Row> apply(QueryResult queryResult) {
+ * return queryResult.getRows();
+ * }
+ * };
+ * ListenableFuture<List<Row>> rowsFuture =
+ * 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>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}
+ * is cancelled, it will attempt to cancel the input, and if the input is
+ * cancelled, the returned {@code Future} will receive a callback in which it
+ * will attempt to cancel itself.
+ *
+ * <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 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,
+ final Function<? super I, ? extends O> function) {
+ return transform(input, function, MoreExecutors.sameThreadExecutor());
+ }
+
+ /**
+ * Returns a new {@code ListenableFuture} whose result is the product of
+ * applying the given {@code Function} to the result of the given {@code
+ * Future}. Example:
+ *
+ * <pre> {@code
+ * ListenableFuture<QueryResult> queryFuture = ...;
+ * Function<QueryResult, List<Row>> rowsFunction =
+ * new Function<QueryResult, List<Row>>() {
+ * public List<Row> apply(QueryResult queryResult) {
+ * return queryResult.getRows();
+ * }
+ * };
+ * ListenableFuture<List<Row>> rowsFuture =
+ * transform(queryFuture, rowsFunction, executor);
+ * }</pre>
+ *
+ * <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}
+ * is cancelled, it will attempt to cancel the input, and if the input is
+ * cancelled, the returned {@code Future} will receive a callback in which it
+ * will attempt to cancel itself.
+ *
+ * <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
+ * @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,
+ final Function<? super I, ? extends O> function, Executor executor) {
+ checkNotNull(function);
+ AsyncFunction<I, O> wrapperFunction
+ = new AsyncFunction<I, O>() {
+ @Override public ListenableFuture<O> apply(I input) {
+ O output = function.apply(input);
+ return immediateFuture(output);
+ }
+ };
+ return transform(input, wrapperFunction, executor);
+ }
+
+ /**
+ * Like {@link #transform(ListenableFuture, Function)} except that the
+ * transformation {@code function} is invoked on each call to
+ * {@link Future#get() get()} on the returned future.
+ *
+ * <p>The returned {@code Future} reflects the input's cancellation
+ * state directly, and any attempt to cancel the returned Future is likewise
+ * passed through to the input Future.
+ *
+ * <p>Note that calls to {@linkplain Future#get(long, TimeUnit) timed get}
+ * only apply the timeout to the execution of the underlying {@code Future},
+ * <em>not</em> to the execution of the transformation function.
+ *
+ * <p>The primary audience of this method is callers of {@code transform}
+ * who don't have a {@code ListenableFuture} available and
+ * do not mind repeated, lazy function evaluation.
+ *
+ * @param input 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,
+ final Function<? super I, ? extends O> function) {
+ checkNotNull(input);
+ checkNotNull(function);
+ return new Future<O>() {
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return input.cancel(mayInterruptIfRunning);
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return input.isCancelled();
+ }
+
+ @Override
+ public boolean isDone() {
+ return input.isDone();
+ }
+
+ @Override
+ public O get() throws InterruptedException, ExecutionException {
+ return applyTransformation(input.get());
+ }
+
+ @Override
+ public O get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return applyTransformation(input.get(timeout, unit));
+ }
+
+ private O applyTransformation(I input) throws ExecutionException {
+ try {
+ return function.apply(input);
+ } catch (Throwable t) {
+ throw new ExecutionException(t);
+ }
+ }
+ };
+ }
+
+ /**
+ * An implementation of {@code ListenableFuture} that also implements
+ * {@code Runnable} so that it can be used to nest ListenableFutures.
+ * Once the passed-in {@code ListenableFuture} is complete, it calls the
+ * passed-in {@code Function} to generate the result.
+ *
+ * <p>If the function throws any checked exceptions, they should be wrapped
+ * in a {@code UndeclaredThrowableException} so that this class can get
+ * access to the cause.
+ */
+ private static class ChainingListenableFuture<I, O>
+ extends AbstractFuture<O> implements Runnable {
+
+ 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(
+ AsyncFunction<? super I, ? extends O> function,
+ ListenableFuture<? extends I> inputFuture) {
+ this.function = checkNotNull(function);
+ this.inputFuture = checkNotNull(inputFuture);
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ /*
+ * Our additional cancellation work needs to occur even if
+ * !mayInterruptIfRunning, so we can't move it into interruptTask().
+ */
+ 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;
+ }
+ return false;
+ }
+
+ private void cancel(@Nullable Future<?> future,
+ boolean mayInterruptIfRunning) {
+ if (future != null) {
+ future.cancel(mayInterruptIfRunning);
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ I sourceResult;
+ try {
+ sourceResult = getUninterruptibly(inputFuture);
+ } catch (CancellationException e) {
+ // Cancel this future and return.
+ // At this point, inputFuture is cancelled and outputFuture doesn't
+ // exist, so the value of mayInterruptIfRunning is irrelevant.
+ cancel(false);
+ return;
+ } catch (ExecutionException e) {
+ // Set the cause of the exception as this future's exception
+ setException(e.getCause());
+ return;
+ }
+
+ final ListenableFuture<? extends O> outputFuture = this.outputFuture =
+ function.apply(sourceResult);
+ if (isCancelled()) {
+ // 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;
+ }
+ outputFuture.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // Here it would have been nice to have had an
+ // UninterruptibleListenableFuture, but we don't want to start a
+ // combinatorial explosion of interfaces, so we have to make do.
+ set(getUninterruptibly(outputFuture));
+ } catch (CancellationException e) {
+ // Cancel this future and return.
+ // At this point, inputFuture and outputFuture are done, so the
+ // value of mayInterruptIfRunning is irrelevant.
+ cancel(false);
+ return;
+ } catch (ExecutionException e) {
+ // Set the cause of the exception as this future's exception
+ setException(e.getCause());
+ } finally {
+ // Don't pin inputs beyond completion
+ ChainingListenableFuture.this.outputFuture = null;
+ }
+ }
+ }, MoreExecutors.sameThreadExecutor());
+ } catch (UndeclaredThrowableException e) {
+ // Set the cause of the exception as this future's exception
+ setException(e.getCause());
+ } catch (Exception e) {
+ // This exception is irrelevant in this thread, but useful for the
+ // client
+ setException(e);
+ } catch (Error e) {
+ // Propagate errors up ASAP - our superclass will rethrow the error
+ setException(e);
+ } finally {
+ // Don't pin inputs beyond completion
+ function = null;
+ inputFuture = null;
+ // Allow our get routines to examine outputFuture now.
+ outputCreated.countDown();
+ }
+ }
+ }
+
+ /**
+ * 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 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
+ * @return a future that provides a list of the results of the component
+ * futures
+ * @since 10.0
+ */
+ @Beta
+ public static <V> ListenableFuture<List<V>> allAsList(
+ ListenableFuture<? extends V>... futures) {
+ return new ListFuture<V>(ImmutableList.copyOf(futures), true,
+ MoreExecutors.sameThreadExecutor());
+ }
+
+ /**
+ * 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 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
+ * @return a future that provides a list of the results of the component
+ * futures
+ * @since 10.0
+ */
+ @Beta
+ public static <V> ListenableFuture<List<V>> allAsList(
+ Iterable<? extends ListenableFuture<? extends V>> futures) {
+ return new ListFuture<V>(ImmutableList.copyOf(futures), true,
+ MoreExecutors.sameThreadExecutor());
+ }
+
+ /**
+ * Creates a new {@code ListenableFuture} whose value is a list containing the
+ * values of all its successful input futures. The list of results is in the
+ * same order as the input list, and if any of the provided futures fails or
+ * is canceled, its corresponding position will contain {@code null} (which is
+ * indistinguishable from the future having a successful value of
+ * {@code null}).
+ *
+ * @param futures futures to combine
+ * @return a future that provides a list of the results of the component
+ * futures
+ * @since 10.0
+ */
+ @Beta
+ public static <V> ListenableFuture<List<V>> successfulAsList(
+ ListenableFuture<? extends V>... futures) {
+ return new ListFuture<V>(ImmutableList.copyOf(futures), false,
+ MoreExecutors.sameThreadExecutor());
+ }
+
+ /**
+ * Creates a new {@code ListenableFuture} whose value is a list containing the
+ * values of all its successful input futures. The list of results is in the
+ * same order as the input list, and if any of the provided futures fails or
+ * is canceled, its corresponding position will contain {@code null} (which is
+ * indistinguishable from the future having a successful value of
+ * {@code null}).
+ *
+ * @param futures futures to combine
+ * @return a future that provides a list of the results of the component
+ * futures
+ * @since 10.0
+ */
+ @Beta
+ public static <V> ListenableFuture<List<V>> successfulAsList(
+ Iterable<? extends ListenableFuture<? extends V>> futures) {
+ return new ListFuture<V>(ImmutableList.copyOf(futures), false,
+ MoreExecutors.sameThreadExecutor());
+ }
+
+ /**
+ * Registers separate success and failure callbacks to be run when the {@code
+ * Future}'s computation is {@linkplain java.util.concurrent.Future#isDone()
+ * complete} or, if the computation is already complete, immediately.
+ *
+ * <p>There is no guaranteed ordering of execution of callbacks, but any
+ * callback added through this method is guaranteed to be called once the
+ * computation is complete.
+ *
+ * Example: <pre> {@code
+ * ListenableFuture<QueryResult> future = ...;
+ * addCallback(future,
+ * new FutureCallback<QueryResult> {
+ * public void onSuccess(QueryResult result) {
+ * storeInCache(result);
+ * }
+ * public void onFailure(Throwable t) {
+ * reportError(t);
+ * }
+ * });}</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>For a more general interface to attach a completion listener to a
+ * {@code Future}, see {@link ListenableFuture#addListener addListener}.
+ *
+ * @param future The future attach the callback to.
+ * @param callback The callback to invoke when {@code future} is completed.
+ * @since 10.0
+ */
+ public static <V> void addCallback(ListenableFuture<V> future,
+ FutureCallback<? super V> callback) {
+ addCallback(future, callback, MoreExecutors.sameThreadExecutor());
+ }
+
+ /**
+ * Registers separate success and failure callbacks to be run when the {@code
+ * Future}'s computation is {@linkplain java.util.concurrent.Future#isDone()
+ * complete} or, if the computation is already complete, immediately.
+ *
+ * <p>The callback is run in {@code executor}.
+ * There is no guaranteed ordering of execution of callbacks, but any
+ * callback added through this method is guaranteed to be called once the
+ * computation is complete.
+ *
+ * Example: <pre> {@code
+ * ListenableFuture<QueryResult> future = ...;
+ * Executor e = ...
+ * addCallback(future, e,
+ * new FutureCallback<QueryResult> {
+ * public void onSuccess(QueryResult result) {
+ * storeInCache(result);
+ * }
+ * public void onFailure(Throwable t) {
+ * reportError(t);
+ * }
+ * });}</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.
+ *
+ * <p>For a more general interface to attach a completion listener to a
+ * {@code Future}, see {@link ListenableFuture#addListener addListener}.
+ *
+ * @param future The future attach the callback to.
+ * @param callback The callback to invoke when {@code future} is completed.
+ * @param executor The executor to run {@code callback} when the future
+ * completes.
+ * @since 10.0
+ */
+ public static <V> void addCallback(final ListenableFuture<V> future,
+ final FutureCallback<? super V> callback, Executor executor) {
+ Preconditions.checkNotNull(callback);
+ Runnable callbackListener = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // TODO(user): (Before Guava release), validate that this
+ // is the thing for IE.
+ V value = getUninterruptibly(future);
+ callback.onSuccess(value);
+ } catch (ExecutionException e) {
+ callback.onFailure(e.getCause());
+ } catch (RuntimeException e) {
+ callback.onFailure(e);
+ } catch (Error e) {
+ callback.onFailure(e);
+ }
+ }
+ };
+ future.addListener(callbackListener, executor);
+ }
+
+ /**
+ * Returns the result of {@link Future#get()}, converting most exceptions to a
+ * new instance of the given checked exception type. This reduces boilerplate
+ * for a common use of {@code Future} in which it is unnecessary to
+ * programmatically distinguish between exception types or to extract other
+ * information from the exception instance.
+ *
+ * <p>Exceptions from {@code Future.get} are treated as follows:
+ * <ul>
+ * <li>Any {@link ExecutionException} has its <i>cause</i> wrapped in an
+ * {@code X} if the cause is a checked exception, an {@link
+ * UncheckedExecutionException} if the cause is a {@code
+ * RuntimeException}, or an {@link ExecutionError} if the cause is an
+ * {@code Error}.
+ * <li>Any {@link InterruptedException} is wrapped in an {@code X} (after
+ * restoring the interrupt).
+ * <li>Any {@link CancellationException} is propagated untouched, as is any
+ * other {@link RuntimeException} (though {@code get} implementations are
+ * discouraged from throwing such exceptions).
+ * </ul>
+ *
+ * The overall principle is to continue to treat every checked exception as a
+ * checked exception, every unchecked exception as an unchecked exception, and
+ * every error as an error. In addition, the cause of any {@code
+ * ExecutionException} is wrapped in order to ensure that the new stack trace
+ * matches that of the current thread.
+ *
+ * <p>Instances of {@code exceptionClass} are created by choosing an arbitrary
+ * public constructor that accepts zero or more arguments, all of type {@code
+ * String} or {@code Throwable} (preferring constructors with at least one
+ * {@code String}) and calling the constructor via reflection. If the
+ * exception did not already have a cause, one is set by calling {@link
+ * Throwable#initCause(Throwable)} on it. If no such constructor exists, an
+ * {@code IllegalArgumentException} is thrown.
+ *
+ * @throws X if {@code get} throws any checked exception except for an {@code
+ * ExecutionException} whose cause is not itself a checked exception
+ * @throws UncheckedExecutionException if {@code get} throws an {@code
+ * ExecutionException} with a {@code RuntimeException} as its cause
+ * @throws ExecutionError if {@code get} throws an {@code ExecutionException}
+ * with an {@code Error} as its cause
+ * @throws CancellationException if {@code get} throws a {@code
+ * CancellationException}
+ * @throws IllegalArgumentException if {@code exceptionClass} extends {@code
+ * RuntimeException} or does not have a suitable constructor
+ * @since 10.0
+ */
+ @Beta
+ public static <V, X extends Exception> V get(
+ Future<V> future, Class<X> exceptionClass) throws X {
+ checkNotNull(future);
+ checkArgument(!RuntimeException.class.isAssignableFrom(exceptionClass),
+ "Futures.get exception type (%s) must not be a RuntimeException",
+ exceptionClass);
+ try {
+ return future.get();
+ } catch (InterruptedException e) {
+ currentThread().interrupt();
+ throw newWithCause(exceptionClass, e);
+ } catch (ExecutionException e) {
+ wrapAndThrowExceptionOrError(e.getCause(), exceptionClass);
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Returns the result of {@link Future#get(long, TimeUnit)}, converting most
+ * exceptions to a new instance of the given checked exception type. This
+ * reduces boilerplate for a common use of {@code Future} in which it is
+ * unnecessary to programmatically distinguish between exception types or to
+ * extract other information from the exception instance.
+ *
+ * <p>Exceptions from {@code Future.get} are treated as follows:
+ * <ul>
+ * <li>Any {@link ExecutionException} has its <i>cause</i> wrapped in an
+ * {@code X} if the cause is a checked exception, an {@link
+ * UncheckedExecutionException} if the cause is a {@code
+ * RuntimeException}, or an {@link ExecutionError} if the cause is an
+ * {@code Error}.
+ * <li>Any {@link InterruptedException} is wrapped in an {@code X} (after
+ * restoring the interrupt).
+ * <li>Any {@link TimeoutException} is wrapped in an {@code X}.
+ * <li>Any {@link CancellationException} is propagated untouched, as is any
+ * other {@link RuntimeException} (though {@code get} implementations are
+ * discouraged from throwing such exceptions).
+ * </ul>
+ *
+ * The overall principle is to continue to treat every checked exception as a
+ * checked exception, every unchecked exception as an unchecked exception, and
+ * every error as an error. In addition, the cause of any {@code
+ * ExecutionException} is wrapped in order to ensure that the new stack trace
+ * matches that of the current thread.
+ *
+ * <p>Instances of {@code exceptionClass} are created by choosing an arbitrary
+ * public constructor that accepts zero or more arguments, all of type {@code
+ * String} or {@code Throwable} (preferring constructors with at least one
+ * {@code String}) and calling the constructor via reflection. If the
+ * exception did not already have a cause, one is set by calling {@link
+ * Throwable#initCause(Throwable)} on it. If no such constructor exists, an
+ * {@code IllegalArgumentException} is thrown.
+ *
+ * @throws X if {@code get} throws any checked exception except for an {@code
+ * ExecutionException} whose cause is not itself a checked exception
+ * @throws UncheckedExecutionException if {@code get} throws an {@code
+ * ExecutionException} with a {@code RuntimeException} as its cause
+ * @throws ExecutionError if {@code get} throws an {@code ExecutionException}
+ * with an {@code Error} as its cause
+ * @throws CancellationException if {@code get} throws a {@code
+ * CancellationException}
+ * @throws IllegalArgumentException if {@code exceptionClass} extends {@code
+ * RuntimeException} or does not have a suitable constructor
+ * @since 10.0
+ */
+ @Beta
+ public static <V, X extends Exception> V get(
+ Future<V> future, long timeout, TimeUnit unit, Class<X> exceptionClass)
+ throws X {
+ checkNotNull(future);
+ checkNotNull(unit);
+ checkArgument(!RuntimeException.class.isAssignableFrom(exceptionClass),
+ "Futures.get exception type (%s) must not be a RuntimeException",
+ exceptionClass);
+ try {
+ return future.get(timeout, unit);
+ } catch (InterruptedException e) {
+ currentThread().interrupt();
+ throw newWithCause(exceptionClass, e);
+ } catch (TimeoutException e) {
+ throw newWithCause(exceptionClass, e);
+ } catch (ExecutionException e) {
+ wrapAndThrowExceptionOrError(e.getCause(), exceptionClass);
+ throw new AssertionError();
+ }
+ }
+
+ private static <X extends Exception> void wrapAndThrowExceptionOrError(
+ Throwable cause, Class<X> exceptionClass) throws X {
+ if (cause instanceof Error) {
+ throw new ExecutionError((Error) cause);
+ }
+ if (cause instanceof RuntimeException) {
+ throw new UncheckedExecutionException(cause);
+ }
+ throw newWithCause(exceptionClass, cause);
+ }
+
+ /**
+ * Returns the result of calling {@link Future#get()} uninterruptibly on a
+ * task known not to throw a checked exception. This makes {@code Future} more
+ * suitable for lightweight, fast-running tasks that, barring bugs in the
+ * code, will not fail. This gives it exception-handling behavior similar to
+ * that of {@code ForkJoinTask.join}.
+ *
+ * <p>Exceptions from {@code Future.get} are treated as follows:
+ * <ul>
+ * <li>Any {@link ExecutionException} has its <i>cause</i> wrapped in an
+ * {@link UncheckedExecutionException} (if the cause is an {@code
+ * Exception}) or {@link ExecutionError} (if the cause is an {@code
+ * Error}).
+ * <li>Any {@link InterruptedException} causes a retry of the {@code get}
+ * call. The interrupt is restored before {@code getUnchecked} returns.
+ * <li>Any {@link CancellationException} is propagated untouched. So is any
+ * other {@link RuntimeException} ({@code get} implementations are
+ * discouraged from throwing such exceptions).
+ * </ul>
+ *
+ * The overall principle is to eliminate all checked exceptions: to loop to
+ * avoid {@code InterruptedException}, to pass through {@code
+ * CancellationException}, and to wrap any exception from the underlying
+ * computation in an {@code UncheckedExecutionException} or {@code
+ * ExecutionError}.
+ *
+ * <p>For an uninterruptible {@code get} that preserves other exceptions, see
+ * {@link Uninterruptibles#getUninterruptibly(Future)}.
+ *
+ * @throws UncheckedExecutionException if {@code get} throws an {@code
+ * ExecutionException} with an {@code Exception} as its cause
+ * @throws ExecutionError if {@code get} throws an {@code ExecutionException}
+ * with an {@code Error} as its cause
+ * @throws CancellationException if {@code get} throws a {@code
+ * CancellationException}
+ * @since 10.0
+ */
+ @Beta
+ public static <V> V getUnchecked(Future<V> future) {
+ checkNotNull(future);
+ try {
+ return getUninterruptibly(future);
+ } catch (ExecutionException e) {
+ wrapAndThrowUnchecked(e.getCause());
+ throw new AssertionError();
+ }
+ }
+
+ private static void wrapAndThrowUnchecked(Throwable cause) {
+ if (cause instanceof Error) {
+ throw new ExecutionError((Error) cause);
+ }
+ /*
+ * It's a non-Error, non-Exception Throwable. From my survey of such
+ * classes, I believe that most users intended to extend Exception, so we'll
+ * treat it like an Exception.
+ */
+ throw new UncheckedExecutionException(cause);
+ }
+
+ /*
+ * TODO(user): FutureChecker interface for these to be static methods on? If
+ * so, refer to it in the (static-method) Futures.get documentation
+ */
+
+ /*
+ * Arguably we don't need a timed getUnchecked because any operation slow
+ * enough to require a timeout is heavyweight enough to throw a checked
+ * exception and therefore be inappropriate to use with getUnchecked. Further,
+ * it's not clear that converting the checked TimeoutException to a
+ * RuntimeException -- especially to an UncheckedExecutionException, since it
+ * wasn't thrown by the computation -- makes sense, and if we don't convert
+ * it, the user still has to write a try-catch block.
+ *
+ * If you think you would use this method, let us know.
+ */
+
+ private static <X extends Exception> X newWithCause(
+ Class<X> exceptionClass, Throwable cause) {
+ // getConstructors() guarantees this as long as we don't modify the array.
+ @SuppressWarnings("unchecked")
+ List<Constructor<X>> constructors =
+ (List) Arrays.asList(exceptionClass.getConstructors());
+ for (Constructor<X> constructor : preferringStrings(constructors)) {
+ @Nullable X instance = newFromConstructor(constructor, cause);
+ if (instance != null) {
+ if (instance.getCause() == null) {
+ instance.initCause(cause);
+ }
+ return instance;
+ }
+ }
+ throw new IllegalArgumentException(
+ "No appropriate constructor for exception of type " + exceptionClass
+ + " in response to chained exception", cause);
+ }
+
+ private static <X extends Exception> List<Constructor<X>>
+ preferringStrings(List<Constructor<X>> constructors) {
+ return WITH_STRING_PARAM_FIRST.sortedCopy(constructors);
+ }
+
+ private static final Ordering<Constructor<?>> WITH_STRING_PARAM_FIRST =
+ Ordering.natural().onResultOf(new Function<Constructor<?>, Boolean>() {
+ @Override public Boolean apply(Constructor<?> input) {
+ return asList(input.getParameterTypes()).contains(String.class);
+ }
+ }).reverse();
+
+ @Nullable private static <X> X newFromConstructor(
+ Constructor<X> constructor, Throwable cause) {
+ Class<?>[] paramTypes = constructor.getParameterTypes();
+ Object[] params = new Object[paramTypes.length];
+ for (int i = 0; i < paramTypes.length; i++) {
+ Class<?> paramType = paramTypes[i];
+ if (paramType.equals(String.class)) {
+ params[i] = cause.toString();
+ } else if (paramType.equals(Throwable.class)) {
+ params[i] = cause;
+ } else {
+ return null;
+ }
+ }
+ try {
+ return constructor.newInstance(params);
+ } catch (IllegalArgumentException e) {
+ return null;
+ } catch (InstantiationException e) {
+ return null;
+ } catch (IllegalAccessException e) {
+ return null;
+ } catch (InvocationTargetException e) {
+ return null;
+ }
+ }
+
+ /**
+ * 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;
+ List<V> values;
+
+ /**
+ * 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());
+
+ init(listenerExecutor);
+ }
+
+ private void init(final Executor listenerExecutor) {
+ // First, schedule cleanup to execute when the Future is done.
+ addListener(new Runnable() {
+ @Override
+ public void run() {
+ // By now the values array has either been set as the Future's value,
+ // or (in case of failure) is no longer useful.
+ ListFuture.this.values = null;
+
+ // Let go of the memory held by other futures
+ ListFuture.this.futures = null;
+ }
+ }, MoreExecutors.sameThreadExecutor());
+
+ // Now begin the "real" initialization.
+
+ // Corner case: List is empty.
+ if (futures.isEmpty()) {
+ set(Lists.newArrayList(values));
+ return;
+ }
+
+ // Populate the results list with null initially.
+ for (int i = 0; i < futures.size(); ++i) {
+ values.add(null);
+ }
+
+ // Register a listener on each Future in the list to update
+ // the state of this future.
+ // Note that if all the futures on the list are done prior to completing
+ // this loop, the last call to addListener() will callback to
+ // setOneValue(), transitively call our cleanup listener, and set
+ // this.futures to null.
+ // 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() {
+ setOneValue(index, listenable);
+ }
+ }, listenerExecutor);
+ }
+ }
+
+ /**
+ * Sets the value at the given index to that of the given future.
+ */
+ private void setOneValue(int index, Future<? extends V> future) {
+ 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.
+ checkState(allMustSucceed,
+ "Future was done before all dependencies completed");
+ return;
+ }
+
+ try {
+ checkState(future.isDone(),
+ "Tried to set value from future which is not done");
+ localValues.set(index, getUninterruptibly(future));
+ } catch (CancellationException e) {
+ if (allMustSucceed) {
+ // Set ourselves as cancelled. Let the input futures keep running
+ // as some of them may be used elsewhere.
+ // (Currently we don't override interruptTask, so
+ // mayInterruptIfRunning==false isn't technically necessary.)
+ cancel(false);
+ }
+ } catch (ExecutionException e) {
+ if (allMustSucceed) {
+ // As soon as the first one fails, throw the exception up.
+ // The result of all other inputs is then ignored.
+ setException(e.getCause());
+ }
+ } catch (RuntimeException e) {
+ if (allMustSucceed) {
+ setException(e);
+ }
+ } catch (Error e) {
+ // Propagate errors up ASAP - our superclass will rethrow the error
+ setException(e);
+ } finally {
+ int newRemaining = remaining.decrementAndGet();
+ checkState(newRemaining >= 0, "Less than 0 remaining futures");
+ if (newRemaining == 0) {
+ localValues = values;
+ if (localValues != null) {
+ set(Lists.newArrayList(localValues));
+ } else {
+ checkState(isDone());
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * A checked future that uses a function to map from exceptions to the
+ * appropriate checked type.
+ */
+ private static class MappingCheckedFuture<V, X extends Exception> extends
+ AbstractCheckedFuture<V, X> {
+
+ final Function<Exception, X> mapper;
+
+ MappingCheckedFuture(ListenableFuture<V> delegate,
+ Function<Exception, X> mapper) {
+ super(delegate);
+
+ this.mapper = checkNotNull(mapper);
+ }
+
+ @Override
+ protected X mapException(Exception e) {
+ return mapper.apply(e);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java b/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java
new file mode 100644
index 0000000..645a648
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/JdkFutureAdapters.java
@@ -0,0 +1,182 @@
+/*
+ * 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.util.concurrent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Utilities necessary for working with libraries that supply plain {@link
+ * Future} instances. Note that, whenver possible, it is strongly preferred to
+ * modify those libraries to return {@code ListenableFuture} directly.
+ *
+ * @author Sven Mawson
+ * @since 10.0 (replacing {@code Futures.makeListenable}, which
+ * existed in 1.0)
+ */
+@Beta
+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
+ * 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
+ * until the future is {@linkplain Future#isDone() done}.
+ *
+ * <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.
+ */
+ public static <V> ListenableFuture<V> listenInPoolThread(
+ Future<V> future) {
+ 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(
+ Future<V> future, Executor executor) {
+ checkNotNull(executor);
+ if (future instanceof ListenableFuture) {
+ return (ListenableFuture<V>) future;
+ }
+ return new ListenableFutureAdapter<V>(future, executor);
+ }
+
+ /**
+ * An adapter to turn a {@link Future} into a {@link ListenableFuture}. This
+ * will wait on the future to finish, and when it completes, run the
+ * listeners. This implementation will wait on the source future
+ * indefinitely, so if the source future never completes, the adapter will
+ * never complete either.
+ *
+ * <p>If the delegate future is interrupted or throws an unexpected unchecked
+ * exception, the listeners will not be invoked.
+ */
+ private static class ListenableFutureAdapter<V> extends ForwardingFuture<V>
+ implements ListenableFuture<V> {
+
+ private static final ThreadFactory threadFactory =
+ new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setNameFormat("ListenableFutureAdapter-thread-%d")
+ .build();
+ private static final Executor defaultAdapterExecutor =
+ Executors.newCachedThreadPool(threadFactory);
+
+ private final Executor adapterExecutor;
+
+ // The execution list to hold our listeners.
+ private final ExecutionList executionList = new ExecutionList();
+
+ // This allows us to only start up a thread waiting on the delegate future
+ // when the first listener is added.
+ private final AtomicBoolean hasListeners = new AtomicBoolean(false);
+
+ // The delegate future.
+ private final Future<V> delegate;
+
+ ListenableFutureAdapter(Future<V> delegate) {
+ this(delegate, defaultAdapterExecutor);
+ }
+
+ ListenableFutureAdapter(Future<V> delegate, Executor adapterExecutor) {
+ this.delegate = checkNotNull(delegate);
+ this.adapterExecutor = checkNotNull(adapterExecutor);
+ }
+
+ @Override
+ protected Future<V> delegate() {
+ return delegate;
+ }
+
+ @Override
+ public void addListener(Runnable listener, Executor exec) {
+ executionList.add(listener, exec);
+
+ // When a listener is first added, we run a task that will wait for
+ // the delegate to finish, and when it is done will run the listeners.
+ if (hasListeners.compareAndSet(false, true)) {
+ if (delegate.isDone()) {
+ // If the delegate is already done, run the execution list
+ // immediately on the current thread.
+ executionList.execute();
+ return;
+ }
+
+ adapterExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ delegate.get();
+ } catch (Error e) {
+ throw e;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ // Threads from our private pool are never interrupted.
+ throw new AssertionError(e);
+ } catch (Throwable e) {
+ // ExecutionException / CancellationException / RuntimeException
+ // The task is done, run the listeners.
+ }
+ executionList.execute();
+ }
+ });
+ }
+ }
+ }
+
+ private JdkFutureAdapters() {}
+}
diff --git a/guava/src/com/google/common/util/concurrent/ListenableFuture.java b/guava/src/com/google/common/util/concurrent/ListenableFuture.java
new file mode 100644
index 0000000..eb05354
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ListenableFuture.java
@@ -0,0 +1,135 @@
+/*
+ * 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.util.concurrent;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * A {@link Future} that accepts completion listeners. Each listener has an
+ * associated executor, and it is invoked using this executor once the future's
+ * 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>
+ *
+ * Most commonly, {@code ListenableFuture} is used as an input to another
+ * derived {@code Future}, as in {@link Futures#allAsList(Iterable)
+ * Futures.allAsList}. Many such methods are impossible to implement efficiently
+ * without listener support.
+ *
+ * <p>It is possible to call {@link #addListener addListener} directly, but this
+ * is uncommon because the {@code Runnable} interface does not provide direct
+ * access to the {@code Future} result. (Users who want such access may prefer
+ * {@link Futures#addCallback Futures.addCallback}.) Still, direct {@code
+ * addListener} calls are occasionally useful:<pre> {@code
+ * final String name = ...;
+ * inFlight.add(name);
+ * ListenableFuture<Result> future = service.query(name);
+ * future.addListener(new Runnable() {
+ * public void run() {
+ * processedCount.incrementAndGet();
+ * inFlight.remove(name);
+ * lastProcessed.set(name);
+ * logger.info("Done with {0}", name);
+ * }
+ * }, executor);}</pre>
+ *
+ * <h3>How to get an instance</h3>
+ *
+ * Developers are encouraged to return {@code ListenableFuture} from their
+ * methods so that users can take advantages of the utilities built atop the
+ * class. The way that they will create {@code ListenableFuture} instances
+ * depends on how they currently create {@code Future} instances:
+ * <ul>
+ * <li>If they are returned from an {@code ExecutorService}, convert that
+ * service to a {@link ListeningExecutorService}, usually by calling {@link
+ * MoreExecutors#listeningDecorator(ExecutorService)
+ * MoreExecutors.listeningDecorator}. (Custom executors may find it more
+ * convenient to use {@link ListenableFutureTask} directly.)
+ * <li>If they are manually filled in by a call to {@link FutureTask#set} or a
+ * similar method, create a {@link SettableFuture} instead. (Users with more
+ * complex needs may prefer {@link AbstractFuture}.)
+ * </ul>
+ *
+ * Occasionally, an API will return a plain {@code Future} and it will be
+ * impossible to change the return type. For this case, we provide a more
+ * expensive workaround in {@code JdkFutureAdapters}. However, when possible, it
+ * is more efficient and reliable to create a {@code ListenableFuture} directly.
+ *
+ * @author Sven Mawson
+ * @author Nishant Thakkar
+ * @since 1.0
+ */
+public interface ListenableFuture<V> extends Future<V> {
+ /**
+ * Registers a listener to be {@linkplain Executor#execute(Runnable) run} on
+ * the given executor. The listener will run when the {@code Future}'s
+ * computation is {@linkplain Future#isDone() complete} or, if the computation
+ * is already complete, immediately.
+ *
+ * <p>There is no guaranteed ordering of execution of listeners, but any
+ * listener added through this method is guaranteed to be called once the
+ * computation is complete.
+ *
+ * <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.
+ *
+ * <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:
+ *
+ * <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()}.
+ *
+ * @param listener the listener to run when the computation is complete
+ * @param executor the executor to run the listener in
+ * @throws NullPointerException if the executor or listener was null
+ * @throws RejectedExecutionException if we tried to execute the listener
+ * immediately but the executor rejected it.
+ */
+ void addListener(Runnable listener, Executor executor);
+}
diff --git a/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java b/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java
new file mode 100644
index 0000000..28c2a0a
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ListenableFutureTask.java
@@ -0,0 +1,90 @@
+/*
+ * 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.util.concurrent;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.FutureTask;
+
+import javax.annotation.Nullable;
+
+/**
+ * A {@link FutureTask} that also implements the {@link ListenableFuture}
+ * 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 final class ListenableFutureTask<V> extends FutureTask<V>
+ implements ListenableFuture<V> {
+
+ // The execution list to hold our listeners.
+ private final ExecutionList executionList = new ExecutionList();
+
+ /**
+ * Creates a {@code ListenableFutureTask} that will upon running, execute the
+ * given {@code Callable}.
+ *
+ * @param callable the callable task
+ * @since 10.0
+ */
+ public static <V> ListenableFutureTask<V> create(Callable<V> callable) {
+ return new ListenableFutureTask<V>(callable);
+ }
+
+ /**
+ * Creates a {@code ListenableFutureTask} that will upon running, execute the
+ * given {@code Runnable}, and arrange that {@code get} will return the
+ * given result on successful completion.
+ *
+ * @param runnable the runnable task
+ * @param result the result to return on successful completion. If you don't
+ * need a particular result, consider using constructions of the form:
+ * {@code ListenableFuture<?> f = ListenableFutureTask.create(runnable,
+ * null)}
+ * @since 10.0
+ */
+ public static <V> ListenableFutureTask<V> create(
+ Runnable runnable, @Nullable V result) {
+ return new ListenableFutureTask<V>(runnable, result);
+ }
+
+ private ListenableFutureTask(Callable<V> callable) {
+ super(callable);
+ }
+
+ private ListenableFutureTask(Runnable runnable, @Nullable V result) {
+ super(runnable, result);
+ }
+
+ @Override
+ public void addListener(Runnable listener, Executor exec) {
+ executionList.add(listener, exec);
+ }
+
+ /**
+ * Internal implementation detail used to invoke the listeners.
+ */
+ @Override
+ protected void done() {
+ executionList.execute();
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/ListeningExecutorService.java b/guava/src/com/google/common/util/concurrent/ListeningExecutorService.java
new file mode 100644
index 0000000..9ea8e48
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ListeningExecutorService.java
@@ -0,0 +1,88 @@
+/*
+ * 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.util.concurrent;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An {@link ExecutorService} that returns {@link ListenableFuture} instances. To create an instance
+ * from an existing {@link ExecutorService}, call
+ * {@link MoreExecutors#listeningDecorator(ExecutorService)}.
+ *
+ * @author Chris Povirk
+ * @since 10.0
+ */
+public interface ListeningExecutorService extends ExecutorService {
+ /**
+ * @return a {@code ListenableFuture} representing pending completion of the task
+ * @throws RejectedExecutionException {@inheritDoc}
+ */
+ @Override
+ <T> ListenableFuture<T> submit(Callable<T> task);
+
+ /**
+ * @return a {@code ListenableFuture} representing pending completion of the task
+ * @throws RejectedExecutionException {@inheritDoc}
+ */
+ @Override
+ ListenableFuture<?> submit(Runnable task);
+
+ /**
+ * @return a {@code ListenableFuture} representing pending completion of the task
+ * @throws RejectedExecutionException {@inheritDoc}
+ */
+ @Override
+ <T> ListenableFuture<T> submit(Runnable task, T result);
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>All elements in the returned list must be {@link ListenableFuture} instances.
+ *
+ * @return A list of {@code ListenableFuture} instances representing the tasks, in the same
+ * sequential order as produced by the iterator for the given task list, each of which has
+ * completed.
+ * @throws RejectedExecutionException {@inheritDoc}
+ * @throws NullPointerException if any task is null
+ */
+ @Override
+ <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>All elements in the returned list must be {@link ListenableFuture} instances.
+ *
+ * @return a list of {@code ListenableFuture} instances representing the tasks, in the same
+ * sequential order as produced by the iterator for the given task list. If the operation
+ * did not time out, each task will have completed. If it did time out, some of these
+ * tasks will not have completed.
+ * @throws RejectedExecutionException {@inheritDoc}
+ * @throws NullPointerException if any task is null
+ */
+ @Override
+ <T> List<Future<T>> invokeAll(
+ Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
+ throws InterruptedException;
+}
diff --git a/guava/src/com/google/common/util/concurrent/ListeningScheduledExecutorService.java b/guava/src/com/google/common/util/concurrent/ListeningScheduledExecutorService.java
new file mode 100644
index 0000000..42dcdd2
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ListeningScheduledExecutorService.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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * A {@link ScheduledExecutorService} that returns {@link ListenableFuture}
+ * instances from its {@code ExecutorService} methods. Futures returned by the
+ * {@code schedule*} methods, by contrast, need not implement {@code
+ * ListenableFuture}. (To create an instance from an existing {@link
+ * ScheduledExecutorService}, call {@link
+ * MoreExecutors#listeningDecorator(ScheduledExecutorService)}.
+ *
+ * <p>TODO(cpovirk): make at least the one-time schedule() methods return a
+ * ListenableFuture, too? But then we'll need ListenableScheduledFuture...
+ *
+ * @author Chris Povirk
+ * @since 10.0
+ */
+@Beta
+public interface ListeningScheduledExecutorService
+ extends ScheduledExecutorService, ListeningExecutorService {
+}
diff --git a/guava/src/com/google/common/util/concurrent/Monitor.java b/guava/src/com/google/common/util/concurrent/Monitor.java
new file mode 100644
index 0000000..d8c8693
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/Monitor.java
@@ -0,0 +1,942 @@
+/*
+ * 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.util.concurrent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+
+/**
+ * A synchronization abstraction supporting waiting on arbitrary boolean conditions.
+ *
+ * <p>This class is intended as a replacement for {@link ReentrantLock}. Code using {@code Monitor}
+ * is less error-prone and more readable than code using {@code ReentrantLock}, without significant
+ * performance loss. {@code Monitor} even has the potential for performance gain by optimizing the
+ * evaluation and signaling of conditions. Signaling is entirely
+ * <a href="http://en.wikipedia.org/wiki/Monitor_(synchronization)#Implicit_signaling">
+ * implicit</a>.
+ * By eliminating explicit signaling, this class can guarantee that only one thread is awakened
+ * when a condition becomes true (no "signaling storms" due to use of {@link
+ * java.util.concurrent.locks.Condition#signalAll Condition.signalAll}) and that no signals are lost
+ * (no "hangs" due to incorrect use of {@link java.util.concurrent.locks.Condition#signal
+ * Condition.signal}).
+ *
+ * <p>A thread is said to <i>occupy</i> a monitor if it has <i>entered</i> the monitor but not yet
+ * <i>left</i>. Only one thread may occupy a given monitor at any moment. A monitor is also
+ * reentrant, so a thread may enter a monitor any number of times, and then must leave the same
+ * number of times. The <i>enter</i> and <i>leave</i> operations have the same synchronization
+ * semantics as the built-in Java language synchronization primitives.
+ *
+ * <p>A call to any of the <i>enter</i> methods with <b>void</b> return type should always be
+ * followed immediately by a <i>try/finally</i> block to ensure that the current thread leaves the
+ * monitor cleanly: <pre> {@code
+ *
+ * monitor.enter();
+ * try {
+ * // do things while occupying the monitor
+ * } finally {
+ * monitor.leave();
+ * }}</pre>
+ *
+ * A call to any of the <i>enter</i> methods with <b>boolean</b> return type should always appear as
+ * the condition of an <i>if</i> statement containing a <i>try/finally</i> block to ensure that the
+ * current thread leaves the monitor cleanly: <pre> {@code
+ *
+ * if (monitor.tryEnter()) {
+ * try {
+ * // do things while occupying the monitor
+ * } finally {
+ * monitor.leave();
+ * }
+ * } else {
+ * // do other things since the monitor was not available
+ * }}</pre>
+ *
+ * <h2>Comparison with {@code synchronized} and {@code ReentrantLock}</h2>
+ *
+ * <p>The following examples show a simple threadsafe holder expressed using {@code synchronized},
+ * {@link ReentrantLock}, and {@code Monitor}.
+ *
+ * <h3>{@code synchronized}</h3>
+ *
+ * <p>This version is the fewest lines of code, largely because the synchronization mechanism used
+ * is built into the language and runtime. But the programmer has to remember to avoid a couple of
+ * common bugs: The {@code wait()} must be inside a {@code while} instead of an {@code if}, and
+ * {@code notifyAll()} must be used instead of {@code notify()} because there are two different
+ * logical conditions being awaited. <pre> {@code
+ *
+ * public class SafeBox<V> {
+ * private V value;
+ *
+ * public synchronized V get() throws InterruptedException {
+ * while (value == null) {
+ * wait();
+ * }
+ * V result = value;
+ * value = null;
+ * notifyAll();
+ * return result;
+ * }
+ *
+ * public synchronized void set(V newValue) throws InterruptedException {
+ * while (value != null) {
+ * wait();
+ * }
+ * value = newValue;
+ * notifyAll();
+ * }
+ * }}</pre>
+ *
+ * <h3>{@code ReentrantLock}</h3>
+ *
+ * <p>This version is much more verbose than the {@code synchronized} version, and still suffers
+ * from the need for the programmer to remember to use {@code while} instead of {@code if}.
+ * However, one advantage is that we can introduce two separate {@code Condition} objects, which
+ * allows us to use {@code signal()} instead of {@code signalAll()}, which may be a performance
+ * benefit. <pre> {@code
+ *
+ * public class SafeBox<V> {
+ * private final ReentrantLock lock = new ReentrantLock();
+ * private final Condition valuePresent = lock.newCondition();
+ * private final Condition valueAbsent = lock.newCondition();
+ * private V value;
+ *
+ * public V get() throws InterruptedException {
+ * lock.lock();
+ * try {
+ * while (value == null) {
+ * valuePresent.await();
+ * }
+ * V result = value;
+ * value = null;
+ * valueAbsent.signal();
+ * return result;
+ * } finally {
+ * lock.unlock();
+ * }
+ * }
+ *
+ * public void set(V newValue) throws InterruptedException {
+ * lock.lock();
+ * try {
+ * while (value != null) {
+ * valueAbsent.await();
+ * }
+ * value = newValue;
+ * valuePresent.signal();
+ * } finally {
+ * lock.unlock();
+ * }
+ * }
+ * }}</pre>
+ *
+ * <h3>{@code Monitor}</h3>
+ *
+ * <p>This version adds some verbosity around the {@code Guard} objects, but removes that same
+ * verbosity, and more, from the {@code get} and {@code set} methods. {@code Monitor} implements the
+ * same efficient signaling as we had to hand-code in the {@code ReentrantLock} version above.
+ * Finally, the programmer no longer has to hand-code the wait loop, and therefore doesn't have to
+ * remember to use {@code while} instead of {@code if}. <pre> {@code
+ *
+ * public class SafeBox<V> {
+ * private final Monitor monitor = new Monitor();
+ * private final Monitor.Guard valuePresent = new Monitor.Guard(monitor) {
+ * public boolean isSatisfied() {
+ * return value != null;
+ * }
+ * };
+ * private final Monitor.Guard valueAbsent = new Monitor.Guard(monitor) {
+ * public boolean isSatisfied() {
+ * return value == null;
+ * }
+ * };
+ * private V value;
+ *
+ * public V get() throws InterruptedException {
+ * monitor.enterWhen(valuePresent);
+ * try {
+ * V result = value;
+ * value = null;
+ * return result;
+ * } finally {
+ * monitor.leave();
+ * }
+ * }
+ *
+ * public void set(V newValue) throws InterruptedException {
+ * monitor.enterWhen(valueAbsent);
+ * try {
+ * value = newValue;
+ * } finally {
+ * monitor.leave();
+ * }
+ * }
+ * }}</pre>
+ *
+ * @author Justin T. Sampson
+ * @since 10.0
+ */
+@Beta
+public final class Monitor {
+ // TODO: Use raw LockSupport or AbstractQueuedSynchronizer instead of ReentrantLock.
+
+ /**
+ * A boolean condition for which a thread may wait. A {@code Guard} is associated with a single
+ * {@code Monitor}. The monitor may check the guard at arbitrary times from any thread occupying
+ * the monitor, so code should not be written to rely on how often a guard might or might not be
+ * checked.
+ *
+ * <p>If a {@code Guard} is passed into any method of a {@code Monitor} other than the one it is
+ * associated with, an {@link IllegalMonitorStateException} is thrown.
+ *
+ * @since 10.0
+ */
+ @Beta
+ public abstract static class Guard {
+
+ final Monitor monitor;
+ final Condition condition;
+
+ @GuardedBy("monitor.lock")
+ int waiterCount = 0;
+
+ protected Guard(Monitor monitor) {
+ this.monitor = checkNotNull(monitor, "monitor");
+ this.condition = monitor.lock.newCondition();
+ }
+
+ /**
+ * Evaluates this guard's boolean condition. This method is always called with the associated
+ * monitor already occupied. Implementations of this method must depend only on state protected
+ * by the associated monitor, and must not modify that state.
+ */
+ public abstract boolean isSatisfied();
+
+ @Override
+ public final boolean equals(Object other) {
+ // Overridden as final to ensure identity semantics in Monitor.activeGuards.
+ return this == other;
+ }
+
+ @Override
+ public final int hashCode() {
+ // Overridden as final to ensure identity semantics in Monitor.activeGuards.
+ return super.hashCode();
+ }
+
+ }
+
+ /**
+ * Whether this monitor is fair.
+ */
+ private final boolean fair;
+
+ /**
+ * The lock underlying this monitor.
+ */
+ private final ReentrantLock lock;
+
+ /**
+ * The guards associated with this monitor that currently have waiters ({@code waiterCount > 0}).
+ * This is an ArrayList rather than, say, a HashSet so that iteration and almost all adds don't
+ * incur any object allocation overhead.
+ */
+ @GuardedBy("lock")
+ private final ArrayList<Guard> activeGuards = Lists.newArrayListWithCapacity(1);
+
+ /**
+ * Creates a monitor with a non-fair (but fast) ordering policy. Equivalent to {@code
+ * Monitor(false)}.
+ */
+ public Monitor() {
+ this(false);
+ }
+
+ /**
+ * Creates a monitor with the given ordering policy.
+ *
+ * @param fair whether this monitor should use a fair ordering policy rather than a non-fair (but
+ * fast) one
+ */
+ public Monitor(boolean fair) {
+ this.fair = fair;
+ this.lock = new ReentrantLock(fair);
+ }
+
+ /**
+ * Enters this monitor. Blocks indefinitely.
+ */
+ public void enter() {
+ lock.lock();
+ }
+
+ /**
+ * Enters this monitor. Blocks indefinitely, but may be interrupted.
+ */
+ public void enterInterruptibly() throws InterruptedException {
+ lock.lockInterruptibly();
+ }
+
+ /**
+ * Enters this monitor. Blocks at most the given time.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean enter(long time, TimeUnit unit) {
+ final ReentrantLock lock = this.lock;
+ if (!fair && lock.tryLock()) {
+ return true;
+ }
+ long startNanos = System.nanoTime();
+ long timeoutNanos = unit.toNanos(time);
+ long remainingNanos = timeoutNanos;
+ boolean interruptIgnored = false;
+ try {
+ while (true) {
+ try {
+ return lock.tryLock(remainingNanos, TimeUnit.NANOSECONDS);
+ } catch (InterruptedException ignored) {
+ interruptIgnored = true;
+ remainingNanos = (timeoutNanos - (System.nanoTime() - startNanos));
+ }
+ }
+ } finally {
+ if (interruptIgnored) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Enters this monitor. Blocks at most the given time, and may be interrupted.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean enterInterruptibly(long time, TimeUnit unit) throws InterruptedException {
+ return lock.tryLock(time, unit);
+ }
+
+ /**
+ * Enters this monitor if it is possible to do so immediately. Does not block.
+ *
+ * <p><b>Note:</b> This method disregards the fairness setting of this monitor.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean tryEnter() {
+ return lock.tryLock();
+ }
+
+ /**
+ * Enters this monitor when the guard is satisfied. Blocks indefinitely, but may be interrupted.
+ */
+ public void enterWhen(Guard guard) throws InterruptedException {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ final ReentrantLock lock = this.lock;
+ boolean reentrant = lock.isHeldByCurrentThread();
+ boolean success = false;
+ lock.lockInterruptibly();
+ try {
+ waitInterruptibly(guard, reentrant);
+ success = true;
+ } finally {
+ if (!success) {
+ lock.unlock();
+ }
+ }
+ }
+
+ /**
+ * Enters this monitor when the guard is satisfied. Blocks indefinitely.
+ */
+ public void enterWhenUninterruptibly(Guard guard) {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ final ReentrantLock lock = this.lock;
+ boolean reentrant = lock.isHeldByCurrentThread();
+ boolean success = false;
+ lock.lock();
+ try {
+ waitUninterruptibly(guard, reentrant);
+ success = true;
+ } finally {
+ if (!success) {
+ lock.unlock();
+ }
+ }
+ }
+
+ /**
+ * Enters this monitor when the guard is satisfied. Blocks at most the given time, including both
+ * the time to acquire the lock and the time to wait for the guard to be satisfied, and may be
+ * interrupted.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean enterWhen(Guard guard, long time, TimeUnit unit) throws InterruptedException {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ final ReentrantLock lock = this.lock;
+ boolean reentrant = lock.isHeldByCurrentThread();
+ long remainingNanos;
+ if (!fair && lock.tryLock()) {
+ remainingNanos = unit.toNanos(time);
+ } else {
+ long startNanos = System.nanoTime();
+ if (!lock.tryLock(time, unit)) {
+ return false;
+ }
+ remainingNanos = unit.toNanos(time) - (System.nanoTime() - startNanos);
+ }
+ boolean satisfied = false;
+ try {
+ satisfied = waitInterruptibly(guard, remainingNanos, reentrant);
+ } finally {
+ if (!satisfied) {
+ lock.unlock();
+ }
+ }
+ return satisfied;
+ }
+
+ /**
+ * Enters this monitor when the guard is satisfied. Blocks at most the given time, including
+ * both the time to acquire the lock and the time to wait for the guard to be satisfied.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean enterWhenUninterruptibly(Guard guard, long time, TimeUnit unit) {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ final ReentrantLock lock = this.lock;
+ boolean reentrant = lock.isHeldByCurrentThread();
+ boolean interruptIgnored = false;
+ try {
+ long remainingNanos;
+ if (!fair && lock.tryLock()) {
+ remainingNanos = unit.toNanos(time);
+ } else {
+ long startNanos = System.nanoTime();
+ long timeoutNanos = unit.toNanos(time);
+ remainingNanos = timeoutNanos;
+ while (true) {
+ try {
+ if (lock.tryLock(remainingNanos, TimeUnit.NANOSECONDS)) {
+ break;
+ } else {
+ return false;
+ }
+ } catch (InterruptedException ignored) {
+ interruptIgnored = true;
+ } finally {
+ remainingNanos = (timeoutNanos - (System.nanoTime() - startNanos));
+ }
+ }
+ }
+ boolean satisfied = false;
+ try {
+ satisfied = waitUninterruptibly(guard, remainingNanos, reentrant);
+ } finally {
+ if (!satisfied) {
+ lock.unlock();
+ }
+ }
+ return satisfied;
+ } finally {
+ if (interruptIgnored) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Enters this monitor if the guard is satisfied. Blocks indefinitely acquiring the lock, but
+ * does not wait for the guard to be satisfied.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean enterIf(Guard guard) {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ final ReentrantLock lock = this.lock;
+ lock.lock();
+ boolean satisfied = false;
+ try {
+ satisfied = guard.isSatisfied();
+ } finally {
+ if (!satisfied) {
+ lock.unlock();
+ }
+ }
+ return satisfied;
+ }
+
+ /**
+ * Enters this monitor if the guard is satisfied. Blocks indefinitely acquiring the lock, but does
+ * not wait for the guard to be satisfied, and may be interrupted.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean enterIfInterruptibly(Guard guard) throws InterruptedException {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ final ReentrantLock lock = this.lock;
+ lock.lockInterruptibly();
+ boolean satisfied = false;
+ try {
+ satisfied = guard.isSatisfied();
+ } finally {
+ if (!satisfied) {
+ lock.unlock();
+ }
+ }
+ return satisfied;
+ }
+
+ /**
+ * Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the
+ * lock, but does not wait for the guard to be satisfied.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean enterIf(Guard guard, long time, TimeUnit unit) {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ final ReentrantLock lock = this.lock;
+ if (!enter(time, unit)) {
+ return false;
+ }
+ boolean satisfied = false;
+ try {
+ satisfied = guard.isSatisfied();
+ } finally {
+ if (!satisfied) {
+ lock.unlock();
+ }
+ }
+ return satisfied;
+ }
+
+ /**
+ * Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the
+ * lock, but does not wait for the guard to be satisfied, and may be interrupted.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean enterIfInterruptibly(Guard guard, long time, TimeUnit unit)
+ throws InterruptedException {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ final ReentrantLock lock = this.lock;
+ if (!lock.tryLock(time, unit)) {
+ return false;
+ }
+ boolean satisfied = false;
+ try {
+ satisfied = guard.isSatisfied();
+ } finally {
+ if (!satisfied) {
+ lock.unlock();
+ }
+ }
+ return satisfied;
+ }
+
+ /**
+ * Enters this monitor if it is possible to do so immediately and the guard is satisfied. Does not
+ * block acquiring the lock and does not wait for the guard to be satisfied.
+ *
+ * <p><b>Note:</b> This method disregards the fairness setting of this monitor.
+ *
+ * @return whether the monitor was entered
+ */
+ public boolean tryEnterIf(Guard guard) {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ final ReentrantLock lock = this.lock;
+ if (!lock.tryLock()) {
+ return false;
+ }
+ boolean satisfied = false;
+ try {
+ satisfied = guard.isSatisfied();
+ } finally {
+ if (!satisfied) {
+ lock.unlock();
+ }
+ }
+ return satisfied;
+ }
+
+ /**
+ * Waits for the guard to be satisfied. Waits indefinitely, but may be interrupted. May be
+ * called only by a thread currently occupying this monitor.
+ */
+ public void waitFor(Guard guard) throws InterruptedException {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ waitInterruptibly(guard, true);
+ }
+
+ /**
+ * Waits for the guard to be satisfied. Waits indefinitely. May be called only by a thread
+ * currently occupying this monitor.
+ */
+ public void waitForUninterruptibly(Guard guard) {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ waitUninterruptibly(guard, true);
+ }
+
+ /**
+ * Waits for the guard to be satisfied. Waits at most the given time, and may be interrupted.
+ * May be called only by a thread currently occupying this monitor.
+ *
+ * @return whether the guard is now satisfied
+ */
+ public boolean waitFor(Guard guard, long time, TimeUnit unit) throws InterruptedException {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ return waitInterruptibly(guard, unit.toNanos(time), true);
+ }
+
+ /**
+ * Waits for the guard to be satisfied. Waits at most the given time. May be called only by a
+ * thread currently occupying this monitor.
+ *
+ * @return whether the guard is now satisfied
+ */
+ public boolean waitForUninterruptibly(Guard guard, long time, TimeUnit unit) {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ return waitUninterruptibly(guard, unit.toNanos(time), true);
+ }
+
+ /**
+ * Leaves this monitor. May be called only by a thread currently occupying this monitor.
+ */
+ public void leave() {
+ final ReentrantLock lock = this.lock;
+ if (!lock.isHeldByCurrentThread()) {
+ throw new IllegalMonitorStateException();
+ }
+ try {
+ signalConditionsOfSatisfiedGuards(null);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns whether this monitor is using a fair ordering policy.
+ */
+ public boolean isFair() {
+ return lock.isFair();
+ }
+
+ /**
+ * Returns whether this monitor is occupied by any thread. This method is designed for use in
+ * monitoring of the system state, not for synchronization control.
+ */
+ public boolean isOccupied() {
+ return lock.isLocked();
+ }
+
+ /**
+ * Returns whether the current thread is occupying this monitor (has entered more times than it
+ * has left).
+ */
+ public boolean isOccupiedByCurrentThread() {
+ return lock.isHeldByCurrentThread();
+ }
+
+ /**
+ * Returns the number of times the current thread has entered this monitor in excess of the number
+ * of times it has left. Returns 0 if the current thread is not occupying this monitor.
+ */
+ public int getOccupiedDepth() {
+ return lock.getHoldCount();
+ }
+
+ /**
+ * Returns an estimate of the number of threads waiting to enter this monitor. The value is only
+ * an estimate because the number of threads may change dynamically while this method traverses
+ * internal data structures. This method is designed for use in monitoring of the system state,
+ * not for synchronization control.
+ */
+ public int getQueueLength() {
+ return lock.getQueueLength();
+ }
+
+ /**
+ * Returns whether any threads are waiting to enter this monitor. Note that because cancellations
+ * may occur at any time, a {@code true} return does not guarantee that any other thread will ever
+ * enter this monitor. This method is designed primarily for use in monitoring of the system
+ * state.
+ */
+ public boolean hasQueuedThreads() {
+ return lock.hasQueuedThreads();
+ }
+
+ /**
+ * Queries whether the given thread is waiting to enter this monitor. Note that because
+ * cancellations may occur at any time, a {@code true} return does not guarantee that this thread
+ * will ever enter this monitor. This method is designed primarily for use in monitoring of the
+ * system state.
+ */
+ public boolean hasQueuedThread(Thread thread) {
+ return lock.hasQueuedThread(thread);
+ }
+
+ /**
+ * Queries whether any threads are waiting for the given guard to become satisfied. Note that
+ * because timeouts and interrupts may occur at any time, a {@code true} return does not guarantee
+ * that the guard becoming satisfied in the future will awaken any threads. This method is
+ * designed primarily for use in monitoring of the system state.
+ */
+ public boolean hasWaiters(Guard guard) {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ lock.lock();
+ try {
+ return guard.waiterCount > 0;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns an estimate of the number of threads waiting for the given guard to become satisfied.
+ * Note that because timeouts and interrupts may occur at any time, the estimate serves only as an
+ * upper bound on the actual number of waiters. This method is designed for use in monitoring of
+ * the system state, not for synchronization control.
+ */
+ public int getWaitQueueLength(Guard guard) {
+ if (guard.monitor != this) {
+ throw new IllegalMonitorStateException();
+ }
+ lock.lock();
+ try {
+ return guard.waiterCount;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @GuardedBy("lock")
+ private void signalConditionsOfSatisfiedGuards(@Nullable Guard interruptedGuard) {
+ final ArrayList<Guard> guards = this.activeGuards;
+ final int guardCount = guards.size();
+ try {
+ for (int i = 0; i < guardCount; i++) {
+ Guard guard = guards.get(i);
+ if ((guard == interruptedGuard) && (guard.waiterCount == 1)) {
+ // That one waiter was just interrupted and is throwing InterruptedException rather than
+ // paying attention to the guard being satisfied, so find another waiter on another guard.
+ continue;
+ }
+ if (guard.isSatisfied()) {
+ guard.condition.signal();
+ return;
+ }
+ }
+ } catch (Throwable throwable) {
+ for (int i = 0; i < guardCount; i++) {
+ Guard guard = guards.get(i);
+ guard.condition.signalAll();
+ }
+ throw Throwables.propagate(throwable);
+ }
+ }
+
+ @GuardedBy("lock")
+ private void incrementWaiters(Guard guard) {
+ int waiters = guard.waiterCount++;
+ if (waiters == 0) {
+ activeGuards.add(guard);
+ }
+ }
+
+ @GuardedBy("lock")
+ private void decrementWaiters(Guard guard) {
+ int waiters = --guard.waiterCount;
+ if (waiters == 0) {
+ activeGuards.remove(guard);
+ }
+ }
+
+ @GuardedBy("lock")
+ private void waitInterruptibly(Guard guard, boolean signalBeforeWaiting)
+ throws InterruptedException {
+ if (!guard.isSatisfied()) {
+ if (signalBeforeWaiting) {
+ signalConditionsOfSatisfiedGuards(null);
+ }
+ incrementWaiters(guard);
+ try {
+ final Condition condition = guard.condition;
+ do {
+ try {
+ condition.await();
+ } catch (InterruptedException interrupt) {
+ try {
+ signalConditionsOfSatisfiedGuards(guard);
+ } catch (Throwable throwable) {
+ Thread.currentThread().interrupt();
+ throw Throwables.propagate(throwable);
+ }
+ throw interrupt;
+ }
+ } while (!guard.isSatisfied());
+ } finally {
+ decrementWaiters(guard);
+ }
+ }
+ }
+
+ @GuardedBy("lock")
+ private void waitUninterruptibly(Guard guard, boolean signalBeforeWaiting) {
+ if (!guard.isSatisfied()) {
+ if (signalBeforeWaiting) {
+ signalConditionsOfSatisfiedGuards(null);
+ }
+ incrementWaiters(guard);
+ try {
+ final Condition condition = guard.condition;
+ do {
+ condition.awaitUninterruptibly();
+ } while (!guard.isSatisfied());
+ } finally {
+ decrementWaiters(guard);
+ }
+ }
+ }
+
+ @GuardedBy("lock")
+ private boolean waitInterruptibly(Guard guard, long remainingNanos, boolean signalBeforeWaiting)
+ throws InterruptedException {
+ if (!guard.isSatisfied()) {
+ if (signalBeforeWaiting) {
+ signalConditionsOfSatisfiedGuards(null);
+ }
+ incrementWaiters(guard);
+ try {
+ final Condition condition = guard.condition;
+ do {
+ if (remainingNanos <= 0) {
+ return false;
+ }
+ try {
+ remainingNanos = condition.awaitNanos(remainingNanos);
+ } catch (InterruptedException interrupt) {
+ try {
+ signalConditionsOfSatisfiedGuards(guard);
+ } catch (Throwable throwable) {
+ Thread.currentThread().interrupt();
+ throw Throwables.propagate(throwable);
+ }
+ throw interrupt;
+ }
+ } while (!guard.isSatisfied());
+ } finally {
+ decrementWaiters(guard);
+ }
+ }
+ return true;
+ }
+
+ @GuardedBy("lock")
+ private boolean waitUninterruptibly(Guard guard, long timeoutNanos,
+ boolean signalBeforeWaiting) {
+ if (!guard.isSatisfied()) {
+ long startNanos = System.nanoTime();
+ if (signalBeforeWaiting) {
+ signalConditionsOfSatisfiedGuards(null);
+ }
+ boolean interruptIgnored = false;
+ try {
+ incrementWaiters(guard);
+ try {
+ final Condition condition = guard.condition;
+ long remainingNanos = timeoutNanos;
+ do {
+ if (remainingNanos <= 0) {
+ return false;
+ }
+ try {
+ remainingNanos = condition.awaitNanos(remainingNanos);
+ } catch (InterruptedException ignored) {
+ try {
+ signalConditionsOfSatisfiedGuards(guard);
+ } catch (Throwable throwable) {
+ Thread.currentThread().interrupt();
+ throw Throwables.propagate(throwable);
+ }
+ interruptIgnored = true;
+ remainingNanos = (timeoutNanos - (System.nanoTime() - startNanos));
+ }
+ } while (!guard.isSatisfied());
+ } finally {
+ decrementWaiters(guard);
+ }
+ } finally {
+ if (interruptIgnored) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/guava/src/com/google/common/util/concurrent/MoreExecutors.java b/guava/src/com/google/common/util/concurrent/MoreExecutors.java
new file mode 100644
index 0000000..8699b5a
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/MoreExecutors.java
@@ -0,0 +1,587 @@
+/*
+ * 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.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.collect.Lists;
+import com.google.common.collect.Queues;
+
+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;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+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;
+
+/**
+ * Factory and utility methods for {@link java.util.concurrent.Executor}, {@link
+ * ExecutorService}, and {@link ThreadFactory}.
+ *
+ * @author Eric Fellheimer
+ * @author Kyle Littlefield
+ * @author Justin Mahoney
+ * @since 3.0
+ */
+public final class MoreExecutors {
+ private MoreExecutors() {}
+
+ /**
+ * Converts the given ThreadPoolExecutor into an ExecutorService that exits
+ * when the application is complete. It does so by using daemon threads and
+ * adding a shutdown hook to wait for their completion.
+ *
+ * <p>This is mainly for fixed thread pools.
+ * See {@link Executors#newFixedThreadPool(int)}.
+ *
+ * @param executor the executor to modify to make sure it exits when the
+ * application is finished
+ * @param terminationTimeout how long to wait for the executor to
+ * finish before terminating the JVM
+ * @param timeUnit unit of time for the time parameter
+ * @return an unmodifiable version of the input which will not hang the JVM
+ */
+ @Beta
+ public static ExecutorService getExitingExecutorService(
+ ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
+ executor.setThreadFactory(new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setThreadFactory(executor.getThreadFactory())
+ .build());
+
+ ExecutorService service = Executors.unconfigurableExecutorService(executor);
+
+ addDelayedShutdownHook(service, terminationTimeout, timeUnit);
+
+ return service;
+ }
+
+ /**
+ * Converts the given ScheduledThreadPoolExecutor into a
+ * ScheduledExecutorService that exits when the application is complete. It
+ * does so by using daemon threads and adding a shutdown hook to wait for
+ * their completion.
+ *
+ * <p>This is mainly for fixed thread pools.
+ * See {@link Executors#newScheduledThreadPool(int)}.
+ *
+ * @param executor the executor to modify to make sure it exits when the
+ * application is finished
+ * @param terminationTimeout how long to wait for the executor to
+ * finish before terminating the JVM
+ * @param timeUnit unit of time for the time parameter
+ * @return an unmodifiable version of the input which will not hang the JVM
+ */
+ @Beta
+ public static ScheduledExecutorService getExitingScheduledExecutorService(
+ 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;
+ }
+
+ /**
+ * Add a shutdown hook to wait for thread completion in the given
+ * {@link ExecutorService service}. This is useful if the given service uses
+ * daemon threads, and we want to keep the JVM from exiting immediately on
+ * shutdown, instead giving these daemon threads a chance to terminate
+ * normally.
+ * @param service ExecutorService which uses daemon threads
+ * @param terminationTimeout how long to wait for the executor to finish
+ * before terminating the JVM
+ * @param timeUnit unit of time for the time parameter
+ */
+ @Beta
+ public static void addDelayedShutdownHook(
+ 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.
+ }
+ }
+ }, "DelayedShutdownHook-for-" + service));
+ }
+
+ /**
+ * Converts the given ThreadPoolExecutor into an ExecutorService that exits
+ * when the application is complete. It does so by using daemon threads and
+ * adding a shutdown hook to wait for their completion.
+ *
+ * <p>This method waits 120 seconds before continuing with JVM termination,
+ * even if the executor has not finished its work.
+ *
+ * <p>This is mainly for fixed thread pools.
+ * See {@link Executors#newFixedThreadPool(int)}.
+ *
+ * @param executor the executor to modify to make sure it exits when the
+ * application is finished
+ * @return an unmodifiable version of the input which will not hang the JVM
+ */
+ @Beta
+ public static ExecutorService getExitingExecutorService(
+ ThreadPoolExecutor executor) {
+ return getExitingExecutorService(executor, 120, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Converts the given ThreadPoolExecutor into a ScheduledExecutorService that
+ * exits when the application is complete. It does so by using daemon threads
+ * and adding a shutdown hook to wait for their completion.
+ *
+ * <p>This method waits 120 seconds before continuing with JVM termination,
+ * even if the executor has not finished its work.
+ *
+ * <p>This is mainly for fixed thread pools.
+ * See {@link Executors#newScheduledThreadPool(int)}.
+ *
+ * @param executor the executor to modify to make sure it exits when the
+ * application is finished
+ * @return an unmodifiable version of the input which will not hang the JVM
+ */
+ @Beta
+ public static ScheduledExecutorService getExitingScheduledExecutorService(
+ ScheduledThreadPoolExecutor executor) {
+ return getExitingScheduledExecutorService(executor, 120, TimeUnit.SECONDS);
+ }
+
+ /**
+ * Creates an executor service that runs each task in the thread
+ * that invokes {@code execute/submit}, as in {@link CallerRunsPolicy} This
+ * applies both to individually submitted tasks and to collections of tasks
+ * submitted via {@code invokeAll} or {@code invokeAny}. In the latter case,
+ * tasks will run serially on the calling thread. Tasks are run to
+ * completion before a {@code Future} is returned to the caller (unless the
+ * executor has been shutdown).
+ *
+ * <p>Although all tasks are immediately executed in the thread that
+ * submitted the task, this {@code ExecutorService} imposes a small
+ * locking overhead on each task submission in order to implement shutdown
+ * and termination behavior.
+ *
+ * <p>The implementation deviates from the {@code ExecutorService}
+ * specification with regards to the {@code shutdownNow} method. First,
+ * "best-effort" with regards to canceling running tasks is implemented
+ * as "no-effort". No interrupts or other attempts are made to stop
+ * threads executing tasks. Second, the returned list will always be empty,
+ * as any submitted task is considered to have started execution.
+ * This applies also to tasks given to {@code invokeAll} or {@code invokeAny}
+ * which are pending serial execution, even the subset of the tasks that
+ * have not yet started execution. It is unclear from the
+ * {@code ExecutorService} specification if these should be included, and
+ * it's much easier to implement the interpretation that they not be.
+ * Finally, a call to {@code shutdown} or {@code shutdownNow} may result
+ * in concurrent calls to {@code invokeAll/invokeAny} throwing
+ * RejectedExecutionException, although a subset of the tasks may already
+ * have been executed.
+ *
+ * @since 10.0 (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility"
+ * >mostly source-compatible</a> since 3.0)
+ */
+ public static ListeningExecutorService sameThreadExecutor() {
+ return new SameThreadExecutorService();
+ }
+
+ // See sameThreadExecutor javadoc for behavioral notes.
+ private static class SameThreadExecutorService
+ extends AbstractListeningExecutorService {
+ /**
+ * Lock used whenever accessing the state variables
+ * (runningTasks, shutdown, terminationCondition) of the executor
+ */
+ private final Lock lock = new ReentrantLock();
+
+ /** Signaled after the executor is shutdown and running tasks are done */
+ private final Condition termination = lock.newCondition();
+
+ /*
+ * Conceptually, these two variables describe the executor being in
+ * one of three states:
+ * - Active: shutdown == false
+ * - Shutdown: runningTasks > 0 and shutdown == true
+ * - Terminated: runningTasks == 0 and shutdown == true
+ */
+ private int runningTasks = 0;
+ private boolean shutdown = false;
+
+ @Override
+ public void execute(Runnable command) {
+ startTask();
+ try {
+ command.run();
+ } finally {
+ endTask();
+ }
+ }
+
+ @Override
+ public boolean isShutdown() {
+ lock.lock();
+ try {
+ return shutdown;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ lock.lock();
+ try {
+ shutdown = true;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ // See sameThreadExecutor javadoc for unusual behavior of this method.
+ @Override
+ public List<Runnable> shutdownNow() {
+ shutdown();
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ lock.lock();
+ try {
+ return shutdown && runningTasks == 0;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ long nanos = unit.toNanos(timeout);
+ lock.lock();
+ try {
+ for (;;) {
+ if (isTerminated()) {
+ return true;
+ } else if (nanos <= 0) {
+ return false;
+ } else {
+ nanos = termination.awaitNanos(nanos);
+ }
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Checks if the executor has been shut down and increments the running
+ * task count.
+ *
+ * @throws RejectedExecutionException if the executor has been previously
+ * shutdown
+ */
+ private void startTask() {
+ lock.lock();
+ try {
+ if (isShutdown()) {
+ throw new RejectedExecutionException("Executor already shutdown");
+ }
+ runningTasks++;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Decrements the running task count.
+ */
+ private void endTask() {
+ lock.lock();
+ try {
+ runningTasks--;
+ if (isTerminated()) {
+ termination.signalAll();
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ }
+
+ /**
+ * Creates an {@link ExecutorService} whose {@code submit} and {@code
+ * invokeAll} methods submit {@link ListenableFutureTask} instances to the
+ * given delegate executor. Those methods, as well as {@code execute} and
+ * {@code invokeAny}, are implemented in terms of calls to {@code
+ * delegate.execute}. All other methods are forwarded unchanged to the
+ * delegate. This implies that the returned {@code ListeningExecutorService}
+ * never calls the delegate's {@code submit}, {@code invokeAll}, and {@code
+ * invokeAny} methods, so any special handling of tasks must be implemented in
+ * the delegate's {@code execute} method or by wrapping the returned {@code
+ * ListeningExecutorService}.
+ *
+ * <p>If the delegate executor was already an instance of {@code
+ * ListeningExecutorService}, it is returned untouched, and the rest of this
+ * documentation does not apply.
+ *
+ * @since 10.0
+ */
+ public static ListeningExecutorService listeningDecorator(
+ ExecutorService delegate) {
+ return (delegate instanceof ListeningExecutorService)
+ ? (ListeningExecutorService) delegate
+ : (delegate instanceof ScheduledExecutorService)
+ ? new ScheduledListeningDecorator((ScheduledExecutorService) delegate)
+ : new ListeningDecorator(delegate);
+ }
+
+ /**
+ * Creates a {@link ScheduledExecutorService} whose {@code submit} and {@code
+ * invokeAll} methods submit {@link ListenableFutureTask} instances to the
+ * given delegate executor. Those methods, as well as {@code execute} and
+ * {@code invokeAny}, are implemented in terms of calls to {@code
+ * delegate.execute}. All other methods are forwarded unchanged to the
+ * delegate. This implies that the returned {@code
+ * SchedulingListeningExecutorService} never calls the delegate's {@code
+ * submit}, {@code invokeAll}, and {@code invokeAny} methods, so any special
+ * handling of tasks must be implemented in the delegate's {@code execute}
+ * method or by wrapping the returned {@code
+ * SchedulingListeningExecutorService}.
+ *
+ * <p>If the delegate executor was already an instance of {@code
+ * ListeningScheduledExecutorService}, it is returned untouched, and the rest
+ * of this documentation does not apply.
+ *
+ * @since 10.0
+ */
+ public static ListeningScheduledExecutorService listeningDecorator(
+ ScheduledExecutorService delegate) {
+ return (delegate instanceof ListeningScheduledExecutorService)
+ ? (ListeningScheduledExecutorService) delegate
+ : new ScheduledListeningDecorator(delegate);
+ }
+
+ private static class ListeningDecorator
+ extends AbstractListeningExecutorService {
+ final ExecutorService delegate;
+
+ ListeningDecorator(ExecutorService delegate) {
+ this.delegate = checkNotNull(delegate);
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return delegate.awaitTermination(timeout, unit);
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return delegate.isShutdown();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return delegate.isTerminated();
+ }
+
+ @Override
+ public void shutdown() {
+ delegate.shutdown();
+ }
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ return delegate.shutdownNow();
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ delegate.execute(command);
+ }
+ }
+
+ private static class ScheduledListeningDecorator
+ extends ListeningDecorator implements ListeningScheduledExecutorService {
+ @SuppressWarnings("hiding")
+ final ScheduledExecutorService delegate;
+
+ ScheduledListeningDecorator(ScheduledExecutorService delegate) {
+ super(delegate);
+ this.delegate = checkNotNull(delegate);
+ }
+
+ @Override
+ public ScheduledFuture<?> schedule(
+ Runnable command, long delay, TimeUnit unit) {
+ return delegate.schedule(command, delay, unit);
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(
+ Callable<V> callable, long delay, TimeUnit unit) {
+ return delegate.schedule(callable, delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(
+ Runnable command, long initialDelay, long period, TimeUnit unit) {
+ return delegate.scheduleAtFixedRate(command, initialDelay, period, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(
+ Runnable command, long initialDelay, long delay, TimeUnit unit) {
+ return delegate.scheduleWithFixedDelay(
+ 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 {
+ 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;
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/RateLimiter.java b/guava/src/com/google/common/util/concurrent/RateLimiter.java
new file mode 100644
index 0000000..eaf3aa9
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/RateLimiter.java
@@ -0,0 +1,658 @@
+/*
+ * 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.
+ */
+ double stableIntervalMicros;
+
+ /**
+ * 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 synchronized void setRate(double permitsPerSecond) {
+ Preconditions.checkArgument(permitsPerSecond > 0.0
+ && !Double.isNaN(permitsPerSecond), "rate must be positive");
+ 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 synchronized 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 (this) {
+ 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 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) {
+ checkPermits(permits);
+ long timeoutMicros = unit.toMicros(timeout);
+ long microsToWait;
+ synchronized (this) {
+ 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
new file mode 100644
index 0000000..1c3bed6
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/Service.java
@@ -0,0 +1,234 @@
+/*
+ * 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.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:
+ * <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}
+ * </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.
+ *
+ * <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})
+ */
+@Beta
+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.
+ *
+ * @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}.
+ *
+ * @throws UncheckedExecutionException if startup failed
+ * @return the state of the service when startup finished.
+ */
+ State startAndWait();
+
+ /**
+ * Returns {@code true} if this service is {@linkplain State#RUNNING running}.
+ */
+ boolean isRunning();
+
+ /**
+ * Returns the lifecycle state of the 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.
+ *
+ * @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.
+ *
+ * @throws UncheckedExecutionException if the service has failed or fails during shutdown
+ * @return the state of the service when shutdown finished.
+ */
+ State stopAndWait();
+
+ /**
+ * 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})
+ */
+ @Beta // should come out of Beta when Service does
+ enum State {
+ /**
+ * A service in this state is inactive. It does minimal work and consumes
+ * minimal resources.
+ */
+ NEW,
+
+ /**
+ * A service in this state is transitioning to {@link #RUNNING}.
+ */
+ STARTING,
+
+ /**
+ * A service in this state is operational.
+ */
+ RUNNING,
+
+ /**
+ * A service in this state is transitioning to {@link #TERMINATED}.
+ */
+ STOPPING,
+
+ /**
+ * 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.
+ */
+ 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/SettableFuture.java b/guava/src/com/google/common/util/concurrent/SettableFuture.java
new file mode 100644
index 0000000..23e14f9
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/SettableFuture.java
@@ -0,0 +1,70 @@
+/*
+ * 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.util.concurrent;
+
+import javax.annotation.Nullable;
+
+/**
+ * A {@link ListenableFuture} whose result may be set by a {@link #set(Object)}
+ * or {@link #setException(Throwable)} call. It may also be cancelled.
+ *
+ * @author Sven Mawson
+ * @since 9.0 (in 1.0 as {@code ValueFuture})
+ */
+public final class SettableFuture<V> extends AbstractFuture<V> {
+
+ /**
+ * Creates a new {@code SettableFuture} in the default state.
+ */
+ public static <V> SettableFuture<V> create() {
+ return new SettableFuture<V>();
+ }
+
+ /**
+ * Explicit private constructor, use the {@link #create} factory method to
+ * create instances of {@code SettableFuture}.
+ */
+ private SettableFuture() {}
+
+ /**
+ * Sets the value of this future. This method will return {@code true} if
+ * the value was successfully set, or {@code false} if the future has already
+ * been set or cancelled.
+ *
+ * @param value the value the future should hold.
+ * @return true if the value was successfully set.
+ */
+ @Override
+ public boolean set(@Nullable V value) {
+ return super.set(value);
+ }
+
+ /**
+ * Sets the future to having failed with the given exception. This exception
+ * will be wrapped in an {@code ExecutionException} and thrown from the {@code
+ * get} methods. This method will return {@code true} if the exception was
+ * successfully set, or {@code false} if the future has already been set or
+ * cancelled.
+ *
+ * @param throwable the exception the future should hold.
+ * @return true if the exception was successfully set.
+ */
+ @Override
+ public boolean setException(Throwable throwable) {
+ return super.setException(throwable);
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/SimpleTimeLimiter.java b/guava/src/com/google/common/util/concurrent/SimpleTimeLimiter.java
new file mode 100644
index 0000000..0f7c3e4
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/SimpleTimeLimiter.java
@@ -0,0 +1,195 @@
+/*
+ * 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.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.collect.ObjectArrays;
+import com.google.common.collect.Sets;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Set;
+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.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A TimeLimiter that runs method calls in the background using an
+ * {@link ExecutorService}. If the time limit expires for a given method call,
+ * the thread running the call will be interrupted.
+ *
+ * @author Kevin Bourrillion
+ * @since 1.0
+ */
+@Beta
+public final class SimpleTimeLimiter implements TimeLimiter {
+
+ private final ExecutorService executor;
+
+ /**
+ * Constructs a TimeLimiter instance using the given executor service to
+ * execute proxied method calls.
+ * <p>
+ * <b>Warning:</b> using a bounded executor
+ * may be counterproductive! If the thread pool fills up, any time callers
+ * spend waiting for a thread may count toward their time limit, and in
+ * this case the call may even time out before the target method is ever
+ * invoked.
+ *
+ * @param executor the ExecutorService that will execute the method calls on
+ * the target objects; for example, a {@link
+ * Executors#newCachedThreadPool()}.
+ */
+ public SimpleTimeLimiter(ExecutorService executor) {
+ this.executor = checkNotNull(executor);
+ }
+
+ /**
+ * Constructs a TimeLimiter instance using a {@link
+ * Executors#newCachedThreadPool()} to execute proxied method calls.
+ *
+ * <p><b>Warning:</b> using a bounded executor may be counterproductive! If
+ * the thread pool fills up, any time callers spend waiting for a thread may
+ * count toward their time limit, and in this case the call may even time out
+ * before the target method is ever invoked.
+ */
+ public SimpleTimeLimiter() {
+ this(Executors.newCachedThreadPool());
+ }
+
+ @Override
+ public <T> T newProxy(final T target, Class<T> interfaceType,
+ final long timeoutDuration, final TimeUnit timeoutUnit) {
+ checkNotNull(target);
+ checkNotNull(interfaceType);
+ checkNotNull(timeoutUnit);
+ checkArgument(timeoutDuration > 0, "bad timeout: " + timeoutDuration);
+ checkArgument(interfaceType.isInterface(),
+ "interfaceType must be an interface type");
+
+ final Set<Method> interruptibleMethods
+ = findInterruptibleMethods(interfaceType);
+
+ InvocationHandler handler = new InvocationHandler() {
+ @Override
+ public Object invoke(Object obj, final Method method, final Object[] args)
+ throws Throwable {
+ Callable<Object> callable = new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ try {
+ return method.invoke(target, args);
+ } catch (InvocationTargetException e) {
+ throwCause(e, false);
+ throw new AssertionError("can't get here");
+ }
+ }
+ };
+ return callWithTimeout(callable, timeoutDuration, timeoutUnit,
+ interruptibleMethods.contains(method));
+ }
+ };
+ return newProxy(interfaceType, handler);
+ }
+
+ // TODO: should this actually throw only ExecutionException?
+ @Override
+ public <T> T callWithTimeout(Callable<T> callable, long timeoutDuration,
+ TimeUnit timeoutUnit, boolean amInterruptible) throws Exception {
+ checkNotNull(callable);
+ checkNotNull(timeoutUnit);
+ checkArgument(timeoutDuration > 0, "timeout must be positive: %s",
+ timeoutDuration);
+ Future<T> future = executor.submit(callable);
+ try {
+ if (amInterruptible) {
+ try {
+ return future.get(timeoutDuration, timeoutUnit);
+ } catch (InterruptedException e) {
+ future.cancel(true);
+ throw e;
+ }
+ } else {
+ return Uninterruptibles.getUninterruptibly(future,
+ timeoutDuration, timeoutUnit);
+ }
+ } catch (ExecutionException e) {
+ throw throwCause(e, true);
+ } catch (TimeoutException e) {
+ future.cancel(true);
+ throw new UncheckedTimeoutException(e);
+ }
+ }
+
+ private static Exception throwCause(Exception e, boolean combineStackTraces)
+ throws Exception {
+ Throwable cause = e.getCause();
+ if (cause == null) {
+ throw e;
+ }
+ if (combineStackTraces) {
+ StackTraceElement[] combined = ObjectArrays.concat(cause.getStackTrace(),
+ e.getStackTrace(), StackTraceElement.class);
+ cause.setStackTrace(combined);
+ }
+ if (cause instanceof Exception) {
+ throw (Exception) cause;
+ }
+ if (cause instanceof Error) {
+ throw (Error) cause;
+ }
+ // The cause is a weird kind of Throwable, so throw the outer exception.
+ throw e;
+ }
+
+ private static Set<Method> findInterruptibleMethods(Class<?> interfaceType) {
+ Set<Method> set = Sets.newHashSet();
+ for (Method m : interfaceType.getMethods()) {
+ if (declaresInterruptedEx(m)) {
+ set.add(m);
+ }
+ }
+ return set;
+ }
+
+ private static boolean declaresInterruptedEx(Method method) {
+ for (Class<?> exType : method.getExceptionTypes()) {
+ // debate: == or isAssignableFrom?
+ if (exType == InterruptedException.class) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // TODO: replace with version in common.reflect if and when it's open-sourced
+ private static <T> T newProxy(
+ Class<T> interfaceType, InvocationHandler handler) {
+ Object object = Proxy.newProxyInstance(interfaceType.getClassLoader(),
+ new Class<?>[] { interfaceType }, handler);
+ return interfaceType.cast(object);
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/Striped.java b/guava/src/com/google/common/util/concurrent/Striped.java
new file mode 100644
index 0000000..3c426f0
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/Striped.java
@@ -0,0 +1,376 @@
+/*
+ * 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
new file mode 100644
index 0000000..167ad11
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/ThreadFactoryBuilder.java
@@ -0,0 +1,176 @@
+/*
+ * 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.util.concurrent;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A ThreadFactory builder, providing any combination of these features:
+ * <ul>
+ * <li> whether threads should be marked as {@linkplain Thread#setDaemon daemon}
+ * threads
+ * <li> a {@linkplain ThreadFactoryBuilder#setNameFormat naming format}
+ * <li> a {@linkplain Thread#setPriority thread priority}
+ * <li> an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception
+ * handler}
+ * <li> a {@linkplain ThreadFactory#newThread backing thread factory}
+ * </ul>
+ * If no backing thread factory is provided, a default backing thread factory is
+ * used as if by calling {@code setThreadFactory(}{@link
+ * Executors#defaultThreadFactory()}{@code )}.
+ *
+ * @author Kurt Alfred Kluever
+ * @since 4.0
+ */
+public final class ThreadFactoryBuilder {
+ private String nameFormat = null;
+ private Boolean daemon = null;
+ private Integer priority = null;
+ private UncaughtExceptionHandler uncaughtExceptionHandler = null;
+ private ThreadFactory backingThreadFactory = null;
+
+ /**
+ * Creates a new {@link ThreadFactory} builder.
+ */
+ public ThreadFactoryBuilder() {}
+
+ /**
+ * Sets the naming format to use when naming threads ({@link Thread#setName})
+ * which are created with this ThreadFactory.
+ *
+ * @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.
+ * @return this for the builder pattern
+ */
+ public ThreadFactoryBuilder setNameFormat(String nameFormat) {
+ String.format(nameFormat, 0); // fail fast if the format is bad or null
+ this.nameFormat = nameFormat;
+ return this;
+ }
+
+ /**
+ * Sets daemon or not for new threads created with this ThreadFactory.
+ *
+ * @param daemon whether or not new Threads created with this ThreadFactory
+ * will be daemon threads
+ * @return this for the builder pattern
+ */
+ public ThreadFactoryBuilder setDaemon(boolean daemon) {
+ this.daemon = daemon;
+ return this;
+ }
+
+ /**
+ * Sets the priority for new threads created with this ThreadFactory.
+ *
+ * @param priority the priority for new Threads created with this
+ * ThreadFactory
+ * @return this for the builder pattern
+ */
+ public ThreadFactoryBuilder setPriority(int priority) {
+ // Thread#setPriority() already checks for validity. These error messages
+ // are nicer though and will fail-fast.
+ checkArgument(priority >= Thread.MIN_PRIORITY,
+ "Thread priority (%s) must be >= %s", priority, Thread.MIN_PRIORITY);
+ checkArgument(priority <= Thread.MAX_PRIORITY,
+ "Thread priority (%s) must be <= %s", priority, Thread.MAX_PRIORITY);
+ this.priority = priority;
+ return this;
+ }
+
+ /**
+ * Sets the {@link UncaughtExceptionHandler} for new threads created with this
+ * ThreadFactory.
+ *
+ * @param uncaughtExceptionHandler the uncaught exception handler for new
+ * Threads created with this ThreadFactory
+ * @return this for the builder pattern
+ */
+ public ThreadFactoryBuilder setUncaughtExceptionHandler(
+ UncaughtExceptionHandler uncaughtExceptionHandler) {
+ this.uncaughtExceptionHandler = checkNotNull(uncaughtExceptionHandler);
+ return this;
+ }
+
+ /**
+ * Sets the backing {@link ThreadFactory} for new threads created with this
+ * ThreadFactory. Threads will be created by invoking #newThread(Runnable) on
+ * this backing {@link ThreadFactory}.
+ *
+ * @param backingThreadFactory the backing {@link ThreadFactory} which will
+ * be delegated to during thread creation.
+ * @return this for the builder pattern
+ *
+ * @see MoreExecutors
+ */
+ public ThreadFactoryBuilder setThreadFactory(
+ ThreadFactory backingThreadFactory) {
+ this.backingThreadFactory = checkNotNull(backingThreadFactory);
+ return this;
+ }
+
+ /**
+ * Returns a new thread factory using the options supplied during the building
+ * process. After building, it is still possible to change the options used to
+ * build the ThreadFactory and/or build again. State is not shared amongst
+ * built instances.
+ *
+ * @return the fully constructed {@link ThreadFactory}
+ */
+ public ThreadFactory build() {
+ return build(this);
+ }
+
+ private static ThreadFactory build(ThreadFactoryBuilder builder) {
+ final String nameFormat = builder.nameFormat;
+ final Boolean daemon = builder.daemon;
+ final Integer priority = builder.priority;
+ final UncaughtExceptionHandler uncaughtExceptionHandler =
+ builder.uncaughtExceptionHandler;
+ final ThreadFactory backingThreadFactory =
+ (builder.backingThreadFactory != null)
+ ? builder.backingThreadFactory
+ : Executors.defaultThreadFactory();
+ final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
+ return new ThreadFactory() {
+ @Override public Thread newThread(Runnable runnable) {
+ Thread thread = backingThreadFactory.newThread(runnable);
+ if (nameFormat != null) {
+ thread.setName(String.format(nameFormat, count.getAndIncrement()));
+ }
+ if (daemon != null) {
+ thread.setDaemon(daemon);
+ }
+ if (priority != null) {
+ thread.setPriority(priority);
+ }
+ if (uncaughtExceptionHandler != null) {
+ thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
+ }
+ return thread;
+ }
+ };
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/TimeLimiter.java b/guava/src/com/google/common/util/concurrent/TimeLimiter.java
new file mode 100644
index 0000000..a9938de
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/TimeLimiter.java
@@ -0,0 +1,106 @@
+/*
+ * 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.util.concurrent;
+
+import com.google.common.annotations.Beta;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Produces proxies that impose a time limit on method
+ * calls to the proxied object. For example, to return the value of
+ * {@code target.someMethod()}, but substitute {@code DEFAULT_VALUE} if this
+ * method call takes over 50 ms, you can use this code:
+ * <pre>
+ * TimeLimiter limiter = . . .;
+ * TargetType proxy = limiter.newProxy(
+ * target, TargetType.class, 50, TimeUnit.MILLISECONDS);
+ * try {
+ * return proxy.someMethod();
+ * } catch (UncheckedTimeoutException e) {
+ * return DEFAULT_VALUE;
+ * }
+ * </pre>
+ * Please see {@code SimpleTimeLimiterTest} for more usage examples.
+ *
+ * @author Kevin Bourrillion
+ * @since 1.0
+ */
+@Beta
+public interface TimeLimiter {
+
+ /**
+ * Returns an instance of {@code interfaceType} that delegates all method
+ * calls to the {@code target} object, enforcing the specified time limit on
+ * each call. This time-limited delegation is also performed for calls to
+ * {@link Object#equals}, {@link Object#hashCode}, and
+ * {@link Object#toString}.
+ * <p>
+ * If the target method call finishes before the limit is reached, the return
+ * value or exception is propagated to the caller exactly as-is. If, on the
+ * other hand, the time limit is reached, the proxy will attempt to abort the
+ * call to the target, and will throw an {@link UncheckedTimeoutException} to
+ * the caller.
+ * <p>
+ * It is important to note that the primary purpose of the proxy object is to
+ * return control to the caller when the timeout elapses; aborting the target
+ * method call is of secondary concern. The particular nature and strength
+ * of the guarantees made by the proxy is implementation-dependent. However,
+ * it is important that each of the methods on the target object behaves
+ * appropriately when its thread is interrupted.
+ *
+ * @param target the object to proxy
+ * @param interfaceType the interface you wish the returned proxy to
+ * implement
+ * @param timeoutDuration with timeoutUnit, the maximum length of time that
+ * callers are willing to wait on each method call to the proxy
+ * @param timeoutUnit with timeoutDuration, the maximum length of time that
+ * callers are willing to wait on each method call to the proxy
+ * @return a time-limiting proxy
+ * @throws IllegalArgumentException if {@code interfaceType} is a regular
+ * class, enum, or annotation type, rather than an interface
+ */
+ <T> T newProxy(T target, Class<T> interfaceType,
+ long timeoutDuration, TimeUnit timeoutUnit);
+
+ /**
+ * Invokes a specified Callable, timing out after the specified time limit.
+ * If the target method call finished before the limit is reached, the return
+ * value or exception is propagated to the caller exactly as-is. If, on the
+ * other hand, the time limit is reached, we attempt to abort the call to the
+ * target, and throw an {@link UncheckedTimeoutException} to the caller.
+ * <p>
+ * <b>Warning:</b> The future of this method is in doubt. It may be nuked, or
+ * changed significantly.
+ *
+ * @param callable the Callable to execute
+ * @param timeoutDuration with timeoutUnit, the maximum length of time to wait
+ * @param timeoutUnit with timeoutDuration, the maximum length of time to wait
+ * @param interruptible whether to respond to thread interruption by aborting
+ * the operation and throwing InterruptedException; if false, the
+ * operation is allowed to complete or time out, and the current thread's
+ * interrupt status is re-asserted.
+ * @return the result returned by the Callable
+ * @throws InterruptedException if {@code interruptible} is true and our
+ * thread is interrupted during execution
+ * @throws UncheckedTimeoutException if the time limit is reached
+ * @throws Exception
+ */
+ <T> T callWithTimeout(Callable<T> callable, long timeoutDuration,
+ TimeUnit timeoutUnit, boolean interruptible) throws Exception;
+}
diff --git a/guava/src/com/google/common/util/concurrent/UncaughtExceptionHandlers.java b/guava/src/com/google/common/util/concurrent/UncaughtExceptionHandlers.java
new file mode 100644
index 0000000..bdff7db
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/UncaughtExceptionHandlers.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util.concurrent;
+
+import static java.util.logging.Level.SEVERE;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.logging.Logger;
+
+/**
+ * Factories for {@link UncaughtExceptionHandler} instances.
+ *
+ * @author Gregory Kick
+ * @since 8.0
+ */
+public final class UncaughtExceptionHandlers {
+ private UncaughtExceptionHandlers() {}
+
+ /**
+ * Returns an exception handler that exits the system. This is particularly useful for the main
+ * thread, which may start up other, non-daemon threads, but fail to fully initialize the
+ * application successfully.
+ *
+ * <p>Example usage:
+ * <pre>public static void main(String[] args) {
+ * Thread.currentThread().setUncaughtExceptionHandler(UncaughtExceptionHandlers.systemExit());
+ * ...
+ * </pre>
+ */
+ public static UncaughtExceptionHandler systemExit() {
+ return new Exiter(Runtime.getRuntime());
+ }
+
+ @VisibleForTesting static final class Exiter implements UncaughtExceptionHandler {
+ private static final Logger logger = Logger.getLogger(Exiter.class.getName());
+
+ private final Runtime runtime;
+
+ Exiter(Runtime runtime) {
+ this.runtime = runtime;
+ }
+
+ @Override public void uncaughtException(Thread t, Throwable e) {
+ // cannot use FormattingLogger due to a dependency loop
+ logger.log(SEVERE, String.format("Caught an exception in %s. Shutting down.", t), e);
+ runtime.exit(1);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/util/concurrent/UncheckedExecutionException.java b/guava/src/com/google/common/util/concurrent/UncheckedExecutionException.java
new file mode 100644
index 0000000..ad84535
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/UncheckedExecutionException.java
@@ -0,0 +1,69 @@
+/*
+ * 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.annotations.GwtCompatible;
+
+/**
+ * Unchecked variant of {@link java.util.concurrent.ExecutionException}. As with
+ * {@code ExecutionException}, the exception's {@linkplain #getCause() cause}
+ * comes from a failed task, possibly run in another thread.
+ *
+ * <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.
+ *
+ * <p>When wrapping an {@code Error} from another thread, prefer {@link
+ * ExecutionError}. When wrapping a checked exception, prefer {@code
+ * ExecutionException}.
+ *
+ * @author Charles Fry
+ * @since 10.0
+ */
+@Beta
+@GwtCompatible
+public class UncheckedExecutionException extends RuntimeException {
+ /**
+ * Creates a new instance with {@code null} as its detail message.
+ */
+ protected UncheckedExecutionException() {}
+
+ /**
+ * Creates a new instance with the given detail message.
+ */
+ protected UncheckedExecutionException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new instance with the given detail message and cause.
+ */
+ public UncheckedExecutionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Creates a new instance with the given cause.
+ */
+ public UncheckedExecutionException(Throwable cause) {
+ super(cause);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/util/concurrent/UncheckedTimeoutException.java b/guava/src/com/google/common/util/concurrent/UncheckedTimeoutException.java
new file mode 100644
index 0000000..d821c84
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/UncheckedTimeoutException.java
@@ -0,0 +1,41 @@
+/*
+ * 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.util.concurrent;
+
+/**
+ * Unchecked version of {@link java.util.concurrent.TimeoutException}.
+ *
+ * @author Kevin Bourrillion
+ * @since 1.0
+ */
+public class UncheckedTimeoutException extends RuntimeException {
+ public UncheckedTimeoutException() {}
+
+ public UncheckedTimeoutException(String message) {
+ super(message);
+ }
+
+ public UncheckedTimeoutException(Throwable cause) {
+ super(cause);
+ }
+
+ public UncheckedTimeoutException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/guava/src/com/google/common/util/concurrent/Uninterruptibles.java b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
new file mode 100644
index 0000000..89f30b8
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/Uninterruptibles.java
@@ -0,0 +1,278 @@
+/*
+ * 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 java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Utilities for treating interruptible operations as uninterruptible.
+ * In all cases, if a thread is interrupted during such a call, the call
+ * continues to block until the result is available or the timeout elapses,
+ * and only then re-interrupts the thread.
+ *
+ * @author Anthony Zana
+ * @since 10.0
+ */
+@Beta
+public final class Uninterruptibles {
+
+ // Implementation Note: As of 3-7-11, the logic for each blocking/timeout
+ // methods is identical, save for method being invoked.
+
+ /**
+ * Invokes {@code latch.}{@link CountDownLatch#await() await()}
+ * uninterruptibly.
+ */
+ public static void awaitUninterruptibly(CountDownLatch latch) {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ latch.await();
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes
+ * {@code latch.}{@link CountDownLatch#await(long, TimeUnit)
+ * await(timeout, unit)} uninterruptibly.
+ */
+ public static boolean awaitUninterruptibly(CountDownLatch latch,
+ long timeout, TimeUnit unit) {
+ boolean interrupted = false;
+ try {
+ long remainingNanos = unit.toNanos(timeout);
+ long end = System.nanoTime() + remainingNanos;
+
+ while (true) {
+ try {
+ // CountDownLatch treats negative timeouts just like zero.
+ return latch.await(remainingNanos, NANOSECONDS);
+ } catch (InterruptedException e) {
+ interrupted = true;
+ remainingNanos = end - System.nanoTime();
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes {@code toJoin.}{@link Thread#join() join()} uninterruptibly.
+ */
+ public static void joinUninterruptibly(Thread toJoin) {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ toJoin.join();
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes {@code future.}{@link Future#get() get()} uninterruptibly.
+ * To get uninterruptibility and remove checked exceptions, see
+ * {@link Futures#getUnchecked}.
+ *
+ * <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}.
+ */
+ public static <V> V getUninterruptibly(Future<V> future)
+ throws ExecutionException {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ return future.get();
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes
+ * {@code future.}{@link Future#get(long, TimeUnit) get(timeout, unit)}
+ * uninterruptibly.
+ *
+ * <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}.
+ */
+ public static <V> V getUninterruptibly(
+ Future<V> future, long timeout, TimeUnit unit)
+ throws ExecutionException, TimeoutException {
+ boolean interrupted = false;
+ try {
+ long remainingNanos = unit.toNanos(timeout);
+ long end = System.nanoTime() + remainingNanos;
+
+ while (true) {
+ try {
+ // Future treats negative timeouts just like zero.
+ return future.get(remainingNanos, NANOSECONDS);
+ } catch (InterruptedException e) {
+ interrupted = true;
+ remainingNanos = end - System.nanoTime();
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes
+ * {@code unit.}{@link TimeUnit#timedJoin(Thread, long)
+ * timedJoin(toJoin, timeout)} uninterruptibly.
+ */
+ public static void joinUninterruptibly(Thread toJoin,
+ long timeout, TimeUnit unit) {
+ Preconditions.checkNotNull(toJoin);
+ boolean interrupted = false;
+ try {
+ long remainingNanos = unit.toNanos(timeout);
+ long end = System.nanoTime() + remainingNanos;
+ while (true) {
+ try {
+ // TimeUnit.timedJoin() treats negative timeouts just like zero.
+ NANOSECONDS.timedJoin(toJoin, remainingNanos);
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ remainingNanos = end - System.nanoTime();
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes {@code queue.}{@link BlockingQueue#take() take()} uninterruptibly.
+ */
+ public static <E> E takeUninterruptibly(BlockingQueue<E> queue) {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ return queue.take();
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * Invokes {@code queue.}{@link BlockingQueue#put(Object) put(element)}
+ * uninterruptibly.
+ */
+ public static <E> void putUninterruptibly(BlockingQueue<E> queue, E element) {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ queue.put(element);
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ // TODO(user): Support Sleeper somehow (wrapper or interface method)?
+ /**
+ * Invokes {@code unit.}{@link TimeUnit#sleep(long) sleep(sleepFor)}
+ * uninterruptibly.
+ */
+ public static void sleepUninterruptibly(long sleepFor, TimeUnit unit) {
+ boolean interrupted = false;
+ try {
+ long remainingNanos = unit.toNanos(sleepFor);
+ long end = System.nanoTime() + remainingNanos;
+ while (true) {
+ try {
+ // TimeUnit.sleep() treats negative timeouts just like zero.
+ NANOSECONDS.sleep(remainingNanos);
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ remainingNanos = end - System.nanoTime();
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ // TODO(user): Add support for waitUninterruptibly.
+
+ private Uninterruptibles() {}
+}
diff --git a/guava/src/com/google/common/util/concurrent/package-info.java b/guava/src/com/google/common/util/concurrent/package-info.java
new file mode 100644
index 0000000..6ea5069
--- /dev/null
+++ b/guava/src/com/google/common/util/concurrent/package-info.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+/**
+ * Concurrency utilities.
+ *
+ * <p>Commonly used types include {@link
+ * com.google.common.util.concurrent.ListenableFuture} and {@link
+ * com.google.common.util.concurrent.Service}.
+ *
+ * <p>Commonly used utilities include {@link
+ * com.google.common.util.concurrent.Futures}, {@link
+ * com.google.common.util.concurrent.MoreExecutors}, and {@link
+ * com.google.common.util.concurrent.ThreadFactoryBuilder}.
+ *
+ * <p>This package is a part of the open-source
+ * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
+ */
+@ParametersAreNonnullByDefault
+package com.google.common.util.concurrent;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/guava/test/com/google/common/base/CaseFormatTest.java b/guava/test/com/google/common/base/CaseFormatTest.java
new file mode 100644
index 0000000..733330e
--- /dev/null
+++ b/guava/test/com/google/common/base/CaseFormatTest.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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.CaseFormat.LOWER_CAMEL;
+import static com.google.common.base.CaseFormat.LOWER_HYPHEN;
+import static com.google.common.base.CaseFormat.LOWER_UNDERSCORE;
+import static com.google.common.base.CaseFormat.UPPER_CAMEL;
+import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link CaseFormat}.
+ *
+ * @author Mike Bostock
+ */
+public class CaseFormatTest extends TestCase {
+
+ public void testIdentity() {
+ for (CaseFormat from : CaseFormat.values()) {
+ assertSame(from + " to " + from, "foo", from.to(from, "foo"));
+ for (CaseFormat to : CaseFormat.values()) {
+ assertEquals(from + " to " + to, "", from.to(to, ""));
+ assertEquals(from + " to " + to, " ", from.to(to, " "));
+ }
+ }
+ }
+
+ public void testNullPointer() {
+ try {
+ LOWER_CAMEL.to(null, "");
+ fail();
+ } catch (NullPointerException expected) {}
+ try {
+ LOWER_CAMEL.to(LOWER_HYPHEN, null);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
+ public void testLowerHyphenToLowerHyphen() {
+ assertEquals("foo", LOWER_HYPHEN.to(LOWER_HYPHEN, "foo"));
+ assertEquals("foo-bar", LOWER_HYPHEN.to(LOWER_HYPHEN, "foo-bar"));
+ }
+
+ public void testLowerHyphenToLowerUnderscore() {
+ assertEquals("foo", LOWER_HYPHEN.to(LOWER_UNDERSCORE, "foo"));
+ assertEquals("foo_bar", LOWER_HYPHEN.to(LOWER_UNDERSCORE, "foo-bar"));
+ }
+
+ public void testLowerHyphenToLowerCamel() {
+ assertEquals("foo", LOWER_HYPHEN.to(LOWER_CAMEL, "foo"));
+ assertEquals("fooBar", LOWER_HYPHEN.to(LOWER_CAMEL, "foo-bar"));
+ }
+
+ public void testLowerHyphenToUpperCamel() {
+ assertEquals("Foo", LOWER_HYPHEN.to(UPPER_CAMEL, "foo"));
+ assertEquals("FooBar", LOWER_HYPHEN.to(UPPER_CAMEL, "foo-bar"));
+ }
+
+ public void testLowerHyphenToUpperUnderscore() {
+ assertEquals("FOO", LOWER_HYPHEN.to(UPPER_UNDERSCORE, "foo"));
+ assertEquals("FOO_BAR", LOWER_HYPHEN.to(UPPER_UNDERSCORE, "foo-bar"));
+ }
+
+ public void testLowerUnderscoreToLowerHyphen() {
+ assertEquals("foo", LOWER_UNDERSCORE.to(LOWER_HYPHEN, "foo"));
+ assertEquals("foo-bar", LOWER_UNDERSCORE.to(LOWER_HYPHEN, "foo_bar"));
+ }
+
+ public void testLowerUnderscoreToLowerUnderscore() {
+ assertEquals("foo", LOWER_UNDERSCORE.to(LOWER_UNDERSCORE, "foo"));
+ assertEquals("foo_bar", LOWER_UNDERSCORE.to(LOWER_UNDERSCORE, "foo_bar"));
+ }
+
+ public void testLowerUnderscoreToLowerCamel() {
+ assertEquals("foo", LOWER_UNDERSCORE.to(LOWER_CAMEL, "foo"));
+ assertEquals("fooBar", LOWER_UNDERSCORE.to(LOWER_CAMEL, "foo_bar"));
+ }
+
+ public void testLowerUnderscoreToUpperCamel() {
+ assertEquals("Foo", LOWER_UNDERSCORE.to(UPPER_CAMEL, "foo"));
+ assertEquals("FooBar", LOWER_UNDERSCORE.to(UPPER_CAMEL, "foo_bar"));
+ }
+
+ public void testLowerUnderscoreToUpperUnderscore() {
+ assertEquals("FOO", LOWER_UNDERSCORE.to(UPPER_UNDERSCORE, "foo"));
+ assertEquals("FOO_BAR", LOWER_UNDERSCORE.to(UPPER_UNDERSCORE, "foo_bar"));
+ }
+
+ public void testLowerCamelToLowerHyphen() {
+ assertEquals("foo", LOWER_CAMEL.to(LOWER_HYPHEN, "foo"));
+ assertEquals("foo-bar", LOWER_CAMEL.to(LOWER_HYPHEN, "fooBar"));
+ assertEquals("h-t-t-p", LOWER_CAMEL.to(LOWER_HYPHEN, "HTTP"));
+ }
+
+ public void testLowerCamelToLowerUnderscore() {
+ assertEquals("foo", LOWER_CAMEL.to(LOWER_UNDERSCORE, "foo"));
+ assertEquals("foo_bar", LOWER_CAMEL.to(LOWER_UNDERSCORE, "fooBar"));
+ assertEquals("h_t_t_p", LOWER_CAMEL.to(LOWER_UNDERSCORE, "hTTP"));
+ }
+
+ public void testLowerCamelToLowerCamel() {
+ assertEquals("foo", LOWER_CAMEL.to(LOWER_CAMEL, "foo"));
+ assertEquals("fooBar", LOWER_CAMEL.to(LOWER_CAMEL, "fooBar"));
+ }
+
+ public void testLowerCamelToUpperCamel() {
+ assertEquals("Foo", LOWER_CAMEL.to(UPPER_CAMEL, "foo"));
+ assertEquals("FooBar", LOWER_CAMEL.to(UPPER_CAMEL, "fooBar"));
+ assertEquals("HTTP", LOWER_CAMEL.to(UPPER_CAMEL, "hTTP"));
+ }
+
+ public void testLowerCamelToUpperUnderscore() {
+ assertEquals("FOO", LOWER_CAMEL.to(UPPER_UNDERSCORE, "foo"));
+ assertEquals("FOO_BAR", LOWER_CAMEL.to(UPPER_UNDERSCORE, "fooBar"));
+ }
+
+ public void testUpperCamelToLowerHyphen() {
+ assertEquals("foo", UPPER_CAMEL.to(LOWER_HYPHEN, "Foo"));
+ assertEquals("foo-bar", UPPER_CAMEL.to(LOWER_HYPHEN, "FooBar"));
+ }
+
+ public void testUpperCamelToLowerUnderscore() {
+ assertEquals("foo", UPPER_CAMEL.to(LOWER_UNDERSCORE, "Foo"));
+ assertEquals("foo_bar", UPPER_CAMEL.to(LOWER_UNDERSCORE, "FooBar"));
+ }
+
+ public void testUpperCamelToLowerCamel() {
+ assertEquals("foo", UPPER_CAMEL.to(LOWER_CAMEL, "Foo"));
+ assertEquals("fooBar", UPPER_CAMEL.to(LOWER_CAMEL, "FooBar"));
+ assertEquals("hTTP", UPPER_CAMEL.to(LOWER_CAMEL, "HTTP"));
+ }
+
+ public void testUpperCamelToUpperCamel() {
+ assertEquals("Foo", UPPER_CAMEL.to(UPPER_CAMEL, "Foo"));
+ assertEquals("FooBar", UPPER_CAMEL.to(UPPER_CAMEL, "FooBar"));
+ }
+
+ public void testUpperCamelToUpperUnderscore() {
+ assertEquals("FOO", UPPER_CAMEL.to(UPPER_UNDERSCORE, "Foo"));
+ assertEquals("FOO_BAR", UPPER_CAMEL.to(UPPER_UNDERSCORE, "FooBar"));
+ assertEquals("H_T_T_P", UPPER_CAMEL.to(UPPER_UNDERSCORE, "HTTP"));
+ assertEquals("H__T__T__P", UPPER_CAMEL.to(UPPER_UNDERSCORE, "H_T_T_P"));
+ }
+
+ public void testUpperUnderscoreToLowerHyphen() {
+ assertEquals("foo", UPPER_UNDERSCORE.to(LOWER_HYPHEN, "FOO"));
+ assertEquals("foo-bar", UPPER_UNDERSCORE.to(LOWER_HYPHEN, "FOO_BAR"));
+ }
+
+ public void testUpperUnderscoreToLowerUnderscore() {
+ assertEquals("foo", UPPER_UNDERSCORE.to(LOWER_UNDERSCORE, "FOO"));
+ assertEquals("foo_bar", UPPER_UNDERSCORE.to(LOWER_UNDERSCORE, "FOO_BAR"));
+ }
+
+ public void testUpperUnderscoreToLowerCamel() {
+ assertEquals("foo", UPPER_UNDERSCORE.to(LOWER_CAMEL, "FOO"));
+ assertEquals("fooBar", UPPER_UNDERSCORE.to(LOWER_CAMEL, "FOO_BAR"));
+ }
+
+ public void testUpperUnderscoreToUpperCamel() {
+ assertEquals("Foo", UPPER_UNDERSCORE.to(UPPER_CAMEL, "FOO"));
+ assertEquals("FooBar", UPPER_UNDERSCORE.to(UPPER_CAMEL, "FOO_BAR"));
+ assertEquals("HTTP", UPPER_UNDERSCORE.to(UPPER_CAMEL, "H_T_T_P"));
+ }
+
+ public void testUpperUnderscoreToUpperUnderscore() {
+ assertEquals("FOO", UPPER_UNDERSCORE.to(UPPER_UNDERSCORE, "FOO"));
+ assertEquals("FOO_BAR", UPPER_UNDERSCORE.to(UPPER_UNDERSCORE, "FOO_BAR"));
+ }
+
+ private static final String IGNORED = "`1234567890-=~!@#$%^&*()_+[]\\{}|;':\",./<>?'";
+ private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private static final String LOWER = "abcdefghijklmnopqrstuvwxyz";
+
+ public void testToUpperCase() {
+ assertEquals(UPPER, CaseFormat.toUpperCaseAscii(LOWER));
+ assertEquals(UPPER, CaseFormat.toUpperCaseAscii(UPPER));
+ assertEquals(IGNORED, CaseFormat.toUpperCaseAscii(IGNORED));
+ }
+
+ public void testToLowerCase() {
+ assertEquals(LOWER, CaseFormat.toLowerCaseAscii(UPPER));
+ assertEquals(LOWER, CaseFormat.toLowerCaseAscii(LOWER));
+ assertEquals(IGNORED, CaseFormat.toUpperCaseAscii(IGNORED));
+ }
+}
diff --git a/guava/test/com/google/common/base/CharMatcherTest.java b/guava/test/com/google/common/base/CharMatcherTest.java
new file mode 100644
index 0000000..16fe50a
--- /dev/null
+++ b/guava/test/com/google/common/base/CharMatcherTest.java
@@ -0,0 +1,613 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.CharMatcher.anyOf;
+import static com.google.common.base.CharMatcher.forPredicate;
+import static com.google.common.base.CharMatcher.inRange;
+import static com.google.common.base.CharMatcher.is;
+import static com.google.common.base.CharMatcher.isNot;
+import static com.google.common.base.CharMatcher.noneOf;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.testing.util.NullPointerTester;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link CharMatcher}.
+ *
+ * @author Kevin Bourrillion
+ */
+@GwtCompatible(emulated = true)
+public class CharMatcherTest extends TestCase {
+
+ @GwtIncompatible("NullPointerTester")
+ public void testStaticNullPointers() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ tester.testAllPublicStaticMethods(CharMatcher.class);
+ tester.testAllPublicInstanceMethods(CharMatcher.ANY);
+ tester.testAllPublicInstanceMethods(CharMatcher.anyOf("abc"));
+ }
+
+ private static final CharMatcher WHATEVER = new CharMatcher() {
+ @Override public boolean matches(char c) {
+ throw new AssertionFailedError(
+ "You weren't supposed to actually invoke me!");
+ }
+ };
+
+ public void testAnyAndNone_logicalOps() throws Exception {
+ // These are testing behavior that's never promised by the API, but since
+ // we're lucky enough that these do pass, it saves us from having to write
+ // more excruciating tests! Hooray!
+
+ assertSame(CharMatcher.ANY, CharMatcher.NONE.negate());
+ assertSame(CharMatcher.NONE, CharMatcher.ANY.negate());
+
+ assertSame(WHATEVER, CharMatcher.ANY.and(WHATEVER));
+ assertSame(CharMatcher.ANY, CharMatcher.ANY.or(WHATEVER));
+
+ assertSame(CharMatcher.NONE, CharMatcher.NONE.and(WHATEVER));
+ assertSame(WHATEVER, CharMatcher.NONE.or(WHATEVER));
+ }
+
+ // The rest of the behavior of ANY and NONE will be covered in the tests for
+ // the text processing methods below.
+
+ // The next tests require ICU4J and have, at least for now, been sliced out
+ // of the open-source view of the tests.
+
+ // For GWT-compatibility reasons, CharMatcher.JAVA_WHITESPACE doesn't actually
+ // use Character.isWhitespace. This test ensures that its custom
+ // implementation stays in sync with the implementation of
+ // Character.isWhitespace.
+
+ @GwtIncompatible("Character.isWhitespace")
+ public void testJavaWhitespace() {
+ for (int c = 0; c <= Character.MAX_VALUE; c++) {
+ assertEquals("" + c, Character.isWhitespace(c),
+ CharMatcher.JAVA_WHITESPACE.matches((char) c));
+ }
+ }
+
+ @GwtIncompatible("Character.isISOControl")
+ public void testJavaIsoControl() {
+ for (int c = 0; c <= Character.MAX_VALUE; c++) {
+ assertEquals("" + c, Character.isISOControl(c),
+ CharMatcher.JAVA_ISO_CONTROL.matches((char) c));
+ }
+ }
+
+ // There's no way to test LEGACY_WHITESPACE, really; it just is what it is.
+
+ // Omitting tests for the rest of the JAVA_* constants as these are defined
+ // as extremely straightforward pass-throughs to the JDK methods.
+
+ // We're testing the is(), isNot(), anyOf(), noneOf() and inRange() methods
+ // below by testing their text-processing methods.
+
+ // The organization of this test class is unusual, as it's not done by
+ // method, but by overall "scenario". Also, the variety of actual tests we
+ // do borders on absurd overkill. Better safe than sorry, though?
+
+ public void testEmpty() throws Exception {
+ doTestEmpty(CharMatcher.ANY);
+ doTestEmpty(CharMatcher.NONE);
+ doTestEmpty(is('a'));
+ doTestEmpty(isNot('a'));
+ doTestEmpty(anyOf(""));
+ doTestEmpty(anyOf("x"));
+ doTestEmpty(anyOf("xy"));
+ doTestEmpty(anyOf("CharMatcher"));
+ doTestEmpty(noneOf("CharMatcher"));
+ doTestEmpty(inRange('n', 'q'));
+ doTestEmpty(forPredicate(Predicates.equalTo('c')));
+ }
+
+ @GwtIncompatible("NullPointerTester")
+ public void testNull() throws Exception {
+ doTestNull(CharMatcher.ANY);
+ doTestNull(CharMatcher.NONE);
+ doTestNull(is('a'));
+ doTestNull(isNot('a'));
+ doTestNull(anyOf(""));
+ doTestNull(anyOf("x"));
+ doTestNull(anyOf("xy"));
+ doTestNull(anyOf("CharMatcher"));
+ doTestNull(noneOf("CharMatcher"));
+ doTestNull(inRange('n', 'q'));
+ doTestNull(forPredicate(Predicates.equalTo('c')));
+ }
+
+ private void doTestEmpty(CharMatcher matcher) throws Exception {
+ reallyTestEmpty(matcher);
+ reallyTestEmpty(matcher.negate());
+ reallyTestEmpty(matcher.precomputed());
+ }
+
+ private void reallyTestEmpty(CharMatcher matcher) throws Exception {
+ assertEquals(-1, matcher.indexIn(""));
+ assertEquals(-1, matcher.indexIn("", 0));
+ try {
+ matcher.indexIn("", 1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ matcher.indexIn("", -1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ assertEquals(-1, matcher.lastIndexIn(""));
+ assertTrue(matcher.matchesAllOf(""));
+ assertTrue(matcher.matchesNoneOf(""));
+ assertEquals("", matcher.removeFrom(""));
+ assertEquals("", matcher.replaceFrom("", 'z'));
+ assertEquals("", matcher.replaceFrom("", "ZZ"));
+ assertEquals("", matcher.trimFrom(""));
+ assertEquals(0, matcher.countIn(""));
+ }
+
+ @GwtIncompatible("NullPointerTester")
+ private void doTestNull(CharMatcher matcher) throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ tester.testAllPublicInstanceMethods(matcher);
+ }
+
+ public void testNoMatches() {
+ doTestNoMatches(CharMatcher.NONE, "blah");
+ doTestNoMatches(is('a'), "bcde");
+ doTestNoMatches(isNot('a'), "aaaa");
+ doTestNoMatches(anyOf(""), "abcd");
+ doTestNoMatches(anyOf("x"), "abcd");
+ doTestNoMatches(anyOf("xy"), "abcd");
+ doTestNoMatches(anyOf("CharMatcher"), "zxqy");
+ doTestNoMatches(noneOf("CharMatcher"), "ChMa");
+ doTestNoMatches(inRange('p', 'x'), "mom");
+ doTestNoMatches(forPredicate(Predicates.equalTo('c')), "abe");
+ doTestNoMatches(inRange('A', 'Z').and(inRange('F', 'K').negate()), "F1a");
+ doTestNoMatches(CharMatcher.DIGIT, "\tAz()");
+ doTestNoMatches(CharMatcher.JAVA_DIGIT, "\tAz()");
+ doTestNoMatches(CharMatcher.DIGIT.and(CharMatcher.ASCII), "\tAz()");
+ doTestNoMatches(CharMatcher.SINGLE_WIDTH, "\u05bf\u3000");
+ }
+
+ private void doTestNoMatches(CharMatcher matcher, String s) {
+ reallyTestNoMatches(matcher, s);
+ reallyTestAllMatches(matcher.negate(), s);
+ reallyTestNoMatches(matcher.precomputed(), s);
+ reallyTestAllMatches(matcher.negate().precomputed(), s);
+ reallyTestAllMatches(matcher.precomputed().negate(), s);
+ reallyTestNoMatches(forPredicate(matcher), s);
+
+ reallyTestNoMatches(matcher, new StringBuilder(s));
+ }
+
+ public void testAllMatches() {
+ doTestAllMatches(CharMatcher.ANY, "blah");
+ doTestAllMatches(isNot('a'), "bcde");
+ doTestAllMatches(is('a'), "aaaa");
+ doTestAllMatches(noneOf("CharMatcher"), "zxqy");
+ doTestAllMatches(anyOf("x"), "xxxx");
+ doTestAllMatches(anyOf("xy"), "xyyx");
+ doTestAllMatches(anyOf("CharMatcher"), "ChMa");
+ doTestAllMatches(inRange('m', 'p'), "mom");
+ doTestAllMatches(forPredicate(Predicates.equalTo('c')), "ccc");
+ doTestAllMatches(CharMatcher.DIGIT, "0123456789\u0ED0\u1B59");
+ doTestAllMatches(CharMatcher.JAVA_DIGIT, "0123456789");
+ doTestAllMatches(CharMatcher.DIGIT.and(CharMatcher.ASCII), "0123456789");
+ doTestAllMatches(CharMatcher.SINGLE_WIDTH, "\t0123ABCdef~\u00A0\u2111");
+ }
+
+ private void doTestAllMatches(CharMatcher matcher, String s) {
+ reallyTestAllMatches(matcher, s);
+ reallyTestNoMatches(matcher.negate(), s);
+ reallyTestAllMatches(matcher.precomputed(), s);
+ reallyTestNoMatches(matcher.negate().precomputed(), s);
+ reallyTestNoMatches(matcher.precomputed().negate(), s);
+ reallyTestAllMatches(forPredicate(matcher), s);
+
+ reallyTestAllMatches(matcher, new StringBuilder(s));
+ }
+
+ private void reallyTestNoMatches(CharMatcher matcher, CharSequence s) {
+ assertFalse(matcher.matches(s.charAt(0)));
+ assertEquals(-1, matcher.indexIn(s));
+ assertEquals(-1, matcher.indexIn(s, 0));
+ assertEquals(-1, matcher.indexIn(s, 1));
+ assertEquals(-1, matcher.indexIn(s, s.length()));
+ try {
+ matcher.indexIn(s, s.length() + 1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ try {
+ matcher.indexIn(s, -1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ }
+ assertEquals(-1, matcher.lastIndexIn(s));
+ assertFalse(matcher.matchesAllOf(s));
+ assertTrue(matcher.matchesNoneOf(s));
+
+ assertEquals(s.toString(), matcher.removeFrom(s));
+ assertEquals(s.toString(), matcher.replaceFrom(s, 'z'));
+ assertEquals(s.toString(), matcher.replaceFrom(s, "ZZ"));
+ assertEquals(s.toString(), matcher.trimFrom(s));
+ assertEquals(0, matcher.countIn(s));
+ }
+
+ private void reallyTestAllMatches(CharMatcher matcher, CharSequence s) {
+ assertTrue(matcher.matches(s.charAt(0)));
+ assertEquals(0, matcher.indexIn(s));
+ assertEquals(0, matcher.indexIn(s, 0));
+ assertEquals(1, matcher.indexIn(s, 1));
+ assertEquals(-1, matcher.indexIn(s, s.length()));
+ assertEquals(s.length() - 1, matcher.lastIndexIn(s));
+ assertTrue(matcher.matchesAllOf(s));
+ assertFalse(matcher.matchesNoneOf(s));
+ assertEquals("", matcher.removeFrom(s));
+ assertEquals(Strings.repeat("z", s.length()),
+ matcher.replaceFrom(s, 'z'));
+ assertEquals(Strings.repeat("ZZ", s.length()),
+ matcher.replaceFrom(s, "ZZ"));
+ assertEquals("", matcher.trimFrom(s));
+ assertEquals(s.length(), matcher.countIn(s));
+ }
+
+ public void testGeneral() {
+ doTestGeneral(is('a'), 'a', 'b');
+ doTestGeneral(isNot('a'), 'b', 'a');
+ doTestGeneral(anyOf("x"), 'x', 'z');
+ doTestGeneral(anyOf("xy"), 'y', 'z');
+ doTestGeneral(anyOf("CharMatcher"), 'C', 'z');
+ doTestGeneral(noneOf("CharMatcher"), 'z', 'C');
+ doTestGeneral(inRange('p', 'x'), 'q', 'z');
+ }
+
+ private void doTestGeneral(CharMatcher matcher, char match, char noMatch) {
+ doTestOneCharMatch(matcher, "" + match);
+ doTestOneCharNoMatch(matcher, "" + noMatch);
+ doTestMatchThenNoMatch(matcher, "" + match + noMatch);
+ doTestNoMatchThenMatch(matcher, "" + noMatch + match);
+ }
+
+ private void doTestOneCharMatch(CharMatcher matcher, String s) {
+ reallyTestOneCharMatch(matcher, s);
+ reallyTestOneCharNoMatch(matcher.negate(), s);
+ reallyTestOneCharMatch(matcher.precomputed(), s);
+ reallyTestOneCharNoMatch(matcher.negate().precomputed(), s);
+ reallyTestOneCharNoMatch(matcher.precomputed().negate(), s);
+ }
+
+ private void doTestOneCharNoMatch(CharMatcher matcher, String s) {
+ reallyTestOneCharNoMatch(matcher, s);
+ reallyTestOneCharMatch(matcher.negate(), s);
+ reallyTestOneCharNoMatch(matcher.precomputed(), s);
+ reallyTestOneCharMatch(matcher.negate().precomputed(), s);
+ reallyTestOneCharMatch(matcher.precomputed().negate(), s);
+ }
+
+ private void doTestMatchThenNoMatch(CharMatcher matcher, String s) {
+ reallyTestMatchThenNoMatch(matcher, s);
+ reallyTestNoMatchThenMatch(matcher.negate(), s);
+ reallyTestMatchThenNoMatch(matcher.precomputed(), s);
+ reallyTestNoMatchThenMatch(matcher.negate().precomputed(), s);
+ reallyTestNoMatchThenMatch(matcher.precomputed().negate(), s);
+ }
+
+ private void doTestNoMatchThenMatch(CharMatcher matcher, String s) {
+ reallyTestNoMatchThenMatch(matcher, s);
+ reallyTestMatchThenNoMatch(matcher.negate(), s);
+ reallyTestNoMatchThenMatch(matcher.precomputed(), s);
+ reallyTestMatchThenNoMatch(matcher.negate().precomputed(), s);
+ reallyTestMatchThenNoMatch(matcher.precomputed().negate(), s);
+ }
+
+ private void reallyTestOneCharMatch(CharMatcher matcher, String s) {
+ assertTrue(matcher.matches(s.charAt(0)));
+ assertTrue(matcher.apply(s.charAt(0)));
+ assertEquals(0, matcher.indexIn(s));
+ assertEquals(0, matcher.indexIn(s, 0));
+ assertEquals(-1, matcher.indexIn(s, 1));
+ assertEquals(0, matcher.lastIndexIn(s));
+ assertTrue(matcher.matchesAllOf(s));
+ assertFalse(matcher.matchesNoneOf(s));
+ assertEquals("", matcher.removeFrom(s));
+ assertEquals("z", matcher.replaceFrom(s, 'z'));
+ assertEquals("ZZ", matcher.replaceFrom(s, "ZZ"));
+ assertEquals("", matcher.trimFrom(s));
+ assertEquals(1, matcher.countIn(s));
+ }
+
+ private void reallyTestOneCharNoMatch(CharMatcher matcher, String s) {
+ assertFalse(matcher.matches(s.charAt(0)));
+ assertFalse(matcher.apply(s.charAt(0)));
+ assertEquals(-1, matcher.indexIn(s));
+ assertEquals(-1, matcher.indexIn(s, 0));
+ assertEquals(-1, matcher.indexIn(s, 1));
+ assertEquals(-1, matcher.lastIndexIn(s));
+ assertFalse(matcher.matchesAllOf(s));
+ assertTrue(matcher.matchesNoneOf(s));
+
+ // Note: only 'assertEquals' is promised by the API. Although they could
+ // have been assertSame() on the server side, they have to be assertEquals
+ // in GWT, because of GWT issue 4491.
+ assertEquals(s, matcher.removeFrom(s));
+ assertEquals(s, matcher.replaceFrom(s, 'z'));
+ assertEquals(s, matcher.replaceFrom(s, "ZZ"));
+ assertEquals(s, matcher.trimFrom(s));
+ assertEquals(0, matcher.countIn(s));
+ }
+
+ private void reallyTestMatchThenNoMatch(CharMatcher matcher, String s) {
+ assertEquals(0, matcher.indexIn(s));
+ assertEquals(0, matcher.indexIn(s, 0));
+ assertEquals(-1, matcher.indexIn(s, 1));
+ assertEquals(-1, matcher.indexIn(s, 2));
+ assertEquals(0, matcher.lastIndexIn(s));
+ assertFalse(matcher.matchesAllOf(s));
+ assertFalse(matcher.matchesNoneOf(s));
+ assertEquals(s.substring(1), matcher.removeFrom(s));
+ assertEquals("z" + s.substring(1), matcher.replaceFrom(s, 'z'));
+ assertEquals("ZZ" + s.substring(1), matcher.replaceFrom(s, "ZZ"));
+ assertEquals(s.substring(1), matcher.trimFrom(s));
+ assertEquals(1, matcher.countIn(s));
+ }
+
+ private void reallyTestNoMatchThenMatch(CharMatcher matcher, String s) {
+ assertEquals(1, matcher.indexIn(s));
+ assertEquals(1, matcher.indexIn(s, 0));
+ assertEquals(1, matcher.indexIn(s, 1));
+ assertEquals(-1, matcher.indexIn(s, 2));
+ assertEquals(1, matcher.lastIndexIn(s));
+ assertFalse(matcher.matchesAllOf(s));
+ assertFalse(matcher.matchesNoneOf(s));
+ assertEquals(s.substring(0, 1), matcher.removeFrom(s));
+ assertEquals(s.substring(0, 1) + "z", matcher.replaceFrom(s, 'z'));
+ assertEquals(s.substring(0, 1) + "ZZ", matcher.replaceFrom(s, "ZZ"));
+ assertEquals(s.substring(0, 1), matcher.trimFrom(s));
+ assertEquals(1, matcher.countIn(s));
+ }
+
+ // Test collapse() a little differently than the rest, as we really want to
+ // cover lots of different configurations of input text
+ public void testCollapse() {
+ // collapsing groups of - into _
+ doTestCollapse("-", "_");
+ doTestCollapse("x-", "x_");
+ doTestCollapse("-x", "_x");
+ doTestCollapse("--", "_");
+ doTestCollapse("x--", "x_");
+ doTestCollapse("--x", "_x");
+ doTestCollapse("-x-", "_x_");
+ doTestCollapse("x-x", "x_x");
+ doTestCollapse("---", "_");
+ doTestCollapse("--x-", "_x_");
+ doTestCollapse("--xx", "_xx");
+ doTestCollapse("-x--", "_x_");
+ doTestCollapse("-x-x", "_x_x");
+ doTestCollapse("-xx-", "_xx_");
+ doTestCollapse("x--x", "x_x");
+ doTestCollapse("x-x-", "x_x_");
+ doTestCollapse("x-xx", "x_xx");
+ doTestCollapse("x-x--xx---x----x", "x_x_xx_x_x");
+
+ doTestCollapseWithNoChange("");
+ doTestCollapseWithNoChange("x");
+ doTestCollapseWithNoChange("xx");
+ }
+
+ private void doTestCollapse(String in, String out) {
+ // Try a few different matchers which all match '-' and not 'x'
+ assertEquals(out, is('-').collapseFrom(in, '_'));
+ assertEquals(out, is('-').or(is('#')).collapseFrom(in, '_'));
+ assertEquals(out, isNot('x').collapseFrom(in, '_'));
+ assertEquals(out, is('x').negate().collapseFrom(in, '_'));
+ assertEquals(out, anyOf("-").collapseFrom(in, '_'));
+ assertEquals(out, anyOf("-#").collapseFrom(in, '_'));
+ assertEquals(out, anyOf("-#123").collapseFrom(in, '_'));
+ }
+
+ private void doTestCollapseWithNoChange(String inout) {
+ /*
+ * Note: assertSame(), not promised by the spec, happens to work with the
+ * current implementation because String.toString() promises to return
+ * |this|. However, GWT bug 4491 keeps it from working there, so we stick
+ * with assertEquals().
+ */
+ assertEquals(inout, is('-').collapseFrom(inout, '_'));
+ assertEquals(inout, is('-').or(is('#')).collapseFrom(inout, '_'));
+ assertEquals(inout, isNot('x').collapseFrom(inout, '_'));
+ assertEquals(inout, is('x').negate().collapseFrom(inout, '_'));
+ assertEquals(inout, anyOf("-").collapseFrom(inout, '_'));
+ assertEquals(inout, anyOf("-#").collapseFrom(inout, '_'));
+ assertEquals(inout, anyOf("-#123").collapseFrom(inout, '_'));
+ assertEquals(inout, CharMatcher.NONE.collapseFrom(inout, '_'));
+ }
+
+ public void testCollapse_any() {
+ assertEquals("", CharMatcher.ANY.collapseFrom("", '_'));
+ assertEquals("_", CharMatcher.ANY.collapseFrom("a", '_'));
+ assertEquals("_", CharMatcher.ANY.collapseFrom("ab", '_'));
+ assertEquals("_", CharMatcher.ANY.collapseFrom("abcd", '_'));
+ }
+
+ public void testTrimFrom() {
+ // trimming -
+ doTestTrimFrom("-", "");
+ doTestTrimFrom("x-", "x");
+ doTestTrimFrom("-x", "x");
+ doTestTrimFrom("--", "");
+ doTestTrimFrom("x--", "x");
+ doTestTrimFrom("--x", "x");
+ doTestTrimFrom("-x-", "x");
+ doTestTrimFrom("x-x", "x-x");
+ doTestTrimFrom("---", "");
+ doTestTrimFrom("--x-", "x");
+ doTestTrimFrom("--xx", "xx");
+ doTestTrimFrom("-x--", "x");
+ doTestTrimFrom("-x-x", "x-x");
+ doTestTrimFrom("-xx-", "xx");
+ doTestTrimFrom("x--x", "x--x");
+ doTestTrimFrom("x-x-", "x-x");
+ doTestTrimFrom("x-xx", "x-xx");
+ doTestTrimFrom("x-x--xx---x----x", "x-x--xx---x----x");
+ // additional testing using the doc example
+ assertEquals("cat", anyOf("ab").trimFrom("abacatbab"));
+ }
+
+ private void doTestTrimFrom(String in, String out) {
+ // Try a few different matchers which all match '-' and not 'x'
+ assertEquals(out, is('-').trimFrom(in));
+ assertEquals(out, is('-').or(is('#')).trimFrom(in));
+ assertEquals(out, isNot('x').trimFrom(in));
+ assertEquals(out, is('x').negate().trimFrom(in));
+ assertEquals(out, anyOf("-").trimFrom(in));
+ assertEquals(out, anyOf("-#").trimFrom(in));
+ assertEquals(out, anyOf("-#123").trimFrom(in));
+ }
+
+ public void testTrimLeadingFrom() {
+ // trimming -
+ doTestTrimLeadingFrom("-", "");
+ doTestTrimLeadingFrom("x-", "x-");
+ doTestTrimLeadingFrom("-x", "x");
+ doTestTrimLeadingFrom("--", "");
+ doTestTrimLeadingFrom("x--", "x--");
+ doTestTrimLeadingFrom("--x", "x");
+ doTestTrimLeadingFrom("-x-", "x-");
+ doTestTrimLeadingFrom("x-x", "x-x");
+ doTestTrimLeadingFrom("---", "");
+ doTestTrimLeadingFrom("--x-", "x-");
+ doTestTrimLeadingFrom("--xx", "xx");
+ doTestTrimLeadingFrom("-x--", "x--");
+ doTestTrimLeadingFrom("-x-x", "x-x");
+ doTestTrimLeadingFrom("-xx-", "xx-");
+ doTestTrimLeadingFrom("x--x", "x--x");
+ doTestTrimLeadingFrom("x-x-", "x-x-");
+ doTestTrimLeadingFrom("x-xx", "x-xx");
+ doTestTrimLeadingFrom("x-x--xx---x----x", "x-x--xx---x----x");
+ // additional testing using the doc example
+ assertEquals("catbab", anyOf("ab").trimLeadingFrom("abacatbab"));
+ }
+
+ private void doTestTrimLeadingFrom(String in, String out) {
+ // Try a few different matchers which all match '-' and not 'x'
+ assertEquals(out, is('-').trimLeadingFrom(in));
+ assertEquals(out, is('-').or(is('#')).trimLeadingFrom(in));
+ assertEquals(out, isNot('x').trimLeadingFrom(in));
+ assertEquals(out, is('x').negate().trimLeadingFrom(in));
+ assertEquals(out, anyOf("-#").trimLeadingFrom(in));
+ assertEquals(out, anyOf("-#123").trimLeadingFrom(in));
+ }
+
+ public void testTrimTrailingFrom() {
+ // trimming -
+ doTestTrimTrailingFrom("-", "");
+ doTestTrimTrailingFrom("x-", "x");
+ doTestTrimTrailingFrom("-x", "-x");
+ doTestTrimTrailingFrom("--", "");
+ doTestTrimTrailingFrom("x--", "x");
+ doTestTrimTrailingFrom("--x", "--x");
+ doTestTrimTrailingFrom("-x-", "-x");
+ doTestTrimTrailingFrom("x-x", "x-x");
+ doTestTrimTrailingFrom("---", "");
+ doTestTrimTrailingFrom("--x-", "--x");
+ doTestTrimTrailingFrom("--xx", "--xx");
+ doTestTrimTrailingFrom("-x--", "-x");
+ doTestTrimTrailingFrom("-x-x", "-x-x");
+ doTestTrimTrailingFrom("-xx-", "-xx");
+ doTestTrimTrailingFrom("x--x", "x--x");
+ doTestTrimTrailingFrom("x-x-", "x-x");
+ doTestTrimTrailingFrom("x-xx", "x-xx");
+ doTestTrimTrailingFrom("x-x--xx---x----x", "x-x--xx---x----x");
+ // additional testing using the doc example
+ assertEquals("abacat", anyOf("ab").trimTrailingFrom("abacatbab"));
+ }
+
+ private void doTestTrimTrailingFrom(String in, String out) {
+ // Try a few different matchers which all match '-' and not 'x'
+ assertEquals(out, is('-').trimTrailingFrom(in));
+ assertEquals(out, is('-').or(is('#')).trimTrailingFrom(in));
+ assertEquals(out, isNot('x').trimTrailingFrom(in));
+ assertEquals(out, is('x').negate().trimTrailingFrom(in));
+ assertEquals(out, anyOf("-#").trimTrailingFrom(in));
+ assertEquals(out, anyOf("-#123").trimTrailingFrom(in));
+ }
+
+ public void testTrimAndCollapse() {
+ // collapsing groups of - into _
+ doTestTrimAndCollapse("-", "");
+ doTestTrimAndCollapse("x-", "x");
+ doTestTrimAndCollapse("-x", "x");
+ doTestTrimAndCollapse("--", "");
+ doTestTrimAndCollapse("x--", "x");
+ doTestTrimAndCollapse("--x", "x");
+ doTestTrimAndCollapse("-x-", "x");
+ doTestTrimAndCollapse("x-x", "x_x");
+ doTestTrimAndCollapse("---", "");
+ doTestTrimAndCollapse("--x-", "x");
+ doTestTrimAndCollapse("--xx", "xx");
+ doTestTrimAndCollapse("-x--", "x");
+ doTestTrimAndCollapse("-x-x", "x_x");
+ doTestTrimAndCollapse("-xx-", "xx");
+ doTestTrimAndCollapse("x--x", "x_x");
+ doTestTrimAndCollapse("x-x-", "x_x");
+ doTestTrimAndCollapse("x-xx", "x_xx");
+ doTestTrimAndCollapse("x-x--xx---x----x", "x_x_xx_x_x");
+ }
+
+ private void doTestTrimAndCollapse(String in, String out) {
+ // Try a few different matchers which all match '-' and not 'x'
+ assertEquals(out, is('-').trimAndCollapseFrom(in, '_'));
+ assertEquals(out, is('-').or(is('#')).trimAndCollapseFrom(in, '_'));
+ assertEquals(out, isNot('x').trimAndCollapseFrom(in, '_'));
+ assertEquals(out, is('x').negate().trimAndCollapseFrom(in, '_'));
+ assertEquals(out, anyOf("-").trimAndCollapseFrom(in, '_'));
+ assertEquals(out, anyOf("-#").trimAndCollapseFrom(in, '_'));
+ assertEquals(out, anyOf("-#123").trimAndCollapseFrom(in, '_'));
+ }
+
+ public void testReplaceFrom() {
+ assertEquals("yoho", is('a').replaceFrom("yaha", 'o'));
+ assertEquals("yh", is('a').replaceFrom("yaha", ""));
+ assertEquals("yoho", is('a').replaceFrom("yaha", "o"));
+ assertEquals("yoohoo", is('a').replaceFrom("yaha", "oo"));
+ assertEquals("12 &gt; 5", is('>').replaceFrom("12 > 5", "&gt;"));
+ }
+
+ public void testPrecomputedOptimizations() {
+ // These are testing behavior that's never promised by the API.
+ // Some matchers are so efficient that it is a waste of effort to
+ // build a precomputed version.
+ CharMatcher m1 = is('x');
+ assertSame(m1, m1.precomputed());
+
+ CharMatcher m2 = anyOf("Az");
+ assertSame(m2, m2.precomputed());
+
+ CharMatcher m3 = inRange('A', 'Z');
+ assertSame(m3, m3.precomputed());
+
+ assertSame(CharMatcher.NONE, CharMatcher.NONE.precomputed());
+ assertSame(CharMatcher.ANY, CharMatcher.ANY.precomputed());
+ }
+}
diff --git a/guava/test/com/google/common/base/CharsetsTest.java b/guava/test/com/google/common/base/CharsetsTest.java
new file mode 100644
index 0000000..5a6d607
--- /dev/null
+++ b/guava/test/com/google/common/base/CharsetsTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 junit.framework.TestCase;
+
+import java.nio.charset.Charset;
+
+/**
+ * Unit test for {@link Charsets}.
+ *
+ * @author Mike Bostock
+ */
+public class CharsetsTest extends TestCase {
+ public void testUsAscii() {
+ assertEquals(Charset.forName("US-ASCII"), Charsets.US_ASCII);
+ }
+
+ public void testIso88591() {
+ assertEquals(Charset.forName("ISO-8859-1"), Charsets.ISO_8859_1);
+ }
+
+ public void testUtf8() {
+ assertEquals(Charset.forName("UTF-8"), Charsets.UTF_8);
+ }
+
+ public void testUtf16be() {
+ assertEquals(Charset.forName("UTF-16BE"), Charsets.UTF_16BE);
+ }
+
+ public void testUtf16le() {
+ assertEquals(Charset.forName("UTF-16LE"), Charsets.UTF_16LE);
+ }
+
+ public void testUtf16() {
+ assertEquals(Charset.forName("UTF-16"), Charsets.UTF_16);
+ }
+}
diff --git a/guava/test/com/google/common/base/DefaultsTest.java b/guava/test/com/google/common/base/DefaultsTest.java
new file mode 100644
index 0000000..5f76f58
--- /dev/null
+++ b/guava/test/com/google/common/base/DefaultsTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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 junit.framework.TestCase;
+
+/**
+ * Unit test for {@link Defaults}.
+ *
+ * @author Jige Yu
+ */
+public class DefaultsTest extends TestCase {
+ public void testGetDefaultValue() {
+ assertEquals(false, Defaults.defaultValue(boolean.class).booleanValue());
+ assertEquals('\0', Defaults.defaultValue(char.class).charValue());
+ assertEquals(0, Defaults.defaultValue(byte.class).byteValue());
+ assertEquals(0, Defaults.defaultValue(short.class).shortValue());
+ assertEquals(0, Defaults.defaultValue(int.class).intValue());
+ assertEquals(0, Defaults.defaultValue(long.class).longValue());
+ assertEquals(0.0f, Defaults.defaultValue(float.class).floatValue());
+ assertEquals(0.0d, Defaults.defaultValue(double.class).doubleValue());
+ assertNull(Defaults.defaultValue(void.class));
+ assertNull(Defaults.defaultValue(String.class));
+ }
+}
diff --git a/guava/test/com/google/common/base/FinalizableReferenceQueueTest.java b/guava/test/com/google/common/base/FinalizableReferenceQueueTest.java
new file mode 100644
index 0000000..d405c6c
--- /dev/null
+++ b/guava/test/com/google/common/base/FinalizableReferenceQueueTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2005 Google Inc.
+ *
+ * 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.base.internal.Finalizer;
+
+import junit.framework.TestCase;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * Unit test for {@link FinalizableReferenceQueue}.
+ *
+ * @author Bob Lee
+ */
+public class FinalizableReferenceQueueTest extends TestCase {
+
+ private FinalizableReferenceQueue frq;
+
+ @Override
+ protected void tearDown() throws Exception {
+ frq = null;
+ }
+
+ public void testFinalizeReferentCalled() {
+ MockReference reference = new MockReference(
+ frq = new FinalizableReferenceQueue());
+ // wait up to 5s
+ for (int i = 0; i < 500; i++) {
+ if (reference.finalizeReferentCalled) {
+ return;
+ }
+ try {
+ System.gc();
+ Thread.sleep(10);
+ } catch (InterruptedException e) { /* ignore */ }
+ }
+ fail();
+ }
+
+ static class MockReference extends FinalizableWeakReference<Object> {
+
+ volatile boolean finalizeReferentCalled;
+
+ MockReference(FinalizableReferenceQueue frq) {
+ super(new Object(), frq);
+ }
+
+ public void finalizeReferent() {
+ finalizeReferentCalled = true;
+ }
+ }
+
+ /**
+ * Keeps a weak reference to the underlying reference queue. When this
+ * reference is cleared, we know that the background thread has stopped
+ * and released its strong reference.
+ */
+ private WeakReference<ReferenceQueue<Object>> queueReference;
+
+ public void testThatFinalizerStops() {
+ weaklyReferenceQueue();
+
+ // wait up to 5s
+ for (int i = 0; i < 500; i++) {
+ if (queueReference.get() == null) {
+ return;
+ }
+ try {
+ System.gc();
+ Thread.sleep(10);
+ } catch (InterruptedException e) { /* ignore */ }
+ }
+ fail();
+ }
+
+ /**
+ * If we don't keep a strong reference to the reference object, it won't
+ * be enqueued.
+ */
+ FinalizableWeakReference<Object> reference;
+
+ /**
+ * Create the FRQ in a method that goes out of scope so that we're sure
+ * it will be reclaimed.
+ */
+ private void weaklyReferenceQueue() {
+ frq = new FinalizableReferenceQueue();
+ queueReference = new WeakReference<ReferenceQueue<Object>>(frq.queue);
+
+ /*
+ * Queue and clear a reference for good measure. We test later on that
+ * the finalizer thread stopped, but we should test that it actually
+ * started first.
+ */
+ reference = new FinalizableWeakReference<Object>(new Object(), frq) {
+ public void finalizeReferent() {
+ reference = null;
+ frq = null;
+ }
+ };
+ }
+
+ public void testDecoupledLoader() {
+ FinalizableReferenceQueue.DecoupledLoader decoupledLoader =
+ new FinalizableReferenceQueue.DecoupledLoader() {
+ @Override
+ URLClassLoader newLoader(URL base) {
+ return new DecoupledClassLoader(new URL[] { base });
+ }
+ };
+
+ Class<?> finalizerCopy = decoupledLoader.loadFinalizer();
+
+ assertNotNull(finalizerCopy);
+ assertNotSame(Finalizer.class, finalizerCopy);
+
+ assertNotNull(FinalizableReferenceQueue.getStartFinalizer(finalizerCopy));
+ }
+
+ static class DecoupledClassLoader extends URLClassLoader {
+
+ public DecoupledClassLoader(URL[] urls) {
+ super(urls);
+ }
+
+ @Override
+ protected synchronized Class<?> loadClass(String name, boolean resolve)
+ throws ClassNotFoundException {
+ // Force Finalizer to load from this class loader, not its parent.
+ if (name.equals(Finalizer.class.getName())) {
+ Class<?> clazz = findClass(name);
+ if (resolve) {
+ resolveClass(clazz);
+ }
+ return clazz;
+ }
+
+ return super.loadClass(name, resolve);
+ }
+ }
+
+ public void testGetFinalizerUrl() {
+ assertNotNull(getClass().getResource("internal/Finalizer.class"));
+ }
+}
diff --git a/guava/test/com/google/common/base/FunctionsTest.java b/guava/test/com/google/common/base/FunctionsTest.java
new file mode 100644
index 0000000..ab886ff
--- /dev/null
+++ b/guava/test/com/google/common/base/FunctionsTest.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2005 Google Inc.
+ *
+ * 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.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.testing.util.EqualsTester;
+import com.google.testing.util.NullPointerTester;
+import com.google.testing.util.SerializableTester;
+
+import junit.framework.TestCase;
+
+import java.util.Map;
+
+/**
+ * Tests for {@link Functions}.
+ *
+ * @author Mike Bostock
+ * @author Vlad Patryshev
+ */
+@GwtCompatible(emulated = true)
+public class FunctionsTest extends TestCase {
+
+ public void testIdentity_same() {
+ Function<String, String> identity = Functions.identity();
+ assertNull(identity.apply(null));
+ assertSame("foo", identity.apply("foo"));
+ }
+
+ public void testIdentity_notSame() {
+ Function<Long, Long> identity = Functions.identity();
+ assertNotSame(new Long(135135L), identity.apply(new Long(135135L)));
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testIdentitySerializable() {
+ checkCanReserializeSingleton(Functions.identity());
+ }
+
+ public void testToStringFunction_apply() {
+ assertEquals("3", Functions.toStringFunction().apply(3));
+ assertEquals("hiya", Functions.toStringFunction().apply("hiya"));
+ assertEquals("I'm a string",
+ Functions.toStringFunction().apply(
+ new Object() {
+ @Override public String toString() {
+ return "I'm a string";
+ }
+ }));
+ try {
+ Functions.toStringFunction().apply(null);
+ fail("expected NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testToStringFunctionSerializable() {
+ checkCanReserializeSingleton(Functions.toStringFunction());
+ }
+
+ @GwtIncompatible("NullPointerTester")
+ public void testNullPointerExceptions() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ tester.testAllPublicStaticMethods(Functions.class);
+ }
+
+ public void testForMapWithoutDefault() {
+ Map<String, Integer> map = Maps.newHashMap();
+ map.put("One", 1);
+ map.put("Three", 3);
+ Function<String, Integer> function = Functions.forMap(map);
+
+ assertEquals(1, function.apply("One").intValue());
+ assertEquals(3, function.apply("Three").intValue());
+
+ try {
+ function.apply("Two");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ new EqualsTester(function)
+ .addEqualObject(Functions.forMap(map))
+ .addEqualObject(Functions.forMap(map))
+ .addNotEqualObject(Functions.forMap(map, 42))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testForMapWithoutDefaultSerializable() {
+ checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2)));
+ }
+
+ public void testForMapWithDefault() {
+ Map<String, Integer> map = Maps.newHashMap();
+ map.put("One", 1);
+ map.put("Three", 3);
+ Function<String, Integer> function = Functions.forMap(map, 42);
+
+ assertEquals(1, function.apply("One").intValue());
+ assertEquals(42, function.apply("Two").intValue());
+ assertEquals(3, function.apply("Three").intValue());
+
+ new EqualsTester()
+ .addEqualityGroup(function, Functions.forMap(map, 42))
+ .addEqualityGroup(Functions.forMap(map))
+ .addEqualityGroup(Functions.forMap(map, null))
+ .addEqualityGroup(Functions.forMap(map, 43))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testForMapWithDefault_includeSerializable() {
+ Map<String, Integer> map = Maps.newHashMap();
+ map.put("One", 1);
+ map.put("Three", 3);
+ Function<String, Integer> function = Functions.forMap(map, 42);
+
+ assertEquals(1, function.apply("One").intValue());
+ assertEquals(42, function.apply("Two").intValue());
+ assertEquals(3, function.apply("Three").intValue());
+
+ new EqualsTester(function)
+ .addEqualObject(Functions.forMap(map, 42))
+ .addEqualObject(SerializableTester.reserialize(function))
+ .addNotEqualObject(Functions.forMap(map))
+ .addNotEqualObject(Functions.forMap(map, null))
+ .addNotEqualObject(Functions.forMap(map, 43))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testForMapWithDefaultSerializable() {
+ checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2), 3));
+ }
+
+ public void testForMapWithDefault_null() {
+ ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
+ Function<String, Integer> function = Functions.forMap(map, null);
+
+ assertEquals((Integer) 1, function.apply("One"));
+ assertNull(function.apply("Two"));
+
+ // check basic sanity of equals and hashCode
+ new EqualsTester(function)
+ .addNotEqualObject(Functions.forMap(map, 1))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testForMapWithDefault_null_compareWithSerializable() {
+ ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
+ Function<String, Integer> function = Functions.forMap(map, null);
+
+ assertEquals((Integer) 1, function.apply("One"));
+ assertNull(function.apply("Two"));
+
+ // check basic sanity of equals and hashCode
+ new EqualsTester(function)
+ .addEqualObject(SerializableTester.reserialize(function))
+ .addNotEqualObject(Functions.forMap(map, 1))
+ .testEquals();
+ }
+
+ public void testForMapWildCardWithDefault() {
+ Map<String, Integer> map = Maps.newHashMap();
+ map.put("One", 1);
+ map.put("Three", 3);
+ Number number = Double.valueOf(42);
+ Function<String, Number> function = Functions.forMap(map, number);
+
+ assertEquals(1, function.apply("One").intValue());
+ assertEquals(number, function.apply("Two"));
+ assertEquals(3L, function.apply("Three").longValue());
+ }
+
+ public void testComposition() {
+ Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
+ mJapaneseToInteger.put("Ichi", 1);
+ mJapaneseToInteger.put("Ni", 2);
+ mJapaneseToInteger.put("San", 3);
+ Function<String, Integer> japaneseToInteger =
+ Functions.forMap(mJapaneseToInteger);
+
+ Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
+ mIntegerToSpanish.put(1, "Uno");
+ mIntegerToSpanish.put(3, "Tres");
+ mIntegerToSpanish.put(4, "Cuatro");
+ Function<Integer, String> integerToSpanish =
+ Functions.forMap(mIntegerToSpanish);
+
+ Function<String, String> japaneseToSpanish =
+ Functions.compose(integerToSpanish, japaneseToInteger);
+
+ assertEquals("Uno", japaneseToSpanish.apply("Ichi"));
+ try {
+ japaneseToSpanish.apply("Ni");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ assertEquals("Tres", japaneseToSpanish.apply("San"));
+ try {
+ japaneseToSpanish.apply("Shi");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ new EqualsTester(japaneseToSpanish)
+ .addEqualObject(
+ Functions.compose(integerToSpanish, japaneseToInteger))
+ .addNotEqualObject(japaneseToInteger)
+ .addNotEqualObject(integerToSpanish)
+ .addNotEqualObject(
+ Functions.compose(japaneseToInteger, integerToSpanish))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testComposition_includeReserializabled() {
+ Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
+ mJapaneseToInteger.put("Ichi", 1);
+ mJapaneseToInteger.put("Ni", 2);
+ mJapaneseToInteger.put("San", 3);
+ Function<String, Integer> japaneseToInteger =
+ Functions.forMap(mJapaneseToInteger);
+
+ Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
+ mIntegerToSpanish.put(1, "Uno");
+ mIntegerToSpanish.put(3, "Tres");
+ mIntegerToSpanish.put(4, "Cuatro");
+ Function<Integer, String> integerToSpanish =
+ Functions.forMap(mIntegerToSpanish);
+
+ Function<String, String> japaneseToSpanish =
+ Functions.compose(integerToSpanish, japaneseToInteger);
+
+ new EqualsTester(japaneseToSpanish)
+ .addEqualObject(
+ Functions.compose(integerToSpanish, japaneseToInteger))
+ .addEqualObject(
+ SerializableTester.reserialize(japaneseToSpanish))
+ .addNotEqualObject(japaneseToInteger)
+ .addNotEqualObject(integerToSpanish)
+ .addNotEqualObject(
+ Functions.compose(japaneseToInteger, integerToSpanish))
+ .testEquals();
+ }
+
+ public void testCompositionWildcard() {
+ Map<String, Integer> mapJapaneseToInteger = Maps.newHashMap();
+ Function<String, Integer> japaneseToInteger =
+ Functions.forMap(mapJapaneseToInteger);
+
+ Function<Object, String> numberToSpanish = Functions.constant("Yo no se");
+
+ Function<String, String> japaneseToSpanish =
+ Functions.compose(numberToSpanish, japaneseToInteger);
+ }
+
+ private static class HashCodeFunction implements Function<Object, Integer> {
+ public Integer apply(Object o) {
+ return (o == null) ? 0 : o.hashCode();
+ }
+ }
+
+ public void testComposeOfFunctionsIsAssociative() {
+ Map<Float, String> m = ImmutableMap.of(
+ 4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
+ Function<? super Integer, Boolean> h = Functions.constant(Boolean.TRUE);
+ Function<? super String, Integer> g = new HashCodeFunction();
+ Function<Float, String> f = Functions.forMap(m, "F");
+
+ Function<Float, Boolean> c1 = Functions.compose(Functions.compose(h, g), f);
+ Function<Float, Boolean> c2 = Functions.compose(h, Functions.compose(g, f));
+
+ // Might be nice (eventually) to have:
+ // assertEquals(c1, c2);
+
+ // But for now, settle for this:
+ assertEquals(c1.hashCode(), c2.hashCode());
+
+ assertEquals(c1.apply(1.0f), c2.apply(1.0f));
+ assertEquals(c1.apply(5.0f), c2.apply(5.0f));
+ }
+
+ public void testComposeOfPredicateAndFunctionIsAssociative() {
+ Map<Float, String> m = ImmutableMap.of(
+ 4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
+ Predicate<? super Integer> h = Predicates.equalTo(42);
+ Function<? super String, Integer> g = new HashCodeFunction();
+ Function<Float, String> f = Functions.forMap(m, "F");
+
+ Predicate<Float> p1 = Predicates.compose(Predicates.compose(h, g), f);
+ Predicate<Float> p2 = Predicates.compose(h, Functions.compose(g, f));
+
+ // Might be nice (eventually) to have:
+ // assertEquals(p1, p2);
+
+ // But for now, settle for this:
+ assertEquals(p1.hashCode(), p2.hashCode());
+
+ assertEquals(p1.apply(1.0f), p2.apply(1.0f));
+ assertEquals(p1.apply(5.0f), p2.apply(5.0f));
+ }
+
+ public void testForPredicate() {
+ Function<Object, Boolean> alwaysTrue =
+ Functions.forPredicate(Predicates.alwaysTrue());
+ Function<Object, Boolean> alwaysFalse =
+ Functions.forPredicate(Predicates.alwaysFalse());
+
+ assertTrue(alwaysTrue.apply(0));
+ assertFalse(alwaysFalse.apply(0));
+
+ new EqualsTester(alwaysTrue)
+ .addEqualObject(Functions.forPredicate(Predicates.alwaysTrue()))
+ .addNotEqualObject(alwaysFalse)
+ .addNotEqualObject(Functions.identity())
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testForPredicateSerializable() {
+ checkCanReserialize(Functions.forPredicate(Predicates.equalTo(5)));
+ }
+
+ public void testConstant() {
+ Function<Object, Object> f = Functions.<Object>constant("correct");
+ assertEquals("correct", f.apply(new Object()));
+ assertEquals("correct", f.apply(null));
+
+ Function<Object, String> g = Functions.constant(null);
+ assertEquals(null, g.apply(2));
+ assertEquals(null, g.apply(null));
+
+ new EqualsTester(f)
+ .addEqualObject(Functions.constant("correct"))
+ .addNotEqualObject(Functions.constant("incorrect"))
+ .addNotEqualObject(Functions.toStringFunction())
+ .addNotEqualObject(g)
+ .testEquals();
+
+ new EqualsTester(g)
+ .addEqualObject(Functions.constant(null))
+ .addNotEqualObject(Functions.constant("incorrect"))
+ .addNotEqualObject(Functions.toStringFunction())
+ .addNotEqualObject(f)
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testConstantSerializable() {
+ checkCanReserialize(Functions.constant(5));
+ }
+
+ @GwtIncompatible("SerializableTester")
+ private <Y> void checkCanReserialize(Function<? super Integer, Y> f) {
+ Function<? super Integer, Y> g = SerializableTester.reserializeAndAssert(f);
+ for (int i = 1; i < 5; i++) {
+ // convoluted way to check that the same result happens from each
+ Y expected = null;
+ try {
+ expected = f.apply(i);
+ } catch (IllegalArgumentException e) {
+ try {
+ g.apply(i);
+ fail();
+ } catch (IllegalArgumentException ok) {
+ continue;
+ }
+ }
+ assertEquals(expected, g.apply(i));
+ }
+ }
+
+ @GwtIncompatible("SerializableTester")
+ private <Y> void checkCanReserializeSingleton(Function<? super String, Y> f) {
+ Function<? super String, Y> g = SerializableTester.reserializeAndAssert(f);
+ assertSame(f, g);
+ for (Integer i = 1; i < 5; i++) {
+ assertEquals(f.apply(i.toString()), g.apply(i.toString()));
+ }
+ }
+
+}
diff --git a/guava/test/com/google/common/base/JoinerTest.java b/guava/test/com/google/common/base/JoinerTest.java
new file mode 100644
index 0000000..d783b7d
--- /dev/null
+++ b/guava/test/com/google/common/base/JoinerTest.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.base.Joiner.MapJoiner;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.testing.util.NullPointerTester;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Unit test for {@link Joiner}.
+ *
+ * @author Kevin Bourrillion
+ */
+public class JoinerTest extends TestCase {
+ static final Joiner J = Joiner.on("-");
+
+ // <Integer> needed to prevent warning :(
+ static final Iterable<Integer> ITERABLE_ = Arrays.<Integer>asList();
+ static final Iterable<Integer> ITERABLE_1 = Arrays.asList(1);
+ static final Iterable<Integer> ITERABLE_12 = Arrays.asList(1, 2);
+ static final Iterable<Integer> ITERABLE_123 = Arrays.asList(1, 2, 3);
+ static final Iterable<Integer> ITERABLE_NULL = Arrays.asList((Integer) null);
+ static final Iterable<Integer> ITERABLE_NULL_NULL
+ = Arrays.asList((Integer) null, null);
+ static final Iterable<Integer> ITERABLE_NULL_1 = Arrays.asList(null, 1);
+ static final Iterable<Integer> ITERABLE_1_NULL = Arrays.asList(1, null);
+ static final Iterable<Integer> ITERABLE_1_NULL_2 = Arrays.asList(1, null, 2);
+ static final Iterable<Integer> ITERABLE_FOUR_NULLS
+ = Arrays.asList((Integer) null, null, null, null);
+
+ public void testNoSpecialNullBehavior() {
+ checkNoOutput(J, ITERABLE_);
+ checkResult(J, ITERABLE_1, "1");
+ checkResult(J, ITERABLE_12, "1-2");
+ checkResult(J, ITERABLE_123, "1-2-3");
+
+ try {
+ J.join(ITERABLE_NULL);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ try {
+ J.join(ITERABLE_1_NULL_2);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testOnCharOverride() {
+ Joiner onChar = Joiner.on('-');
+ checkNoOutput(onChar, ITERABLE_);
+ checkResult(onChar, ITERABLE_1, "1");
+ checkResult(onChar, ITERABLE_12, "1-2");
+ checkResult(onChar, ITERABLE_123, "1-2-3");
+ }
+
+ public void testSkipNulls() {
+ Joiner skipNulls = J.skipNulls();
+ checkNoOutput(skipNulls, ITERABLE_);
+ checkNoOutput(skipNulls, ITERABLE_NULL);
+ checkNoOutput(skipNulls, ITERABLE_NULL_NULL);
+ checkNoOutput(skipNulls, ITERABLE_FOUR_NULLS);
+ checkResult(skipNulls, ITERABLE_1, "1");
+ checkResult(skipNulls, ITERABLE_12, "1-2");
+ checkResult(skipNulls, ITERABLE_123, "1-2-3");
+ checkResult(skipNulls, ITERABLE_NULL_1, "1");
+ checkResult(skipNulls, ITERABLE_1_NULL, "1");
+ checkResult(skipNulls, ITERABLE_1_NULL_2, "1-2");
+ }
+
+ public void testUseForNull() {
+ Joiner zeroForNull = J.useForNull("0");
+ checkNoOutput(zeroForNull, ITERABLE_);
+ checkResult(zeroForNull, ITERABLE_1, "1");
+ checkResult(zeroForNull, ITERABLE_12, "1-2");
+ checkResult(zeroForNull, ITERABLE_123, "1-2-3");
+ checkResult(zeroForNull, ITERABLE_NULL, "0");
+ checkResult(zeroForNull, ITERABLE_NULL_NULL, "0-0");
+ checkResult(zeroForNull, ITERABLE_NULL_1, "0-1");
+ checkResult(zeroForNull, ITERABLE_1_NULL, "1-0");
+ checkResult(zeroForNull, ITERABLE_1_NULL_2, "1-0-2");
+ checkResult(zeroForNull, ITERABLE_FOUR_NULLS, "0-0-0-0");
+ }
+
+ private static void checkNoOutput(Joiner joiner, Iterable<Integer> set) {
+ Object[] array = Iterables.toArray(set, Integer.class);
+ assertEquals("", joiner.join(set));
+ assertEquals("", joiner.join(array));
+
+ StringBuilder sb1 = new StringBuilder();
+ assertSame(sb1, joiner.appendTo(sb1, set));
+ assertEquals(0, sb1.length());
+
+ StringBuilder sb2 = new StringBuilder();
+ assertSame(sb2, joiner.appendTo(sb2, array));
+ assertEquals(0, sb2.length());
+
+ try {
+ joiner.appendTo(NASTY_APPENDABLE, set);
+ joiner.appendTo(NASTY_APPENDABLE, array);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private static final Appendable NASTY_APPENDABLE = new Appendable() {
+ public Appendable append(CharSequence csq) throws IOException {
+ throw new IOException();
+ }
+ public Appendable append(CharSequence csq, int start, int end)
+ throws IOException {
+ throw new IOException();
+ }
+ public Appendable append(char c) throws IOException {
+ throw new IOException();
+ }
+ };
+
+ private static void checkResult(
+ Joiner joiner, Iterable<Integer> parts, String expected) {
+ Integer[] partsArray = Iterables.toArray(parts, Integer.class);
+
+ assertEquals(expected, joiner.join(parts));
+
+ StringBuilder sb1 = new StringBuilder().append('x');
+ joiner.appendTo(sb1, parts);
+ assertEquals("x" + expected, sb1.toString());
+
+ assertEquals(expected, joiner.join(partsArray));
+
+ StringBuilder sb2 = new StringBuilder().append('x');
+ joiner.appendTo(sb2, partsArray);
+ assertEquals("x" + expected, sb2.toString());
+
+ int num = partsArray.length - 2;
+ if (num >= 0) {
+ Object[] rest = new Integer[num];
+ for (int i = 0; i < num; i++) {
+ rest[i] = partsArray[i + 2];
+ }
+
+ assertEquals(expected, joiner.join(partsArray[0], partsArray[1], rest));
+
+ StringBuilder sb3 = new StringBuilder().append('x');
+ joiner.appendTo(sb3, partsArray[0], partsArray[1], rest);
+ assertEquals("x" + expected, sb3.toString());
+ }
+ }
+
+ public void test_useForNull_skipNulls() {
+ Joiner j = Joiner.on("x").useForNull("y");
+ try {
+ j.skipNulls();
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ public void test_skipNulls_useForNull() {
+ Joiner j = Joiner.on("x").skipNulls();
+ try {
+ j.useForNull("y");
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ public void test_useForNull_twice() {
+ Joiner j = Joiner.on("x").useForNull("y");
+ try {
+ j.useForNull("y");
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ public void testMap() {
+ MapJoiner j = Joiner.on(";").withKeyValueSeparator(":");
+ assertEquals("", j.join(ImmutableMap.of()));
+ assertEquals(":", j.join(ImmutableMap.of("", "")));
+
+ Map<String, String> mapWithNulls = Maps.newLinkedHashMap();
+ mapWithNulls.put("a", null);
+ mapWithNulls.put(null, "b");
+
+ try {
+ j.join(mapWithNulls);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ assertEquals("a:00;00:b", j.useForNull("00").join(mapWithNulls));
+
+ StringBuilder sb = new StringBuilder();
+ j.appendTo(sb, ImmutableMap.of(1, 2, 3, 4, 5, 6));
+ assertEquals("1:2;3:4;5:6", sb.toString());
+ }
+
+ public void test_skipNulls_onMap() {
+ Joiner j = Joiner.on(",").skipNulls();
+ try {
+ j.withKeyValueSeparator("/");
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ private static class DontStringMeBro implements CharSequence {
+ public int length() {
+ return 3;
+ }
+ public char charAt(int index) {
+ return "foo".charAt(index);
+ }
+ public CharSequence subSequence(int start, int end) {
+ return "foo".subSequence(start, end);
+ }
+ @Override public String toString() {
+ Assert.fail("shouldn't be invoked");
+ return null;
+ }
+ }
+
+ public void testDontConvertCharSequenceToString() {
+ assertEquals("foo,foo", Joiner.on(",").join(
+ new DontStringMeBro(), new DontStringMeBro()));
+ assertEquals("foo,bar,foo", Joiner.on(",").useForNull("bar").join(
+ new DontStringMeBro(), null, new DontStringMeBro()));
+ }
+
+ public void testNullPointers() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ tester.setDefault(StringBuilder.class, new StringBuilder());
+ tester.testAllPublicStaticMethods(Joiner.class);
+ tester.testAllPublicInstanceMethods(Joiner.on(","));
+ tester.testAllPublicInstanceMethods(Joiner.on(",").skipNulls());
+ tester.testAllPublicInstanceMethods(Joiner.on(",").useForNull("x"));
+ tester.testAllPublicInstanceMethods(
+ Joiner.on(",").withKeyValueSeparator("="));
+ }
+}
diff --git a/guava/test/com/google/common/base/ObjectsTest.java b/guava/test/com/google/common/base/ObjectsTest.java
new file mode 100644
index 0000000..59b858e
--- /dev/null
+++ b/guava/test/com/google/common/base/ObjectsTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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 junit.framework.TestCase;
+
+/**
+ * Tests for {@link Objects}.
+ *
+ * @author Laurence Gonsalves
+ */
+public class ObjectsTest extends TestCase {
+ public void testEqual() throws Exception {
+ assertTrue(Objects.equal(1, 1));
+ assertTrue(Objects.equal(null, null));
+
+ // test distinct string objects
+ String s1 = "foobar";
+ String s2 = new String(s1);
+ assertTrue(Objects.equal(s1, s2));
+
+ assertFalse(Objects.equal(s1, null));
+ assertFalse(Objects.equal(null, s1));
+ assertFalse(Objects.equal("foo", "bar"));
+ assertFalse(Objects.equal("1", 1));
+ }
+
+ public void testHashCode() throws Exception {
+ int h1 = Objects.hashCode(1, "two", 3.0);
+ int h2 = Objects.hashCode(new Integer(1), new String("two"),
+ new Double(3.0));
+ // repeatable
+ assertEquals(h1, h2);
+
+ // These don't strictly need to be true, but they're nice properties.
+ assertTrue(Objects.hashCode(1, 2, null) != Objects.hashCode(1, 2));
+ assertTrue(Objects.hashCode(1, 2, null) != Objects.hashCode(1, null, 2));
+ assertTrue(Objects.hashCode(1, null, 2) != Objects.hashCode(1, 2));
+ assertTrue(Objects.hashCode(1, 2, 3) != Objects.hashCode(3, 2, 1));
+ assertTrue(Objects.hashCode(1, 2, 3) != Objects.hashCode(2, 3, 1));
+ }
+
+ public void testFirstNonNull_withNonNull() throws Exception {
+ String s1 = "foo";
+ String s2 = Objects.firstNonNull(s1, "bar");
+ assertSame(s1, s2);
+
+ Long n1 = new Long(42);
+ Long n2 = Objects.firstNonNull(null, n1);
+ assertSame(n1, n2);
+ }
+
+ public void testFirstNonNull_throwsNullPointerException() throws Exception {
+ try {
+ Objects.firstNonNull(null, null);
+ fail("expected NullPointerException");
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ // TODO: enable this when we address the GWT issue
+ // public void testNullPointers() throws Exception {
+ // NullPointerTester tester = new NullPointerTester();
+ // tester.testAllPublicStaticMethods(Objects.class);
+ // }
+}
diff --git a/guava/test/com/google/common/base/PreconditionsTest.java b/guava/test/com/google/common/base/PreconditionsTest.java
new file mode 100644
index 0000000..9fc3e2e
--- /dev/null
+++ b/guava/test/com/google/common/base/PreconditionsTest.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2006 Google Inc.
+ *
+ * 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.testing.util.NullPointerTester;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for {@link Preconditions}.
+ *
+ * @author Kevin Bourrillion
+ * @author Jared Levy
+ */
+public class PreconditionsTest extends TestCase {
+ public void testCheckArgument_simple_success() {
+ Preconditions.checkArgument(true);
+ }
+
+ public void testCheckArgument_simple_failure() {
+ try {
+ Preconditions.checkArgument(false);
+ fail("no exception thrown");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testCheckArgument_simpleMessage_success() {
+ Preconditions.checkArgument(true, IGNORE_ME);
+ }
+
+ public void testCheckArgument_simpleMessage_failure() {
+ try {
+ Preconditions.checkArgument(false, new Message());
+ fail("no exception thrown");
+ } catch (IllegalArgumentException expected) {
+ verifySimpleMessage(expected);
+ }
+ }
+
+ public void testCheckArgument_nullMessage_failure() {
+ try {
+ Preconditions.checkArgument(false, null);
+ fail("no exception thrown");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("null", expected.getMessage());
+ }
+ }
+
+ public void testCheckArgument_complexMessage_success() {
+ Preconditions.checkArgument(true, "%s", IGNORE_ME);
+ }
+
+ public void testCheckArgument_complexMessage_failure() {
+ try {
+ Preconditions.checkArgument(false, FORMAT, 5);
+ fail("no exception thrown");
+ } catch (IllegalArgumentException expected) {
+ verifyComplexMessage(expected);
+ }
+ }
+
+ public void testCheckState_simple_success() {
+ Preconditions.checkState(true);
+ }
+
+ public void testCheckState_simple_failure() {
+ try {
+ Preconditions.checkState(false);
+ fail("no exception thrown");
+ } catch (IllegalStateException expected) {
+ }
+ }
+
+ public void testCheckState_simpleMessage_success() {
+ Preconditions.checkState(true, IGNORE_ME);
+ }
+
+ public void testCheckState_simpleMessage_failure() {
+ try {
+ Preconditions.checkState(false, new Message());
+ fail("no exception thrown");
+ } catch (IllegalStateException expected) {
+ verifySimpleMessage(expected);
+ }
+ }
+
+ public void testCheckState_nullMessage_failure() {
+ try {
+ Preconditions.checkState(false, null);
+ fail("no exception thrown");
+ } catch (IllegalStateException expected) {
+ assertEquals("null", expected.getMessage());
+ }
+ }
+
+ public void testCheckState_complexMessage_success() {
+ Preconditions.checkState(true, "%s", IGNORE_ME);
+ }
+
+ public void testCheckState_complexMessage_failure() {
+ try {
+ Preconditions.checkState(false, FORMAT, 5);
+ fail("no exception thrown");
+ } catch (IllegalStateException expected) {
+ verifyComplexMessage(expected);
+ }
+ }
+
+ private static final String NON_NULL_STRING = "foo";
+
+ public void testCheckNotNull_simple_success() {
+ String result = Preconditions.checkNotNull(NON_NULL_STRING);
+ assertSame(NON_NULL_STRING, result);
+ }
+
+ public void testCheckNotNull_simple_failure() {
+ try {
+ Preconditions.checkNotNull(null);
+ fail("no exception thrown");
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testCheckNotNull_simpleMessage_success() {
+ String result = Preconditions.checkNotNull(NON_NULL_STRING, IGNORE_ME);
+ assertSame(NON_NULL_STRING, result);
+ }
+
+ public void testCheckNotNull_simpleMessage_failure() {
+ try {
+ Preconditions.checkNotNull(null, new Message());
+ fail("no exception thrown");
+ } catch (NullPointerException expected) {
+ verifySimpleMessage(expected);
+ }
+ }
+
+ public void testCheckNotNull_complexMessage_success() {
+ String result = Preconditions.checkNotNull(
+ NON_NULL_STRING, "%s", IGNORE_ME);
+ assertSame(NON_NULL_STRING, result);
+ }
+
+ public void testCheckNotNull_complexMessage_failure() {
+ try {
+ Preconditions.checkNotNull(null, FORMAT, 5);
+ fail("no exception thrown");
+ } catch (NullPointerException expected) {
+ verifyComplexMessage(expected);
+ }
+ }
+
+ public void testCheckElementIndex_ok() {
+ assertEquals(0, Preconditions.checkElementIndex(0, 1));
+ assertEquals(0, Preconditions.checkElementIndex(0, 2));
+ assertEquals(1, Preconditions.checkElementIndex(1, 2));
+ }
+
+ public void testCheckElementIndex_badSize() {
+ try {
+ Preconditions.checkElementIndex(1, -1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // don't care what the message text is, as this is an invalid usage of
+ // the Preconditions class, unlike all the other exceptions it throws
+ }
+ }
+
+ public void testCheckElementIndex_negative() {
+ try {
+ Preconditions.checkElementIndex(-1, 1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("index (-1) must not be negative", expected.getMessage());
+ }
+ }
+
+ public void testCheckElementIndex_tooHigh() {
+ try {
+ Preconditions.checkElementIndex(1, 1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("index (1) must be less than size (1)",
+ expected.getMessage());
+ }
+ }
+
+ public void testCheckElementIndex_withDesc_negative() {
+ try {
+ Preconditions.checkElementIndex(-1, 1, "foo");
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("foo (-1) must not be negative", expected.getMessage());
+ }
+ }
+
+ public void testCheckElementIndex_withDesc_tooHigh() {
+ try {
+ Preconditions.checkElementIndex(1, 1, "foo");
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("foo (1) must be less than size (1)",
+ expected.getMessage());
+ }
+ }
+
+ public void testCheckPositionIndex_ok() {
+ assertEquals(0, Preconditions.checkPositionIndex(0, 0));
+ assertEquals(0, Preconditions.checkPositionIndex(0, 1));
+ assertEquals(1, Preconditions.checkPositionIndex(1, 1));
+ }
+
+ public void testCheckPositionIndex_badSize() {
+ try {
+ Preconditions.checkPositionIndex(1, -1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // don't care what the message text is, as this is an invalid usage of
+ // the Preconditions class, unlike all the other exceptions it throws
+ }
+ }
+
+ public void testCheckPositionIndex_negative() {
+ try {
+ Preconditions.checkPositionIndex(-1, 1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("index (-1) must not be negative", expected.getMessage());
+ }
+ }
+
+ public void testCheckPositionIndex_tooHigh() {
+ try {
+ Preconditions.checkPositionIndex(2, 1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("index (2) must not be greater than size (1)",
+ expected.getMessage());
+ }
+ }
+
+ public void testCheckPositionIndex_withDesc_negative() {
+ try {
+ Preconditions.checkPositionIndex(-1, 1, "foo");
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("foo (-1) must not be negative", expected.getMessage());
+ }
+ }
+
+ public void testCheckPositionIndex_withDesc_tooHigh() {
+ try {
+ Preconditions.checkPositionIndex(2, 1, "foo");
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("foo (2) must not be greater than size (1)",
+ expected.getMessage());
+ }
+ }
+
+ public void testCheckPositionIndexes_ok() {
+ Preconditions.checkPositionIndexes(0, 0, 0);
+ Preconditions.checkPositionIndexes(0, 0, 1);
+ Preconditions.checkPositionIndexes(0, 1, 1);
+ Preconditions.checkPositionIndexes(1, 1, 1);
+ }
+
+ public void testCheckPositionIndexes_badSize() {
+ try {
+ Preconditions.checkPositionIndexes(1, 1, -1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testCheckPositionIndex_startNegative() {
+ try {
+ Preconditions.checkPositionIndexes(-1, 1, 1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("start index (-1) must not be negative",
+ expected.getMessage());
+ }
+ }
+
+ public void testCheckPositionIndexes_endTooHigh() {
+ try {
+ Preconditions.checkPositionIndexes(0, 2, 1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("end index (2) must not be greater than size (1)",
+ expected.getMessage());
+ }
+ }
+
+ public void testCheckPositionIndexes_reversed() {
+ try {
+ Preconditions.checkPositionIndexes(1, 0, 1);
+ fail();
+ } catch (IndexOutOfBoundsException expected) {
+ assertEquals("end index (0) must not be less than start index (1)",
+ expected.getMessage());
+ }
+ }
+
+ public void testFormat() {
+ assertEquals("%s", Preconditions.format("%s"));
+ assertEquals("5", Preconditions.format("%s", 5));
+ assertEquals("foo [5]", Preconditions.format("foo", 5));
+ assertEquals("foo [5, 6, 7]", Preconditions.format("foo", 5, 6, 7));
+ assertEquals("%s 1 2", Preconditions.format("%s %s %s", "%s", 1, 2));
+ assertEquals(" [5, 6]", Preconditions.format("", 5, 6));
+ assertEquals("123", Preconditions.format("%s%s%s", 1, 2, 3));
+ assertEquals("1%s%s", Preconditions.format("%s%s%s", 1));
+ assertEquals("5 + 6 = 11", Preconditions.format("%s + 6 = 11", 5));
+ assertEquals("5 + 6 = 11", Preconditions.format("5 + %s = 11", 6));
+ assertEquals("5 + 6 = 11", Preconditions.format("5 + 6 = %s", 11));
+ assertEquals("5 + 6 = 11", Preconditions.format("%s + %s = %s", 5, 6, 11));
+ assertEquals("null [null, null]",
+ Preconditions.format("%s", null, null, null));
+ assertEquals("null [5, 6]", Preconditions.format(null, 5, 6));
+ }
+
+ public void testNullPointers() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ tester.testAllPublicStaticMethods(Preconditions.class);
+ }
+
+ private static final Object IGNORE_ME = new Object() {
+ @Override public String toString() {
+ fail();
+ return null;
+ }
+ };
+
+ private static class Message {
+ boolean invoked;
+ @Override public String toString() {
+ assertFalse(invoked);
+ invoked = true;
+ return "A message";
+ }
+ }
+
+ private static final String FORMAT = "I ate %s pies.";
+
+ private static void verifySimpleMessage(Exception e) {
+ assertEquals("A message", e.getMessage());
+ }
+
+ private static void verifyComplexMessage(Exception e) {
+ assertEquals("I ate 5 pies.", e.getMessage());
+ }
+}
diff --git a/guava/test/com/google/common/base/PredicatesTest.java b/guava/test/com/google/common/base/PredicatesTest.java
new file mode 100644
index 0000000..85d308f
--- /dev/null
+++ b/guava/test/com/google/common/base/PredicatesTest.java
@@ -0,0 +1,963 @@
+/*
+ * Copyright (C) 2005 Google Inc.
+ *
+ * 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.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.collect.ImmutableSet;
+import com.google.testing.util.EqualsTester;
+import com.google.testing.util.NullPointerTester;
+import com.google.testing.util.SerializableTester;
+
+import junit.framework.TestCase;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * Unit test for {@link Predicates}.
+ *
+ * @author Kevin Bourrillion
+ */
+@GwtCompatible(emulated = true)
+public class PredicatesTest extends TestCase {
+ private static final Predicate<Integer> TRUE = Predicates.alwaysTrue();
+ private static final Predicate<Integer> FALSE = Predicates.alwaysFalse();
+ private static final Predicate<Integer> NEVER_REACHED =
+ new Predicate<Integer>() {
+ public boolean apply(Integer i) {
+ fail("This predicate should never have been evaluated");
+ return false;
+ }
+ };
+
+ /** Instantiable predicate with reasonable hashCode() and equals() methods. */
+ static class IsOdd implements Predicate<Integer>, Serializable {
+ private static final long serialVersionUID = 0x150ddL;
+ public boolean apply(Integer i) {
+ return (i.intValue() & 1) == 1;
+ }
+ @Override public int hashCode() {
+ return 0x150dd;
+ }
+ @Override public boolean equals(Object obj) {
+ return obj instanceof IsOdd;
+ }
+ @Override public String toString() {
+ return "IsOdd";
+ }
+ }
+
+ /**
+ * Generates a new Predicate per call.
+ *
+ * <p>Creating a new Predicate each time helps catch cases where code is
+ * using {@code x == y} instead of {@code x.equals(y)}.
+ */
+ private static IsOdd isOdd() {
+ return new IsOdd();
+ }
+
+ /*
+ * Tests for Predicates.alwaysTrue().
+ */
+
+ public void testAlwaysTrue_apply() {
+ assertEvalsToTrue(Predicates.alwaysTrue());
+ }
+
+ public void testAlwaysTrue_equality() throws Exception {
+ new EqualsTester(TRUE)
+ .addEqualObject(Predicates.alwaysTrue())
+ .addNotEqualObject(isOdd())
+ .addNotEqualObject(Predicates.alwaysFalse())
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testAlwaysTrue_serialization() {
+ checkSerialization(Predicates.alwaysTrue());
+ }
+
+ /*
+ * Tests for Predicates.alwaysFalse().
+ */
+
+ public void testAlwaysFalse_apply() throws Exception {
+ assertEvalsToFalse(Predicates.alwaysFalse());
+ }
+
+ public void testAlwaysFalse_equality() throws Exception {
+ new EqualsTester(FALSE)
+ .addEqualObject(Predicates.alwaysFalse())
+ .addNotEqualObject(isOdd())
+ .addNotEqualObject(Predicates.alwaysTrue())
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testAlwaysFalse_serialization() {
+ checkSerialization(Predicates.alwaysFalse());
+ }
+
+ /*
+ * Tests for Predicates.not(predicate).
+ */
+
+ public void testNot_apply() {
+ assertEvalsToTrue(Predicates.not(FALSE));
+ assertEvalsToFalse(Predicates.not(TRUE));
+ assertEvalsLikeOdd(Predicates.not(Predicates.not(isOdd())));
+ }
+
+ public void testNot_equality() {
+ new EqualsTester(Predicates.not(isOdd()))
+ .addEqualObject(Predicates.not(isOdd()))
+ .addNotEqualObject(Predicates.not(TRUE))
+ .addNotEqualObject(isOdd())
+ .testEquals();
+ }
+
+ public void testNot_equalityForNotOfKnownValues() {
+ /* Would be nice to have .addEqualObject(Predicates.not(FALSE)). */
+ new EqualsTester(TRUE)
+ .addEqualObject(Predicates.alwaysTrue())
+ .addNotEqualObject(FALSE)
+ .addNotEqualObject(Predicates.not(TRUE))
+ .testEquals();
+
+ /* Would be nice to have .addEqualObject(Predicates.not(TRUE)). */
+ new EqualsTester(FALSE)
+ .addEqualObject(Predicates.alwaysFalse())
+ .addNotEqualObject(TRUE)
+ .addNotEqualObject(Predicates.not(FALSE))
+ .testEquals();
+
+ /* Would be nice to have .addEqualObject(Predicates.not(notNull())). */
+ new EqualsTester(Predicates.isNull())
+ .addEqualObject(Predicates.isNull())
+ .addNotEqualObject(Predicates.notNull())
+ .addNotEqualObject(Predicates.not(Predicates.isNull()))
+ .testEquals();
+
+ /* Would be nice to have .addEqualObject(Predicates.not(isNull())). */
+ new EqualsTester(Predicates.notNull())
+ .addEqualObject(Predicates.notNull())
+ .addNotEqualObject(Predicates.isNull())
+ .addNotEqualObject(Predicates.not(Predicates.notNull()))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testNot_serialization() {
+ checkSerialization(Predicates.not(isOdd()));
+ }
+
+ /*
+ * Tests for all the different flavors of Predicates.and().
+ */
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_applyNoArgs() {
+ assertEvalsToTrue(Predicates.and());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_equalityNoArgs() {
+ new EqualsTester(Predicates.and())
+ .addEqualObject(Predicates.and())
+ .addNotEqualObject(Predicates.and(FALSE))
+ .addNotEqualObject(Predicates.or())
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ @SuppressWarnings("unchecked")
+ public void testAnd_serializationNoArgs() {
+ checkSerialization(Predicates.and());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_applyOneArg() {
+ assertEvalsLikeOdd(Predicates.and(isOdd()));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_equalityOneArg() {
+ new EqualsTester(Predicates.and(NEVER_REACHED))
+ .addEqualObject(Predicates.and(NEVER_REACHED))
+ .addNotEqualObject(Predicates.and(NEVER_REACHED, FALSE))
+ .addNotEqualObject(Predicates.and(isOdd()))
+ .addNotEqualObject(Predicates.and())
+ .addNotEqualObject(Predicates.or(NEVER_REACHED))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ @SuppressWarnings("unchecked")
+ public void testAnd_serializationOneArg() {
+ checkSerialization(Predicates.and(isOdd()));
+ }
+
+ public void testAnd_applyBinary() {
+ assertEvalsLikeOdd(Predicates.and(isOdd(), TRUE));
+ assertEvalsLikeOdd(Predicates.and(TRUE, isOdd()));
+ assertEvalsToFalse(Predicates.and(FALSE, NEVER_REACHED));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_equalityBinary() {
+ new EqualsTester(Predicates.and(TRUE, NEVER_REACHED))
+ .addEqualObject(Predicates.and(TRUE, NEVER_REACHED))
+ .addNotEqualObject(Predicates.and(NEVER_REACHED, TRUE))
+ .addNotEqualObject(Predicates.and(TRUE))
+ .addNotEqualObject(Predicates.or(TRUE, NEVER_REACHED))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testAnd_serializationBinary() {
+ checkSerialization(Predicates.and(TRUE, isOdd()));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_applyTernary() {
+ assertEvalsLikeOdd(Predicates.and(isOdd(), TRUE, TRUE));
+ assertEvalsLikeOdd(Predicates.and(TRUE, isOdd(), TRUE));
+ assertEvalsLikeOdd(Predicates.and(TRUE, TRUE, isOdd()));
+ assertEvalsToFalse(Predicates.and(TRUE, FALSE, NEVER_REACHED));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_equalityTernary() {
+ new EqualsTester(Predicates.and(TRUE, isOdd(), NEVER_REACHED))
+ .addEqualObject(Predicates.and(TRUE, isOdd(), NEVER_REACHED))
+ .addNotEqualObject(Predicates.and(isOdd(), NEVER_REACHED, TRUE))
+ .addNotEqualObject(Predicates.and(TRUE))
+ .addNotEqualObject(Predicates.or(TRUE, isOdd(), NEVER_REACHED))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ @SuppressWarnings("unchecked")
+ public void testAnd_serializationTernary() {
+ checkSerialization(Predicates.and(TRUE, isOdd(), FALSE));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_applyIterable() {
+ Collection<Predicate<Integer>> empty = Arrays.asList();
+ assertEvalsToTrue(Predicates.and(empty));
+ assertEvalsLikeOdd(Predicates.and(Arrays.asList(isOdd())));
+ assertEvalsLikeOdd(Predicates.and(Arrays.asList(TRUE, isOdd())));
+ assertEvalsToFalse(Predicates.and(Arrays.asList(FALSE, NEVER_REACHED)));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_equalityIterable() {
+ new EqualsTester(Predicates.and(Arrays.asList(TRUE, NEVER_REACHED)))
+ .addEqualObject(Predicates.and(Arrays.asList(TRUE, NEVER_REACHED)))
+ .addEqualObject(Predicates.and(TRUE, NEVER_REACHED))
+ .addNotEqualObject(Predicates.and(FALSE, NEVER_REACHED))
+ .addNotEqualObject(Predicates.or(TRUE, NEVER_REACHED))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ @SuppressWarnings("unchecked")
+ public void testAnd_serializationIterable() {
+ checkSerialization(Predicates.and(Arrays.asList(TRUE, FALSE)));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_arrayDefensivelyCopied() {
+ Predicate[] array = {Predicates.alwaysFalse()};
+ Predicate<Object> predicate = Predicates.and(array);
+ assertFalse(predicate.apply(1));
+ array[0] = Predicates.alwaysTrue();
+ assertFalse(predicate.apply(1));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_listDefensivelyCopied() {
+ List list = new ArrayList<Predicate>();
+ Predicate<Object> predicate = Predicates.and(list);
+ assertTrue(predicate.apply(1));
+ list.add(Predicates.alwaysFalse());
+ assertTrue(predicate.apply(1));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testAnd_iterableDefensivelyCopied() {
+ final List list = new ArrayList<Predicate>();
+ Iterable iterable = new Iterable<Predicate>() {
+ public Iterator<Predicate> iterator() {
+ return list.iterator();
+ }
+ };
+ Predicate<Object> predicate = Predicates.and(iterable);
+ assertTrue(predicate.apply(1));
+ list.add(Predicates.alwaysFalse());
+ assertTrue(predicate.apply(1));
+ }
+
+ /*
+ * Tests for all the different flavors of Predicates.or().
+ */
+
+ @SuppressWarnings("unchecked")
+ public void testOr_applyNoArgs() {
+ assertEvalsToFalse(Predicates.or());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_equalityNoArgs() {
+ new EqualsTester(Predicates.or())
+ .addEqualObject(Predicates.or())
+ .addNotEqualObject(Predicates.or(TRUE))
+ .addNotEqualObject(Predicates.and())
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ @SuppressWarnings("unchecked")
+ public void testOr_serializationNoArgs() {
+ checkSerialization(Predicates.or());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_applyOneArg() {
+ assertEvalsToTrue(Predicates.or(TRUE));
+ assertEvalsToFalse(Predicates.or(FALSE));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_equalityOneArg() {
+ new EqualsTester(Predicates.or(NEVER_REACHED))
+ .addEqualObject(Predicates.or(NEVER_REACHED))
+ .addNotEqualObject(Predicates.or(NEVER_REACHED, TRUE))
+ .addNotEqualObject(Predicates.or(TRUE))
+ .addNotEqualObject(Predicates.or())
+ .addNotEqualObject(Predicates.and(NEVER_REACHED))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ @SuppressWarnings("unchecked")
+ public void testOr_serializationOneArg() {
+ checkSerialization(Predicates.or(isOdd()));
+ }
+
+ public void testOr_applyBinary() {
+ Predicate<Integer> falseOrFalse = Predicates.or(FALSE, FALSE);
+ Predicate<Integer> falseOrTrue = Predicates.or(FALSE, TRUE);
+ Predicate<Integer> trueOrAnything = Predicates.or(TRUE, NEVER_REACHED);
+
+ assertEvalsToFalse(falseOrFalse);
+ assertEvalsToTrue(falseOrTrue);
+ assertEvalsToTrue(trueOrAnything);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_equalityBinary() {
+ new EqualsTester(Predicates.or(FALSE, NEVER_REACHED))
+ .addEqualObject(Predicates.or(FALSE, NEVER_REACHED))
+ .addNotEqualObject(Predicates.or(NEVER_REACHED, FALSE))
+ .addNotEqualObject(Predicates.or(TRUE))
+ .addNotEqualObject(Predicates.and(FALSE, NEVER_REACHED))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testOr_serializationBinary() {
+ checkSerialization(Predicates.or(isOdd(), TRUE));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_applyTernary() {
+ assertEvalsLikeOdd(Predicates.or(isOdd(), FALSE, FALSE));
+ assertEvalsLikeOdd(Predicates.or(FALSE, isOdd(), FALSE));
+ assertEvalsLikeOdd(Predicates.or(FALSE, FALSE, isOdd()));
+ assertEvalsToTrue(Predicates.or(FALSE, TRUE, NEVER_REACHED));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_equalityTernary() {
+ new EqualsTester(Predicates.or(FALSE, NEVER_REACHED, TRUE))
+ .addEqualObject(Predicates.or(FALSE, NEVER_REACHED, TRUE))
+ .addNotEqualObject(Predicates.or(TRUE, NEVER_REACHED, FALSE))
+ .addNotEqualObject(Predicates.or(TRUE))
+ .addNotEqualObject(Predicates.and(FALSE, NEVER_REACHED, TRUE))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ @SuppressWarnings("unchecked")
+ public void testOr_serializationTernary() {
+ checkSerialization(Predicates.or(FALSE, isOdd(), TRUE));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_applyIterable() {
+ Predicate<Integer> vacuouslyFalse =
+ Predicates.or(Collections.<Predicate<Integer>>emptyList());
+ Predicate<Integer> troo = Predicates.or(Collections.singletonList(TRUE));
+ /*
+ * newLinkedList() takes varargs. TRUE and FALSE are both instances of
+ * Predicate<Integer>, so the call is safe.
+ */
+ Predicate<Integer> trueAndFalse = Predicates.or(Arrays.asList(TRUE, FALSE));
+
+ assertEvalsToFalse(vacuouslyFalse);
+ assertEvalsToTrue(troo);
+ assertEvalsToTrue(trueAndFalse);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_equalityIterable() {
+ new EqualsTester(Predicates.or(Arrays.asList(FALSE, NEVER_REACHED)))
+ .addEqualObject(Predicates.or(Arrays.asList(FALSE, NEVER_REACHED)))
+ .addEqualObject(Predicates.or(FALSE, NEVER_REACHED))
+ .addNotEqualObject(Predicates.or(TRUE, NEVER_REACHED))
+ .addNotEqualObject(Predicates.and(FALSE, NEVER_REACHED))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ @SuppressWarnings("unchecked")
+ public void testOr_serializationIterable() {
+ Predicate<Integer> pre = Predicates.or(Arrays.asList(TRUE, FALSE));
+ Predicate<Integer> post = SerializableTester.reserializeAndAssert(pre);
+ assertEquals(pre.apply(0), post.apply(0));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_arrayDefensivelyCopied() {
+ Predicate[] array = {Predicates.alwaysFalse()};
+ Predicate<Object> predicate = Predicates.or(array);
+ assertFalse(predicate.apply(1));
+ array[0] = Predicates.alwaysTrue();
+ assertFalse(predicate.apply(1));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_listDefensivelyCopied() {
+ List list = new ArrayList<Predicate>();
+ Predicate<Object> predicate = Predicates.or(list);
+ assertFalse(predicate.apply(1));
+ list.add(Predicates.alwaysTrue());
+ assertFalse(predicate.apply(1));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testOr_iterableDefensivelyCopied() {
+ final List list = new ArrayList<Predicate>();
+ Iterable iterable = new Iterable<Predicate>() {
+ public Iterator<Predicate> iterator() {
+ return list.iterator();
+ }
+ };
+ Predicate<Object> predicate = Predicates.or(iterable);
+ assertFalse(predicate.apply(1));
+ list.add(Predicates.alwaysTrue());
+ assertFalse(predicate.apply(1));
+ }
+
+ /*
+ * Tests for Predicates.equalTo(x).
+ */
+
+ public void testIsEqualTo_apply() {
+ Predicate<Integer> isOne = Predicates.equalTo(1);
+
+ assertTrue(isOne.apply(1));
+ assertFalse(isOne.apply(2));
+ assertFalse(isOne.apply(null));
+ }
+
+ public void testIsEqualTo_equality() {
+ new EqualsTester(Predicates.equalTo(1))
+ .addEqualObject(Predicates.equalTo(1))
+ .addNotEqualObject(Predicates.equalTo(2))
+ .addNotEqualObject(Predicates.equalTo(null))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testIsEqualTo_serialization() {
+ checkSerialization(Predicates.equalTo(1));
+ }
+
+ public void testIsEqualToNull_apply() {
+ Predicate<Integer> isNull = Predicates.equalTo(null);
+ assertTrue(isNull.apply(null));
+ assertFalse(isNull.apply(1));
+ }
+
+ public void testIsEqualToNull_equality() {
+ new EqualsTester(Predicates.equalTo(null))
+ .addEqualObject(Predicates.equalTo(null))
+ .addNotEqualObject(Predicates.equalTo(1))
+ .addNotEqualObject(Predicates.equalTo("null"))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testIsEqualToNull_serialization() {
+ checkSerialization(Predicates.equalTo(null));
+ }
+
+ /**
+ * Tests for Predicates.instanceOf(x).
+ * TODO: Fix the comment style after fixing annotation stripper to remove
+ * comments properly. Currently, all tests before the comments are removed
+ * as well.
+ */
+
+ @GwtIncompatible("Predicates.instanceOf")
+ public void testIsInstanceOf_apply() {
+ Predicate<Object> isInteger = Predicates.instanceOf(Integer.class);
+
+ assertTrue(isInteger.apply(1));
+ assertFalse(isInteger.apply(2.0f));
+ assertFalse(isInteger.apply(""));
+ assertFalse(isInteger.apply(null));
+ }
+
+ @GwtIncompatible("Predicates.instanceOf")
+ public void testIsInstanceOf_subclass() {
+ Predicate<Object> isNumber = Predicates.instanceOf(Number.class);
+
+ assertTrue(isNumber.apply(1));
+ assertTrue(isNumber.apply(2.0f));
+ assertFalse(isNumber.apply(""));
+ assertFalse(isNumber.apply(null));
+ }
+
+ @GwtIncompatible("Predicates.instanceOf")
+ public void testIsInstanceOf_interface() {
+ Predicate<Object> isComparable = Predicates.instanceOf(Comparable.class);
+
+ assertTrue(isComparable.apply(1));
+ assertTrue(isComparable.apply(2.0f));
+ assertTrue(isComparable.apply(""));
+ assertFalse(isComparable.apply(null));
+ }
+
+ @GwtIncompatible("Predicates.instanceOf")
+ public void testIsInstanceOf_equality() {
+ new EqualsTester(Predicates.instanceOf(Integer.class))
+ .addEqualObject(Predicates.instanceOf(Integer.class))
+ .addNotEqualObject(Predicates.instanceOf(Number.class))
+ .addNotEqualObject(Predicates.instanceOf(Float.class))
+ .testEquals();
+ }
+
+ @GwtIncompatible("Predicates.instanceOf, SerializableTester")
+ public void testIsInstanceOf_serialization() {
+ checkSerialization(Predicates.instanceOf(Integer.class));
+ }
+
+ /*
+ * Tests for Predicates.isNull()
+ */
+
+ public void testIsNull_apply() {
+ Predicate<Integer> isNull = Predicates.isNull();
+ assertTrue(isNull.apply(null));
+ assertFalse(isNull.apply(1));
+ }
+
+ public void testIsNull_equality() {
+ new EqualsTester(Predicates.isNull())
+ .addEqualObject(Predicates.isNull())
+ .addNotEqualObject(Predicates.notNull())
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testIsNull_serialization() {
+ Predicate<String> pre = Predicates.isNull();
+ Predicate<String> post = SerializableTester.reserializeAndAssert(pre);
+ assertEquals(pre.apply("foo"), post.apply("foo"));
+ assertEquals(pre.apply(null), post.apply(null));
+ }
+
+ public void testNotNull_apply() {
+ Predicate<Integer> notNull = Predicates.notNull();
+ assertFalse(notNull.apply(null));
+ assertTrue(notNull.apply(1));
+ }
+
+ public void testNotNull_equality() {
+ new EqualsTester(Predicates.notNull())
+ .addEqualObject(Predicates.notNull())
+ .addNotEqualObject(Predicates.isNull())
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testNotNull_serialization() {
+ checkSerialization(Predicates.notNull());
+ }
+
+ public void testIn_apply() {
+ Collection<Integer> nums = Arrays.asList(1, 5);
+ Predicate<Integer> isOneOrFive = Predicates.in(nums);
+
+ assertTrue(isOneOrFive.apply(1));
+ assertTrue(isOneOrFive.apply(5));
+ assertFalse(isOneOrFive.apply(3));
+ assertFalse(isOneOrFive.apply(null));
+ }
+
+ public void testIn_equality() {
+ Collection<Integer> nums = ImmutableSet.of(1, 5);
+ Collection<Integer> sameOrder = ImmutableSet.of(1, 5);
+ Collection<Integer> differentOrder = ImmutableSet.of(5, 1);
+ Collection<Integer> differentNums = ImmutableSet.of(1, 3, 5);
+
+ new EqualsTester(Predicates.in(nums))
+ .addEqualObject(Predicates.in(nums))
+ .addEqualObject(Predicates.in(sameOrder))
+ .addEqualObject(Predicates.in(differentOrder))
+ .addNotEqualObject(Predicates.in(differentNums))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testIn_serialization() {
+ checkSerialization(Predicates.in(Arrays.asList(1, 2, 3, null)));
+ }
+
+ public void testIn_handlesNullPointerException() {
+ class CollectionThatThrowsNPE<T> extends ArrayList<T> {
+ private static final long serialVersionUID = 1L;
+
+ @Override public boolean contains(Object element) {
+ Preconditions.checkNotNull(element);
+ return super.contains(element);
+ }
+ }
+ Collection<Integer> nums = new CollectionThatThrowsNPE<Integer>();
+ Predicate<Integer> isFalse = Predicates.in(nums);
+ assertFalse(isFalse.apply(null));
+ }
+
+ public void testIn_handlesClassCastException() {
+ class CollectionThatThrowsCCE<T> extends ArrayList<T> {
+ private static final long serialVersionUID = 1L;
+
+ @Override public boolean contains(Object element) {
+ throw new ClassCastException("");
+ }
+ }
+ Collection<Integer> nums = new CollectionThatThrowsCCE<Integer>();
+ nums.add(3);
+ Predicate<Integer> isThree = Predicates.in(nums);
+ assertFalse(isThree.apply(3));
+ }
+
+ /*
+ * Tests that compilation will work when applying explicit types.
+ */
+ public void testIn_compilesWithExplicitSupertype() {
+ Collection<Number> nums = ImmutableSet.of();
+ Predicate<Number> p1 = Predicates.in(nums);
+ Predicate<Object> p2 = Predicates.<Object>in(nums);
+ // The next two lines are not expected to compile.
+ // Predicate<Integer> p3 = Predicates.in(nums);
+ // Predicate<Integer> p4 = Predicates.<Integer>in(nums);
+ }
+
+ @GwtIncompatible("NullPointerTester")
+ public void testNullPointerExceptions() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ tester.testAllPublicStaticMethods(Predicates.class);
+ }
+
+ @SuppressWarnings("unchecked") // varargs
+ @GwtIncompatible("SerializbleTester")
+ public void testCascadingSerialization() throws Exception {
+ // Eclipse says Predicate<Integer>; javac says Predicate<Object>.
+ Predicate<? super Integer> nasty = Predicates.not(Predicates.and(
+ Predicates.or(
+ Predicates.equalTo((Object) 1), Predicates.equalTo(null),
+ Predicates.alwaysFalse(), Predicates.alwaysTrue(),
+ Predicates.isNull(), Predicates.notNull(),
+ Predicates.in(Arrays.asList(1)))));
+ assertEvalsToFalse(nasty);
+
+ Predicate<? super Integer> stillNasty =
+ SerializableTester.reserializeAndAssert(nasty);
+
+ assertEvalsToFalse(stillNasty);
+ }
+
+ // enum singleton pattern
+ private enum TrimStringFunction implements Function<String, String> {
+ INSTANCE;
+
+ public String apply(String string) {
+ return string.trim();
+ }
+ }
+
+ public void testCompose() {
+ Function<String, String> trim = TrimStringFunction.INSTANCE;
+ Predicate<String> equalsFoo = Predicates.equalTo("Foo");
+ Predicate<String> equalsBar = Predicates.equalTo("Bar");
+ Predicate<String> trimEqualsFoo = Predicates.compose(equalsFoo, trim);
+ Function<String, String> identity = Functions.identity();
+
+ assertTrue(trimEqualsFoo.apply("Foo"));
+ assertTrue(trimEqualsFoo.apply(" Foo "));
+ assertFalse(trimEqualsFoo.apply("Foo-b-que"));
+
+ new EqualsTester(trimEqualsFoo)
+ .addEqualObject(Predicates.compose(equalsFoo, trim))
+ .addNotEqualObject(equalsFoo)
+ .addNotEqualObject(trim)
+ .addNotEqualObject(Predicates.compose(equalsFoo, identity))
+ .addNotEqualObject(Predicates.compose(equalsBar, trim))
+ .testEquals();
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testComposeSerialization() {
+ Function<String, String> trim = TrimStringFunction.INSTANCE;
+ Predicate<String> equalsFoo = Predicates.equalTo("Foo");
+ Predicate<String> trimEqualsFoo = Predicates.compose(equalsFoo, trim);
+ SerializableTester.reserializeAndAssert(trimEqualsFoo);
+ }
+
+ /**
+ * Tests for Predicates.contains(Pattern) and .containsPattern(String).
+ * We assume the regex level works, so there are only trivial tests of that
+ * aspect.
+ * TODO: Fix comment style once annotation stripper is fixed.
+ */
+
+ @GwtIncompatible("Predicates.containsPattern")
+ public void testContainsPattern_apply() {
+ Predicate<CharSequence> isFoobar =
+ Predicates.containsPattern("^Fo.*o.*bar$");
+ assertTrue(isFoobar.apply("Foxyzoabcbar"));
+ assertFalse(isFoobar.apply("Foobarx"));
+ }
+
+ @GwtIncompatible("Predicates.containsPattern")
+ public void testContains_apply() {
+ Predicate<CharSequence> isFoobar =
+ Predicates.contains(Pattern.compile("^Fo.*o.*bar$"));
+
+ assertTrue(isFoobar.apply("Foxyzoabcbar"));
+ assertFalse(isFoobar.apply("Foobarx"));
+ }
+
+ @GwtIncompatible("NullPointerTester")
+ public void testContainsPattern_nulls() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ Predicate<CharSequence> isWooString = Predicates.containsPattern("Woo");
+
+ tester.testAllPublicInstanceMethods(isWooString);
+ }
+
+ @GwtIncompatible("NullPointerTester")
+ public void testContains_nulls() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ Predicate<CharSequence> isWooPattern =
+ Predicates.contains(Pattern.compile("Woo"));
+
+ tester.testAllPublicInstanceMethods(isWooPattern);
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testContainsPattern_serialization() {
+ Predicate<CharSequence> pre = Predicates.containsPattern("foo");
+ Predicate<CharSequence> post = SerializableTester.reserializeAndAssert(pre);
+ assertEquals(pre.apply("foo"), post.apply("foo"));
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testContains_equals() {
+ new EqualsTester()
+ .addEqualityGroup(
+ Predicates.contains(Pattern.compile("foo")),
+ Predicates.containsPattern("foo"))
+ .addEqualityGroup(
+ Predicates.contains(
+ Pattern.compile("foo", Pattern.CASE_INSENSITIVE)))
+ .addEqualityGroup(
+ Predicates.containsPattern("bar"))
+ .testEquals();
+ }
+
+ public void checkConsistency(
+ Predicate<? super Integer> expected, Predicate<? super Integer> actual) {
+ assertEvalsLike(expected, actual);
+ assertEquals(actual.toString() + " should hash like " + expected.toString(),
+ expected.hashCode(), actual.hashCode());
+ }
+
+ public void testHashCodeForBooleanOperationsIsConsistentWithBooleanLogic() {
+ /*
+ * This isn't a "requirement" yet, as much as it's a "nice to have for
+ * future design."
+ *
+ * Maybe it will be possible to eventually have these predicates do
+ * certain simplifying logical transformations to simpler equivalent
+ * forms. If so, this checks that the hash codes have been chosen in such
+ * a way that the fundamental building-block operations:
+ *
+ * alwaysTrue()
+ * alwaysFalse()
+ * not(p)
+ * and(p1, p2)
+ * or(p1, p2)
+ *
+ * have hashCode() calculations that coincidentally cause equivalent logical
+ * expressions to have equivalent hashCode() values.
+ */
+ Predicate<Integer> p1 = Predicates.isNull();
+ Predicate<Integer> p2 = isOdd();
+ Predicate<Integer> p3 = new Predicate<Integer>() {
+ public boolean apply(Integer i) {
+ return (Integer.bitCount(i) & 1) == 1;
+ }
+ @Override public String toString() {
+ return "oddBitCount";
+ }
+ };
+
+ checkConsistency(
+ p1,
+ Predicates.not(Predicates.not(p1)));
+
+ checkConsistency(
+ Predicates.and(Predicates.not(p1), Predicates.not(p2)),
+ Predicates.not(Predicates.or(p1, p2)));
+
+ checkConsistency(
+ Predicates.or(Predicates.not(p1), Predicates.not(p2)),
+ Predicates.not(Predicates.and(p1, p2)));
+
+ checkConsistency(
+ Predicates.and(Predicates.and(p1, p2), p3),
+ Predicates.and(p1, Predicates.and(p2, p3)));
+
+ checkConsistency(
+ Predicates.or(Predicates.or(p1, p2), p3),
+ Predicates.or(p1, Predicates.or(p2, p3)));
+
+ checkConsistency(
+ Predicates.or(Predicates.and(p1, p2), p3),
+ Predicates.and(Predicates.or(p1, p3), Predicates.or(p2, p3)));
+
+ checkConsistency(
+ Predicates.and(Predicates.or(p1, p2), p3),
+ Predicates.or(Predicates.and(p1, p3), Predicates.and(p2, p3)));
+
+ /*
+ * Now that alwaysFalse and alwaysTrue follow the enum singleton pattern,
+ * the following tests can't call checkConsistency to compare the hash
+ * codes.
+ */
+
+ assertEvalsLike(
+ Predicates.alwaysTrue(),
+ Predicates.not(Predicates.alwaysFalse()));
+
+ assertEvalsLike(
+ Predicates.alwaysFalse(),
+ Predicates.not(Predicates.alwaysTrue()));
+
+ assertEvalsLike(
+ Predicates.alwaysFalse(),
+ Predicates.and(p1, Predicates.not(p1)));
+
+ assertEvalsLike(
+ Predicates.alwaysTrue(),
+ Predicates.or(p1, Predicates.not(p1)));
+ }
+
+ private static void assertEvalsToTrue(Predicate<? super Integer> predicate) {
+ assertTrue(predicate.apply(0));
+ assertTrue(predicate.apply(1));
+ assertTrue(predicate.apply(null));
+ }
+
+ private static void assertEvalsToFalse(Predicate<? super Integer> predicate) {
+ assertFalse(predicate.apply(0));
+ assertFalse(predicate.apply(1));
+ assertFalse(predicate.apply(null));
+ }
+
+ private static void assertEvalsLikeOdd(Predicate<? super Integer> predicate) {
+ assertEvalsLike(isOdd(), predicate);
+ }
+
+ private static void assertEvalsLike(
+ Predicate<? super Integer> expected,
+ Predicate<? super Integer> actual) {
+ assertEvalsLike(expected, actual, 0);
+ assertEvalsLike(expected, actual, 1);
+ assertEvalsLike(expected, actual, null);
+ }
+
+ private static void assertEvalsLike(
+ Predicate<? super Integer> expected,
+ Predicate<? super Integer> actual,
+ Integer input) {
+ Boolean expectedResult = null;
+ RuntimeException expectedRuntimeException = null;
+ try {
+ expectedResult = expected.apply(input);
+ } catch (RuntimeException e) {
+ expectedRuntimeException = e;
+ }
+
+ Boolean actualResult = null;
+ RuntimeException actualRuntimeException = null;
+ try {
+ actualResult = actual.apply(input);
+ } catch (RuntimeException e) {
+ actualRuntimeException = e;
+ }
+
+ assertEquals(expectedResult, actualResult);
+ if (expectedRuntimeException != null) {
+ assertNotNull(actualRuntimeException);
+ assertEquals(
+ expectedRuntimeException.getClass(),
+ actualRuntimeException.getClass());
+ }
+ }
+
+ @GwtIncompatible("SerializableTester")
+ private static void checkSerialization(Predicate<? super Integer> predicate) {
+ Predicate<? super Integer> reserialized =
+ SerializableTester.reserializeAndAssert(predicate);
+ assertEvalsLike(predicate, reserialized);
+ }
+}
diff --git a/guava/test/com/google/common/base/SplitterTest.java b/guava/test/com/google/common/base/SplitterTest.java
new file mode 100644
index 0000000..bec7183
--- /dev/null
+++ b/guava/test/com/google/common/base/SplitterTest.java
@@ -0,0 +1,529 @@
+/*
+ * 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.
+ * 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.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.collect.Lists;
+import com.google.testing.util.NullPointerTester;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+
+/**
+ * @author Julien Silland
+ */
+@GwtCompatible(emulated = true)
+public class SplitterTest extends TestCase {
+
+ public void testSplitNullString() {
+ try {
+ Splitter.on(',').split(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testCharacterSimpleSplit() {
+ String simple = "a,b,c";
+ Iterable<String> letters = Splitter.on(',').split(simple);
+ assertContentsInOrder(letters, "a", "b", "c");
+ }
+
+ public void testCharacterSimpleSplitWithNoDelimiter() {
+ String simple = "a,b,c";
+ Iterable<String> letters = Splitter.on('.').split(simple);
+ assertContentsInOrder(letters, "a,b,c");
+ }
+
+ public void testCharacterSplitWithDoubleDelimiter() {
+ String doubled = "a,,b,c";
+ Iterable<String> letters = Splitter.on(',').split(doubled);
+ assertContentsInOrder(letters, "a", "", "b", "c");
+ }
+
+ public void testCharacterSplitWithDoubleDelimiterAndSpace() {
+ String doubled = "a,, b,c";
+ Iterable<String> letters = Splitter.on(',').split(doubled);
+ assertContentsInOrder(letters, "a", "", " b", "c");
+ }
+
+ public void testCharacterSplitWithTrailingDelimiter() {
+ String trailing = "a,b,c,";
+ Iterable<String> letters = Splitter.on(',').split(trailing);
+ assertContentsInOrder(letters, "a", "b", "c", "");
+ }
+
+ public void testCharacterSplitWithLeadingDelimiter() {
+ String leading = ",a,b,c";
+ Iterable<String> letters = Splitter.on(',').split(leading);
+ assertContentsInOrder(letters, "", "a", "b", "c");
+ }
+
+ public void testCharacterSplitWithMulitpleLetters() {
+ Iterable<String> testCharacteringMotto = Splitter.on('-').split(
+ "Testing-rocks-Debugging-sucks");
+ assertContentsInOrder(testCharacteringMotto,
+ "Testing", "rocks", "Debugging", "sucks");
+ }
+
+ public void testCharacterSplitWithMatcherDelimiter() {
+ Iterable<String> testCharacteringMotto = Splitter
+ .on(CharMatcher.WHITESPACE)
+ .split("Testing\nrocks\tDebugging sucks");
+ assertContentsInOrder(testCharacteringMotto,
+ "Testing", "rocks", "Debugging", "sucks");
+ }
+
+ public void testCharacterSplitWithDoubleDelimiterOmitEmptyStrings() {
+ String doubled = "a..b.c";
+ Iterable<String> letters = Splitter.on('.')
+ .omitEmptyStrings().split(doubled);
+ assertContentsInOrder(letters, "a", "b", "c");
+ }
+
+ public void testCharacterSplitEmptyToken() {
+ String emptyToken = "a. .c";
+ Iterable<String> letters = Splitter.on('.').trimResults()
+ .split(emptyToken);
+ assertContentsInOrder(letters, "a", "", "c");
+ }
+
+ public void testCharacterSplitEmptyTokenOmitEmptyStrings() {
+ String emptyToken = "a. .c";
+ Iterable<String> letters = Splitter.on('.')
+ .omitEmptyStrings().trimResults().split(emptyToken);
+ assertContentsInOrder(letters, "a", "c");
+ }
+
+ public void testCharacterSplitOnEmptyString() {
+ Iterable<String> nothing = Splitter.on('.').split("");
+ assertContentsInOrder(nothing, "");
+ }
+
+ public void testCharacterSplitOnEmptyStringOmitEmptyStrings() {
+ assertFalse(
+ Splitter.on('.').omitEmptyStrings().split("").iterator().hasNext());
+ }
+
+ public void testCharacterSplitOnOnlyDelimiter() {
+ Iterable<String> blankblank = Splitter.on('.').split(".");
+ assertContentsInOrder(blankblank, "", "");
+ }
+
+ public void testCharacterSplitOnOnlyDelimitersOmitEmptyStrings() {
+ Iterable<String> empty = Splitter.on('.').omitEmptyStrings().split("...");
+ assertContentsInOrder(empty);
+ }
+
+ public void testCharacterSplitWithTrim() {
+ String jacksons = "arfo(Marlon)aorf, (Michael)orfa, afro(Jackie)orfa, "
+ + "ofar(Jemaine), aff(Tito)";
+ Iterable<String> family = Splitter.on(',')
+ .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE))
+ .split(jacksons);
+ assertContentsInOrder(family,
+ "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)");
+ }
+
+ public void testStringSimpleSplit() {
+ String simple = "a,b,c";
+ Iterable<String> letters = Splitter.on(",").split(simple);
+ assertContentsInOrder(letters, "a", "b", "c");
+ }
+
+ public void testStringSimpleSplitWithNoDelimiter() {
+ String simple = "a,b,c";
+ Iterable<String> letters = Splitter.on(".").split(simple);
+ assertContentsInOrder(letters, "a,b,c");
+ }
+
+ public void testStringSplitWithDoubleDelimiter() {
+ String doubled = "a,,b,c";
+ Iterable<String> letters = Splitter.on(",").split(doubled);
+ assertContentsInOrder(letters, "a", "", "b", "c");
+ }
+
+ public void testStringSplitWithDoubleDelimiterAndSpace() {
+ String doubled = "a,, b,c";
+ Iterable<String> letters = Splitter.on(",").split(doubled);
+ assertContentsInOrder(letters, "a", "", " b", "c");
+ }
+
+ public void testStringSplitWithTrailingDelimiter() {
+ String trailing = "a,b,c,";
+ Iterable<String> letters = Splitter.on(",").split(trailing);
+ assertContentsInOrder(letters, "a", "b", "c", "");
+ }
+
+ public void testStringSplitWithLeadingDelimiter() {
+ String leading = ",a,b,c";
+ Iterable<String> letters = Splitter.on(",").split(leading);
+ assertContentsInOrder(letters, "", "a", "b", "c");
+ }
+
+ public void testStringSplitWithMultipleLetters() {
+ Iterable<String> testStringingMotto = Splitter.on("-").split(
+ "Testing-rocks-Debugging-sucks");
+ assertContentsInOrder(testStringingMotto,
+ "Testing", "rocks", "Debugging", "sucks");
+ }
+
+ public void testStringSplitWithDoubleDelimiterOmitEmptyStrings() {
+ String doubled = "a..b.c";
+ Iterable<String> letters = Splitter.on(".")
+ .omitEmptyStrings().split(doubled);
+ assertContentsInOrder(letters, "a", "b", "c");
+ }
+
+ public void testStringSplitEmptyToken() {
+ String emptyToken = "a. .c";
+ Iterable<String> letters = Splitter.on(".").trimResults()
+ .split(emptyToken);
+ assertContentsInOrder(letters, "a", "", "c");
+ }
+
+ public void testStringSplitEmptyTokenOmitEmptyStrings() {
+ String emptyToken = "a. .c";
+ Iterable<String> letters = Splitter.on(".")
+ .omitEmptyStrings().trimResults().split(emptyToken);
+ assertContentsInOrder(letters, "a", "c");
+ }
+
+ public void testStringSplitWithLongDelimiter() {
+ String longDelimiter = "a, b, c";
+ Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
+ assertContentsInOrder(letters, "a", "b", "c");
+ }
+
+ public void testStringSplitWithLongLeadingDelimiter() {
+ String longDelimiter = ", a, b, c";
+ Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
+ assertContentsInOrder(letters, "", "a", "b", "c");
+ }
+
+ public void testStringSplitWithLongTrailingDelimiter() {
+ String longDelimiter = "a, b, c, ";
+ Iterable<String> letters = Splitter.on(", ").split(longDelimiter);
+ assertContentsInOrder(letters, "a", "b", "c", "");
+ }
+
+ public void testStringSplitWithDelimiterSubstringInValue() {
+ String fourCommasAndFourSpaces = ",,,, ";
+ Iterable<String> threeCommasThenTreeSpaces = Splitter.on(", ").split(
+ fourCommasAndFourSpaces);
+ assertContentsInOrder(threeCommasThenTreeSpaces, ",,,", " ");
+ }
+
+ public void testStringSplitWithEmptyString() {
+ try {
+ Splitter.on("");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testStringSplitOnEmptyString() {
+ Iterable<String> notMuch = Splitter.on(".").split("");
+ assertContentsInOrder(notMuch, "");
+ }
+
+ public void testStringSplitOnEmptyStringOmitEmptyString() {
+ assertFalse(
+ Splitter.on(".").omitEmptyStrings().split("").iterator().hasNext());
+ }
+
+ public void testStringSplitOnOnlyDelimiter() {
+ Iterable<String> blankblank = Splitter.on(".").split(".");
+ assertContentsInOrder(blankblank, "", "");
+ }
+
+ public void testStringSplitOnOnlyDelimitersOmitEmptyStrings() {
+ Iterable<String> empty = Splitter.on(".").omitEmptyStrings().split("...");
+ assertContentsInOrder(empty);
+ }
+
+ public void testStringSplitWithTrim() {
+ String jacksons = "arfo(Marlon)aorf, (Michael)orfa, afro(Jackie)orfa, "
+ + "ofar(Jemaine), aff(Tito)";
+ Iterable<String> family = Splitter.on(",")
+ .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE))
+ .split(jacksons);
+ assertContentsInOrder(family,
+ "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)");
+ }
+
+ @GwtIncompatible("Splitter.onPattern")
+ public void testPatternSimpleSplit() {
+ String simple = "a,b,c";
+ Iterable<String> letters = Splitter.onPattern(",").split(simple);
+ assertContentsInOrder(letters, "a", "b", "c");
+ }
+
+ @GwtIncompatible("Splitter.onPattern")
+ public void testPatternSimpleSplitWithNoDelimiter() {
+ String simple = "a,b,c";
+ Iterable<String> letters = Splitter.onPattern("foo").split(simple);
+ assertContentsInOrder(letters, "a,b,c");
+ }
+
+ @GwtIncompatible("Splitter.onPattern")
+ public void testPatternSplitWithDoubleDelimiter() {
+ String doubled = "a,,b,c";
+ Iterable<String> letters = Splitter.onPattern(",").split(doubled);
+ assertContentsInOrder(letters, "a", "", "b", "c");
+ }
+
+ @GwtIncompatible("Splitter.onPattern")
+ public void testPatternSplitWithDoubleDelimiterAndSpace() {
+ String doubled = "a,, b,c";
+ Iterable<String> letters = Splitter.onPattern(",").split(doubled);
+ assertContentsInOrder(letters, "a", "", " b", "c");
+ }
+
+ @GwtIncompatible("Splitter.onPattern")
+ public void testPatternSplitWithTrailingDelimiter() {
+ String trailing = "a,b,c,";
+ Iterable<String> letters = Splitter.onPattern(",").split(trailing);
+ assertContentsInOrder(letters, "a", "b", "c", "");
+ }
+
+ @GwtIncompatible("Splitter.onPattern")
+ public void testPatternSplitWithLeadingDelimiter() {
+ String leading = ",a,b,c";
+ Iterable<String> letters = Splitter.onPattern(",").split(leading);
+ assertContentsInOrder(letters, "", "a", "b", "c");
+ }
+
+ @GwtIncompatible("Splitter.onPattern")
+ public void testPatternSplitWithMultipleLetters() {
+ Iterable<String> testPatterningMotto = Splitter.onPattern("-").split(
+ "Testing-rocks-Debugging-sucks");
+ assertContentsInOrder(testPatterningMotto,
+ "Testing", "rocks", "Debugging", "sucks");
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ private static Pattern literalDotPattern() {
+ return Pattern.compile("\\.");
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitWithDoubleDelimiterOmitEmptyStrings() {
+ String doubled = "a..b.c";
+ Iterable<String> letters = Splitter.on(literalDotPattern())
+ .omitEmptyStrings().split(doubled);
+ assertContentsInOrder(letters, "a", "b", "c");
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitEmptyToken() {
+ String emptyToken = "a. .c";
+ Iterable<String> letters = Splitter.on(literalDotPattern()).trimResults()
+ .split(emptyToken);
+ assertContentsInOrder(letters, "a", "", "c");
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitEmptyTokenOmitEmptyStrings() {
+ String emptyToken = "a. .c";
+ Iterable<String> letters = Splitter.on(literalDotPattern())
+ .omitEmptyStrings().trimResults().split(emptyToken);
+ assertContentsInOrder(letters, "a", "c");
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitOnOnlyDelimiter() {
+ Iterable<String> blankblank = Splitter.on(literalDotPattern()).split(".");
+
+ assertContentsInOrder(blankblank, "", "");
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitOnOnlyDelimitersOmitEmptyStrings() {
+ Iterable<String> empty = Splitter.on(literalDotPattern()).omitEmptyStrings()
+ .split("...");
+ assertContentsInOrder(empty);
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitMatchingIsGreedy() {
+ String longDelimiter = "a, b, c";
+ Iterable<String> letters = Splitter.on(Pattern.compile(",\\s*"))
+ .split(longDelimiter);
+ assertContentsInOrder(letters, "a", "b", "c");
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitWithLongLeadingDelimiter() {
+ String longDelimiter = ", a, b, c";
+ Iterable<String> letters = Splitter.on(Pattern.compile(", "))
+ .split(longDelimiter);
+ assertContentsInOrder(letters, "", "a", "b", "c");
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitWithLongTrailingDelimiter() {
+ String longDelimiter = "a, b, c/ ";
+ Iterable<String> letters = Splitter.on(Pattern.compile("[,/]\\s"))
+ .split(longDelimiter);
+ assertContentsInOrder(letters, "a", "b", "c", "");
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitInvalidPattern() {
+ try {
+ Splitter.on(Pattern.compile("a*"));
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testPatternSplitWithTrim() {
+ String jacksons = "arfo(Marlon)aorf, (Michael)orfa, afro(Jackie)orfa, "
+ + "ofar(Jemaine), aff(Tito)";
+ Iterable<String> family = Splitter.on(Pattern.compile(","))
+ .trimResults(CharMatcher.anyOf("afro").or(CharMatcher.WHITESPACE))
+ .split(jacksons);
+ assertContentsInOrder(family,
+ "(Marlon)", "(Michael)", "(Jackie)", "(Jemaine)", "(Tito)");
+ }
+
+ public void testSplitterIterableIsUnmodifiable() {
+ assertIteratorIsUnmodifiable(Splitter.on(',').split("a,b").iterator());
+ assertIteratorIsUnmodifiable(Splitter.on(",").split("a,b").iterator());
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testSplitterIterableIsUnmodifiable_pattern() {
+ assertIteratorIsUnmodifiable(
+ Splitter.on(Pattern.compile(",")).split("a,b").iterator());
+ }
+
+ private void assertIteratorIsUnmodifiable(Iterator<?> iterator) {
+ iterator.next();
+ try {
+ iterator.remove();
+ fail();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ public void testSplitterIterableIsLazy() {
+ assertSplitterIterableIsLazy(Splitter.on(','));
+ assertSplitterIterableIsLazy(Splitter.on(","));
+ }
+
+ @GwtIncompatible("java.util.regex.Pattern")
+ public void testSplitterIterableIsLazy_pattern() {
+ assertSplitterIterableIsLazy(Splitter.on(Pattern.compile(",")));
+ }
+
+ /**
+ * This test really pushes the boundaries of what we support. In general the
+ * splitter's behaviour is not well defined if the char sequence it's
+ * splitting is mutated during iteration.
+ */
+ private void assertSplitterIterableIsLazy(Splitter splitter) {
+ StringBuilder builder = new StringBuilder();
+ Iterator<String> iterator = splitter.split(builder).iterator();
+
+ builder.append("A,");
+ assertEquals("A", iterator.next());
+ builder.append("B,");
+ assertEquals("B", iterator.next());
+ builder.append("C");
+ assertEquals("C", iterator.next());
+ assertFalse(iterator.hasNext());
+ }
+
+ public void testAtEachSimpleSplit() {
+ String simple = "abcde";
+ Iterable<String> letters = Splitter.fixedLength(2).split(simple);
+ assertContentsInOrder(letters, "ab", "cd", "e");
+ }
+
+ public void testAtEachSplitEqualChunkLength() {
+ String simple = "abcdef";
+ Iterable<String> letters = Splitter.fixedLength(2).split(simple);
+ assertContentsInOrder(letters, "ab", "cd", "ef");
+ }
+
+ public void testAtEachSplitOnlyOneChunk() {
+ String simple = "abc";
+ Iterable<String> letters = Splitter.fixedLength(3).split(simple);
+ assertContentsInOrder(letters, "abc");
+ }
+
+ public void testAtEachSplitSmallerString() {
+ String simple = "ab";
+ Iterable<String> letters = Splitter.fixedLength(3).split(simple);
+ assertContentsInOrder(letters, "ab");
+ }
+
+ public void testAtEachSplitEmptyString() {
+ String simple = "";
+ Iterable<String> letters = Splitter.fixedLength(3).split(simple);
+ assertContentsInOrder(letters, "");
+ }
+
+ public void testAtEachSplitEmptyStringWithOmitEmptyStrings() {
+ assertFalse(Splitter.fixedLength(3).omitEmptyStrings().split("").iterator()
+ .hasNext());
+ }
+
+ public void testAtEachSplitIntoChars() {
+ String simple = "abcd";
+ Iterable<String> letters = Splitter.fixedLength(1).split(simple);
+ assertContentsInOrder(letters, "a", "b", "c", "d");
+ }
+
+ public void testAtEachSplitZeroChunkLen() {
+ try {
+ Splitter.fixedLength(0);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testAtEachSplitNegativeChunkLen() {
+ try {
+ Splitter.fixedLength(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @GwtIncompatible("NullPointerTester")
+ public void testNullPointers() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ tester.testAllPublicStaticMethods(Splitter.class);
+ tester.testAllPublicInstanceMethods(Splitter.on(","));
+ tester.testAllPublicInstanceMethods(Splitter.on(",").trimResults());
+ }
+
+ // TODO: use common one when we settle where that is...
+ private void assertContentsInOrder(
+ Iterable<String> actual, String... expected) {
+ assertEquals(Arrays.asList(expected), Lists.newArrayList(actual));
+ }
+}
+
diff --git a/guava/test/com/google/common/base/StringsTest.java b/guava/test/com/google/common/base/StringsTest.java
new file mode 100644
index 0000000..f92814e
--- /dev/null
+++ b/guava/test/com/google/common/base/StringsTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 junit.framework.TestCase;
+
+/**
+ * Unit test for {@link Strings}.
+ *
+ * @author Kevin Bourrillion
+ */
+public class StringsTest extends TestCase {
+ public void testNullToEmpty() {
+ assertEquals("", Strings.nullToEmpty(null));
+ assertEquals("", Strings.nullToEmpty(""));
+ assertEquals("a", Strings.nullToEmpty("a"));
+ }
+
+ public void testEmptyToNull() {
+ assertNull(Strings.emptyToNull(null));
+ assertNull(Strings.emptyToNull(""));
+ assertEquals("a", Strings.emptyToNull("a"));
+ }
+
+ public void testIsNullOrEmpty() {
+ assertTrue(Strings.isNullOrEmpty(null));
+ assertTrue(Strings.isNullOrEmpty(""));
+ assertFalse(Strings.isNullOrEmpty("a"));
+ }
+
+ public void testPadStart_noPadding() {
+ assertSame("", Strings.padStart("", 0, '-'));
+ assertSame("x", Strings.padStart("x", 0, '-'));
+ assertSame("x", Strings.padStart("x", 1, '-'));
+ assertSame("xx", Strings.padStart("xx", 0, '-'));
+ assertSame("xx", Strings.padStart("xx", 2, '-'));
+ }
+
+ public void testPadStart_somePadding() {
+ assertEquals("-", Strings.padStart("", 1, '-'));
+ assertEquals("--", Strings.padStart("", 2, '-'));
+ assertEquals("-x", Strings.padStart("x", 2, '-'));
+ assertEquals("--x", Strings.padStart("x", 3, '-'));
+ assertEquals("-xx", Strings.padStart("xx", 3, '-'));
+ }
+
+ public void testPadStart_negativeMinLength() {
+ assertSame("x", Strings.padStart("x", -1, '-'));
+ }
+
+ // TODO: could remove if we got NPT working in GWT somehow
+ public void testPadStart_null() {
+ try {
+ Strings.padStart(null, 5, '0');
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testPadEnd_noPadding() {
+ assertSame("", Strings.padEnd("", 0, '-'));
+ assertSame("x", Strings.padEnd("x", 0, '-'));
+ assertSame("x", Strings.padEnd("x", 1, '-'));
+ assertSame("xx", Strings.padEnd("xx", 0, '-'));
+ assertSame("xx", Strings.padEnd("xx", 2, '-'));
+ }
+
+ public void testPadEnd_somePadding() {
+ assertEquals("-", Strings.padEnd("", 1, '-'));
+ assertEquals("--", Strings.padEnd("", 2, '-'));
+ assertEquals("x-", Strings.padEnd("x", 2, '-'));
+ assertEquals("x--", Strings.padEnd("x", 3, '-'));
+ assertEquals("xx-", Strings.padEnd("xx", 3, '-'));
+ }
+
+ public void testPadEnd_negativeMinLength() {
+ assertSame("x", Strings.padEnd("x", -1, '-'));
+ }
+
+ // TODO: could remove if we got NPT working in GWT somehow
+ public void testPadEnd_null() {
+ try {
+ Strings.padEnd(null, 5, '0');
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testRepeat() {
+ String input = "20";
+ assertEquals("", Strings.repeat(input, 0));
+ assertEquals("20", Strings.repeat(input, 1));
+ assertEquals("202020", Strings.repeat(input, 3));
+
+ assertEquals("", Strings.repeat("", 4));
+
+ try {
+ Strings.repeat("x", -1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ // TODO: could remove if we got NPT working in GWT somehow
+ public void testRepeat_null() {
+ try {
+ Strings.repeat(null, 5);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ // TODO: salvage the nullpointer testing in a gwt-safe way
+ // public void testNullPointers() throws Exception {
+ // NullPointerTester tester = new NullPointerTester();
+ // tester.testAllPublicStaticMethods(Strings.class);
+ // }
+}
diff --git a/guava/test/com/google/common/base/SuppliersTest.java b/guava/test/com/google/common/base/SuppliersTest.java
new file mode 100644
index 0000000..bf972c0
--- /dev/null
+++ b/guava/test/com/google/common/base/SuppliersTest.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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.testing.util.SerializableTester.reserialize;
+
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.collect.Lists;
+import com.google.testing.util.NullPointerTester;
+
+import junit.framework.TestCase;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests com.google.common.base.Suppliers.
+ *
+ * @author Laurence Gonsalves
+ * @author Harry Heymann
+ */
+@GwtCompatible(emulated = true)
+public class SuppliersTest extends TestCase {
+ public void testCompose() {
+ Supplier<Integer> fiveSupplier = new Supplier<Integer>() {
+ public Integer get() {
+ return 5;
+ }
+ };
+
+ Function<Number,Integer> intValueFunction =
+ new Function<Number,Integer>() {
+ public Integer apply(Number x) {
+ return x.intValue();
+ }
+ };
+
+ Supplier<Integer> squareSupplier = Suppliers.compose(intValueFunction,
+ fiveSupplier);
+
+ assertEquals(Integer.valueOf(5), squareSupplier.get());
+ }
+
+ public void testComposeWithLists() {
+ Supplier<ArrayList<Integer>> listSupplier
+ = new Supplier<ArrayList<Integer>>() {
+ public ArrayList<Integer> get() {
+ return Lists.newArrayList(0);
+ }
+ };
+
+ Function<List<Integer>, List<Integer>> addElementFunction =
+ new Function<List<Integer>, List<Integer>>() {
+ public List<Integer> apply(List<Integer> list) {
+ ArrayList<Integer> result = Lists.newArrayList(list);
+ result.add(1);
+ return result;
+ }
+ };
+
+ Supplier<List<Integer>> addSupplier = Suppliers.compose(addElementFunction,
+ listSupplier);
+
+ List<Integer> result = addSupplier.get();
+ assertEquals(Integer.valueOf(0), result.get(0));
+ assertEquals(Integer.valueOf(1), result.get(1));
+ }
+
+ static class CountingSupplier implements Supplier<Integer>, Serializable {
+ transient int calls = 0;
+ public Integer get() {
+ calls++;
+ return calls * 10;
+ }
+ }
+
+ public void testMemoize() {
+ CountingSupplier countingSupplier = new CountingSupplier();
+ Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
+ checkMemoize(countingSupplier, memoizedSupplier);
+ }
+
+ @GwtIncompatible("SerializableTester")
+ public void testMemoizeSerialized() {
+ CountingSupplier countingSupplier = new CountingSupplier();
+ Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
+ checkMemoize(countingSupplier, memoizedSupplier);
+ // Calls to the original memoized supplier shouldn't affect its copy.
+ memoizedSupplier.get();
+
+ Supplier<Integer> copy = reserialize(memoizedSupplier);
+ memoizedSupplier.get();
+
+ CountingSupplier countingCopy = (CountingSupplier)
+ ((Suppliers.MemoizingSupplier<Integer>) copy).delegate;
+ checkMemoize(countingCopy, copy);
+ }
+
+ private void checkMemoize(
+ CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier) {
+ // the underlying supplier hasn't executed yet
+ assertEquals(0, countingSupplier.calls);
+
+ assertEquals(10, (int) memoizedSupplier.get());
+
+ // now it has
+ assertEquals(1, countingSupplier.calls);
+
+ assertEquals(10, (int) memoizedSupplier.get());
+
+ // it still should only have executed once due to memoization
+ assertEquals(1, countingSupplier.calls);
+ }
+
+ public void testMemoizeExceptionThrown() {
+ Supplier<Integer> exceptingSupplier = new Supplier<Integer>() {
+ public Integer get() {
+ throw new NullPointerException();
+ }
+ };
+
+ Supplier<Integer> memoizedSupplier = Suppliers.memoize(exceptingSupplier);
+
+ // call get() twice to make sure that memoization doesn't interfere
+ // with throwing the exception
+ for (int i = 0; i < 2; i++) {
+ try {
+ memoizedSupplier.get();
+ fail("failed to throw NullPointerException");
+ } catch (NullPointerException e) {
+ // this is what should happen
+ }
+ }
+ }
+
+ @GwtIncompatible("Thread.sleep")
+ public void testMemoizeWithExpiration() throws InterruptedException {
+ CountingSupplier countingSupplier = new CountingSupplier();
+
+ Supplier<Integer> memoizedSupplier = Suppliers.memoizeWithExpiration(
+ countingSupplier, 75, TimeUnit.MILLISECONDS);
+
+ checkExpiration(countingSupplier, memoizedSupplier);
+ }
+
+ @GwtIncompatible("Thread.sleep, SerializationTester")
+ public void testMemoizeWithExpirationSerialized()
+ throws InterruptedException {
+ CountingSupplier countingSupplier = new CountingSupplier();
+
+ Supplier<Integer> memoizedSupplier = Suppliers.memoizeWithExpiration(
+ countingSupplier, 75, TimeUnit.MILLISECONDS);
+ // Calls to the original memoized supplier shouldn't affect its copy.
+ memoizedSupplier.get();
+
+ Supplier<Integer> copy = reserialize(memoizedSupplier);
+ memoizedSupplier.get();
+
+ CountingSupplier countingCopy = (CountingSupplier)
+ ((Suppliers.ExpiringMemoizingSupplier<Integer>) copy).delegate;
+ checkExpiration(countingCopy, copy);
+ }
+
+ @GwtIncompatible("Thread.sleep")
+ private void checkExpiration(
+ CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)
+ throws InterruptedException {
+ // the underlying supplier hasn't executed yet
+ assertEquals(0, countingSupplier.calls);
+
+ assertEquals(10, (int) memoizedSupplier.get());
+ // now it has
+ assertEquals(1, countingSupplier.calls);
+
+ assertEquals(10, (int) memoizedSupplier.get());
+ // it still should only have executed once due to memoization
+ assertEquals(1, countingSupplier.calls);
+
+ Thread.sleep(150);
+
+ assertEquals(20, (int) memoizedSupplier.get());
+ // old value expired
+ assertEquals(2, countingSupplier.calls);
+
+ assertEquals(20, (int) memoizedSupplier.get());
+ // it still should only have executed twice due to memoization
+ assertEquals(2, countingSupplier.calls);
+ }
+
+ public void testOfInstanceSuppliesSameInstance() {
+ Object toBeSupplied = new Object();
+ Supplier<Object> objectSupplier = Suppliers.ofInstance(toBeSupplied);
+ assertSame(toBeSupplied,objectSupplier.get());
+ assertSame(toBeSupplied,objectSupplier.get()); // idempotent
+ }
+
+ public void testOfInstanceSuppliesNull() {
+ Supplier<Integer> nullSupplier = Suppliers.ofInstance(null);
+ assertNull(nullSupplier.get());
+ }
+
+ @GwtIncompatible("Thread")
+ public void testThreadSafe() throws InterruptedException {
+ final Supplier<Integer> nonThreadSafe = new Supplier<Integer>() {
+ int counter = 0;
+ public Integer get() {
+ int nextValue = counter + 1;
+ Thread.yield();
+ counter = nextValue;
+ return counter;
+ }
+ };
+
+ final int numThreads = 10;
+ final int iterations = 1000;
+ Thread[] threads = new Thread[numThreads];
+ for (int i = 0; i < numThreads; i++) {
+ threads[i] = new Thread() {
+ @Override
+ public void run() {
+ for (int j = 0; j < iterations; j++) {
+ Suppliers.synchronizedSupplier(nonThreadSafe).get();
+ }
+ }
+ };
+ }
+ for (Thread t : threads) {
+ t.start();
+ }
+ for (Thread t : threads) {
+ t.join();
+ }
+
+ assertEquals(new Integer(numThreads * iterations + 1), nonThreadSafe.get());
+ }
+
+ @GwtIncompatible("SerializationTester")
+ public void testSerialization() {
+ assertEquals(
+ Integer.valueOf(5), reserialize(Suppliers.ofInstance(5)).get());
+ assertEquals(Integer.valueOf(5), reserialize(Suppliers.compose(
+ Functions.identity(), Suppliers.ofInstance(5))).get());
+ assertEquals(Integer.valueOf(5),
+ reserialize(Suppliers.memoize(Suppliers.ofInstance(5))).get());
+ assertEquals(Integer.valueOf(5),
+ reserialize(Suppliers.memoizeWithExpiration(
+ Suppliers.ofInstance(5), 30, TimeUnit.MINUTES)).get());
+ assertEquals(Integer.valueOf(5), reserialize(
+ Suppliers.synchronizedSupplier(Suppliers.ofInstance(5))).get());
+ }
+
+ @GwtIncompatible("NullPointerTest")
+ public void testNullPointers() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ tester.testAllPublicStaticMethods(Suppliers.class);
+ }
+}
diff --git a/guava/test/com/google/common/base/ThrowablesTest.java b/guava/test/com/google/common/base/ThrowablesTest.java
new file mode 100644
index 0000000..e35cfd0
--- /dev/null
+++ b/guava/test/com/google/common/base/ThrowablesTest.java
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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.Throwables.getStackTraceAsString;
+import static java.util.Arrays.asList;
+import static java.util.regex.Pattern.quote;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.ObjectArrays;
+import com.google.testing.util.NullPointerTester;
+
+import junit.framework.TestCase;
+
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit test for {@link Throwables}.
+ *
+ * @author Kevin Bourrillion
+ */
+@SuppressWarnings("serial") // this warning is silly for exceptions in tests
+public class ThrowablesTest extends TestCase {
+ public void testPropagateIfPossible_NoneDeclared_NoneThrown() {
+ Sample sample = new Sample() {
+ @Override public void noneDeclared() {
+ try {
+ methodThatDoesntThrowAnything();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect no exception to be thrown
+ sample.noneDeclared();
+ }
+
+ public void testPropagateIfPossible_NoneDeclared_UncheckedThrown() {
+ Sample sample = new Sample() {
+ @Override public void noneDeclared() {
+ try {
+ methodThatThrowsUnchecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect the unchecked exception to propagate as-is
+ try {
+ sample.noneDeclared();
+ fail();
+ } catch (SomeUncheckedException expected) {
+ }
+ }
+
+ public void testPropagateIfPossible_NoneDeclared_UndeclaredThrown() {
+ Sample sample = new Sample() {
+ @Override public void noneDeclared() {
+ try {
+ methodThatThrowsUndeclaredChecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect the undeclared exception to have been chained inside another
+ try {
+ sample.noneDeclared();
+ fail();
+ } catch (SomeChainingException expected) {
+ }
+ }
+
+ public void testPropagateIfPossible_OneDeclared_NoneThrown()
+ throws SomeCheckedException {
+ Sample sample = new Sample() {
+ @Override public void oneDeclared() throws SomeCheckedException {
+ try {
+ methodThatDoesntThrowAnything();
+ } catch (Throwable t) {
+ // yes, this block is never reached, but for purposes of illustration
+ // we're keeping it the same in each test
+ Throwables.propagateIfPossible(t, SomeCheckedException.class);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect no exception to be thrown
+ sample.oneDeclared();
+ }
+
+ public void testPropagateIfPossible_OneDeclared_UncheckedThrown()
+ throws SomeCheckedException {
+ Sample sample = new Sample() {
+ @Override public void oneDeclared() throws SomeCheckedException {
+ try {
+ methodThatThrowsUnchecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t, SomeCheckedException.class);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect the unchecked exception to propagate as-is
+ try {
+ sample.oneDeclared();
+ fail();
+ } catch (SomeUncheckedException expected) {
+ }
+ }
+
+ public void testPropagateIfPossible_OneDeclared_CheckedThrown() {
+ Sample sample = new Sample() {
+ @Override public void oneDeclared() throws SomeCheckedException {
+ try {
+ methodThatThrowsChecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t, SomeCheckedException.class);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect the checked exception to propagate as-is
+ try {
+ sample.oneDeclared();
+ fail();
+ } catch (SomeCheckedException expected) {
+ }
+ }
+
+ public void testPropagateIfPossible_OneDeclared_UndeclaredThrown()
+ throws SomeCheckedException {
+ Sample sample = new Sample() {
+ @Override public void oneDeclared() throws SomeCheckedException {
+ try {
+ methodThatThrowsUndeclaredChecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t, SomeCheckedException.class);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect the undeclared exception to have been chained inside another
+ try {
+ sample.oneDeclared();
+ fail();
+ } catch (SomeChainingException expected) {
+ }
+ }
+
+ public void testPropagateIfPossible_TwoDeclared_NoneThrown()
+ throws SomeCheckedException, SomeOtherCheckedException {
+ Sample sample = new Sample() {
+ @Override public void twoDeclared() throws SomeCheckedException,
+ SomeOtherCheckedException {
+ try {
+ methodThatDoesntThrowAnything();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t, SomeCheckedException.class,
+ SomeOtherCheckedException.class);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect no exception to be thrown
+ sample.twoDeclared();
+ }
+
+ public void testPropagateIfPossible_TwoDeclared_UncheckedThrown()
+ throws SomeCheckedException, SomeOtherCheckedException {
+ Sample sample = new Sample() {
+ @Override public void twoDeclared() throws SomeCheckedException,
+ SomeOtherCheckedException {
+ try {
+ methodThatThrowsUnchecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t, SomeCheckedException.class,
+ SomeOtherCheckedException.class);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect the unchecked exception to propagate as-is
+ try {
+ sample.twoDeclared();
+ fail();
+ } catch (SomeUncheckedException expected) {
+ }
+ }
+
+ public void testPropagateIfPossible_TwoDeclared_CheckedThrown()
+ throws SomeOtherCheckedException {
+ Sample sample = new Sample() {
+ @Override public void twoDeclared() throws SomeCheckedException,
+ SomeOtherCheckedException {
+ try {
+ methodThatThrowsChecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t, SomeCheckedException.class,
+ SomeOtherCheckedException.class);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect the checked exception to propagate as-is
+ try {
+ sample.twoDeclared();
+ fail();
+ } catch (SomeCheckedException expected) {
+ }
+ }
+
+ public void testPropagateIfPossible_TwoDeclared_OtherCheckedThrown()
+ throws SomeCheckedException {
+ Sample sample = new Sample() {
+ @Override public void twoDeclared() throws SomeCheckedException,
+ SomeOtherCheckedException {
+ try {
+ methodThatThrowsOtherChecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfPossible(t, SomeCheckedException.class,
+ SomeOtherCheckedException.class);
+ throw new SomeChainingException(t);
+ }
+ }
+ };
+
+ // Expect the checked exception to propagate as-is
+ try {
+ sample.twoDeclared();
+ fail();
+ } catch (SomeOtherCheckedException expected) {
+ }
+ }
+
+ public void testPropageIfPossible_null() throws SomeCheckedException {
+ Throwables.propagateIfPossible(null);
+ Throwables.propagateIfPossible(null, SomeCheckedException.class);
+ Throwables.propagateIfPossible(null, SomeCheckedException.class,
+ SomeUncheckedException.class);
+ }
+
+ public void testPropagate_NoneDeclared_NoneThrown() {
+ Sample sample = new Sample() {
+ @Override public void noneDeclared() {
+ try {
+ methodThatDoesntThrowAnything();
+ } catch (Throwable t) {
+ throw Throwables.propagate(t);
+ }
+ }
+ };
+
+ // Expect no exception to be thrown
+ sample.noneDeclared();
+ }
+
+ public void testPropagate_NoneDeclared_UncheckedThrown() {
+ Sample sample = new Sample() {
+ @Override public void noneDeclared() {
+ try {
+ methodThatThrowsUnchecked();
+ } catch (Throwable t) {
+ throw Throwables.propagate(t);
+ }
+ }
+ };
+
+ // Expect the unchecked exception to propagate as-is
+ try {
+ sample.noneDeclared();
+ fail();
+ } catch (SomeUncheckedException expected) {
+ }
+ }
+
+ public void testPropagate_NoneDeclared_ErrorThrown() {
+ Sample sample = new Sample() {
+ @Override public void noneDeclared() {
+ try {
+ methodThatThrowsError();
+ } catch (Throwable t) {
+ throw Throwables.propagate(t);
+ }
+ }
+ };
+
+ // Expect the error to propagate as-is
+ try {
+ sample.noneDeclared();
+ fail();
+ } catch (SomeError expected) {
+ }
+ }
+
+ public void testPropagate_NoneDeclared_CheckedThrown() {
+ Sample sample = new Sample() {
+ @Override public void noneDeclared() {
+ try {
+ methodThatThrowsChecked();
+ } catch (Throwable t) {
+ throw Throwables.propagate(t);
+ }
+ }
+ };
+
+ // Expect the undeclared exception to have been chained inside another
+ try {
+ sample.noneDeclared();
+ fail();
+ } catch (RuntimeException expected) {
+ assertTrue(expected.getCause() instanceof SomeCheckedException);
+ }
+ }
+
+ public void testPropagateIfInstanceOf_NoneThrown()
+ throws SomeCheckedException {
+ Sample sample = new Sample() {
+ @Override public void oneDeclared() throws SomeCheckedException {
+ try {
+ methodThatDoesntThrowAnything();
+ } catch (Throwable t) {
+ Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
+ throw Throwables.propagate(t);
+ }
+ }
+ };
+
+ // Expect no exception to be thrown
+ sample.oneDeclared();
+ }
+
+ public void testPropagateIfInstanceOf_DeclaredThrown() {
+ Sample sample = new Sample() {
+ @Override public void oneDeclared() throws SomeCheckedException {
+ try {
+ methodThatThrowsChecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
+ throw Throwables.propagate(t);
+ }
+ }
+ };
+
+ // Expect declared exception to be thrown as-is
+ try {
+ sample.oneDeclared();
+ fail();
+ } catch (SomeCheckedException e) {
+ }
+ }
+
+ public void testPropagateIfInstanceOf_UncheckedThrown()
+ throws SomeCheckedException {
+ Sample sample = new Sample() {
+ @Override public void oneDeclared() throws SomeCheckedException {
+ try {
+ methodThatThrowsUnchecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
+ throw Throwables.propagate(t);
+ }
+ }
+ };
+
+ // Expect unchecked exception to be thrown as-is
+ try {
+ sample.oneDeclared();
+ fail();
+ } catch (SomeUncheckedException e) {
+ }
+ }
+
+ public void testPropagateIfInstanceOf_UndeclaredThrown()
+ throws SomeCheckedException {
+ Sample sample = new Sample() {
+ @Override public void oneDeclared() throws SomeCheckedException {
+ try {
+ methodThatThrowsOtherChecked();
+ } catch (Throwable t) {
+ Throwables.propagateIfInstanceOf(t, SomeCheckedException.class);
+ throw Throwables.propagate(t);
+ }
+ }
+ };
+
+ // Expect undeclared exception wrapped by RuntimeException to be thrown
+ try {
+ sample.oneDeclared();
+ fail();
+ } catch (RuntimeException e) {
+ assertTrue(e.getCause() instanceof SomeOtherCheckedException);
+ }
+ }
+
+ public void testPropageIfInstanceOf_null() throws SomeCheckedException {
+ Throwables.propagateIfInstanceOf(null, SomeCheckedException.class);
+ }
+
+ public void testGetRootCause_NoCause() {
+ SomeCheckedException exception = new SomeCheckedException();
+ assertSame(exception, Throwables.getRootCause(exception));
+ }
+
+ public void testGetRootCause_SingleWrapped() {
+ SomeCheckedException cause = new SomeCheckedException();
+ SomeChainingException exception = new SomeChainingException(cause);
+ assertSame(cause, Throwables.getRootCause(exception));
+ }
+
+ public void testGetRootCause_DoubleWrapped() {
+ SomeCheckedException cause = new SomeCheckedException();
+ SomeChainingException exception =
+ new SomeChainingException(new SomeChainingException(cause));
+ assertSame(cause, Throwables.getRootCause(exception));
+ }
+
+ private static class SomeThrowable extends Throwable {}
+ private static class SomeError extends Error {}
+ private static class SomeCheckedException extends Exception {}
+ private static class SomeOtherCheckedException extends Exception {}
+ private static class SomeUncheckedException extends RuntimeException {}
+ private static class SomeUndeclaredCheckedException extends Exception {}
+ private static class SomeChainingException extends RuntimeException {
+ public SomeChainingException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+ static class Sample {
+ void noneDeclared() {}
+ /*
+ * Subclasses of Sample will define methods with these signatures that throw
+ * these exceptions, so we must declare them in the throws clause here.
+ * Eclipse doesn't think being thrown from a subclass's non-public,
+ * non-protected method with the same signature counts as being "used."
+ */
+ @SuppressWarnings("unused")
+ void oneDeclared() throws SomeCheckedException {}
+ @SuppressWarnings("unused")
+ void twoDeclared() throws SomeCheckedException, SomeOtherCheckedException {}
+ }
+
+ static void methodThatDoesntThrowAnything() {}
+ static void methodThatThrowsError() {
+ throw new SomeError();
+ }
+ static void methodThatThrowsUnchecked() {
+ throw new SomeUncheckedException();
+ }
+ static void methodThatThrowsChecked() throws SomeCheckedException {
+ throw new SomeCheckedException();
+ }
+ static void methodThatThrowsOtherChecked() throws SomeOtherCheckedException {
+ throw new SomeOtherCheckedException();
+ }
+ static void methodThatThrowsUndeclaredChecked()
+ throws SomeUndeclaredCheckedException {
+ throw new SomeUndeclaredCheckedException();
+ }
+
+ public void testGetStackTraceAsString() {
+ class StackTraceException extends Exception {
+ StackTraceException(String message) {
+ super(message);
+ }
+ }
+
+ StackTraceException e = new StackTraceException("my message");
+
+ String firstLine = quote(e.getClass().getName() + ": " + e.getMessage());
+ String secondLine = "\\s*at " + ThrowablesTest.class.getName() + "\\..*";
+ String moreLines = "(?:.*\n?)*";
+ String expected = firstLine + "\n" + secondLine + "\n" + moreLines;
+ assertTrue(getStackTraceAsString(e).matches(expected));
+ }
+
+ public void testThrowCause_NoCombine() {
+ SomeCheckedException cause = new SomeCheckedException();
+ SomeChainingException outer = new SomeChainingException(cause);
+ StackTraceElement[] expectedTrace = cause.getStackTrace();
+ try {
+ Throwables.throwCause(outer, false);
+ fail("Exception not thrown properly");
+ } catch (Exception e) {
+ assertSame(e, cause);
+ assertTrue(Arrays.equals(expectedTrace, e.getStackTrace()));
+ }
+ }
+
+ public void testThrowCause_Combine() {
+ SomeCheckedException cause = new SomeCheckedException();
+ SomeChainingException outer = new SomeChainingException(cause);
+ StackTraceElement[] expectedTrace =
+ ObjectArrays.concat(cause.getStackTrace(), outer.getStackTrace(), StackTraceElement.class);
+ try {
+ Throwables.throwCause(outer, true);
+ fail("Exception not thrown properly");
+ } catch (Exception e) {
+ assertSame(e, cause);
+ assertTrue(Arrays.equals(expectedTrace, e.getStackTrace()));
+ }
+ }
+
+ public void testThrowCause_Null() {
+ SomeCheckedException outer = new SomeCheckedException();
+ StackTraceElement[] expectedTrace = outer.getStackTrace();
+ try {
+ Throwables.throwCause(outer, true);
+ fail("Exception not thrown properly");
+ } catch (Exception e) {
+ assertSame(e, outer);
+ assertTrue(Arrays.equals(expectedTrace, e.getStackTrace()));
+ }
+ }
+
+ public void testThrowCause_Error() throws Exception {
+ SomeError cause = new SomeError();
+ SomeChainingException outer = new SomeChainingException(cause);
+ StackTraceElement[] expectedTrace =
+ ObjectArrays.concat(cause.getStackTrace(), outer.getStackTrace(), StackTraceElement.class);
+ try {
+ Throwables.throwCause(outer, true);
+ fail("Exception not thrown properly");
+ } catch (Error e) {
+ assertSame(e, cause);
+ assertTrue(Arrays.equals(expectedTrace, e.getStackTrace()));
+ }
+ }
+
+ public void testThrowCause_Throwable() {
+ SomeThrowable cause = new SomeThrowable();
+ SomeChainingException outer = new SomeChainingException(cause);
+ StackTraceElement[] expectedTrace = outer.getStackTrace();
+ try {
+ Throwables.throwCause(outer, true);
+ fail("Exception not thrown properly");
+ } catch (Throwable e) {
+ assertSame(e, outer);
+ assertTrue(Arrays.equals(expectedTrace, e.getStackTrace()));
+ }
+ }
+
+ public void testGetCausalChain() {
+ FileNotFoundException fnfe = new FileNotFoundException();
+ IllegalArgumentException iae = new IllegalArgumentException(fnfe);
+ RuntimeException re = new RuntimeException(iae);
+ IllegalStateException ex = new IllegalStateException(re);
+
+ assertEquals(asList(ex, re, iae, fnfe), Throwables.getCausalChain(ex));
+ assertSame(fnfe, Iterables.getOnlyElement(Throwables.getCausalChain(fnfe)));
+ try {
+ Throwables.getCausalChain(null);
+ fail("Should have throw NPE");
+ } catch (NullPointerException expected) {
+ }
+
+ List<Throwable> causes = Throwables.getCausalChain(ex);
+ try {
+ causes.add(new RuntimeException());
+ fail("List should be unmodifiable");
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ public void testNullPointers() throws Exception {
+ NullPointerTester tester = new NullPointerTester();
+ tester.setDefault(Throwable.class, new SomeCheckedException());
+ tester.setDefault(Class.class, SomeCheckedException.class);
+ tester.testAllPublicStaticMethods(Throwables.class);
+ }
+}
diff --git a/guava/test/com/google/common/base/ToStringHelperTest.java b/guava/test/com/google/common/base/ToStringHelperTest.java
new file mode 100644
index 0000000..7149938
--- /dev/null
+++ b/guava/test/com/google/common/base/ToStringHelperTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ * 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.collect.ImmutableMap;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Tests for {@link Objects#toStringHelper(Object)}.
+ *
+ * @author Jason Lee
+ */
+public class ToStringHelperTest extends TestCase {
+
+ public void testConstructor_instance() {
+ String toTest = Objects.toStringHelper(this).toString();
+ assertEquals("ToStringHelperTest{}", toTest);
+ }
+
+ public void testConstructor_innerClass() {
+ String toTest = Objects.toStringHelper(new TestClass()).toString();
+ assertEquals("TestClass{}", toTest);
+ }
+
+ public void testConstructor_anonymousClass() {
+ String toTest = Objects.toStringHelper(new Object() {}).toString();
+ assertTrue(toTest.matches("[0-9]+\\{\\}"));
+ }
+
+ // all remaining test are on an inner class with various fields
+ public void testToString_oneField() {
+ String toTest = Objects.toStringHelper(new TestClass())
+ .add("field1", "Hello")
+ .toString();
+ assertEquals("TestClass{field1=Hello}", toTest);
+ }
+
+ public void testToString_complexFields() {
+
+ Map<String, Integer> map = ImmutableMap.<String, Integer>builder()
+ .put("abc", 1)
+ .put("def", 2)
+ .put("ghi", 3)
+ .build();
+ String toTest = Objects.toStringHelper(new TestClass())
+ .add("field1", "This is string.")
+ .add("field2", Arrays.asList("abc", "def", "ghi"))
+ .add("field3", map)
+ .toString();
+ final String expected = "TestClass{"
+ + "field1=This is string., field2=[abc, def, ghi], field3={abc=1, def=2, ghi=3}}";
+
+ assertEquals(expected, toTest);
+ }
+
+ public void testToString_addWithNullName() {
+ Objects.ToStringHelper helper = Objects.toStringHelper(new TestClass());
+ try {
+ helper.add(null, "Hello");
+ fail("No exception was thrown.");
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testToString_addWithNullValue() {
+ final String result = Objects.toStringHelper(new TestClass())
+ .add("Hello", null)
+ .toString();
+
+ assertEquals("TestClass{Hello=null}", result);
+ }
+
+ public void testToString_addValue() {
+ String toTest = Objects.toStringHelper(new TestClass())
+ .add("field1", 1)
+ .addValue("value1")
+ .add("field2", "value2")
+ .addValue(2)
+ .toString();
+ final String expected = "TestClass{field1=1, value1, field2=value2, 2}";
+
+ assertEquals(expected, toTest);
+ }
+
+ public void testToString_addValueWithNullValue() {
+ final String result = Objects.toStringHelper(new TestClass())
+ .addValue(null)
+ .addValue("Hello")
+ .addValue(null)
+ .toString();
+ final String expected = "TestClass{null, Hello, null}";
+
+ assertEquals(expected, result);
+ }
+
+ /**
+ * Test class for testing formatting of inner classes.
+ */
+ private static class TestClass {}
+
+}