aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorszarnekow2009-04-01 09:50:52 (EDT)
committersefftinge2009-04-01 09:50:52 (EDT)
commit91b8c1febce4eb39febd02563837e406e38fc7fd (patch)
tree4eabfdd7edf67dd314a76c0379b4a9cd3039b825
parentbcc5ee7c8916a5e9f10ab2ebaed945e20a75b4a2 (diff)
downloadorg.eclipse.xtext-91b8c1febce4eb39febd02563837e406e38fc7fd.zip
org.eclipse.xtext-91b8c1febce4eb39febd02563837e406e38fc7fd.tar.gz
org.eclipse.xtext-91b8c1febce4eb39febd02563837e406e38fc7fd.tar.bz2
google collections - initial commit
-rw-r--r--plugins/com.google.collect/.classpath7
-rw-r--r--plugins/com.google.collect/.project28
-rw-r--r--plugins/com.google.collect/META-INF/MANIFEST.MF9
-rw-r--r--plugins/com.google.collect/build.properties5
-rwxr-xr-xplugins/com.google.collect/plugin.properties3
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/FinalizablePhantomReference.java35
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/FinalizableReference.java32
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/FinalizableReferenceQueue.java70
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/FinalizableSoftReference.java34
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/FinalizableWeakReference.java34
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Function.java62
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Functions.java349
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Join.java335
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Nullable.java35
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Objects.java78
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Preconditions.java358
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Predicate.java58
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Predicates.java517
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/ReferenceType.java55
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Supplier.java34
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/Suppliers.java131
-rw-r--r--plugins/com.google.collect/src/com/google/common/base/package-info.java20
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/AbstractIterable.java36
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/AbstractIterator.java168
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/AbstractMapBasedMultiset.java381
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/AbstractMapEntry.java77
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/AbstractMultiset.java406
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/AbstractMultisetEntry.java66
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/AbstractRemovableIterator.java56
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ArrayListMultimap.java129
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/BiMap.java97
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ClassToInstanceMap.java55
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Collections2.java300
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Comparators.java896
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ConcurrentMultiset.java455
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Constraint.java60
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Constraints.java366
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/EnumBiMap.java117
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/EnumHashBiMap.java103
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/EnumMultiset.java90
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingCollection.java101
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingConcurrentMap.java51
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingIterator.java46
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingList.java87
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingListIterator.java58
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingMap.java145
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingMapEntry.java54
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingMultimap.java119
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingMultiset.java66
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingObject.java72
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingQueue.java54
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingSet.java42
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingSortedMap.java59
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ForwardingSortedSet.java59
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/HashBiMap.java91
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/HashMultimap.java91
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/HashMultiset.java107
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Hashing.java56
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ImmutableBiMap.java320
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ImmutableCollection.java232
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ImmutableList.java559
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ImmutableMap.java772
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ImmutableMultimap.java591
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ImmutableMultiset.java360
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ImmutableSet.java529
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ImmutableSortedSet.java832
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Iterables.java798
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Iterators.java950
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/LinkedHashMultimap.java326
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/LinkedHashMultiset.java86
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ListMultimap.java79
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Lists.java490
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/MapConstraint.java58
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/MapConstraints.java752
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Maps.java597
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Multimap.java259
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Multimaps.java1400
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Multiset.java435
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Multisets.java465
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/NpeThrowingAbstractMap.java86
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ObjectArrays.java149
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Ordering.java296
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/PeekingIterator.java47
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/PrimitiveArrays.java657
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/ReferenceMap.java705
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Serialization.java169
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/SetMultimap.java91
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Sets.java934
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/SortedSetMultimap.java97
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/StandardBiMap.java384
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/StandardListMultimap.java81
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/StandardMultimap.java1442
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/StandardSetMultimap.java90
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/StandardSortedSetMultimap.java69
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/Synchronized.java1366
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/TreeMultimap.java192
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/TreeMultiset.java182
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/UnmodifiableIterator.java36
-rw-r--r--plugins/com.google.collect/src/com/google/common/collect/package-info.java191
99 files changed, 25659 insertions, 0 deletions
diff --git a/plugins/com.google.collect/.classpath b/plugins/com.google.collect/.classpath
new file mode 100644
index 0000000..304e861
--- /dev/null
+++ b/plugins/com.google.collect/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/com.google.collect/.project b/plugins/com.google.collect/.project
new file mode 100644
index 0000000..9ddfd46
--- /dev/null
+++ b/plugins/com.google.collect/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>com.google.collect</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/com.google.collect/META-INF/MANIFEST.MF b/plugins/com.google.collect/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..e437507
--- /dev/null
+++ b/plugins/com.google.collect/META-INF/MANIFEST.MF
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %bundleName
+Bundle-SymbolicName: com.google.collect
+Bundle-Version: 0.8.0.qualifier
+Bundle-Vendor: %bundleVendor
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Export-Package: com.google.common.base,
+ com.google.common.collect
diff --git a/plugins/com.google.collect/build.properties b/plugins/com.google.collect/build.properties
new file mode 100644
index 0000000..303135f
--- /dev/null
+++ b/plugins/com.google.collect/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.properties \ No newline at end of file
diff --git a/plugins/com.google.collect/plugin.properties b/plugins/com.google.collect/plugin.properties
new file mode 100755
index 0000000..9d226fb
--- /dev/null
+++ b/plugins/com.google.collect/plugin.properties
@@ -0,0 +1,3 @@
+#Properties file for com.google.collection
+bundleVendor = google.com
+bundleName = Google Collections \ No newline at end of file
diff --git a/plugins/com.google.collect/src/com/google/common/base/FinalizablePhantomReference.java b/plugins/com.google.collect/src/com/google/common/base/FinalizablePhantomReference.java
new file mode 100644
index 0000000..bed130a
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/FinalizablePhantomReference.java
@@ -0,0 +1,35 @@
+/*
+ * 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 java.lang.ref.PhantomReference;
+
+/**
+ * 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
+ * java.lang.ref.ReferenceQueue}.
+ *
+ * @author Bob Lee
+ */
+public abstract class FinalizablePhantomReference<T>
+ extends PhantomReference<T> implements FinalizableReference {
+
+ protected FinalizablePhantomReference(T referent) {
+ super(referent, FinalizableReferenceQueue.getInstance());
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/FinalizableReference.java b/plugins/com.google.collect/src/com/google/common/base/FinalizableReference.java
new file mode 100644
index 0000000..7fc443e
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/FinalizableReference.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * Package-private interface implemented by references that have code to run
+ * after garbage collection of their referents.
+ *
+ * @author Bob Lee
+ */
+interface FinalizableReference {
+
+ /**
+ * Invoked on a background thread after the referent has been garbage
+ * collected.
+ */
+ void finalizeReferent();
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/FinalizableReferenceQueue.java b/plugins/com.google.collect/src/com/google/common/base/FinalizableReferenceQueue.java
new file mode 100644
index 0000000..d34990d
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/FinalizableReferenceQueue.java
@@ -0,0 +1,70 @@
+/*
+ * 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 java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Starts a background thread that cleans up after reclaimed referents.
+ *
+ * @author Bob Lee
+ */
+class FinalizableReferenceQueue extends ReferenceQueue<Object> {
+
+ private static final Logger logger =
+ Logger.getLogger(FinalizableReferenceQueue.class.getName());
+
+ /**
+ * Returns the singleton instance.
+ */
+ public static ReferenceQueue<Object> getInstance() {
+ return LazyInstanceHolder.queue;
+ }
+
+ private static class LazyInstanceHolder {
+ static final ReferenceQueue<Object> queue = new FinalizableReferenceQueue();
+ }
+
+ private FinalizableReferenceQueue() {
+ start();
+ }
+
+ void start() {
+ Thread thread = new Thread(getClass().getSimpleName()) {
+ @Override public void run() {
+ while (true) {
+ try {
+ cleanUp(remove());
+ } catch (InterruptedException e) { /* ignore */ }
+ }
+ }
+ };
+ thread.setDaemon(true);
+ thread.start();
+ }
+
+ void cleanUp(Reference<?> reference) {
+ try {
+ ((FinalizableReference) reference).finalizeReferent();
+ } catch (Throwable t) {
+ logger.log(Level.SEVERE, "Error cleaning up after reference.", t);
+ }
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/FinalizableSoftReference.java b/plugins/com.google.collect/src/com/google/common/base/FinalizableSoftReference.java
new file mode 100644
index 0000000..1d95523
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/FinalizableSoftReference.java
@@ -0,0 +1,34 @@
+/*
+ * 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 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 java.lang.ref.ReferenceQueue}.
+ *
+ * @author Bob Lee
+ */
+public abstract class FinalizableSoftReference<T> extends SoftReference<T>
+ implements FinalizableReference {
+
+ protected FinalizableSoftReference(T referent) {
+ super(referent, FinalizableReferenceQueue.getInstance());
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/FinalizableWeakReference.java b/plugins/com.google.collect/src/com/google/common/base/FinalizableWeakReference.java
new file mode 100644
index 0000000..413a865
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/FinalizableWeakReference.java
@@ -0,0 +1,34 @@
+/*
+ * 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 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 java.lang.ref.ReferenceQueue}.
+ *
+ * @author Bob Lee
+ */
+public abstract class FinalizableWeakReference<T> extends WeakReference<T>
+ implements FinalizableReference {
+
+ protected FinalizableWeakReference(T referent) {
+ super(referent, FinalizableReferenceQueue.getInstance());
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/Function.java b/plugins/com.google.collect/src/com/google/common/base/Function.java
new file mode 100644
index 0000000..5c95c4f
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Function.java
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+/**
+ * A transformation from one object to another. For example, a
+ * {@code StringToIntegerFunction} may implement
+ * <code>Function&lt;String,Integer&gt;</code> and transform integers in
+ * {@code String} format to {@code Integer} format.
+ *
+ * <p>The transformation on the source object does not necessarily result in
+ * an object of a different type. For example, a
+ * {@code FarenheitToCelsiusFunction} may implement
+ * <code>Function&lt;Float,Float&gt;</code>.
+ *
+ * <p>Implementations which may cause side effects upon evaluation are strongly
+ * encouraged to state this fact clearly in their API documentation.
+ *
+ * @param <F> the type of the function input
+ * @param <T> the type of the function output
+ * @author Kevin Bourrillion
+ * @author Scott Bonneau
+ */
+public interface Function<F, T> {
+
+ /**
+ * Applies the function to an object of type {@code F}, resulting in an object
+ * of type {@code T}. Note that types {@code F} and {@code T} may or may not
+ * be the same.
+ *
+ * @param from the source object
+ * @return the resulting object
+ */
+ T apply(@Nullable F from);
+
+ /**
+ * Indicates whether some other object is equal to this {@code Function}.
+ * This method can return {@code true} <i>only</i> if the specified object is
+ * also a {@code Function} and, for every input object {@code o}, it returns
+ * exactly the same value. Thus, {@code function1.equals(function2)} implies
+ * that either {@code function1.apply(o)} and {@code function2.apply(o)} are
+ * both null, or {@code function1.apply(o).equals(function2.apply(o))}.
+ *
+ * <p>Note that it is always safe <em>not</em> to override
+ * {@link Object#equals}.
+ */
+ boolean equals(@Nullable Object obj);
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/Functions.java b/plugins/com.google.collect/src/com/google/common/base/Functions.java
new file mode 100644
index 0000000..724b492
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Functions.java
@@ -0,0 +1,349 @@
+/*
+ * 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.Preconditions.checkNotNull;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * Useful functions.
+ *
+ * @author Mike Bostock
+ * @author Vlad Patryshev
+ * @author Jared Levy
+ */
+public final class Functions {
+ private Functions() { }
+
+ /**
+ * A function that calls {@code toString()} on its argument. This function
+ * does not accept nulls; it will throw a {@link NullPointerException} when
+ * applied to {@code null}.
+ *
+ * <p>TODO: Consider deprecating this in favor of {@link #toStringFunction()}.
+ */
+ public static final Function<Object, String> TO_STRING =
+ ToStringFunction.INSTANCE;
+
+ /**
+ * 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}.
+ */
+ @SuppressWarnings("unchecked") // see comment below
+ public static <F> Function<F, String> toStringFunction() {
+ /*
+ * Function<F, T> is contravariant on F, so this is essentially a widening
+ * cast. Note: IntelliJ incorrectly colors the following line red.
+ */
+ return (Function<F, String>) ToStringFunction.INSTANCE;
+ }
+
+ // enum singleton pattern
+ private enum ToStringFunction implements Function<Object, String> {
+ INSTANCE;
+
+ public String apply(Object o) {
+ return o.toString();
+ }
+
+ @Override public String toString() {
+ return "toString";
+ }
+ }
+
+ /**
+ * Returns a function that determines the hash code of its argument. For null
+ * arguments, the function returns 0, for consistency with the hash code
+ * calculations in the Java Collections classes.
+ */
+ public static Function<Object, Integer> toHashCode() {
+ return HashCodeFunction.INSTANCE;
+ }
+
+ // enum singleton pattern
+ private enum HashCodeFunction implements Function<Object, Integer> {
+ INSTANCE;
+
+ public Integer apply(Object o) {
+ return (o == null) ? 0 : o.hashCode();
+ }
+
+ @Override public String toString() {
+ return "hashCode";
+ }
+ }
+
+ // enum singleton pattern
+ private enum TrimStringFunction implements Function<String, String> {
+ INSTANCE;
+
+ public String apply(String string) {
+ return string.trim();
+ }
+
+ @Override public String toString() {
+ return "String.trim";
+ }
+ }
+
+ /**
+ * 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;
+
+ public Object apply(Object o) {
+ return o;
+ }
+
+ @Override public String toString() {
+ return "identity";
+ }
+ }
+
+ /**
+ * Returns a function which performs a map lookup.
+ *
+ * <p>The difference between a map and a function is that a map is defined on
+ * a set of keys, while a function is defined on all inputs of the correct
+ * type. The function created by this method returns {@code null} for all
+ * inputs that do not belong to the map's key set.
+ *
+ * @param map source map that determines the function behavior
+ * @return function that returns {@code map.get(a)} for each {@code a}
+ */
+ public static <A, B> Function<A, B> forMap(
+ final Map<? super A, ? extends B> map) {
+ return new FunctionForMapNoDefault<A, B>(map);
+ }
+
+ private static class FunctionForMapNoDefault<A, B>
+ implements Function<A, B>, Serializable {
+ private final Map<? super A, ? extends B> map;
+
+ public FunctionForMapNoDefault(
+ Map<? super A, ? extends B> map) {
+ this.map = checkNotNull(map);
+ }
+ public B apply(A a) {
+ return map.get(a);
+ }
+ @Override public boolean equals(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 <A, B> Function<A, B> forMap(
+ Map<? super A, ? extends B> map, @Nullable final B defaultValue) {
+ if (defaultValue == null) {
+ return forMap(map);
+ }
+ return new ForMapWithDefault<A, B>(map, defaultValue);
+ }
+
+ private static class ForMapWithDefault<A, B>
+ implements Function<A, B>, Serializable {
+ private final Map<? super A, ? extends B> map;
+ private final B defaultValue;
+
+ public ForMapWithDefault(Map<? super A, ? extends B> map, B defaultValue) {
+ this.map = checkNotNull(map);
+ this.defaultValue = defaultValue;
+ }
+ public B apply(A a) {
+ return map.containsKey(a) ? map.get(a) : defaultValue;
+ }
+ @Override public boolean equals(Object o) {
+ if (o instanceof ForMapWithDefault) {
+ ForMapWithDefault<?, ?> that = (ForMapWithDefault<?, ?>) o;
+ return map.equals(that.map) && defaultValue.equals(that.defaultValue);
+ }
+ return false;
+ }
+ @Override public int hashCode() {
+ return map.hashCode() + defaultValue.hashCode();
+ }
+ @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}.
+ *
+ * @see <a href="//en.wikipedia.org/wiki/Function_composition">
+ * function composition</a>
+ *
+ * @param g the second function to apply
+ * @param f the first function to apply
+ * @return the composition of {@code f} and {@code g}
+ */
+ public static <A, B, C> Function<A, C> compose(
+ final Function<? super B, ? extends C> g,
+ final Function<? super 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<? super B, ? extends C> g;
+ private final Function<? super A, ? extends B> f;
+
+ public FunctionComposition(Function<? super B, ? extends C> g,
+ Function<? super A, ? extends B> f) {
+ this.g = checkNotNull(g);
+ this.f = checkNotNull(f);
+ }
+ public C apply(A a) {
+ return g.apply(f.apply(a));
+ }
+ @Override public boolean equals(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() {
+ /*
+ * TODO: To leave the door open for future enhancement, this
+ * calculation should be coordinated with the hashCode() method of the
+ * corresponding composition method in Predicates. To construct the
+ * composition:
+ * predicate(function2(function1(x)))
+ *
+ * There are two different ways of composing it:
+ * compose(predicate, compose(function2, function1))
+ * compose(compose(predicate, function2), function1)
+ *
+ * It would be nice if these could be equal.
+ */
+ 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.
+ */
+ public static <T> Function<T, Boolean> forPredicate(
+ Predicate<? super T> predicate) {
+ return new PredicateFunction<T>(predicate);
+ }
+
+ /** @see Functions#forPredicate */
+ private static class PredicateFunction<T>
+ implements Function<T, Boolean>, Serializable {
+ private final Predicate<? super T> predicate;
+
+ private PredicateFunction(Predicate<? super T> predicate) {
+ this.predicate = checkNotNull(predicate);
+ }
+
+ public Boolean apply(T t) {
+ return predicate.apply(t);
+ }
+ @Override public boolean equals(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;
+ }
+ public E apply(Object from) {
+ return value;
+ }
+ @Override public boolean equals(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;
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/Join.java b/plugins/com.google.collect/src/com/google/common/base/Join.java
new file mode 100644
index 0000000..2c448d9
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Join.java
@@ -0,0 +1,335 @@
+/*
+ * 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.Preconditions.checkNotNull;
+
+import java.io.IOException;
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Utility for joining pieces of text separated by a delimiter. It can handle
+ * iterators, collections, arrays, and varargs, and can append to any
+ * {@link Appendable} or just return a {@link String}. For example,
+ * {@code join(":", "a", "b", "c")} returns {@code "a:b:c"}.
+ *
+ * <p>All methods of this class throw {@link NullPointerException} when a value
+ * of {@code null} is supplied for any parameter. The elements within the
+ * collection, iterator, array, or varargs parameter list <i>may</i> be null --
+ * these will be represented in the output by the string {@code "null"}.
+ *
+ * @author Kevin Bourrillion
+ */
+public final class Join {
+ private Join() {}
+
+ /**
+ * Returns a string containing the {@code tokens}, converted to strings if
+ * necessary, separated by {@code delimiter}. If {@code tokens} is empty, it
+ * returns an empty string.
+ *
+ * <p>Each token will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param delimiter a string to append between every element, but not at the
+ * beginning or end
+ * @param tokens objects to append
+ * @return a string consisting of the joined elements
+ */
+ public static String join(String delimiter, Iterable<?> tokens) {
+ return join(delimiter, tokens.iterator());
+ }
+
+ /**
+ * Returns a string containing the {@code tokens}, converted to strings if
+ * necessary, separated by {@code delimiter}. If {@code tokens} is empty, it
+ * returns an empty string.
+ *
+ * <p>Each token will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param delimiter a string to append between every element, but not at the
+ * beginning or end
+ * @param tokens objects to append
+ * @return a string consisting of the joined elements
+ */
+ public static String join(String delimiter, Object[] tokens) {
+ return join(delimiter, Arrays.asList(tokens));
+ }
+
+ /**
+ * Returns a string containing the {@code tokens}, converted to strings if
+ * necessary, separated by {@code delimiter}.
+ *
+ * <p>Each token will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param delimiter a string to append between every element, but not at the
+ * beginning or end
+ * @param firstToken the first object to append
+ * @param otherTokens subsequent objects to append
+ * @return a string consisting of the joined elements
+ */
+ public static String join(
+ String delimiter, @Nullable Object firstToken, Object... otherTokens) {
+ checkNotNull(otherTokens);
+ return join(delimiter, asList(firstToken, otherTokens));
+ }
+
+ /**
+ * Returns a string containing the {@code tokens}, converted to strings if
+ * necessary, separated by {@code delimiter}. If {@code tokens} is empty, it
+ * returns an empty string.
+ *
+ * <p>Each token will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param delimiter a string to append between every element, but not at the
+ * beginning or end
+ * @param tokens objects to append
+ * @return a string consisting of the joined elements
+ */
+ public static String join(String delimiter, Iterator<?> tokens) {
+ StringBuilder sb = new StringBuilder();
+ join(sb, delimiter, tokens);
+ return sb.toString();
+ }
+
+ /**
+ * Returns a string containing the contents of {@code map}, with entries
+ * separated by {@code entryDelimiter}, and keys and values separated with
+ * {@code keyValueSeparator}.
+ *
+ * <p>Each key and value will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param keyValueSeparator a string to append between every key and its
+ * associated value
+ * @param entryDelimiter a string to append between every entry, but not at
+ * the beginning or end
+ * @param map the map containing the data to join
+ * @return a string consisting of the joined entries of the map; empty if the
+ * map is empty
+ */
+ public static String join(
+ String keyValueSeparator, String entryDelimiter, Map<?, ?> map) {
+ return join(new StringBuilder(), keyValueSeparator, entryDelimiter, map)
+ .toString();
+ }
+
+ /**
+ * Appends each of the {@code tokens} to {@code appendable}, separated by
+ * {@code delimiter}.
+ *
+ * <p>Each token will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param appendable the object to append the results to
+ * @param delimiter a string to append between every element, but not at the
+ * beginning or end
+ * @param tokens objects to append
+ * @return the same {@code Appendable} instance that was passed in
+ * @throws JoinException if an {@link IOException} occurs
+ */
+ public static <T extends Appendable> T join(
+ T appendable, String delimiter, Iterable<?> tokens) {
+ return join(appendable, delimiter, tokens.iterator());
+ }
+
+ /**
+ * Appends each of the {@code tokens} to {@code appendable}, separated by
+ * {@code delimiter}.
+ *
+ * <p>Each token will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param appendable the object to append the results to
+ * @param delimiter a string to append between every element, but not at the
+ * beginning or end
+ * @param tokens objects to append
+ * @return the same {@code Appendable} instance that was passed in
+ * @throws JoinException if an {@link IOException} occurs
+ */
+ public static <T extends Appendable> T join(
+ T appendable, String delimiter, Object[] tokens) {
+ return join(appendable, delimiter, Arrays.asList(tokens));
+ }
+
+ /**
+ * Appends each of the {@code tokens} to {@code appendable}, separated by
+ * {@code delimiter}.
+ *
+ * <p>Each token will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param appendable the object to append the results to
+ * @param delimiter a string to append between every element, but not at the
+ * beginning or end
+ * @param firstToken the first object to append
+ * @param otherTokens subsequent objects to append
+ * @return the same {@code Appendable} instance that was passed in
+ * @throws JoinException if an {@link IOException} occurs
+ */
+ public static <T extends Appendable> T join(T appendable, String delimiter,
+ @Nullable Object firstToken, Object... otherTokens) {
+ checkNotNull(otherTokens);
+ return join(appendable, delimiter, asList(firstToken, otherTokens));
+ }
+
+ /**
+ * Appends each of the {@code tokens} to {@code appendable}, separated by
+ * {@code delimiter}.
+ *
+ * <p>Each token will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param appendable the object to append the results to
+ * @param delimiter a string to append between every element, but not at the
+ * beginning or end
+ * @param tokens objects to append
+ * @return the same {@code Appendable} instance that was passed in
+ * @throws JoinException if an {@link IOException} occurs
+ */
+ public static <T extends Appendable> T join(
+ T appendable, String delimiter, Iterator<?> tokens) {
+
+ /* This method is the workhorse of the class */
+
+ checkNotNull(appendable);
+ checkNotNull(delimiter);
+ if (tokens.hasNext()) {
+ try {
+ appendOneToken(appendable, tokens.next());
+ while (tokens.hasNext()) {
+ appendable.append(delimiter);
+ appendOneToken(appendable, tokens.next());
+ }
+ } catch (IOException e) {
+ throw new JoinException(e);
+ }
+ }
+ return appendable;
+ }
+
+ /**
+ * Appends the contents of {@code map} to {@code appendable}, with entries
+ * separated by {@code entryDelimiter}, and keys and values separated with
+ * {@code keyValueSeparator}.
+ *
+ * <p>Each key and value will be converted to a {@link CharSequence} using
+ * {@link String#valueOf(Object)}, if it isn't a {@link CharSequence} already.
+ * Note that this implies that null tokens will be appended as the
+ * four-character string {@code "null"}.
+ *
+ * @param appendable the object to append the results to
+ * @param keyValueSeparator a string to append between every key and its
+ * associated value
+ * @param entryDelimiter a string to append between every entry, but not at
+ * the beginning or end
+ * @param map the map containing the data to join
+ * @return the same {@code Appendable} instance that was passed in
+ */
+ public static <T extends Appendable> T join(T appendable,
+ String keyValueSeparator, String entryDelimiter, Map<?, ?> map) {
+ checkNotNull(appendable);
+ checkNotNull(keyValueSeparator);
+ checkNotNull(entryDelimiter);
+ Iterator<? extends Map.Entry<?, ?>> entries = map.entrySet().iterator();
+ if (entries.hasNext()) {
+ try {
+ appendOneEntry(appendable, keyValueSeparator, entries.next());
+ while (entries.hasNext()) {
+ appendable.append(entryDelimiter);
+ appendOneEntry(appendable, keyValueSeparator, entries.next());
+ }
+ } catch (IOException e) {
+ throw new JoinException(e);
+ }
+ }
+ return appendable;
+ }
+
+ private static void appendOneEntry(
+ Appendable appendable, String keyValueSeparator, Map.Entry<?, ?> entry)
+ throws IOException {
+ appendOneToken(appendable, entry.getKey());
+ appendable.append(keyValueSeparator);
+ appendOneToken(appendable, entry.getValue());
+ }
+
+ private static void appendOneToken(Appendable appendable, Object token)
+ throws IOException {
+ appendable.append(toCharSequence(token));
+ }
+
+ private static CharSequence toCharSequence(Object token) {
+ return (token instanceof CharSequence)
+ ? (CharSequence) token
+ : String.valueOf(token);
+ }
+
+ /**
+ * Exception thrown in response to an {@link IOException} from the supplied
+ * {@link Appendable}. This is used because most callers won't want to
+ * worry about catching an IOException.
+ */
+ public static class JoinException extends RuntimeException {
+ private JoinException(IOException cause) {
+ super(cause);
+ }
+
+ private static final long serialVersionUID = 1L;
+ }
+
+ /**
+ * Duplicate of
+ * {@link com.google.common.collect.Lists#asList(Object, Object[])}, copied
+ * here to remove dependencies.
+ */
+ private static List<Object> asList(final Object first, final Object[] rest) {
+ return new AbstractList<Object>() {
+ @Override public int size() {
+ return rest.length + 1;
+ }
+ @Override public Object get(int index) {
+ return (index == 0) ? first : rest[index - 1];
+ }
+ };
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/Nullable.java b/plugins/com.google.collect/src/com/google/common/base/Nullable.java
new file mode 100644
index 0000000..c878815
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Nullable.java
@@ -0,0 +1,35 @@
+/*
+ * 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 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 parameter indicates that
+ * {@code null} is an acceptable value for that parameter. It should not be
+ * used for parameters of primitive types.
+ *
+ * @author Kevin Bourrillion
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.PARAMETER)
+public @interface Nullable { }
diff --git a/plugins/com.google.collect/src/com/google/common/base/Objects.java b/plugins/com.google.collect/src/com/google/common/base/Objects.java
new file mode 100644
index 0000000..4adaba1
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Objects.java
@@ -0,0 +1,78 @@
+/*
+ * 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 java.util.Arrays;
+
+/**
+ * Helper functions that can operate on any {@code Object}.
+ *
+ * @author Laurence Gonsalves
+ */
+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(Object... objects) {
+ return Arrays.hashCode(objects);
+ }
+
+ /**
+ * Returns the first of two given parameters that is not {@code null}, if
+ * either is, or otherwise throws a {@link NullPointerException}.
+ *
+ * @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}
+ */
+ public static <T> T firstNonNull(@Nullable T first, @Nullable T second) {
+ return first != null ? first : Preconditions.checkNotNull(second);
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/Preconditions.java b/plugins/com.google.collect/src/com/google/common/base/Preconditions.java
new file mode 100644
index 0000000..93e4afd
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Preconditions.java
@@ -0,0 +1,358 @@
+/*
+ * 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 java.util.Collection;
+import java.util.NoSuchElementException;
+
+/**
+ * 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>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 <i>ever</i>. Postcondition or other invariant failures should not
+ * throw these types of exceptions.
+ *
+ * <p><b>Note:</b> The methods of the {@code Preconditions} class are highly
+ * unusual in one way: they are <i>supposed to</i> throw exceptions, and promise
+ * in their specifications to do so even when given perfectly valid input. That
+ * is, {@code null} is a valid parameter to the method {@link
+ * #checkNotNull(Object)} -- and technically this parameter could be even marked
+ * as {@link Nullable} -- yet the method will still throw an exception anyway,
+ * because that's what its contract says to do.
+ *
+ * @author Kevin Bourrillion
+ */
+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, 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,
+ String errorMessageTemplate, 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, 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,
+ String errorMessageTemplate, 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, 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, String errorMessageTemplate,
+ 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;
+ }
+
+ /**
+ * Ensures that an {@code Iterable} object passed as a parameter to the
+ * calling method is not null and contains no null elements.
+ *
+ * @param iterable the iterable to check the contents of
+ * @return the non-null {@code iterable} reference just validated
+ * @throws NullPointerException if {@code iterable} is null or contains at
+ * least one null element
+ */
+ public static <T extends Iterable<?>> T checkContentsNotNull(T iterable) {
+ if (containsOrIsNull(iterable)) {
+ throw new NullPointerException();
+ }
+ return iterable;
+ }
+
+ /**
+ * Ensures that an {@code Iterable} object passed as a parameter to the
+ * calling method is not null and contains no null elements.
+ *
+ * @param iterable the iterable to check the contents of
+ * @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 {@code iterable} reference just validated
+ * @throws NullPointerException if {@code iterable} is null or contains at
+ * least one null element
+ */
+ public static <T extends Iterable<?>> T checkContentsNotNull(
+ T iterable, Object errorMessage) {
+ if (containsOrIsNull(iterable)) {
+ throw new NullPointerException(String.valueOf(errorMessage));
+ }
+ return iterable;
+ }
+
+ /**
+ * Ensures that an {@code Iterable} object passed as a parameter to the
+ * calling method is not null and contains no null elements.
+ *
+ * @param iterable the iterable to check the contents of
+ * @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 {@code iterable} reference just validated
+ * @throws NullPointerException if {@code iterable} is null or contains at
+ * least one null element
+ */
+ public static <T extends Iterable<?>> T checkContentsNotNull(T iterable,
+ String errorMessageTemplate, Object... errorMessageArgs) {
+ if (containsOrIsNull(iterable)) {
+ throw new NullPointerException(
+ format(errorMessageTemplate, errorMessageArgs));
+ }
+ return iterable;
+ }
+
+ private static boolean containsOrIsNull(Iterable<?> iterable) {
+ if (iterable == null) {
+ return true;
+ }
+
+ if (iterable instanceof Collection) {
+ Collection<?> collection = (Collection<?>) iterable;
+ try {
+ return collection.contains(null);
+ } catch (NullPointerException e) {
+ // A NPE implies that the collection doesn't contain null.
+ return false;
+ }
+ } else {
+ for (Object element : iterable) {
+ if (element == null) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * 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, Object... args) {
+ // 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/plugins/com.google.collect/src/com/google/common/base/Predicate.java b/plugins/com.google.collect/src/com/google/common/base/Predicate.java
new file mode 100644
index 0000000..db1c995
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Predicate.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+/**
+ * Determines a true or false value for a given input. For example, a
+ * {@code RegexPredicate} might implement {@code Predicate<String>}, and return
+ * {@code true} for any string that matches its given regular expression.
+ *
+ * <p>Implementations which may cause side effects upon evaluation are strongly
+ * encouraged to state this fact clearly in their API documentation.
+ *
+ * @author Kevin Bourrillion
+ */
+public interface Predicate<T> {
+
+ /*
+ * This interface does not extend Function<T, Boolean> because doing so would
+ * let predicates return null.
+ */
+
+ /**
+ * Applies this predicate to the given object.
+ *
+ * @param input the input that the predicate should act on
+ * @return the value of this predicate when applied to the input {@code t}
+ */
+ boolean apply(@Nullable T input);
+
+
+ /**
+ * Indicates whether some other object is equal to this {@code Predicate}.
+ * This method can return {@code true} <i>only</i> if the specified object is
+ * also a {@code Predicate} and, for every input object {@code input}, it
+ * returns exactly the same value. Thus, {@code predicate1.equals(predicate2)}
+ * implies that either {@code predicate1.apply(input)} and
+ * {@code predicate2.apply(input)} are both {@code true} or both
+ * {@code false}.
+ *
+ * <p>Note that it is always safe <i>not</i> to override
+ * {@link Object#equals}.
+ */
+ boolean equals(@Nullable Object obj);
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/Predicates.java b/plugins/com.google.collect/src/com/google/common/base/Predicates.java
new file mode 100644
index 0000000..fb9cac2
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Predicates.java
@@ -0,0 +1,517 @@
+/*
+ * 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.Preconditions.checkContentsNotNull;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Contains static factory methods for creating {@code Predicate} instances.
+ *
+ * @author Kevin Bourrillion
+ */
+public final class Predicates {
+ private Predicates() {}
+
+ // TODO: considering having these implement a VisitablePredicate interface
+ // which specifies an accept(PredicateVisitor) method.
+
+ /**
+ * Returns a predicate that always evaluates to {@code true}.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Predicate<T> alwaysTrue() {
+ return (Predicate<T>) AlwaysTruePredicate.INSTANCE;
+ }
+
+ /**
+ * Returns a predicate that always evaluates to {@code false}.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Predicate<T> alwaysFalse() {
+ return (Predicate<T>) AlwaysFalsePredicate.INSTANCE;
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the object reference
+ * being tested is null.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Predicate<T> isNull() {
+ return (Predicate<T>) IsNullPredicate.INSTANCE;
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the object reference
+ * being tested is not null.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Predicate<T> notNull() {
+ return (Predicate<T>) NotNullPredicate.INSTANCE;
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the given predicate
+ * evaluates to {@code false}.
+ */
+ public static <T> Predicate<T> not(Predicate<? super 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 does not defensively copy the iterable passed in, so
+ * future changes to it will 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>(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 does not defensively copy the array passed in, so
+ * future changes to it will 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 and(Arrays.asList(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.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Predicate<T> and(Predicate<? super T> first,
+ Predicate<? super T> second) {
+ return and(Arrays.<Predicate<? super T>> asList(first, 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 as soon as a
+ * true predicate is found. It does not defensively copy the iterable passed
+ * in, so future changes to it will 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>(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 as soon as a
+ * true predicate is found. It does not defensively copy the array passed in,
+ * so future changes to it will 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 or(Arrays.asList(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 as soon as a
+ * true predicate is found.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Predicate<T> or(Predicate<? super T> first,
+ Predicate<? super T> second) {
+ return or(Arrays.<Predicate<? super T>> asList(first, 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> isEqualTo(@Nullable T target) {
+ // TODO: Change signature to return Predicate<Object>.
+ return (target == null)
+ ? Predicates.<T>isNull()
+ : new IsEqualToPredicate<T>(target);
+ }
+
+ /**
+ * Returns a predicate that evaluates to {@code true} if the object being
+ * tested refers to the same object as the given target or both are null.
+ */
+ public static Predicate<Object> isSameAs(@Nullable Object target) {
+ return (target == null)
+ ? Predicates.isNull()
+ : new IsSameAsPredicate(target);
+ }
+
+ /**
+ * 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.
+ *
+ * @param target the collection that may contain the function input
+ */
+ public static <T> Predicate<T> in(Collection<?> 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<? super B> predicate,
+ Function<? super A, ? extends B> function) {
+ return new CompositionPredicate<A, B>(predicate, function);
+ }
+
+ /** @see Predicates#alwaysTrue() */
+ // enum singleton pattern
+ private enum AlwaysTruePredicate implements Predicate<Object> {
+ INSTANCE;
+
+ public boolean apply(Object o) {
+ return true;
+ }
+ @Override public String toString() {
+ return "AlwaysTrue";
+ }
+ }
+
+ /** @see Predicates#alwaysFalse() */
+ // enum singleton pattern
+ private enum AlwaysFalsePredicate implements Predicate<Object> {
+ INSTANCE;
+
+ public boolean apply(Object o) {
+ return false;
+ }
+ @Override public String toString() {
+ return "AlwaysFalse";
+ }
+ }
+
+ /** @see Predicates#not(Predicate) */
+ private static class NotPredicate<T>
+ implements Predicate<T>, Serializable {
+ private final Predicate<? super T> predicate;
+
+ private NotPredicate(Predicate<? super T> predicate) {
+ this.predicate = checkNotNull(predicate);
+ }
+ public boolean apply(T t) {
+ return !predicate.apply(t);
+ }
+ @Override public int hashCode() {
+ return ~predicate.hashCode(); /* Invert all bits. */
+ }
+ @Override public boolean equals(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;
+ }
+
+ /** @see Predicates#and(Iterable) */
+ private static class AndPredicate<T>
+ implements Predicate<T>, Serializable {
+ private final Iterable<? extends Predicate<? super T>> components;
+
+ private AndPredicate(Iterable<? extends Predicate<? super T>> components) {
+ this.components = checkContentsNotNull(components);
+ }
+ public boolean apply(T t) {
+ for (Predicate<? super T> predicate : components) {
+ if (!predicate.apply(t)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ @Override public int hashCode() {
+ int result = -1; /* Start with all bits on. */
+ for (Predicate<? super T> predicate : components) {
+ result &= predicate.hashCode();
+ }
+ return result;
+ }
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof AndPredicate<?>) {
+ AndPredicate<?> that = (AndPredicate<?>) obj;
+ return iterableElementsEqual(components, that.components);
+ }
+ return false;
+ }
+ @Override public String toString() {
+ return "And(" + Join.join(",", components) + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** @see Predicates#or(Iterable) */
+ private static class OrPredicate<T>
+ implements Predicate<T>, Serializable {
+ private final Iterable<? extends Predicate<? super T>> components;
+
+ private OrPredicate(Iterable<? extends Predicate<? super T>> components) {
+ this.components = checkContentsNotNull(components);
+ }
+ public boolean apply(T t) {
+ for (Predicate<? super T> predicate : components) {
+ if (predicate.apply(t)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ @Override public int hashCode() {
+ int result = 0; /* Start with all bits off. */
+ for (Predicate<? super T> predicate : components) {
+ result |= predicate.hashCode();
+ }
+ return result;
+ }
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof OrPredicate<?>) {
+ OrPredicate<?> that = (OrPredicate<?>) obj;
+ return iterableElementsEqual(components, that.components);
+ }
+ return false;
+ }
+ @Override public String toString() {
+ return "Or(" + Join.join(",", components) + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** @see Predicates#isEqualTo(Object) */
+ private static class IsEqualToPredicate<T>
+ implements Predicate<T>, Serializable {
+ private final T target;
+
+ private IsEqualToPredicate(T target) {
+ this.target = target;
+ }
+ public boolean apply(T t) {
+ return target.equals(t);
+ }
+ @Override public int hashCode() {
+ return target.hashCode();
+ }
+ @Override public boolean equals(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#isSameAs(Object) */
+ private static class IsSameAsPredicate
+ implements Predicate<Object>, Serializable {
+ private final Object target;
+
+ private IsSameAsPredicate(Object target) {
+ this.target = target;
+ }
+ public boolean apply(Object o) {
+ return target == o;
+ }
+ @Override public int hashCode() {
+ return target.hashCode();
+ }
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof IsSameAsPredicate) {
+ IsSameAsPredicate that = (IsSameAsPredicate) obj;
+ return target == that.target;
+ }
+ return false;
+ }
+ @Override public String toString() {
+ return "IsSameAs(" + target + ")";
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** @see Predicates#isNull() */
+ // enum singleton pattern
+ private enum IsNullPredicate implements Predicate<Object> {
+ INSTANCE;
+
+ public boolean apply(Object o) {
+ return o == null;
+ }
+ @Override public String toString() {
+ return "IsNull";
+ }
+ }
+
+ /** @see Predicates#notNull() */
+ // enum singleton pattern
+ private enum NotNullPredicate implements Predicate<Object> {
+ INSTANCE;
+
+ public boolean apply(Object o) {
+ return o != null;
+ }
+ @Override public String toString() {
+ return "NotNull";
+ }
+ }
+
+ /** @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);
+ }
+
+ public boolean apply(T t) {
+ try {
+ return target.contains(t);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override public boolean equals(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<? super B> p;
+ final Function<? super A, ? extends B> f;
+
+ private CompositionPredicate(
+ Predicate<? super B> p, Function<? super A, ? extends B> f) {
+ this.p = checkNotNull(p);
+ this.f = checkNotNull(f);
+ }
+
+ public boolean apply(A a) {
+ return p.apply(f.apply(a));
+ }
+
+ @Override public boolean equals(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() {
+ /*
+ * TODO: To leave the door open for future enhancement, this
+ * calculation should be coordinated with the hashCode() method of the
+ * corresponding composition method in Functions. To construct the
+ * composition:
+ * predicate(function2(function1(x)))
+ *
+ * There are two different ways of composing it:
+ * compose(predicate, compose(function2, function1))
+ * compose(compose(predicate, function2), function1)
+ *
+ * It would be nice if these could be equal.
+ */
+ return f.hashCode() ^ p.hashCode();
+ }
+
+ @Override public String toString() {
+ return p.toString() + "(" + f.toString() + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Determines whether the two Iterables contain equal elements. 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}.
+ *
+ * <p>This is not a general-purpose method; it assumes that the iterations
+ * contain no {@code null} elements.
+ */
+ private static boolean iterableElementsEqual(
+ Iterable<?> iterable1, Iterable<?> iterable2) {
+ Iterator<?> iterator1 = iterable1.iterator();
+ Iterator<?> iterator2 = iterable2.iterator();
+ while (iterator1.hasNext()) {
+ if (!iterator2.hasNext()) {
+ return false;
+ }
+ if (!iterator1.next().equals(iterator2.next())) {
+ return false;
+ }
+ }
+ return !iterator2.hasNext();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/ReferenceType.java b/plugins/com.google.collect/src/com/google/common/base/ReferenceType.java
new file mode 100644
index 0000000..8e26459
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/ReferenceType.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+/**
+ * Reference type. Used to specify what type of reference to keep to a
+ * referent.
+ *
+ * @see java.lang.ref.Reference
+ * @author Bob Lee
+ */
+public enum ReferenceType {
+
+ /**
+ * Prevents referent from being reclaimed by the garbage collector.
+ */
+ STRONG,
+
+ /**
+ * Referent reclaimed in an LRU fashion when the VM runs low on memory and
+ * no strong references exist.
+ *
+ * @see java.lang.ref.SoftReference
+ */
+ SOFT,
+
+ /**
+ * Referent reclaimed when no strong or soft references exist.
+ *
+ * @see java.lang.ref.WeakReference
+ */
+ WEAK,
+
+ /**
+ * Similar to weak references except the garbage collector doesn't actually
+ * reclaim the referent. More flexible alternative to finalization.
+ *
+ * @see java.lang.ref.PhantomReference
+ */
+ PHANTOM;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/Supplier.java b/plugins/com.google.collect/src/com/google/common/base/Supplier.java
new file mode 100644
index 0000000..bd82236
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Supplier.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * 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
+ */
+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
+ */
+ public T get();
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/Suppliers.java b/plugins/com.google.collect/src/com/google/common/base/Suppliers.java
new file mode 100644
index 0000000..6bf7ef5
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/Suppliers.java
@@ -0,0 +1,131 @@
+/*
+ * 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 java.io.Serializable;
+
+/**
+ * Useful suppliers.
+ *
+ * @author Laurence Gonsalves
+ * @author Harry Heymann
+ */
+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 first}, and then applying
+ * {@code function} to that value. Note that the resulting supplier will not
+ * call {@code first} or invoke {@code function} until it is called.
+ */
+ public static <F, T> Supplier<T> compose(
+ Function<? super F, ? extends T> function, Supplier<? extends F> first) {
+ return new SupplierComposition<F, T>(function, first);
+ }
+
+ private static class SupplierComposition<F, T>
+ implements Supplier<T>, Serializable {
+ private final Function<? super F, ? extends T> function;
+ private final Supplier<? extends F> first;
+
+ public SupplierComposition(Function<? super F, ? extends T> function,
+ Supplier<? extends F> first) {
+ this.function = function;
+ this.first = first;
+ }
+ public T get() {
+ return function.apply(first.get());
+ }
+ 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 will throw {@code CyclicDependencyException} if
+ * the call to {@link Supplier#get} tries to get its own value. The returned
+ * supplier is <i>not</i> thread-safe.
+ */
+ public static <T> Supplier<T> memoize(Supplier<T> delegate) {
+ return new MemoizingSupplier<T>(delegate);
+ }
+
+ private static class MemoizingSupplier<T>
+ implements Supplier<T>, Serializable {
+ private final Supplier<T> delegate;
+ private MemoizationState state = MemoizationState.NOT_YET;
+ private T value;
+
+ public MemoizingSupplier(Supplier<T> delegate) {
+ this.delegate = delegate;
+ }
+ public T get() {
+ switch (state) {
+ case NOT_YET:
+ state = MemoizationState.COMPUTING;
+ try {
+ value = delegate.get();
+ } finally {
+ state = MemoizationState.NOT_YET;
+ }
+ state = MemoizationState.DONE;
+ break;
+ case COMPUTING:
+ throw new CyclicDependencyException();
+ }
+ return value;
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ private enum MemoizationState { NOT_YET, COMPUTING, DONE }
+
+ /**
+ * Exception thrown when a memoizing supplier tries to get its own value.
+ */
+ public static class CyclicDependencyException extends RuntimeException {
+ CyclicDependencyException() {
+ super("Cycle detected when invoking a memoizing supplier.");
+ }
+ 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 {
+ private final T instance;
+
+ public SupplierOfInstance(T instance) {
+ this.instance = instance;
+ }
+ public T get() {
+ return instance;
+ }
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/base/package-info.java b/plugins/com.google.collect/src/com/google/common/base/package-info.java
new file mode 100644
index 0000000..1fb94a5
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/base/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * Miscellaneous common util classes and annotations.
+ */
+package com.google.common.base;
diff --git a/plugins/com.google.collect/src/com/google/common/collect/AbstractIterable.java b/plugins/com.google.collect/src/com/google/common/collect/AbstractIterable.java
new file mode 100644
index 0000000..3ca5223
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/AbstractIterable.java
@@ -0,0 +1,36 @@
+/*
+ * 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.collect;
+
+/**
+ * Provides an implementation of {@link Object#toString} for {@link Iterable}
+ * instances.
+ *
+ * @author Mike Bostock
+ */
+public abstract class AbstractIterable<E> implements Iterable<E> {
+ /**
+ * Returns a string representation of this iterable. The string representation
+ * consists of a list of the iterable's elements in the order they are
+ * returned by its iterator, enclosed in square brackets ("[]"). Adjacent
+ * elements are separated by the characters ", " (comma and space). Elements
+ * are converted to strings as by {@link String#valueOf(Object)}.
+ */
+ @Override public String toString() {
+ return Iterables.toString(this);
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/AbstractIterator.java b/plugins/com.google.collect/src/com/google/common/collect/AbstractIterator.java
new file mode 100644
index 0000000..9684b50
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/AbstractIterator.java
@@ -0,0 +1,168 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Iterator;
+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. The {@link
+ * #remove()} method throws an {@link UnsupportedOperationException}, but the
+ * similar class {@link AbstractRemovableIterator} does support {@code remove}.
+ *
+ * @author Kevin Bourrillion
+ */
+public abstract class AbstractIterator<T> implements Iterator<T> {
+ private State state = State.NOT_READY;
+
+ 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}.
+ *
+ * @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 {@code computeNext} <b>must</b> invoke this method when
+ * there are no elements left in the iteration.
+ *
+ * @return {@code null}; a convenience so your {@link #computeNext}
+ * implementation can use the simple statement {@code return endOfData();}
+ */
+ protected final T endOfData() {
+ state = State.DONE;
+ return null;
+ }
+
+ public 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;
+ }
+
+ public 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 T peek() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return next;
+ }
+
+ /**
+ * This method is not supported.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/AbstractMapBasedMultiset.java b/plugins/com.google.collect/src/com/google/common/collect/AbstractMapBasedMultiset.java
new file mode 100644
index 0000000..170a814
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/AbstractMapBasedMultiset.java
@@ -0,0 +1,381 @@
+/*
+ * 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.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.base.Nullable;
+
+import java.io.InvalidObjectException;
+import java.io.Serializable;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Basic implementation of {@code Multiset<E>} backed by an instance of {@code
+ * Map<E, AtomicInteger>}.
+ *
+ * <p>For serialization to work, the subclass must specify explicit {@code
+ * readObject} and {@code writeObject} methods.
+ *
+ * @author Kevin Bourrillion
+ */
+abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
+ implements Serializable {
+
+ // TODO: Replace AtomicInteger with a to-be-written IntegerHolder class for
+ // better performance.
+ private transient Map<E, AtomicInteger> 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, AtomicInteger> backingMap) {
+ this.backingMap = checkNotNull(backingMap);
+ this.size = super.size();
+ }
+
+ protected Map<E, AtomicInteger> backingMap() {
+ return backingMap;
+ }
+
+ /** Used during deserialization only. The backing map must be empty. */
+ protected void setBackingMap(Map<E, AtomicInteger> backingMap) {
+ this.backingMap = backingMap;
+ }
+
+ // Required Implementations
+
+ private transient volatile EntrySet entrySet;
+
+ /**
+ * {@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() {
+ EntrySet result = entrySet;
+ if (result == null) {
+ entrySet = result = new EntrySet();
+ }
+ return result;
+ }
+
+ private class EntrySet extends AbstractSet<Multiset.Entry<E>> {
+ @Override public Iterator<Multiset.Entry<E>> iterator() {
+ final Iterator<Map.Entry<E, AtomicInteger>> backingEntries
+ = backingMap.entrySet().iterator();
+ return new Iterator<Multiset.Entry<E>>() {
+ Map.Entry<E, AtomicInteger> toRemove;
+
+ public boolean hasNext() {
+ return backingEntries.hasNext();
+ }
+
+ public Multiset.Entry<E> next() {
+ final Map.Entry<E, AtomicInteger> mapEntry = backingEntries.next();
+ toRemove = mapEntry;
+ return new AbstractMultisetEntry<E>() {
+ public E getElement() {
+ return mapEntry.getKey();
+ }
+ public int getCount() {
+ int count = mapEntry.getValue().get();
+ if (count == 0) {
+ AtomicInteger frequency = backingMap.get(getElement());
+ if (frequency != null) {
+ count = frequency.get();
+ }
+ }
+ return count;
+ }
+ };
+ }
+
+ public void remove() {
+ checkState(toRemove != null,
+ "no calls to next() since the last call to remove()");
+ size -= toRemove.getValue().getAndSet(0);
+ backingEntries.remove();
+ toRemove = null;
+ }
+ };
+ }
+
+ @Override public int size() {
+ return backingMap.size();
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ return super.retainAll(checkNotNull(c));
+ }
+
+ // The following overrides are for better performance.
+
+ @Override public void clear() {
+ for (AtomicInteger frequency : backingMap.values()) {
+ frequency.set(0);
+ }
+ backingMap.clear();
+ size = 0L;
+ }
+
+ @Override public boolean contains(Object o) {
+ if (o instanceof Entry) {
+ Entry<?> entry = (Entry<?>) o;
+ int count = count(entry.getElement());
+ return (count == entry.getCount()) && (count > 0);
+ }
+ return false;
+ }
+
+ @Override public boolean remove(Object o) {
+ if (contains(o)) {
+ Entry<?> entry = (Entry<?>) o;
+ AtomicInteger frequency = backingMap.remove(entry.getElement());
+ int numberRemoved = frequency.getAndSet(0);
+ size -= numberRemoved;
+ return true;
+ }
+ return false;
+ }
+ }
+
+ // Optimizations - Query Operations
+
+ @Override public int size() {
+ return (int) Math.min(this.size, Integer.MAX_VALUE);
+ }
+
+ @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, AtomicInteger>> entryIterator;
+ Map.Entry<E, AtomicInteger> currentEntry;
+ int occurrencesLeft;
+ boolean canRemove;
+
+ MapBasedMultisetIterator() {
+ this.entryIterator = backingMap.entrySet().iterator();
+ }
+
+ public boolean hasNext() {
+ return occurrencesLeft > 0 || entryIterator.hasNext();
+ }
+
+ public E next() {
+ if (occurrencesLeft == 0) {
+ currentEntry = entryIterator.next();
+ occurrencesLeft = currentEntry.getValue().get();
+ }
+ occurrencesLeft--;
+ canRemove = true;
+ return currentEntry.getKey();
+ }
+
+ 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) {
+ AtomicInteger frequency = backingMap.get(element);
+ return (frequency == null) ? 0 : frequency.get();
+ }
+
+ // 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 boolean add(@Nullable E element, int occurrences) {
+ if (occurrences == 0) {
+ return false;
+ }
+ checkArgument(
+ occurrences > 0, "occurrences cannot be negative: %s", occurrences);
+ AtomicInteger frequency = backingMap.get(element);
+ if (frequency == null) {
+ backingMap.put(element, new AtomicInteger(occurrences));
+ } else {
+ long newCount = (long) frequency.get() + (long) occurrences;
+ checkArgument(newCount <= Integer.MAX_VALUE,
+ "too many occurrences: %s", newCount);
+ frequency.getAndAdd(occurrences);
+ }
+ size += occurrences;
+ return true;
+ }
+
+ @Override public int remove(@Nullable Object element, int occurrences) {
+ if (occurrences == 0) {
+ return 0;
+ }
+ checkArgument(
+ occurrences > 0, "occurrences cannot be negative: %s", occurrences);
+ AtomicInteger frequency = backingMap.get(element);
+ if (frequency == null) {
+ return 0;
+ }
+
+ int numberRemoved;
+ if (frequency.get() > occurrences) {
+ numberRemoved = occurrences;
+ } else {
+ numberRemoved = frequency.get();
+ backingMap.remove(element);
+ }
+
+ frequency.addAndGet(-numberRemoved);
+ size -= numberRemoved;
+ return numberRemoved;
+ }
+
+ @Override public int removeAllOccurrences(@Nullable Object element) {
+ return removeAllOccurrences(element, backingMap);
+ }
+
+ private int removeAllOccurrences(@Nullable Object element,
+ Map<E, AtomicInteger> map) {
+ AtomicInteger frequency = map.remove(element);
+ if (frequency == null) {
+ return 0;
+ }
+ int numberRemoved = frequency.getAndSet(0);
+ size -= numberRemoved;
+ return numberRemoved;
+ }
+
+ // Views
+
+ @Override protected Set<E> createElementSet() {
+ return new MapBasedElementSet(backingMap);
+ }
+
+ class MapBasedElementSet extends ForwardingSet<E> {
+ /**
+ * This mapping is the usually the same as {@code backingMap}, but can
+ * be a submap in some implementations.
+ */
+ private final Map<E, AtomicInteger> map;
+ private final Set<E> delegate;
+
+ MapBasedElementSet(Map<E, AtomicInteger> map) {
+ this.map = map;
+ delegate = map.keySet();
+ }
+
+ @Override protected Set<E> delegate() {
+ return delegate;
+ }
+
+ // TODO: a way to not have to write this much code?
+
+ @Override public Iterator<E> iterator() {
+ final Iterator<Map.Entry<E, AtomicInteger>> entries
+ = map.entrySet().iterator();
+ return new Iterator<E>() {
+ Map.Entry<E, AtomicInteger> toRemove;
+
+ public boolean hasNext() {
+ return entries.hasNext();
+ }
+
+ public E next() {
+ toRemove = entries.next();
+ return toRemove.getKey();
+ }
+
+ public void remove() {
+ checkState(toRemove != null,
+ "no calls to next() since the last call to remove()");
+ size -= toRemove.getValue().getAndSet(0);
+ entries.remove();
+ toRemove = null;
+ }
+ };
+ }
+
+ @Override public boolean remove(Object element) {
+ return removeAllOccurrences(element, map) != 0;
+ }
+
+ @Override public boolean removeAll(Collection<?> elementsToRemove) {
+ return Iterators.removeAll(iterator(), elementsToRemove);
+ }
+
+ @Override public boolean retainAll(Collection<?> elementsToRetain) {
+ return Iterators.retainAll(iterator(), elementsToRetain);
+ }
+
+ @Override public void clear() {
+ if (map == backingMap) {
+ AbstractMapBasedMultiset.this.clear();
+ } else {
+ Iterator<E> i = iterator();
+ while (i.hasNext()) {
+ i.next();
+ i.remove();
+ }
+ }
+ }
+
+ public Map<E, AtomicInteger> getMap() {
+ return map;
+ }
+ }
+
+ /** Don't allow default serialization. */
+ protected void readObjectNoData() throws InvalidObjectException {
+ throw new InvalidObjectException("Stream data required");
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/AbstractMapEntry.java b/plugins/com.google.collect/src/com/google/common/collect/AbstractMapEntry.java
new file mode 100644
index 0000000..903bb49
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/AbstractMapEntry.java
@@ -0,0 +1,77 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Objects;
+
+import java.util.Map.Entry;
+
+/**
+ * Implementation of the {@code equals}, {@code hashCode}, and {@code toString}
+ * methods of {@code Entry}.
+ *
+ * @author Jared Levy
+ */
+public abstract class AbstractMapEntry<K, V> implements Entry<K, V> {
+
+ public abstract K getKey();
+
+ public abstract V getValue();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation throws an {@link UnsupportedOperationException}.
+ * Override this method to support mutable map entries.
+ */
+ public V setValue(V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Indicates whether an object equals this entry, following the behavior
+ * specified in {@link Entry#equals}.
+ */
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ Entry<?, ?> e = (Entry<?, ?>) o;
+ return Objects.equal(e.getKey(), getKey())
+ && Objects.equal(e.getValue(), getValue());
+ }
+
+ /**
+ * Return this entry's hash code, following the behavior specified in
+ * {@link Entry#hashCode}.
+ */
+ @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();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/AbstractMultiset.java b/plugins/com.google.collect/src/com/google/common/collect/AbstractMultiset.java
new file mode 100644
index 0000000..ad6fb3b
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/AbstractMultiset.java
@@ -0,0 +1,406 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+import com.google.common.base.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.AbstractCollection;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * 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 #contains}, {@link #containsAll}, {@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
+ */
+public abstract class AbstractMultiset<E> extends AbstractCollection<E>
+ implements Multiset<E> {
+ public abstract Set<Entry<E>> entrySet();
+
+ // Query Operations
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation iterates across {@link Multiset#entrySet()} and
+ * sums the counts of the entries.
+ */
+ @Override public int size() {
+ long sum = 0L;
+ for (Entry<E> entry : entrySet()) {
+ sum += entry.getCount();
+ }
+ return (int) Math.min(sum, Integer.MAX_VALUE);
+ }
+
+ @Override public boolean isEmpty() {
+ return entrySet().isEmpty();
+ }
+
+ /**
+ * Returns {@code true} if this collection contains the specified element.
+ *
+ * <p>This implementation checks whether {@link #elementSet} contains the
+ * element.
+ */
+ @Override public boolean contains(@Nullable Object element) {
+ return elementSet().contains(element);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation usually invokes methods of the
+ * {@link Multiset#entrySet()} iterator. However, the iterator's
+ * {@code remove} method sometimes calls the multiset's {@code remove}.
+ */
+ @Override public Iterator<E> iterator() {
+ return new MultisetIterator();
+ }
+
+ private class MultisetIterator implements Iterator<E> {
+ 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;
+
+ MultisetIterator() {
+ this.entryIterator = entrySet().iterator();
+ }
+
+ public boolean hasNext() {
+ return laterCount > 0 || entryIterator.hasNext();
+ }
+
+ public E next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ if (laterCount == 0) {
+ currentEntry = entryIterator.next();
+ totalCount = laterCount = currentEntry.getCount();
+ }
+ laterCount--;
+ canRemove = true;
+ return currentEntry.getElement();
+ }
+
+ public void remove() {
+ checkState(canRemove,
+ "no calls to next() since the last call to remove()");
+ if (totalCount == 1) {
+ entryIterator.remove();
+ } else {
+ AbstractMultiset.this.remove(currentEntry.getElement());
+ }
+ totalCount--;
+ canRemove = false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation iterates across {@link Multiset#entrySet()} and
+ * sums the count of all entries.
+ */
+ public int count(Object element) {
+ for (Entry<E> entry : entrySet()) {
+ if (Objects.equal(entry.getElement(), element)) {
+ return entry.getCount();
+ }
+ }
+ return 0;
+ }
+
+ // Modification Operations
+
+ /**
+ * Ensures that this collection contains the specified element.
+ *
+ * <p>This implementation calls {@link #add(Object, int)} with one occurrence.
+ *
+ * @return {@code true} always
+ */
+ @Override public boolean add(@Nullable E element) {
+ add(element, 1);
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation always throws an
+ * {@link UnsupportedOperationException}. To support adding elements, override
+ * it.
+ */
+ public boolean add(E element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Removes a single instance of the specified element from this collection, if
+ * it is present.
+ *
+ * <p>This implementation calls {@link #remove(Object, int)} with 1
+ * occurrence.
+ */
+ @Override public boolean remove(Object element) {
+ return remove(element, 1) == 1;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation always throws an
+ * {@link UnsupportedOperationException}. To support removing elements,
+ * override it.
+ */
+ public int remove(Object element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation calls {@link #remove(Object, int)} with
+ * {@code Integer.MAX_VALUE} occurrences.
+ */
+ public int removeAllOccurrences(Object element) {
+ return remove(element, Integer.MAX_VALUE);
+ }
+
+ // Bulk Operations
+
+ /**
+ * Returns {@code true} if this multiset contains all of the elements in the
+ * specified collection.
+ *
+ * <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.
+ *
+ * <p>This implementation checks whether {@link #elementSet} contains the
+ * elements.
+ */
+ @Override public boolean containsAll(Collection<?> elements) {
+ return elementSet().containsAll(elements);
+ }
+
+ /**
+ * Adds all of the elements in the specified collection to this multiset.
+ *
+ * <p>If the collection being added is a multiset, this implementation
+ * iterates over that multiset's entry set to add the appropriate number of
+ * occurrences of each of its elements to this multiset. Otherwise, it calls
+ * {@link AbstractCollection#addAll}.
+ */
+ @Override public boolean addAll(Collection<? extends E> elementsToAdd) {
+ if (elementsToAdd.isEmpty()) {
+ return false;
+ }
+ if (elementsToAdd instanceof Multiset) {
+ @SuppressWarnings("unchecked")
+ Multiset<? extends E> that = (Multiset<? extends E>) elementsToAdd;
+ for (Entry<? extends E> entry : that.entrySet()) {
+ add(entry.getElement(), entry.getCount());
+ }
+ } else {
+ super.addAll(elementsToAdd);
+ }
+ return true;
+ }
+
+ /**
+ * Removes all of this multiset's elements that are also contained in the
+ * specified collection.
+ *
+ * <p>This implementation iterates over the elements in the collection or, if
+ * {@code elementsToRemove} is a multiset, the elements in its element set,
+ * and calls {@link #removeAllOccurrences} on each element. In some cases,
+ * this approach has better performance than
+ * {@link AbstractCollection#removeAll}.
+ */
+ @Override public boolean removeAll(Collection<?> elementsToRemove) {
+ Iterable<?> iterable = (elementsToRemove instanceof Multiset)
+ ? ((Multiset<?>) elementsToRemove).elementSet() : elementsToRemove;
+
+ boolean modified = false;
+ for (Object element : iterable) {
+ if (removeAllOccurrences(element) != 0) {
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ /**
+ * Retains only the elements in this multiset that are contained in the
+ * specified collection.
+ *
+ * <p>This implementation iterates over {@link #entrySet()}, checking each
+ * entry's element to see if it's contained in the provided collection.
+ * If it's not found, the {@code remove} method of the entry set's
+ * iterator is invoked. In some cases, this approach has better performance
+ * than {@link AbstractCollection#removeAll}.
+ */
+ @Override public boolean retainAll(Collection<?> elementsToRetain) {
+ checkNotNull(elementsToRetain);
+ Iterator<Entry<E>> entries = entrySet().iterator();
+ boolean modified = false;
+ while (entries.hasNext()) {
+ Entry<E> entry = entries.next();
+ if (!elementsToRetain.contains(entry.getElement())) {
+ entries.remove();
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ /**
+ * Removes all of the elements from this multiset.
+ *
+ * <p>This implementation calls {@code clear} on {@link Multiset#entrySet()}.
+ */
+ @Override public void clear() {
+ entrySet().clear();
+ }
+
+ // Views
+
+ private transient volatile Set<E> elementSet;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned set's methods are implemented by calling
+ * {@link Multiset#entrySet()} methods.
+ */
+ 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}.
+ */
+ protected Set<E> createElementSet() {
+ return new ElementSet();
+ }
+
+ private class ElementSet extends AbstractSet<E> {
+ @Override public Iterator<E> iterator() {
+ final Iterator<Entry<E>> entryIterator = entrySet().iterator();
+ return new Iterator<E>() {
+ public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+ public E next() {
+ return entryIterator.next().getElement();
+ }
+ public void remove() {
+ entryIterator.remove();
+ }
+ };
+ }
+ @Override public int size() {
+ return entrySet().size();
+ }
+ }
+
+ // Object methods
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation returns {@code true} if {@code other} 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 other) {
+ if (other instanceof Multiset) {
+ Multiset<?> that = (Multiset<?>) other;
+ /*
+ * 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 (this.size() != that.size()) {
+ return false;
+ }
+
+ for (Entry<?> entry : that.entrySet()) {
+ if (count(entry.getElement()) != entry.getCount()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@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/plugins/com.google.collect/src/com/google/common/collect/AbstractMultisetEntry.java b/plugins/com.google.collect/src/com/google/common/collect/AbstractMultisetEntry.java
new file mode 100644
index 0000000..595f83b
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/AbstractMultisetEntry.java
@@ -0,0 +1,66 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Multiset.Entry;
+
+/**
+ * Implementation of the {@code equals}, {@code hashCode}, and {@code toString}
+ * methods of {@link Entry}.
+ *
+ * @author Mike Bostock
+ */
+public abstract class AbstractMultisetEntry<E> implements Entry<E> {
+ /**
+ * Indicates whether an object equals this entry, following the behavior
+ * specified in {@link Entry#equals}.
+ */
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof Entry)) {
+ return false;
+ }
+ Entry<?> e = (Entry<?>) o;
+ return Objects.equal(e.getElement(), getElement())
+ && (e.getCount() == getCount());
+ }
+
+ /**
+ * Return this entry's hash code, following the behavior specified in
+ * {@link 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);
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/AbstractRemovableIterator.java b/plugins/com.google.collect/src/com/google/common/collect/AbstractRemovableIterator.java
new file mode 100644
index 0000000..9221506
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/AbstractRemovableIterator.java
@@ -0,0 +1,56 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * A specialization of {@code AbstractIterator} for data sources which can
+ * handle arbitrary removal by element, concurrently with iteration. Subclasses
+ * must implement both the {@link AbstractIterator#computeNext} and {@link
+ * #remove(Object)} methods.
+ *
+ * @author Kevin Bourrillion
+ */
+public abstract class AbstractRemovableIterator<T> extends AbstractIterator<T> {
+ private T elementToRemove;
+ private boolean canRemove;
+
+ /** Removes {@code element} from the backing data source. */
+ protected abstract void remove(T element);
+
+ @Override public T next() {
+ T element = super.next();
+ canRemove = true;
+ elementToRemove = element;
+ return element;
+ }
+
+ /**
+ * Removes from the underlying collection the last element returned by the
+ * iterator.
+ */
+ @Override public void remove() {
+ checkState(canRemove, "no calls to next() since the last call to remove()");
+ try {
+ remove(elementToRemove);
+ } finally {
+ elementToRemove = null;
+ canRemove = false;
+ }
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ArrayListMultimap.java b/plugins/com.google.collect/src/com/google/common/collect/ArrayListMultimap.java
new file mode 100644
index 0000000..5d78567
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ArrayListMultimap.java
@@ -0,0 +1,129 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+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;
+
+/**
+ * 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>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}.
+ *
+ * @author Jared Levy
+ */
+public final class ArrayListMultimap<K, V> extends StandardListMultimap<K, V> {
+ // Default from ArrayList
+ /*@VisibleForTesting*/ static final int DEFAULT_CAPACITY = 10;
+
+ /*@VisibleForTesting*/ transient int initialListCapacity;
+
+ /** Constructs an empty {@code ArrayListMultimap}. */
+ public ArrayListMultimap() {
+ super(new HashMap<K, Collection<V>>());
+ initialListCapacity = DEFAULT_CAPACITY;
+ }
+
+ /**
+ * Constructs an empty {@code ArrayListMultimap} with the expected number of
+ * distinct keys and the expected number of values per distinct key.
+ *
+ * @param distinctKeys the expected number of distinct keys
+ * @param valuesPerKey the expected number of values per distinct key
+ * @throws IllegalArgumentException if either argument is negative
+ */
+ public ArrayListMultimap(int distinctKeys, int valuesPerKey) {
+ super(new HashMap<K, Collection<V>>(Maps.capacity(distinctKeys)));
+ checkArgument(valuesPerKey >= 0);
+ initialListCapacity = valuesPerKey;
+ }
+
+ /**
+ * Constructs an {@code ArrayListMultimap} with the same mappings as the
+ * specified {@code Multimap}.
+ */
+ public ArrayListMultimap(Multimap<? extends K, ? extends V> multimap) {
+ this(multimap.keySet().size(),
+ (multimap instanceof ArrayListMultimap) ?
+ ((ArrayListMultimap<?, ?>) multimap).initialListCapacity :
+ DEFAULT_CAPACITY);
+ 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>(initialListCapacity);
+ }
+
+ /**
+ * 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 initial list capacity, number of distinct keys, and then for
+ * each distinct key: the key, number of values for that key, and the
+ * key's values
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeInt(initialListCapacity);
+ Serialization.writeMultimap(this, stream);
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ setMap(new HashMap<K, Collection<V>>());
+ initialListCapacity = stream.readInt();
+ Serialization.populateMultimap(this, stream);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/BiMap.java b/plugins/com.google.collect/src/com/google/common/collect/BiMap.java
new file mode 100644
index 0000000..421cc00
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/BiMap.java
@@ -0,0 +1,97 @@
+/*
+ * 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.collect;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 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.
+ *
+ * @author Kevin Bourrillion
+ */
+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.
+ */
+ V put(K key, 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(K key, 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.
+ */
+ 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.
+ */
+ 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/plugins/com.google.collect/src/com/google/common/collect/ClassToInstanceMap.java b/plugins/com.google.collect/src/com/google/common/collect/ClassToInstanceMap.java
new file mode 100644
index 0000000..40524a9
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ClassToInstanceMap.java
@@ -0,0 +1,55 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.util.Map;
+
+/**
+ * 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.
+ *
+ * @param <B> the common supertype that all entries must share; often this is
+ * simply {@link Object}
+ *
+ * @author Kevin Bourrillion
+ */
+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/plugins/com.google.collect/src/com/google/common/collect/Collections2.java b/plugins/com.google.collect/src/com/google/common/collect/Collections2.java
new file mode 100644
index 0000000..ad9455f
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Collections2.java
@@ -0,0 +1,300 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Predicate;
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Provides static methods for working with {@code Collection} instances.
+ *
+ * @author Chris Povirk
+ * @author Mike Bostock
+ * @author Jared Levy
+ */
+public final class Collections2 {
+ private Collections2() {}
+
+ /**
+ * Returns a limited {@link Collection} view of the given {@link Iterable}, or
+ * the {@code Iterable} itself if it is already a {@code Collection} (in which
+ * case the rest of this documentation does not apply). The returned
+ * collection is not appropriate for general use for a number of reasons.
+ * Instead, it exists to provide frequently desired methods for dealing with
+ * {@code Iterable} objects -- such as
+ * {@link Collection#removeAll(Collection)} -- through the familiar
+ * {@code Collection} interface. To treat the contents of an {@code Iterable}
+ * as a full-fledged, performant {@code Collection}, it is recommended that
+ * clients call a method like {@link ImmutableSet#copyOf(Iterable)} or
+ * {@link Iterables#addAll(Collection, Iterable)} to dump the contents of the
+ * {@code Iterable} into a standard {@code Collection}. For cases in which a
+ * view of the {@code Iterable} is required, {@code forIterable()} is
+ * available.
+ *
+ * <p>A number of limitations result from building on the {@code Iterable}
+ * interface. Notably, {@code size()}, {@code contains()}, and many other
+ * methods of the returned collection are O(n). The returned collection does
+ * not support the insertion of items. Removal of elements is supported if the
+ * underlying {@code Iterable} supports it, and all non-mutative operations
+ * are supported. Additionally, each method call on the returned collection
+ * calls {@link Iterable#iterator()} on the source {@code Iterable}. Thus, if
+ * you wish to call more than one method on the collection or to otherwise
+ * access the contents of the {@code Iterable} after calling a method, the
+ * {@code Iterable} must support the creation of multiple iterators.
+ *
+ * <p>{@link #equals(Object)} and {@link #hashCode()} are inherited from
+ * {@link Object}, as the returned {@code Collection} is not an implementation
+ * of any additional interface, such as {@link java.util.List} or
+ * {@link java.util.Set}.
+ *
+ * <p>The behavior of the returned collection's iterator in the face of
+ * concurrent structural modification of the returned collection or of the
+ * underlying {@code Iterable} is undefined, and no guarantee is made that the
+ * objects are fail-fast.
+ *
+ * <p><b>Usage Example</b>
+ *
+ * <pre>
+ * // Remove all instances of "foo" from an Iterable:
+ * Collections2.forIterable(iterable).removeAll(ImmutableSet.of("foo"));
+ * </pre>
+ */
+ public static <T> Collection<T> forIterable(final Iterable<T> iterable) {
+ checkNotNull(iterable);
+
+ if (iterable instanceof Collection) {
+ return (Collection<T>) iterable;
+ }
+
+ return new AbstractCollection<T>() {
+ @Override public Iterator<T> iterator() {
+ return iterable.iterator();
+ }
+
+ @Override public int size() {
+ return Iterables.size(iterable);
+ }
+
+ @Override public boolean isEmpty() {
+ return Iterables.isEmpty(iterable);
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ return Iterators.removeAll(iterator(), c);
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ return Iterators.retainAll(iterator(), c);
+ }
+ };
+ }
+
+ /**
+ * 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}
+ */
+ // TODO: Make public?
+ static boolean containsAll(Collection<?> self, Collection<?> c) {
+ checkNotNull(self);
+ for (Object o : c) {
+ if (!self.contains(o)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 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 same iteration order.
+ */
+ static <E> Collection<E> toCollection(Iterable<E> iterable) {
+ return (iterable instanceof Collection)
+ ? (Collection<E>) iterable : Lists.newArrayList(iterable);
+ }
+
+ /**
+ * 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. The collection's
+ * {@code add()} and {@code addAll()} methods throw an
+ * {@link IllegalArgumentException} if an element that doesn't satisfy the
+ * predicate is provided. 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 the filtered collection and use the copy.
+ *
+ * <p>The {@code clear()}, {@code removeAll()}, and {@code retainAll()}
+ * methods all call {@link Iterator#remove()} on the underlying collection's
+ * iterator. Consequently, methods like the following throw an
+ * {@link UnsupportedOperationException}.
+ * <pre> Collections2.filter(Collections2.filter(collection, predicate1),
+ * predicate2)).clear();</pre>
+ * Instead, call
+ * {@link com.google.common.base.Predicates#and(Predicate, Predicate)} to
+ * combine the predicates and pass the combined predicate to this method.
+ *
+ */
+ public static <T> Collection<T> filter(
+ Collection<T> unfiltered, Predicate<? super T> predicate) {
+ return new FilteredCollection<T>(unfiltered, predicate);
+ }
+
+ static class FilteredCollection<T> implements Collection<T> {
+ private final Collection<T> unfiltered;
+ private final Predicate<? super T> predicate;
+
+ FilteredCollection(Collection<T> unfiltered,
+ Predicate<? super T> predicate) {
+ this.unfiltered = checkNotNull(unfiltered);
+ this.predicate = checkNotNull(predicate);
+ }
+
+ public boolean add(T element) {
+ checkArgument(predicate.apply(element));
+ return unfiltered.add(element);
+ }
+
+ public boolean addAll(Collection<? extends T> collection) {
+ for (T element : collection) {
+ checkArgument(predicate.apply(element));
+ }
+ return unfiltered.addAll(collection);
+ }
+
+ public void clear() {
+ Iterator<T> iterator = unfiltered.iterator();
+ while (iterator.hasNext()) {
+ T element = iterator.next();
+ if (predicate.apply(element)) {
+ iterator.remove();
+ }
+ }
+ }
+
+ // if a ClassCastException occurs, contains() returns false
+ @SuppressWarnings("unchecked")
+ public boolean contains(Object element) {
+ try {
+ return predicate.apply((T) element) && unfiltered.contains(element);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ public boolean containsAll(Collection<?> collection) {
+ for (Object element : collection) {
+ if (!contains(element)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isEmpty() {
+ return !Iterators.any(unfiltered.iterator(), predicate);
+ }
+
+ public Iterator<T> iterator() {
+ return Iterators.filter(unfiltered.iterator(), predicate);
+ }
+
+ // if a ClassCastException occurs, remove() returns false
+ @SuppressWarnings("unchecked")
+ public boolean remove(Object element) {
+ try {
+ return predicate.apply((T) element) && unfiltered.remove(element);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ public boolean removeAll(Collection<?> collection) {
+ checkNotNull(collection);
+ boolean changed = false;
+ Iterator<T> iterator = unfiltered.iterator();
+ while (iterator.hasNext()) {
+ T element = iterator.next();
+ if (predicate.apply(element) && collection.contains(element)) {
+ iterator.remove();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ public boolean retainAll(Collection<?> collection) {
+ checkNotNull(collection);
+ boolean changed = false;
+ Iterator<T> iterator = unfiltered.iterator();
+ while (iterator.hasNext()) {
+ T element = iterator.next();
+ if (predicate.apply(element) && !collection.contains(element)) {
+ iterator.remove();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ public int size() {
+ return Iterators.size(iterator());
+ }
+
+ public Object[] toArray() {
+ // creating an ArrayList so filtering happens once
+ return Lists.newArrayList(iterator()).toArray();
+ }
+
+ public <T> T[] toArray(T[] array) {
+ return Lists.newArrayList(iterator()).toArray(array);
+ }
+
+ @Override public String toString() {
+ return Iterators.toString(iterator());
+ }
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Comparators.java b/plugins/com.google.collect/src/com/google/common/collect/Comparators.java
new file mode 100644
index 0000000..9c99498
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Comparators.java
@@ -0,0 +1,896 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkContentsNotNull;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Function;
+import com.google.common.base.Nullable;
+import com.google.common.base.Objects;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Standard comparators and utilities for creating and working with comparators.
+ *
+ * <p>Some of these methods return an {@link Ordering}, a serializable class
+ * that implements {@link Comparator} and includes many additional methods.
+ *
+ * <p>Several method signatures include {@code <C extends Comparable>} with a
+ * raw {@link Comparable}, instead of
+ * {@code <C extends Comparable<? super C>}. That's necessary to support classes
+ * defined without generics.
+ *
+ * @author Jared Levy
+ * @author Kevin Bourrillion
+ * @author Mike Bostock
+ */
+public final class Comparators {
+ private Comparators() {}
+
+ /**
+ * Returns a comparator that uses the natural ordering of the values. The
+ * comparator throws a {@link NullPointerException} when passed a null
+ * parameter.
+ */
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ public static <T extends Comparable> Ordering<T> naturalOrder() {
+ return (Ordering<T>) NATURAL_ORDER;
+ }
+
+ /** @see #naturalOrder */
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ private static final Ordering<Comparable> NATURAL_ORDER
+ = new NaturalOrdering();
+
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ private static class NaturalOrdering extends Ordering<Comparable> {
+ public int compare(Comparable left, Comparable right) {
+ checkNotNull(right); // later code throws NPE when only left is null
+ if (left == right) {
+ return 0;
+ }
+
+ /*
+ * compareTo() may throw a ClassCastException if the elements are not
+ * mutually comparable.
+ */
+ int result = left.compareTo(right);
+ return result;
+ }
+
+ // preserve singleton-ness, so equals() and hashCode() work correctly
+ private Object readResolve() {
+ return NATURAL_ORDER;
+ }
+
+ @Override public String toString() {
+ return "naturalOrder()";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a comparator that treats {@code null} as less than all other
+ * values and uses {@code comparator} to compare non-null values.
+ */
+ public static <T> Ordering<T> nullLeastOrder(Comparator<T> comparator) {
+ checkNotNull(comparator);
+ return new NullLeastOrdering<T>(comparator);
+ }
+
+ private static class NullLeastOrdering<T> extends NullHandlingOrdering<T> {
+ NullLeastOrdering(Comparator<T> comparator) {
+ super(comparator);
+ }
+
+ @Override int compareNullAndNonNull() {
+ return -1;
+ }
+
+ @Override public String toString() {
+ return "nullLeastOrder(" + comparator + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a comparator that uses the natural ordering of the values, but also
+ * handles null values, treating them as less than all other values.
+ */
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ public static <T extends Comparable> Ordering<T> nullLeastOrder() {
+ return (Ordering<T>) NULL_LEAST_ORDER;
+ }
+
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ private static final Ordering<Comparable> NULL_LEAST_ORDER
+ = new NaturalNullLeastOrder();
+
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ private static class NaturalNullLeastOrder
+ extends NullLeastOrdering<Comparable> {
+ private NaturalNullLeastOrder() {
+ super(NATURAL_ORDER);
+ }
+
+ // preserve singleton-ness
+ private Object readResolve() {
+ return NULL_LEAST_ORDER;
+ }
+
+ @Override public String toString() {
+ return "nullLeastOrder()";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a comparator that treats {@code null} as greater than all other
+ * values and uses the given comparator to compare non-null values.
+ */
+ public static <T> Ordering<T> nullGreatestOrder(Comparator<T> comparator) {
+ checkNotNull(comparator);
+ return new NullGreatestOrdering<T>(comparator);
+ }
+
+ private static class NullGreatestOrdering<T> extends NullHandlingOrdering<T> {
+ NullGreatestOrdering(Comparator<T> comparator) {
+ super(comparator);
+ }
+
+ @Override int compareNullAndNonNull() {
+ return 1;
+ }
+
+ @Override public String toString() {
+ return "nullGreatestOrder(" + comparator + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a comparator that uses the natural ordering of the values, but also
+ * handles null values, treating them as greater than all other values.
+ */
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ public static <T extends Comparable> Ordering<T> nullGreatestOrder() {
+ return (Ordering<T>) NULL_GREATEST_ORDER;
+ }
+
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ private static final Ordering<Comparable> NULL_GREATEST_ORDER
+ = new NaturalNullGreatestOrder();
+
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ private static class NaturalNullGreatestOrder
+ extends NullGreatestOrdering<Comparable> {
+ private NaturalNullGreatestOrder() {
+ super(NATURAL_ORDER);
+ }
+
+ // preserve singleton-ness
+ private Object readResolve() {
+ return NULL_GREATEST_ORDER;
+ }
+
+ @Override public String toString() {
+ return "nullGreatestOrder()";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static abstract class NullHandlingOrdering<T> extends Ordering<T> {
+ final Comparator<T> comparator;
+
+ public NullHandlingOrdering(Comparator<T> comparator) {
+ this.comparator = comparator;
+ }
+
+ public int compare(T left, T right) {
+ if (left == right) {
+ return 0;
+ }
+ if (left == null) {
+ return compareNullAndNonNull();
+ }
+ if (right == null) {
+ return -compareNullAndNonNull();
+ }
+ return comparator.compare(left, right);
+ }
+
+ /**
+ * Returns the value this comparator should produce when comparing {@code
+ * null} to any non-null value (in that order).
+ */
+ abstract int compareNullAndNonNull();
+
+ @Override public boolean equals(Object object) {
+ if (object == null) {
+ return false;
+ }
+ if (object instanceof NullHandlingOrdering) {
+ NullHandlingOrdering<?> that = (NullHandlingOrdering<?>) object;
+ return (this.compareNullAndNonNull() == that.compareNullAndNonNull())
+ && this.comparator.equals(that.comparator);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return comparator.hashCode();
+ }
+ }
+
+ /**
+ * Returns a comparator which tries two comparators in order until a non-zero
+ * result is found, returning that result, and returning zero only if both
+ * comparators return zero.
+ *
+ * @param first the first comparator to invoke
+ * @param second the second comparator to invoke
+ * @see #compound(Iterable)
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Ordering<T> compound(Comparator<? super T> first,
+ Comparator<? super T> second) {
+ Comparator<T> firstT = (Comparator<T>) first;
+ Comparator<T> secondT = (Comparator<T>) second;
+ return compound(Arrays.asList(firstT, secondT));
+ }
+
+ /**
+ * Returns a comparator which tries three comparators in order until a
+ * non-zero result is found, returning that result, and returning zero only if
+ * all comparators return zero.
+ *
+ * @param first the first comparator to invoke
+ * @param second the second comparator to invoke
+ * @param third the third comparator to invoke
+ * @see #compound(Iterable)
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Ordering<T> compound(Comparator<? super T> first,
+ Comparator<? super T> second, Comparator<? super T> third) {
+ Comparator<T> firstT = (Comparator<T>) first;
+ Comparator<T> secondT = (Comparator<T>) second;
+ Comparator<T> thirdT = (Comparator<T>) third;
+ return compound(Arrays.asList(firstT, secondT, thirdT));
+ }
+
+ /**
+ * Returns a comparator which tries four comparators in order until a non-zero
+ * result is found, returning that result, and returning zero only if all
+ * comparators return zero.
+ *
+ * @param first the first comparator to invoke
+ * @param second the second comparator to invoke
+ * @param third the third comparator to invoke
+ * @param forth the fourth comparator to invoke
+ * @see #compound(Iterable)
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Ordering<T> compound(Comparator<? super T> first,
+ Comparator<? super T> second, Comparator<? super T> third,
+ Comparator<? super T> forth) {
+ Comparator<T> firstT = (Comparator<T>) first;
+ Comparator<T> secondT = (Comparator<T>) second;
+ Comparator<T> thirdT = (Comparator<T>) third;
+ Comparator<T> forthT = (Comparator<T>) forth;
+ return compound(Arrays.asList(firstT, secondT, thirdT, forthT));
+ }
+
+ /**
+ * Returns a comparator 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.
+ *
+ * <p>Subsequent changes to the {@code rest} array do not affect the behavior
+ * of the returned comparator.
+ *
+ * @param first the first comparator to invoke
+ * @param second the second comparator to invoke
+ * @param third the third comparator to invoke
+ * @param forth the fourth comparator to invoke
+ * @param rest additional comparators to invoke as necessary
+ * @see #compound(Iterable)
+ */
+ @SuppressWarnings("unchecked") // TODO: check that this is right
+ public static <T> Ordering<T> compound(Comparator<? super T> first,
+ Comparator<? super T> second, Comparator<? super T> third,
+ Comparator<? super T> forth, Comparator<? super T>... rest) {
+ // TODO: is this really the best way? if so, explain why.
+ Comparator<T> firstT = (Comparator<T>) first;
+ Comparator<T> secondT = (Comparator<T>) second;
+ Comparator<T> thirdT = (Comparator<T>) third;
+ Comparator<T> forthT = (Comparator<T>) forth;
+ List<Comparator<T>> list = Lists.newArrayList(
+ firstT, secondT, thirdT, forthT);
+ list.addAll(Arrays.asList((Comparator<T>[]) rest));
+ return compound(list);
+ }
+
+ /**
+ * Returns a comparator 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.
+ *
+ * <p>The returned comparator is a "view" of the specified {@code Iterable}
+ * instance; changes to the iterable will be reflected in the behavior of the
+ * returned comparator.
+ *
+ * <p><b>Warning:</b> Supplying an argument with undefined iteration order,
+ * such as a {@link java.util.HashSet}, will produce non-deterministic
+ * results.
+ *
+ * @param comparators the comparators to try in order
+ */
+ public static <T> Ordering<T> compound(
+ Iterable<? extends Comparator<? super T>> comparators) {
+ return new CompoundOrder<T>(comparators);
+ }
+
+ /** @see Comparators#compound(Iterable) */
+ static class CompoundOrder<T> extends Ordering<T> {
+ private final Iterable<? extends Comparator<? super T>> comparators;
+
+ CompoundOrder(Iterable<? extends Comparator<? super T>> comparators) {
+ this.comparators = checkContentsNotNull(comparators);
+ }
+
+ public int compare(T left, T right) {
+ if (left == right) {
+ return 0;
+ }
+ for (Comparator<? super T> comparator : comparators) {
+ int result = comparator.compare(left, right);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return 0;
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object instanceof CompoundOrder) {
+ CompoundOrder<?> that = (CompoundOrder<?>) object;
+ return (this.comparators).equals(that.comparators);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return comparators.hashCode();
+ }
+
+ @Override public String toString() {
+ return "compound(" + comparators + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Creates a comparator that compares any two items by applying a function to
+ * each of them and using the natural ordering of the results.
+ *
+ * @param function the function returning the value to compare. The function
+ * should never return {@code null}.
+ * @return the generated comparator
+ */
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ public static <F, T extends Comparable> Ordering<F>
+ fromFunction(Function<F, T> function) {
+ return new TransformingNaturalOrder<F, T>(function);
+ }
+
+ /** @see Comparators#fromFunction(Function) */
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ private static class TransformingNaturalOrder<F, T extends Comparable>
+ extends Ordering<F> {
+ private final Function<F, T> function;
+
+ TransformingNaturalOrder(Function<F, T> function) {
+ this.function = checkNotNull(function);
+ }
+
+ public int compare(F left, F right) {
+ T leftTransformed = function.apply(left);
+ T rightTransformed = function.apply(right);
+
+ /*
+ * Let this throw a ClassCastException if T is a bizarre Comparable that
+ * can't be compared to itself.
+ */
+ return leftTransformed.compareTo(rightTransformed);
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object instanceof TransformingNaturalOrder) {
+ TransformingNaturalOrder<?, ?> that
+ = (TransformingNaturalOrder<?, ?>) object;
+ return (this.function).equals(that.function);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return function.hashCode();
+ }
+
+ @Override public String toString() {
+ return "fromFunction(" + function + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Creates a comparator that compares any two items by applying a function to
+ * each of them and using the supplied comparator to compare the results.
+ *
+ * @param function the function returning the value to compare
+ * @param comparator the comparator that receives the function output
+ * @return the generated comparator
+ */
+ public static <F, T> Ordering<F> fromFunction(
+ Function<F, T> function, Comparator<? super T> comparator) {
+ return new TransformingOrder<F, T>(function, comparator);
+ }
+
+ /** @see Comparators#fromFunction(Function,Comparator) */
+ private static class TransformingOrder<F, T> extends Ordering<F> {
+ private final Function<F, T> function;
+ private final Comparator<? super T> comparator;
+
+ TransformingOrder(
+ Function<F, T> function, Comparator<? super T> comparator) {
+ this.function = checkNotNull(function);
+ this.comparator = checkNotNull(comparator);
+ }
+
+ public int compare(F left, F right) {
+ return comparator.compare(function.apply(left), function.apply(right));
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object instanceof TransformingOrder) {
+ TransformingOrder<?, ?> that = (TransformingOrder<?, ?>) object;
+ return (this.function).equals(that.function)
+ && (this.comparator).equals(that.comparator);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hashCode(function, comparator);
+ }
+
+ @Override public String toString() {
+ return "fromFunction(" + function + ", " + comparator + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * A comparator that compares objects by the natural ordering of their string
+ * representations as returned by {@code toString()}. It does not support null
+ * values.
+ *
+ * <p>TODO: Deprecate this in favor of {@link #toStringOrder}.
+ */
+ public static final Ordering<Object> STRING_FORM_ORDER = new ToStringOrder();
+
+ private static class ToStringOrder extends Ordering<Object> {
+ public int compare(Object o1, Object o2) {
+ return o1.toString().compareTo(o2.toString());
+ }
+
+ // preserve singleton-ness, so equals() and hashCode() work correctly
+ private Object readResolve() {
+ return STRING_FORM_ORDER;
+ }
+
+ @Override public String toString() {
+ return "toStringOrder()";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns a comparator that compares objects by the natural ordering of their
+ * string representations as returned by {@code toString()}. It does not
+ * support null values.
+ */
+ @SuppressWarnings("unchecked") // casting STRING_FORM_ORDER
+ public static final <T> Ordering<T> toStringOrder() {
+ return (Ordering<T>) STRING_FORM_ORDER;
+ }
+
+ /**
+ * Returns the smaller of the two values, according to their natural ordering.
+ * If the values are equal, the first is returned.
+ *
+ * <p>To handle more than two values, call
+ * {@link Ordering#min(Object, Object, Object, Object...)} or
+ * {@link Ordering#min(Iterable)} on the {@link Ordering} returned by
+ * {@link Ordering#natural()}.
+ *
+ * @param a non-null value to compare, returned if less than or equal to b.
+ * @param b non-null value to compare.
+ * @throws ClassCastException if the parameters are not mutually comparable
+ * (for example, a string and an integer).
+ */
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ public static <T extends Comparable> T min(T a, T b) {
+ /*
+ * Let this throw a ClassCastException if T is a bizarre Comparable that
+ * can't be compared to itself, as documented.
+ */
+ int result = a.compareTo(b);
+ return result <= 0 ? a : b;
+ }
+
+ /**
+ * Returns the larger of the two values, according to their natural ordering.
+ * If the values are equal, the first is returned.
+ *
+ * <p>To handle more than two values, call
+ * {@link Ordering#max(Object, Object, Object, Object...)} or
+ * {@link Ordering#max(Iterable)} on the {@link Ordering} returned by
+ * {@link Ordering#natural()}.
+ *
+ * @param a non-null value to compare, returned if greater than or equal to b.
+ * @param b non-null value to compare.
+ * @throws ClassCastException if the parameters are not mutually comparable
+ * (for example, a string and an integer).
+ */
+ @SuppressWarnings("unchecked") // see explanation in class Javadoc
+ public static <T extends Comparable> T max(T a, T b) {
+ /*
+ * Let this throw a ClassCastException if T is a bizarre Comparable that
+ * can't be compared to itself, as documented.
+ */
+ int result = a.compareTo(b);
+ return result >= 0 ? a : b;
+ }
+
+ /**
+ * Returns the smaller of the two values according to the specified
+ * comparator. If the values are equal, the first is returned. Null values
+ * are allowed if the comparator supports them.
+ *
+ * <p>To handle more than two values, call
+ * {@link Ordering#min(Object, Object, Object, Object...)} or
+ * {@link Ordering#min(Iterable)} on the {@link Ordering} returned by
+ * {@link Ordering#forComparator(Comparator)}.
+ *
+ * @param comparator comparator that compares the two values
+ * @param a value to compare, returned if less than or equal to b
+ * @param b value to compare
+ */
+ public static <T> T min(Comparator<? super T> comparator, @Nullable T a,
+ @Nullable T b) {
+ return comparator.compare(a, b) <= 0 ? a : b;
+ }
+
+ /**
+ * Returns the larger of the two values according to the specified comparator.
+ * If the values are equal, the first is returned. Null values are allowed if
+ * the comparator supports them.
+ *
+ * <p>To handle more than two values, call
+ * {@link Ordering#max(Object, Object, Object, Object...)} or
+ * {@link Ordering#max(Iterable)} on the {@link Ordering} returned by
+ * {@link Ordering#forComparator(Comparator)}.
+ *
+ * @param comparator comparator that compares the two values
+ * @param a value to compare, returned if greater than or equal to b
+ * @param b value to compare
+ */
+ public static <T> T max(Comparator<? super T> comparator, @Nullable T a,
+ @Nullable T b) {
+ return comparator.compare(a, b) >= 0 ? a : b;
+ }
+
+ /**
+ * Returns a comparator 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 supported.
+ *
+ * <p>The returned comparator throws an {@link ClassCastException} when it
+ * receives an input parameter that isn't in {@code valuesInOrder}.
+ *
+ * @param valuesInOrder the values that the returned comparator will be able
+ * to compare, in the order the comparator should follow
+ * @return the comparator described above
+ * @throws IllegalArgumentException if {@code valuesInOrder} contains any
+ * non-consecutive duplicate values (according to {@link Object#equals})
+ */
+ public static <T> Ordering<T> givenOrder(List<? extends T> valuesInOrder) {
+ return new GivenOrder<T>(valuesInOrder);
+ }
+
+ /**
+ * Returns the comparator 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 supported.
+ *
+ * <p>The returned comparator throws a {@link ClassCastException} when it
+ * receives an input parameter that isn't equal to {@code leastValue}
+ * or in {@code remainingValuesInOrder}.
+ *
+ * @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 IllegalArgumentException if any non-consecutive duplicate values
+ * (according to {@link Object#equals}) are present among the method
+ * arguments
+ */
+ public static <T> Ordering<T> givenOrder(
+ @Nullable T leastValue, T... remainingValuesInOrder) {
+ return givenOrder(Lists.asList(leastValue, remainingValuesInOrder));
+ }
+
+ /** @see Comparators#givenOrder(List) */
+ private static class GivenOrder<T> extends Ordering<T> {
+ final Map<T, Integer> rankMap;
+
+ GivenOrder(List<? extends T> valuesInOrder) {
+ rankMap = buildRankMap(valuesInOrder);
+ }
+
+ public int compare(T left, T right) {
+ return rank(left) - rank(right); // safe because both are nonnegative
+ }
+
+ int rank(T value) {
+ Integer rank = rankMap.get(value);
+ if (rank == null) {
+ throw new IncomparableValueException(value);
+ }
+ return rank;
+ }
+
+ static <T> Map<T, Integer> buildRankMap(
+ Collection<? extends T> valuesInOrder) {
+ Map<T, Integer> ranks
+ = Maps.newHashMapWithExpectedSize(valuesInOrder.size());
+ T previousValue = null;
+ int rank = 0;
+ for (T value : valuesInOrder) {
+ if ((rank == 0) || !Objects.equal(value, previousValue)) {
+ Integer priorRank = ranks.put(value, rank);
+ if (priorRank != null) {
+ throw new DuplicateValueException(value, priorRank, rank);
+ }
+ }
+ rank++;
+ previousValue = value;
+ }
+ return ranks;
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object instanceof GivenOrder) {
+ GivenOrder<?> that = (GivenOrder<?>) object;
+ return (this.rankMap).equals(that.rankMap);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return rankMap.hashCode();
+ }
+
+ @Override public String toString() {
+ return "givenOrder(" + rankMap + ")";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Exception thrown by a {@link #givenOrder(List)} or
+ * {@link #givenOrder(Object, Object...)} comparator when comparing a value
+ * outside the set of values it can compare. Extending
+ * {@link ClassCastException} may seem odd, but it fits the spirit of the
+ * {@link Comparator#compare} specification, if you consider that we are
+ * handling what is conceptually a "subtype" of {@code T}.
+ */
+ 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;
+ }
+
+ /**
+ * Exception thrown when a duplicate value is found in a list or array which
+ * is not expected to contain any.
+ */
+ static class DuplicateValueException extends IllegalArgumentException {
+ private static final long serialVersionUID = 0;
+ final Object value;
+ final int firstIndex;
+ final int secondIndex;
+
+ DuplicateValueException(Object value, int firstIndex, int secondIndex) {
+ super(String.format("Duplicate value at indices %s and %s: %s",
+ firstIndex, secondIndex, value));
+ this.value = value;
+ this.firstIndex = firstIndex;
+ this.secondIndex = secondIndex;
+ }
+ }
+
+ /**
+ * Compares the two specified {@code byte} values. The sign of the value
+ * returned is the same as that of the value that would be returned by the
+ * call:
+ *
+ * <pre> Byte.valueOf(a).compareTo(Byte.valueOf(b))</pre>
+ *
+ * @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}; otherwise zero.
+ */
+ public static int compare(byte a, byte b) {
+ return (a < b) ? -1 : ((a > b) ? 1 : 0);
+ }
+
+ /**
+ * Compares the two specified {@code char} values. The sign of the value
+ * returned is the same as that of the value that would be returned by the
+ * call:
+ *
+ * <pre> Character.valueOf(a).compareTo(Character.valueOf(b))</pre>
+ *
+ * @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}; otherwise zero.
+ */
+ public static int compare(char a, char b) {
+ return (a < b) ? -1 : ((a > b) ? 1 : 0);
+ }
+
+ /**
+ * Compares the two specified {@code short} values. The sign of the value
+ * returned is the same as that of the value that would be returned by the
+ * call:
+ *
+ * <pre> Short.valueOf(a).compareTo(Short.valueOf(b))</pre>
+ *
+ * @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}; otherwise zero.
+ */
+ public static int compare(short a, short b) {
+ return (a < b) ? -1 : ((a > b) ? 1 : 0);
+ }
+
+ /**
+ * Compares the two specified {@code int} values. The sign of the value
+ * returned is the same as that of the value that would be returned by the
+ * call:
+ *
+ * <pre> Integer.valueOf(a).compareTo(Integer.valueOf(b))</pre>
+ *
+ * @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}; otherwise zero.
+ */
+ public static int compare(int a, int b) {
+ return (a < b) ? -1 : ((a > b) ? 1 : 0);
+ }
+
+ /**
+ * Compares the two specified {@code long} values. The sign of the value
+ * returned is the same as that of the value that would be returned by the
+ * call:
+ *
+ * <pre> Long.valueOf(a).compareTo(Long.valueOf(b))</pre>
+ *
+ * @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}; otherwise zero.
+ */
+ public static int compare(long a, long b) {
+ return (a < b) ? -1 : ((a > b) ? 1 : 0);
+ }
+
+ /**
+ * Compares the two specified {@code double} values. The sign of the value
+ * returned is the same as that of the value that would be returned by the
+ * call:
+ *
+ * <pre> Double.valueOf(a).compareTo(Double.valueOf(b))</pre>
+ *
+ * @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}; otherwise zero.
+ * @see Double#compare
+ */
+ public static int compare(double a, double b) {
+ return Double.compare(a, b); // takes care of Double.NaN
+ }
+
+ /**
+ * Compares the two specified {@code float} values. The sign of the value
+ * returned is the same as that of the value that would be returned by the
+ * call:
+ *
+ * <pre> Float.valueOf(a).compareTo(Float.valueOf(b))</pre>
+ *
+ * @param a the first {@code float} to compare
+ * @param b the second {@code float} 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}; otherwise zero.
+ * @see Float#compare
+ */
+ public static int compare(float a, float b) {
+ return Float.compare(a, b); // takes care of Float.NaN
+ }
+
+ /**
+ * Compares the two specified {@code boolean} values. The sign of the value
+ * returned is the same as that of the value that would be returned by the
+ * call:
+ *
+ * <pre> Boolean.valueOf(a).compareTo(Boolean.valueOf(b))</pre>
+ *
+ * @param a the first {@code boolean} to compare
+ * @param b the second {@code boolean} to compare
+ * @return a negative value if {@code a} is false and {@code b} is true; a
+ * positive value if {@code a} is true and {@code b} is false; otherwise
+ * zero.
+ */
+ public static int compare(boolean a, boolean b) {
+ return (a == b) ? 0 : (a ? 1 : -1);
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ConcurrentMultiset.java b/plugins/com.google.collect/src/com/google/common/collect/ConcurrentMultiset.java
new file mode 100644
index 0000000..6bd1766
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ConcurrentMultiset.java
@@ -0,0 +1,455 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Nullable;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.AbstractSet;
+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;
+
+/**
+ * A multiset that supports concurrent modifications and that provides atomic
+ * versions of most {@code Multiset} operations (exceptions where noted). Null
+ * elements are not supported.
+ *
+ * @author Cliff L. Biffle
+ */
+public final class ConcurrentMultiset<E> extends AbstractMultiset<E>
+ implements Serializable {
+ /*
+ * The ConcurrentMultiset's atomic operations are implemented in terms of
+ * ConcurrentMap's atomic operations. Many of them, such as add(E, int), are
+ * read-modify-write sequences, and so are implemented as loops that wrap
+ * ConcurrentMap's compare-and-set operations (like putIfAbsent).
+ */
+
+ /** The number of occurrences of each element. */
+ private transient final ConcurrentMap<E, Integer> countMap;
+
+ /**
+ * Creates an empty instance.
+ */
+ public ConcurrentMultiset() {
+ this(new ConcurrentHashMap<E, Integer>());
+ }
+
+ /**
+ * Creates an instance that contains the elements in a given collection.
+ */
+ public ConcurrentMultiset(Collection<? extends E> collection) {
+ this(new ConcurrentHashMap<E, Integer>(Maps.capacity(collection.size())));
+ addAll(collection);
+ }
+
+ /**
+ * 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
+ */
+ ConcurrentMultiset(ConcurrentMap<E, Integer> 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) {
+ try {
+ return unbox(countMap.get(element));
+ } catch (NullPointerException e) {
+ return 0;
+ } catch (ClassCastException e) {
+ return 0;
+ }
+ }
+
+ /**
+ * {@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 (Integer value : countMap.values()) {
+ sum += value;
+ }
+ return (int) Math.min(sum, Integer.MAX_VALUE);
+ }
+
+ /*
+ * 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 {@code true} if the collection changed as a result (this should
+ * always be the case unless {@code occurrences} is zero)
+ * @throws IllegalArgumentException if {@code occurrences} is negative, or if
+ * the resulting amount would exceed {@link Integer#MAX_VALUE}
+ */
+ @Override public boolean add(E element, int occurrences) {
+ if (occurrences == 0) {
+ return false;
+ }
+ checkArgument(occurrences > 0, "Invalid occurrences: %s", occurrences);
+
+ while (true) {
+ int current = count(element);
+ if (current == 0) {
+ if (countMap.putIfAbsent(element, occurrences) == null) {
+ return true;
+ }
+ } else {
+ checkArgument(occurrences <= Integer.MAX_VALUE - current,
+ "Overflow adding %s occurrences to a count of %s",
+ occurrences, current);
+ int next = current + occurrences;
+ if (countMap.replace(element, current, next)) {
+ return true;
+ }
+ }
+ // 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 this element to remove
+ * @return the number of occurrences that were successfully removed (zero if
+ * the element was not present)
+ * @throws IllegalArgumentException if {@code occurrences} is negative
+ */
+ @Override public int remove(@Nullable Object element, int occurrences) {
+ if (occurrences == 0) {
+ return 0;
+ }
+ checkArgument(occurrences > 0, "Invalid occurrences: %s", occurrences);
+
+ while (true) {
+ int current = count(element);
+ if (current == 0) {
+ return 0;
+ }
+ if (occurrences >= current) {
+ if (countMap.remove(element, current)) {
+ return current;
+ }
+ } else {
+ // We know it's an "E" because it already exists in the map.
+ @SuppressWarnings("unchecked")
+ E casted = (E) element;
+
+ if (countMap.replace(casted, current, current - occurrences)) {
+ return occurrences;
+ }
+ }
+ // If we're still here, there was a race, so just try again.
+ }
+ }
+
+ /**
+ * Removes <b>all</b> occurrences of the specified element from this multiset.
+ * This method complements {@link Multiset#remove(Object)}, which removes only
+ * one occurrence at a time.
+ *
+ * @param element the element whose occurrences should all be removed
+ * @return the number of occurrences successfully removed, possibly zero
+ */
+ @Override public int removeAllOccurrences(@Nullable Object element) {
+ try {
+ return unbox(countMap.remove(element));
+ } catch (NullPointerException e) {
+ return 0;
+ } catch (ClassCastException e) {
+ 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);
+
+ while (true) {
+ int current = count(element);
+ if (occurrences > current) {
+ return false;
+ }
+ if (occurrences == current) {
+ if (countMap.remove(element, occurrences)) {
+ return true;
+ }
+ } else {
+ @SuppressWarnings("unchecked") // it's in the map, must be an "E"
+ E casted = (E) element;
+ if (countMap.replace(casted, current, current - occurrences)) {
+ return true;
+ }
+ }
+ // If we're still here, there was a race, so just try again.
+ }
+ }
+ /**
+ * 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
+ */
+ public int setCount(E element, int count) {
+ checkArgument(count >= 0, "Invalid count: %s", count);
+ return (count == 0)
+ ? removeAllOccurrences(element)
+ : unbox(countMap.put(element, count));
+ }
+
+ /**
+ * Sets the number of occurrences of {@code element} to {@code newCount}, but
+ * only if the count is currently {@code oldCount}. If {@code element} does
+ * not appear in the multiset exactly {@code oldCount} 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 oldCount == newCount}, the method will return {@code true} if
+ * the condition was met.
+ * @throws IllegalArgumentException if {@code oldCount} or {@code newCount} is
+ * negative
+ */
+ public boolean setCount(E element, int oldCount, int newCount) {
+ checkArgument(oldCount >= 0, "Invalid oldCount: %s", oldCount);
+ checkArgument(newCount >= 0, "Invalid newCount: %s", newCount);
+ if (newCount == 0) {
+ if (oldCount == 0) {
+ // No change to make, but must return true if the element is not present
+ return !countMap.containsKey(element);
+ } else {
+ return countMap.remove(element, oldCount);
+ }
+ }
+ if (oldCount == 0) {
+ return countMap.putIfAbsent(element, newCount) == null;
+ }
+ return countMap.replace(element, oldCount, newCount);
+ }
+
+ // Views
+
+ @Override public Set<E> elementSet() {
+ return countMap.keySet();
+ }
+
+ private volatile transient EntrySet entrySet;
+
+ @Override public Set<Multiset.Entry<E>> entrySet() {
+ EntrySet result = entrySet;
+ if (result == null) {
+ entrySet = result = new EntrySet();
+ }
+ return result;
+ }
+
+ private class EntrySet extends AbstractSet<Multiset.Entry<E>> {
+ @Override public int size() {
+ return countMap.size();
+ }
+
+ @Override public boolean isEmpty() {
+ return countMap.isEmpty();
+ }
+
+ @Override public boolean contains(Object object) {
+ if (object instanceof Multiset.Entry) {
+ Multiset.Entry<?> entry = (Multiset.Entry<?>) object;
+ Object element = entry.getElement();
+ int entryCount = entry.getCount();
+ return entryCount > 0 && count(element) == entryCount;
+ }
+ return false;
+ }
+
+ @Override public Iterator<Multiset.Entry<E>> iterator() {
+ final Iterator<Map.Entry<E, Integer>> backingIterator
+ = countMap.entrySet().iterator();
+ return new Iterator<Multiset.Entry<E>>() {
+ public boolean hasNext() {
+ return backingIterator.hasNext();
+ }
+
+ public Multiset.Entry<E> next() {
+ Map.Entry<E, Integer> backingEntry = backingIterator.next();
+ return Multisets.immutableEntry(
+ backingEntry.getKey(), backingEntry.getValue());
+ }
+
+ public void remove() {
+ backingIterator.remove();
+ }
+ };
+ }
+
+ /*
+ * 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<Multiset.Entry<E>> snapshot() {
+ List<Multiset.Entry<E>> list = Lists.newArrayListWithExpectedSize(size());
+ for (Multiset.Entry<E> entry : this) {
+ list.add(entry);
+ }
+ 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();
+ return countMap.remove(element, entryCount);
+ }
+ return false;
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ return super.retainAll(checkNotNull(c));
+ }
+
+ @Override public void clear() {
+ countMap.clear();
+ }
+
+ /**
+ * The hash code is the same as countMap's, though the objects aren't equal.
+ */
+ @Override public int hashCode() {
+ return countMap.hashCode();
+ }
+ }
+
+ /**
+ * We use a special form of unboxing that treats null as zero.
+ */
+ private static int unbox(Integer i) {
+ return (i == null) ? 0 : i;
+ }
+
+ /**
+ * @serialData the number of distinct elements, the first element, its count,
+ * the second element, its count, and so on
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ // creating HashMultiset to handle concurrent changes
+ Serialization.writeMultiset(HashMultiset.create(this), stream);
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException, NoSuchFieldException {
+ stream.defaultReadObject();
+ Serialization.setFinalField(ConcurrentMultiset.class, this, "countMap",
+ Maps.newConcurrentHashMap());
+ Serialization.populateMultiset(this, stream);
+ }
+
+ private static final long serialVersionUID = 0L;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Constraint.java b/plugins/com.google.collect/src/com/google/common/collect/Constraint.java
new file mode 100644
index 0000000..4badb91
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Constraint.java
@@ -0,0 +1,60 @@
+/*
+ * 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.collect;
+
+/**
+ * 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
+ */
+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".
+ */
+ String toString();
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Constraints.java b/plugins/com.google.collect/src/com/google/common/collect/Constraints.java
new file mode 100644
index 0000000..b981922
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Constraints.java
@@ -0,0 +1,366 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+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
+ */
+public final class Constraints {
+ private Constraints() {}
+
+ // enum singleton pattern
+ private enum NotNullConstraint implements Constraint<Object> {
+ INSTANCE;
+
+ 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.
+ */
+ @SuppressWarnings("unchecked") // the cast is safe
+ public static final <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 */
+ 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
+ */
+ // TODO: Make public?
+ 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);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ 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) {
+ constraint.checkElement(element);
+ return delegate.add(element);
+ }
+ @Override public boolean addAll(Collection<? extends E> elements) {
+ return delegate.addAll(checkElements(elements, constraint));
+ }
+ @Override public boolean add(E element, int occurrences) {
+ constraint.checkElement(element);
+ return delegate.add(element, occurrences);
+ }
+ }
+
+ // TODO: 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/plugins/com.google.collect/src/com/google/common/collect/EnumBiMap.java b/plugins/com.google.collect/src/com/google/common/collect/EnumBiMap.java
new file mode 100644
index 0000000..4859077
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/EnumBiMap.java
@@ -0,0 +1,117 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+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.
+ *
+ * @author Mike Bostock
+ */
+public final class EnumBiMap<K extends Enum<K>, V extends Enum<V>>
+ extends StandardBiMap<K, V> {
+ private transient Class<K> keyType;
+ private transient Class<V> valueType;
+
+ /**
+ * Constructs a new empty bimap using the specified key type and value type.
+ *
+ * @param keyType the key type
+ * @param valueType the value type
+ */
+ public EnumBiMap(Class<K> keyType, Class<V> valueType) {
+ super(new EnumMap<K, V>(keyType), new EnumMap<V, K>(valueType));
+ this.keyType = keyType;
+ this.valueType = valueType;
+ }
+
+ /**
+ * Constructs 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 EnumBiMap(Map<K, V> map) {
+ this(inferKeyType(map), inferValueType(map));
+ putAll(map); // careful if we make this class non-final
+ }
+
+ 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;
+ }
+
+ /**
+ * @serialData the key class, value class, number of entries, first key, first
+ * value, second key, second value, and so on.
+ */
+ 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
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ keyType = (Class<K>) stream.readObject();
+ valueType = (Class<V>) stream.readObject();
+ setDelegates(new EnumMap<K, V>(keyType), new EnumMap<V, K>(valueType));
+ Serialization.populateMap(this, stream);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/EnumHashBiMap.java b/plugins/com.google.collect/src/com/google/common/collect/EnumHashBiMap.java
new file mode 100644
index 0000000..742f535
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/EnumHashBiMap.java
@@ -0,0 +1,103 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 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.
+ *
+ * @author Mike Bostock
+ */
+public final class EnumHashBiMap<K extends Enum<K>, V>
+ extends StandardBiMap<K, V> {
+ private transient Class<K> keyType;
+
+ /**
+ * Constructs a new empty bimap using the specified key type, sized to contain
+ * an entry for every possible key.
+ *
+ * @param keyType the key type
+ */
+ public EnumHashBiMap(Class<K> keyType) {
+ super(new EnumMap<K, V>(keyType),
+ new HashMap<V, K>(keyType.getEnumConstants().length * 3 / 2));
+ this.keyType = 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 EnumHashBiMap(Map<K, ? extends V> map) {
+ this(EnumBiMap.inferKeyType(map));
+ putAll(map); // careful if we make this class non-final
+ }
+
+ // Overriding these two methods to show that values may be null (but not keys)
+
+ @Override public V put(K key, @Nullable V value) {
+ return super.put(key, value);
+ }
+
+ @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.
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(keyType);
+ Serialization.writeMap(this, stream);
+ }
+
+ @SuppressWarnings("unchecked") // reading field populated by writeObject
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ keyType = (Class<K>) stream.readObject();
+ setDelegates(new EnumMap<K, V>(keyType),
+ new HashMap<V, K>(keyType.getEnumConstants().length * 3 / 2));
+ Serialization.populateMap(this, stream);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/EnumMultiset.java b/plugins/com.google.collect/src/com/google/common/collect/EnumMultiset.java
new file mode 100644
index 0000000..6a25fb2
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/EnumMultiset.java
@@ -0,0 +1,90 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Multiset implementation backed by an {@link EnumMap}.
+ *
+ * @author Jared Levy
+ */
+public final class EnumMultiset<E extends Enum<E>>
+ extends AbstractMapBasedMultiset<E> {
+ private transient Class<E> type;
+
+ /** Creates an empty {@code EnumMultiset}. */
+ public EnumMultiset(Class<E> type) {
+ super(new EnumMap<E, AtomicInteger>(type));
+ this.type = type;
+ }
+
+ /**
+ * Creates a new {@code EnumMultiset} containing the specified elements.
+ *
+ * @param elements the elements that the multiset should contain
+ * @throws IllegalArgumentException if {@code elements} is empty
+ */
+ public EnumMultiset(Iterable<E> elements) {
+ this(findClass(elements));
+ Iterables.addAll(this, elements);
+ }
+
+ /**
+ * Determine the class of the first element in an {@link Iterable}.
+ *
+ * @param elements the elements to examine
+ * @return the {@link Class} of the first element
+ * @throws IllegalArgumentException if {@code elements} is empty
+ */
+ private static <E extends Enum<E>> Class<E> findClass(Iterable<E> elements) {
+ Iterator<E> iterator = elements.iterator();
+ checkArgument(iterator.hasNext(),
+ "EnumMultiset constructor passed empty Iterable");
+ return iterator.next().getDeclaringClass();
+ }
+
+ 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
+ */
+ 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(new EnumMap<E, AtomicInteger>(type));
+ Serialization.populateMultiset(this, stream);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingCollection.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingCollection.java
new file mode 100644
index 0000000..6e1b9c3
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingCollection.java
@@ -0,0 +1,101 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * 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>.
+ *
+ * @see ForwardingObject
+ * @author Kevin Bourrillion
+ */
+public abstract class ForwardingCollection<E> extends ForwardingObject
+ implements Collection<E> {
+
+ @Override protected abstract Collection<E> delegate();
+
+ public Iterator<E> iterator() {
+ return delegate().iterator();
+ }
+
+ public int size() {
+ return delegate().size();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method always throws a {@link NullPointerException} when
+ * {@code collection} is null.
+ */
+ public boolean removeAll(Collection<?> collection) {
+ return delegate().removeAll(checkNotNull(collection));
+ }
+
+ public boolean isEmpty() {
+ return delegate().isEmpty();
+ }
+
+ public boolean contains(Object object) {
+ return delegate().contains(object);
+ }
+
+ public Object[] toArray() {
+ return delegate().toArray();
+ }
+
+ public <T> T[] toArray(T[] array) {
+ return delegate().toArray(array);
+ }
+
+ public boolean add(E element) {
+ return delegate().add(element);
+ }
+
+ public boolean remove(Object object) {
+ return delegate().remove(object);
+ }
+
+ public boolean containsAll(Collection<?> collection) {
+ return delegate().containsAll(collection);
+ }
+
+ public boolean addAll(Collection<? extends E> collection) {
+ return delegate().addAll(collection);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This method always throws a {@link NullPointerException} when
+ * {@code collection} is null.
+ */
+ public boolean retainAll(Collection<?> collection) {
+ return delegate().retainAll(checkNotNull(collection));
+ }
+
+ public void clear() {
+ delegate().clear();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingConcurrentMap.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingConcurrentMap.java
new file mode 100644
index 0000000..ec920c1
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingConcurrentMap.java
@@ -0,0 +1,51 @@
+/*
+ * 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.collect;
+
+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>.
+ *
+ * @see ForwardingObject
+ * @author Charles Fry
+ */
+public abstract class ForwardingConcurrentMap<K, V> extends ForwardingMap<K, V>
+ implements ConcurrentMap<K, V> {
+
+ @Override protected abstract ConcurrentMap<K, V> delegate();
+
+ public V putIfAbsent(K key, V value) {
+ return delegate().putIfAbsent(key, value);
+ }
+
+ public boolean remove(Object key, Object value) {
+ return delegate().remove(key, value);
+ }
+
+ public V replace(K key, V value) {
+ return delegate().replace(key, value);
+ }
+
+ public boolean replace(K key, V oldValue, V newValue) {
+ return delegate().replace(key, oldValue, newValue);
+ }
+
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingIterator.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingIterator.java
new file mode 100644
index 0000000..1474f4b
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingIterator.java
@@ -0,0 +1,46 @@
+/*
+ * 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.collect;
+
+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>.
+ *
+ * @see ForwardingObject
+ * @author Kevin Bourrillion
+ */
+public abstract class ForwardingIterator<T>
+ extends ForwardingObject implements Iterator<T> {
+
+ @Override protected abstract Iterator<T> delegate();
+
+ public boolean hasNext() {
+ return delegate().hasNext();
+ }
+
+ public T next() {
+ return delegate().next();
+ }
+
+ public void remove() {
+ delegate().remove();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingList.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingList.java
new file mode 100644
index 0000000..61da7f7
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingList.java
@@ -0,0 +1,87 @@
+/*
+ * 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.collect;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * 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 ForwadingList} subclass should
+ * implement the {@code RandomAccess} interface.
+ *
+ * @author Mike Bostock
+ */
+public abstract class ForwardingList<E> extends ForwardingCollection<E>
+ implements List<E> {
+
+ @Override protected abstract List<E> delegate();
+
+ public void add(int index, E element) {
+ delegate().add(index, element);
+ }
+
+ public boolean addAll(int index, Collection<? extends E> elements) {
+ return delegate().addAll(index, elements);
+ }
+
+ public E get(int index) {
+ return delegate().get(index);
+ }
+
+ public int indexOf(Object element) {
+ return delegate().indexOf(element);
+ }
+
+ public int lastIndexOf(Object element) {
+ return delegate().lastIndexOf(element);
+ }
+
+ public ListIterator<E> listIterator() {
+ return delegate().listIterator();
+ }
+
+ public ListIterator<E> listIterator(int index) {
+ return delegate().listIterator(index);
+ }
+
+ public E remove(int index) {
+ return delegate().remove(index);
+ }
+
+ public E set(int index, E element) {
+ return delegate().set(index, element);
+ }
+
+ public List<E> subList(int fromIndex, int toIndex) {
+ return delegate().subList(fromIndex, toIndex);
+ }
+
+ @Override public boolean equals(Object obj) {
+ return (this == obj) || delegate().equals(obj);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingListIterator.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingListIterator.java
new file mode 100644
index 0000000..f704680
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingListIterator.java
@@ -0,0 +1,58 @@
+/*
+ * 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.collect;
+
+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>.
+ *
+ * @see ForwardingObject
+ * @author Mike Bostock
+ */
+public abstract class ForwardingListIterator<E> extends ForwardingIterator<E>
+ implements ListIterator<E> {
+
+ @Override protected abstract ListIterator<E> delegate();
+
+ public void add(E element) {
+ delegate().add(element);
+ }
+
+ public boolean hasPrevious() {
+ return delegate().hasPrevious();
+ }
+
+ public int nextIndex() {
+ return delegate().nextIndex();
+ }
+
+ public E previous() {
+ return delegate().previous();
+ }
+
+ public int previousIndex() {
+ return delegate().previousIndex();
+ }
+
+ public void set(E element) {
+ delegate().set(element);
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingMap.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingMap.java
new file mode 100644
index 0000000..fcf7349
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingMap.java
@@ -0,0 +1,145 @@
+/*
+ * 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.collect;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 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>.
+ *
+ * @see ForwardingObject
+ * @author Kevin Bourrillion
+ * @author Jared Levy
+ */
+public abstract class ForwardingMap<K, V> extends ForwardingObject
+ implements Map<K, V> {
+
+ @Override protected abstract Map<K, V> delegate();
+
+ public int size() {
+ return delegate().size();
+ }
+
+ public boolean isEmpty() {
+ return delegate().isEmpty();
+ }
+
+ public V remove(Object object) {
+ return delegate().remove(object);
+ }
+
+ public void clear() {
+ delegate().clear();
+ }
+
+ public boolean containsKey(Object key) {
+ return delegate().containsKey(key);
+ }
+
+ public boolean containsValue(Object value) {
+ return delegate().containsValue(value);
+ }
+
+ public V get(Object key) {
+ return delegate().get(key);
+ }
+
+ public V put(K key, V value) {
+ return delegate().put(key, value);
+ }
+
+ public void putAll(Map<? extends K, ? extends V> map) {
+ delegate().putAll(map);
+ }
+
+ private transient Set<K> keySet;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned set's {@code removeAll} and {@code retainAll} methods
+ * always throw a {@link NullPointerException} when given a null collection.
+ */
+ public Set<K> keySet() {
+ return (keySet == null) ? keySet = createKeySet() : keySet;
+ }
+
+ private Set<K> createKeySet() {
+ final Set<K> delegate = delegate().keySet();
+ return new ForwardingSet<K>() {
+ @Override protected Set<K> delegate() {
+ return delegate;
+ }
+ };
+ }
+
+ private transient Collection<V> values;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned collection's {@code removeAll} and {@code retainAll}
+ * methods always throw a {@link NullPointerException} when given a null
+ * collection.
+ */
+ public Collection<V> values() {
+ return (values == null) ? values = createValues() : values;
+ }
+
+ private Collection<V> createValues() {
+ final Collection<V> delegate = delegate().values();
+ return new ForwardingCollection<V>() {
+ @Override protected Collection<V> delegate() {
+ return delegate;
+ }
+ };
+ }
+
+ private transient Set<Entry<K, V>> entrySet;
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The returned set's {@code removeAll} and {@code retainAll} methods
+ * always throw a {@link NullPointerException} when given a null collection.
+ */
+ public Set<Entry<K, V>> entrySet() {
+ return (entrySet == null) ? entrySet = createEntrySet() : entrySet;
+ }
+
+ private Set<Entry<K, V>> createEntrySet() {
+ final Set<Entry<K, V>> delegate = delegate().entrySet();
+ return new ForwardingSet<Entry<K, V>>() {
+ @Override protected Set<Entry<K, V>> delegate() {
+ return delegate;
+ }
+ };
+ }
+
+ @Override public boolean equals(Object obj) {
+ return (this == obj) || delegate().equals(obj);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingMapEntry.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingMapEntry.java
new file mode 100644
index 0000000..acb9ce2
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingMapEntry.java
@@ -0,0 +1,54 @@
+/*
+ * 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.collect;
+
+import java.util.Map;
+
+/**
+ * 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>.
+ *
+ * @see ForwardingObject
+ * @author Mike Bostock
+ */
+public abstract class ForwardingMapEntry<K, V>
+ extends ForwardingObject implements Map.Entry<K, V> {
+
+ @Override protected abstract Map.Entry<K, V> delegate();
+
+ public K getKey() {
+ return delegate().getKey();
+ }
+
+ public V getValue() {
+ return delegate().getValue();
+ }
+
+ public V setValue(V value) {
+ return delegate().setValue(value);
+ }
+
+ @Override public boolean equals(Object obj) {
+ return delegate().equals(obj);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingMultimap.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingMultimap.java
new file mode 100644
index 0000000..85219a7
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingMultimap.java
@@ -0,0 +1,119 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * 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>.
+ *
+ * @see ForwardingObject
+ * @author Robert Konigsberg
+ */
+public abstract class ForwardingMultimap<K, V> extends ForwardingObject
+ implements Multimap<K, V> {
+
+ @Override protected abstract Multimap<K, V> delegate();
+
+ public Map<K, Collection<V>> asMap() {
+ return delegate().asMap();
+ }
+
+ public void clear() {
+ delegate().clear();
+ }
+
+ public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
+ return delegate().containsEntry(key, value);
+ }
+
+ public boolean containsKey(@Nullable Object key) {
+ return delegate().containsKey(key);
+ }
+
+ public boolean containsValue(@Nullable Object value) {
+ return delegate().containsValue(value);
+ }
+
+ public Collection<Entry<K, V>> entries() {
+ return delegate().entries();
+ }
+
+ public Collection<V> get(@Nullable K key) {
+ return delegate().get(key);
+ }
+
+ public boolean isEmpty() {
+ return delegate().isEmpty();
+ }
+
+ public Multiset<K> keys() {
+ return delegate().keys();
+ }
+
+ public Set<K> keySet() {
+ return delegate().keySet();
+ }
+
+ public boolean put(K key, V value) {
+ return delegate().put(key, value);
+ }
+
+ public boolean putAll(K key, Iterable<? extends V> values) {
+ return delegate().putAll(key, values);
+ }
+
+ public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ return delegate().putAll(multimap);
+ }
+
+ public boolean remove(@Nullable Object key, @Nullable Object value) {
+ return delegate().remove(key, value);
+ }
+
+ public Collection<V> removeAll(@Nullable Object key) {
+ return delegate().removeAll(key);
+ }
+
+ public Collection<V> replaceValues(K key, Iterable<? extends V> values) {
+ return delegate().replaceValues(key, values);
+ }
+
+ public int size() {
+ return delegate().size();
+ }
+
+ public Collection<V> values() {
+ return delegate().values();
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ return (this == obj) || delegate().equals(obj);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingMultiset.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingMultiset.java
new file mode 100644
index 0000000..dd522ee
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingMultiset.java
@@ -0,0 +1,66 @@
+/*
+ * 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.collect;
+
+import java.util.Set;
+
+/**
+ * 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>.
+ *
+ * @see ForwardingObject
+ * @author Kevin Bourrillion
+ */
+public abstract class ForwardingMultiset<E> extends ForwardingCollection<E>
+ implements Multiset<E> {
+
+ @Override protected abstract Multiset<E> delegate();
+
+ public int count(Object element) {
+ return delegate().count(element);
+ }
+
+ public boolean add(E element, int occurrences) {
+ return delegate().add(element, occurrences);
+ }
+
+ public int remove(Object element, int occurrences) {
+ return delegate().remove(element, occurrences);
+ }
+
+ public int removeAllOccurrences(Object element) {
+ return delegate().removeAllOccurrences(element);
+ }
+
+ public Set<E> elementSet() {
+ return delegate().elementSet();
+ }
+
+ public Set<Entry<E>> entrySet() {
+ return delegate().entrySet();
+ }
+
+ @Override public boolean equals(Object obj) {
+ return (this == obj) || delegate().equals(obj);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingObject.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingObject.java
new file mode 100644
index 0000000..ce6784d
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingObject.java
@@ -0,0 +1,72 @@
+/*
+ * 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.collect;
+
+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.
+ *
+ * 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
+ */
+public abstract class ForwardingObject {
+
+ /** Sole constructor. */
+ protected ForwardingObject() {}
+
+ /**
+ * Returns the backing delegate instance that methods are forwarded to.
+ * Abstract subclasses generally override the {@link ForwardingObject} 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/plugins/com.google.collect/src/com/google/common/collect/ForwardingQueue.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingQueue.java
new file mode 100644
index 0000000..c6b0e17
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingQueue.java
@@ -0,0 +1,54 @@
+/*
+ * 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.collect;
+
+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>.
+ *
+ * @see ForwardingObject
+ * @author Mike Bostock
+ */
+public abstract class ForwardingQueue<E> extends ForwardingCollection<E>
+ implements Queue<E> {
+
+ @Override protected abstract Queue<E> delegate();
+
+ public boolean offer(E o) {
+ return delegate().offer(o);
+ }
+
+ public E poll() {
+ return delegate().poll();
+ }
+
+ public E remove() {
+ return delegate().remove();
+ }
+
+ public E peek() {
+ return delegate().peek();
+ }
+
+ public E element() {
+ return delegate().element();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingSet.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingSet.java
new file mode 100644
index 0000000..77201fc
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingSet.java
@@ -0,0 +1,42 @@
+/*
+ * 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.collect;
+
+import java.util.Set;
+
+/**
+ * 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>.
+ *
+ * @see ForwardingObject
+ * @author Kevin Bourrillion
+ */
+public abstract class ForwardingSet<E> extends ForwardingCollection<E>
+ implements Set<E> {
+
+ @Override protected abstract Set<E> delegate();
+
+ @Override public boolean equals(Object obj) {
+ return (this == obj) || delegate().equals(obj);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingSortedMap.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingSortedMap.java
new file mode 100644
index 0000000..94ebe25
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingSortedMap.java
@@ -0,0 +1,59 @@
+/*
+ * 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.collect;
+
+import java.util.Comparator;
+import java.util.SortedMap;
+
+/**
+ * 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>.
+ *
+ * @see ForwardingObject
+ * @author Mike Bostock
+ */
+public abstract class ForwardingSortedMap<K, V> extends ForwardingMap<K, V>
+ implements SortedMap<K, V> {
+
+ @Override protected abstract SortedMap<K, V> delegate();
+
+ public Comparator<? super K> comparator() {
+ return delegate().comparator();
+ }
+
+ public K firstKey() {
+ return delegate().firstKey();
+ }
+
+ public SortedMap<K, V> headMap(K toKey) {
+ return delegate().headMap(toKey);
+ }
+
+ public K lastKey() {
+ return delegate().lastKey();
+ }
+
+ public SortedMap<K, V> subMap(K fromKey, K toKey) {
+ return delegate().subMap(fromKey, toKey);
+ }
+
+ public SortedMap<K, V> tailMap(K fromKey) {
+ return delegate().tailMap(fromKey);
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ForwardingSortedSet.java b/plugins/com.google.collect/src/com/google/common/collect/ForwardingSortedSet.java
new file mode 100644
index 0000000..15993b2
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ForwardingSortedSet.java
@@ -0,0 +1,59 @@
+/*
+ * 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.collect;
+
+import java.util.Comparator;
+import java.util.SortedSet;
+
+/**
+ * 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>.
+ *
+ * @see ForwardingObject
+ * @author Mike Bostock
+ */
+public abstract class ForwardingSortedSet<E> extends ForwardingSet<E>
+ implements SortedSet<E> {
+
+ @Override protected abstract SortedSet<E> delegate();
+
+ public Comparator<? super E> comparator() {
+ return delegate().comparator();
+ }
+
+ public E first() {
+ return delegate().first();
+ }
+
+ public SortedSet<E> headSet(E toElement) {
+ return delegate().headSet(toElement);
+ }
+
+ public E last() {
+ return delegate().last();
+ }
+
+ public SortedSet<E> subSet(E fromElement, E toElement) {
+ return delegate().subSet(fromElement, toElement);
+ }
+
+ public SortedSet<E> tailSet(E fromElement) {
+ return delegate().tailSet(fromElement);
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/HashBiMap.java b/plugins/com.google.collect/src/com/google/common/collect/HashBiMap.java
new file mode 100644
index 0000000..318dc6e
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/HashBiMap.java
@@ -0,0 +1,91 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link BiMap} backed by two {@link HashMap} instances. This implementation
+ * allows null keys and values. A {@code HashBiMap} and its inverse are both
+ * serializable.
+ *
+ * @author Mike Bostock
+ */
+public final class HashBiMap<K, V> extends StandardBiMap<K, V> {
+ /**
+ * Constructs a new empty bimap with the default initial capacity (16).
+ */
+ public HashBiMap() {
+ super(new HashMap<K, V>(), new HashMap<V, K>());
+ }
+
+ /**
+ * 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 HashBiMap(int expectedSize) {
+ super(new HashMap<K, V>(Maps.capacity(expectedSize)),
+ new HashMap<V, K>(Maps.capacity(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 HashBiMap(Map<? extends K, ? extends V> map) {
+ this(map.size());
+ putAll(map); // careful if we make this class non-final
+ }
+
+ // 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.
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMap(this, stream);
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ setDelegates(new HashMap<K, V>(), new HashMap<V, K>());
+ Serialization.populateMap(this, stream);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/HashMultimap.java b/plugins/com.google.collect/src/com/google/common/collect/HashMultimap.java
new file mode 100644
index 0000000..aed5c61
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/HashMultimap.java
@@ -0,0 +1,91 @@
+/*
+ * 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.collect;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+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
+ */
+public final class HashMultimap<K, V> extends StandardSetMultimap<K, V> {
+ /** Constructs an empty {@code HashMultimap}. */
+ public HashMultimap() {
+ super(new HashMap<K, Collection<V>>());
+ }
+
+ /**
+ * Constructs a {@code HashMultimap} with the same mappings as the specified
+ * {@code 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.
+ * @see #putAll(Multimap)
+ */
+ public HashMultimap(Multimap<? extends K, ? extends V> multimap) {
+ super(new HashMap<K, Collection<V>>(
+ Maps.capacity(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 new HashSet<V>();
+ }
+
+ /**
+ * @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
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMultimap(this, stream);
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ setMap(new HashMap<K, Collection<V>>());
+ Serialization.populateMultimap(this, stream);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/HashMultiset.java b/plugins/com.google.collect/src/com/google/common/collect/HashMultiset.java
new file mode 100644
index 0000000..5c398a7
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/HashMultiset.java
@@ -0,0 +1,107 @@
+/*
+ * 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.collect;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Multiset implementation backed by a {@link HashMap}.
+ *
+ * @author Kevin Bourrillion
+ * @author Jared Levy
+ */
+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.
+ *
+ * @param elements the elements that the multiset should contain
+ */
+ public static <E> HashMultiset<E> create(Iterable<? extends E> elements) {
+ return new HashMultiset<E>(elements);
+ }
+
+ /**
+ * Constructs a new empty {@code HashMultiset} using the default initial
+ * capacity.
+ */
+ public HashMultiset() {
+ super(new HashMap<E, AtomicInteger>());
+ }
+
+ /**
+ * Constructs 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
+ */
+ private HashMultiset(int distinctElements) {
+ super(new HashMap<E, AtomicInteger>(Maps.capacity(distinctElements)));
+ }
+
+ /**
+ * Constructs a new {@code HashMultiset} containing the specified elements.
+ *
+ * @param elements the elements that the multiset should contain
+ */
+ private HashMultiset(Iterable<? extends E> elements) {
+ this(Multisets.inferDistinctElements(elements));
+ Iterables.addAll(this, elements); // careful if we make this class non-final
+ }
+
+ /**
+ * @serialData the number of distinct elements, the first element, its count,
+ * the second element, its count, and so on
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMultiset(this, stream);
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ setBackingMap(new HashMap<E, AtomicInteger>());
+ Serialization.populateMultiset(this, stream);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Hashing.java b/plugins/com.google.collect/src/com/google/common/collect/Hashing.java
new file mode 100644
index 0000000..9f2d0cf
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Hashing.java
@@ -0,0 +1,56 @@
+/**
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Static methods for implementing hash-based collections.
+ *
+ * @author Kevin Bourrillion
+ * @author Jesse Wilson
+ */
+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
+ */
+ static int smear(int hashCode) {
+ hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12);
+ return hashCode ^ (hashCode >>> 7) ^ (hashCode >>> 4);
+ }
+
+ // We use power-of-2 tables, and this is the highest int that's a power of 2
+ private static final int MAX_TABLE_SIZE = 1 << 30;
+
+ // If the set has this many elements, it will "max out" the table size
+ private static final int CUTOFF = 1 << 29;
+
+ // Size the table to be at most 50% full, if possible
+ static int chooseTableSize(int setSize) {
+ if (setSize < CUTOFF) {
+ return Integer.highestOneBit(setSize) << 2;
+ }
+
+ // 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;
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ImmutableBiMap.java b/plugins/com.google.collect/src/com/google/common/collect/ImmutableBiMap.java
new file mode 100644
index 0000000..7f31e04
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ImmutableBiMap.java
@@ -0,0 +1,320 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.util.Map;
+
+/**
+ * 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
+ */
+public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K,V>
+ implements BiMap<K, V> {
+
+ private static final ImmutableBiMap<Object, Object> EMPTY_IMMUTABLE_BIMAP
+ = new EmptyBiMap();
+
+ /**
+ * Returns the empty bimap.
+ */
+ // Casting to any type is safe because the set will never hold any elements.
+ @SuppressWarnings("unchecked")
+ public static <K, V> ImmutableBiMap<K, V> of() {
+ return (ImmutableBiMap<K, V>) EMPTY_IMMUTABLE_BIMAP;
+ }
+
+ /**
+ * 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.
+ */
+ 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 {@code 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>(super.build());
+ }
+ }
+
+ /**
+ * 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><b>Note:</b> If {@code map} is an {@code ImmutableBiMap}, the given map
+ * itself will be returned.
+ *
+ * @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;
+ return bimap;
+ }
+
+ if (map.isEmpty()) {
+ return of();
+ }
+
+ ImmutableMap<K, V> immutableMap = ImmutableMap.copyOf(map);
+ return new RegularImmutableBiMap<K, V>(immutableMap);
+ }
+
+ abstract ImmutableMap<K, V> delegate();
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>The inverse of an {@code ImmutableBiMap} is another
+ * {@code ImmutableBiMap}.
+ */
+ public abstract ImmutableBiMap<V, K> inverse();
+
+ @Override public boolean containsKey(@Nullable Object key) {
+ return delegate().containsKey(key);
+ }
+
+ @Override public boolean containsValue(@Nullable Object value) {
+ return inverse().containsKey(value);
+ }
+
+ @Override public ImmutableSet<Entry<K, V>> entrySet() {
+ return delegate().entrySet();
+ }
+
+ @Override public V get(@Nullable Object key) {
+ return delegate().get(key);
+ }
+
+ @Override public ImmutableSet<K> keySet() {
+ return delegate().keySet();
+ }
+
+ /**
+ * Returns an immutable set of the values in this map. The values are in the
+ * same order as the parameters used to build this map.
+ */
+ @Override public ImmutableSet<V> values() {
+ return inverse().keySet();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the bimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public V forcePut(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isEmpty() {
+ return delegate().isEmpty();
+ }
+
+ public int size() {
+ return delegate().size();
+ }
+
+ @Override public boolean equals(@Nullable Object o) {
+ return (o == this) || delegate().equals(o);
+ }
+
+ @Override public int hashCode() {
+ return delegate().hashCode();
+ }
+
+ @Override public String toString() {
+ return delegate().toString();
+ }
+
+ @Override Object writeReplace() {
+ return this; // don't use the ImmutableMap serialized form
+ }
+
+ /** Bimap with no mappings. */
+ private static class EmptyBiMap extends ImmutableBiMap<Object, Object> {
+ @Override ImmutableMap<Object, Object> delegate() {
+ return ImmutableMap.of();
+ }
+ @Override public ImmutableBiMap<Object, Object> inverse() {
+ return this;
+ }
+ Object readResolve() {
+ return EMPTY_IMMUTABLE_BIMAP; // preserve singleton property
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** Bimap with one or more mappings. */
+ private static class RegularImmutableBiMap<K, V>
+ extends ImmutableBiMap<K, V> {
+ final ImmutableMap<K, V> delegate;
+ final 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;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ImmutableCollection.java b/plugins/com.google.collect/src/com/google/common/collect/ImmutableCollection.java
new file mode 100644
index 0000000..719889e
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ImmutableCollection.java
@@ -0,0 +1,232 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * An immutable collection. Does not permit null 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
+ */
+@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() {}
+
+ public Object[] toArray() {
+ Object[] newArray = new Object[size()];
+ return toArray(newArray);
+ }
+
+ 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;
+ }
+ int index = 0;
+ for (E element : this) {
+ /*
+ * Sleazy fake cast. However, if element is not a T, then the very next
+ * line must fail with an ArrayStoreException, so we should be safe.
+ */
+ @SuppressWarnings("unchecked")
+ T elementAsT = (T) element;
+
+ other[index++] = elementAsT;
+ }
+ return other;
+ }
+
+ public boolean contains(@Nullable Object object) {
+ if (object == null) {
+ return false;
+ }
+ for (E element : this) {
+ if (element.equals(object)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean containsAll(Collection<?> targets) {
+ for (Object target : targets) {
+ if (!contains(target)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ @Override public String toString() {
+ StringBuilder sb = new StringBuilder(size() * 16);
+ sb.append('[');
+ Iterator<E> i = iterator();
+ if (i.hasNext()) {
+ sb.append(i.next());
+ }
+ while (i.hasNext()) {
+ sb.append(", ");
+ sb.append(i.next());
+ }
+ return sb.append(']').toString();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final boolean add(E e) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final boolean remove(Object object) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final boolean addAll(Collection<? extends E> newElements) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final boolean removeAll(Collection<?> oldElements) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final boolean retainAll(Collection<?> elementsToKeep) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ private static class EmptyImmutableCollection
+ extends ImmutableCollection<Object> {
+ public int size() {
+ return 0;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public boolean contains(@Nullable Object object) {
+ return false;
+ }
+
+ public Iterator<Object> iterator() {
+ return Iterators.emptyIterator();
+ }
+
+ @Override public Object[] toArray() {
+ return ObjectArrays.EMPTY_ARRAY;
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ if (array.length > 0) {
+ array[0] = null;
+ }
+ return array;
+ }
+ }
+
+ private static class ArrayImmutableCollection<E>
+ extends ImmutableCollection<E> {
+ private final E[] elements;
+
+ ArrayImmutableCollection(E[] elements) {
+ this.elements = elements;
+ }
+
+ public int size() {
+ return elements.length;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ public Iterator<E> iterator() {
+ return Iterators.forArray(elements);
+ }
+ }
+
+ /*
+ * 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>(elements.clone());
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ Object writeReplace() {
+ return new SerializedForm(toArray());
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ImmutableList.java b/plugins/com.google.collect/src/com/google/common/collect/ImmutableList.java
new file mode 100644
index 0000000..ca97ab7
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ImmutableList.java
@@ -0,0 +1,559 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+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.ListIterator;
+import java.util.NoSuchElementException;
+import java.util.RandomAccess;
+
+/**
+ * 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.
+ *
+ * @see ImmutableMap
+ * @see ImmutableSet
+ * @author Kevin Bourrillion
+ */
+@SuppressWarnings("serial") // we're overriding default serialization
+public abstract class ImmutableList<E> extends ImmutableCollection<E>
+ implements List<E>, RandomAccess {
+ private static final ImmutableList<?> EMPTY_IMMUTABLE_LIST
+ = new EmptyImmutableList();
+
+ /**
+ * 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>) EMPTY_IMMUTABLE_LIST;
+ }
+
+ /**
+ * 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) {
+ // TODO: evaluate a specialized SingletonImmutableList
+ return new RegularImmutableList<E>(copyIntoArray(element));
+ }
+
+ // TODO: Add similar overloadings to ImmutableSet and ImmutableSortedSet
+
+ /**
+ * 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 new RegularImmutableList<E>(copyIntoArray(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 new RegularImmutableList<E>(copyIntoArray(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 new RegularImmutableList<E>(copyIntoArray(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 new RegularImmutableList<E>(copyIntoArray(e1, e2, e3, e4, e5));
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableList<E> of(E... elements) {
+ return (elements.length == 0)
+ ? ImmutableList.<E>of()
+ : new RegularImmutableList<E>(copyIntoArray(elements));
+ }
+
+ /**
+ * Returns an immutable list containing the given elements, in order. 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><b>Note:</b> Despite what the method name suggests, if {@code elements}
+ * is an {@code ImmutableList}, no copy will actually be performed, and the
+ * given list itself will be returned.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableList<E> copyOf(Iterable<? extends E> elements) {
+ if (elements instanceof ImmutableList) {
+ @SuppressWarnings("unchecked") // all supported methods are covariant
+ ImmutableList<E> list = (ImmutableList<E>) elements;
+ return list;
+ }
+ return copyOfInternal(Collections2.toCollection(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) {
+ return copyOfInternal(Lists.newArrayList(elements));
+ }
+
+ private static <E> ImmutableList<E> copyOfInternal(Collection<?> collection) {
+ // TODO: Support concurrent collections that change while this method is
+ // running.
+ int size = collection.size();
+ return (size == 0)
+ ? ImmutableList.<E>of()
+ : new RegularImmutableList<E>(copyIntoArray(collection, size));
+ }
+
+ private ImmutableList() {}
+
+ // Mark these two methods with @Nullable
+
+ public abstract int indexOf(@Nullable Object object);
+
+ public abstract int lastIndexOf(@Nullable Object object);
+
+ // 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.)
+ */
+ public abstract ImmutableList<E> subList(int fromIndex, int toIndex);
+
+ /**
+ * Guaranteed to throw an exception and leave the list unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ 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
+ */
+ public final E set(int index, E element) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the list unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final void add(int index, E element) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the list unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final E remove(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ private static final class EmptyImmutableList extends ImmutableList<Object> {
+ public int size() {
+ return 0;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public boolean contains(Object target) {
+ return false;
+ }
+
+ public Iterator<Object> iterator() {
+ return Iterators.emptyIterator();
+ }
+
+ @Override public Object[] toArray() {
+ return ObjectArrays.EMPTY_ARRAY;
+ }
+
+ @Override public <T> T[] toArray(T[] a) {
+ if (a.length > 0) {
+ a[0] = null;
+ }
+ return a;
+ }
+
+ public Object get(int index) {
+ throw new IndexOutOfBoundsException(
+ "Invalid index: " + index + ", list size is 0");
+ }
+
+ @Override public int indexOf(Object target) {
+ return -1;
+ }
+
+ @Override public int lastIndexOf(Object target) {
+ return -1;
+ }
+
+ @Override public ImmutableList<Object> subList(int fromIndex, int toIndex) {
+ if (fromIndex != 0 || toIndex != 0) {
+ throw new IndexOutOfBoundsException("Invalid range: " + fromIndex
+ + ".." + toIndex + ", list size is 0");
+ }
+ return this;
+ }
+
+ public ListIterator<Object> listIterator() {
+ return Iterators.emptyListIterator();
+ }
+
+ public ListIterator<Object> listIterator(int start) {
+ if (start != 0) {
+ throw new IndexOutOfBoundsException(
+ "Invalid index: " + start + ", list size is 0");
+ }
+ return Iterators.emptyListIterator();
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ return targets.isEmpty();
+ }
+
+ @Override public boolean equals(Object object) {
+ return object == this
+ || (object instanceof List && ((List<?>) object).isEmpty());
+ }
+
+ @Override public int hashCode() {
+ return 1;
+ }
+
+ @Override public String toString() {
+ return "[]";
+ }
+
+ private Object readResolve() {
+ return EMPTY_IMMUTABLE_LIST;
+ }
+ }
+
+ private static final class RegularImmutableList<E> extends ImmutableList<E> {
+ private final int offset;
+ private final int size;
+ private final Object[] array;
+
+ private RegularImmutableList(Object[] array, int offset, int size) {
+ this.offset = offset;
+ this.size = size;
+ this.array = array;
+ }
+
+ private RegularImmutableList(Object[] array) {
+ this(array, 0, array.length);
+ }
+
+ public int size() {
+ return size;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public boolean contains(Object target) {
+ return indexOf(target) != -1;
+ }
+
+ // The fake cast to E is safe because the creation methods only allow E's
+ @SuppressWarnings("unchecked")
+ public Iterator<E> iterator() {
+ return (Iterator<E>) Iterators.forArray(array, offset, size);
+ }
+
+ @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
+ @SuppressWarnings("unchecked")
+ public E get(int index) {
+ if (index < 0 || index >= size) {
+ throw new IndexOutOfBoundsException(
+ "Invalid index: " + index + ", list size is " + size);
+ }
+ return (E) array[index + offset];
+ }
+
+ @Override public int indexOf(Object target) {
+ if (target != null) {
+ for (int i = offset; i < offset + size; i++) {
+ if (array[i].equals(target)) {
+ return i - offset;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override public int lastIndexOf(Object target) {
+ if (target != null) {
+ for (int i = offset + size - 1; i >= offset; i--) {
+ if (array[i].equals(target)) {
+ return i - offset;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
+ if (fromIndex < 0 || toIndex > size || fromIndex > toIndex) {
+ throw new IndexOutOfBoundsException("Invalid range: " + fromIndex
+ + ".." + toIndex + ", list size is " + size);
+ }
+
+ return (fromIndex == toIndex)
+ ? ImmutableList.<E>of()
+ : new RegularImmutableList<E>(
+ array, offset + fromIndex, toIndex - fromIndex);
+ }
+
+ public ListIterator<E> listIterator() {
+ return listIterator(0);
+ }
+
+ public ListIterator<E> listIterator(final int start) {
+ if ((start < 0) || (start > size)) {
+ throw new IndexOutOfBoundsException(
+ "Invalid index: " + start + ", list size is " + size);
+ }
+
+ return new ListIterator<E>() {
+ int index = start;
+
+ public boolean hasNext() {
+ return index < size;
+ }
+ public boolean hasPrevious() {
+ return index > 0;
+ }
+
+ public int nextIndex() {
+ return index;
+ }
+ public int previousIndex() {
+ return index - 1;
+ }
+
+ public E next() {
+ E result;
+ try {
+ result = get(index);
+ } catch (IndexOutOfBoundsException rethrown) {
+ throw new NoSuchElementException();
+ }
+ index++;
+ return result;
+ }
+ public E previous() {
+ E result;
+ try {
+ result = get(index - 1);
+ } catch (IndexOutOfBoundsException rethrown) {
+ throw new NoSuchElementException();
+ }
+ index--;
+ return result;
+ }
+
+ public void set(E o) {
+ throw new UnsupportedOperationException();
+ }
+ public void add(E o) {
+ throw new UnsupportedOperationException();
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (!(object instanceof List)) {
+ return false;
+ }
+
+ List<?> that = (List<?>) object;
+ if (that.size() != 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 int hashCode() {
+ // not caching hash code since it could change if the elements are mutable
+ // in a way that modifies their hash codes
+ int hashCode = 1;
+ for (int i = offset; i < offset + size; i++) {
+ hashCode = 31 * hashCode + array[i].hashCode();
+ }
+ return hashCode;
+ }
+
+ @Override public String toString() {
+ StringBuilder sb = new StringBuilder(size() * 16);
+ sb.append('[').append(array[offset]);
+ for (int i = offset + 1; i < offset + size; i++) {
+ sb.append(", ").append(array[i]);
+ }
+ return sb.append(']').toString();
+ }
+ }
+
+ private static Object[] copyIntoArray(Object... source) {
+ Object[] array = new Object[source.length];
+ int index = 0;
+ for (Object element : source) {
+ if (element == null) {
+ throw new NullPointerException("at index " + index);
+ }
+ array[index++] = element;
+ }
+ return array;
+ }
+
+ private static Object[] copyIntoArray(Iterable<?> source, int size) {
+ Object[] array = new Object[size];
+ int index = 0;
+ for (Object element : source) {
+ if (element == null) {
+ throw new NullPointerException("at index " + index);
+ }
+ array[index++] = element;
+ }
+ return array;
+ }
+
+ /*
+ * 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 of(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());
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ImmutableMap.java b/plugins/com.google.collect/src/com/google/common/collect/ImmutableMap.java
new file mode 100644
index 0000000..0c260d4
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ImmutableMap.java
@@ -0,0 +1,772 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.getOnlyElement;
+
+import com.google.common.base.Join;
+import com.google.common.base.Nullable;
+import com.google.common.collect.ImmutableSet.ArrayImmutableSet;
+import com.google.common.collect.ImmutableSet.TransformedImmutableSet;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * 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><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.
+ *
+ * @see ImmutableList
+ * @see ImmutableSet
+ * @author Jesse Wilson
+ * @author Kevin Bourrillion
+ */
+@SuppressWarnings("serial") // we're overriding default serialization
+public abstract class ImmutableMap<K, V>
+ implements ConcurrentMap<K, V>, Serializable {
+ private static final ImmutableMap<?, ?> EMPTY_IMMUTABLE_MAP
+ = new EmptyImmutableMap();
+
+ // TODO: restore prebuilder API? optimize, compare performance to HashMap
+
+ /**
+ * 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>) EMPTY_IMMUTABLE_MAP;
+ }
+
+ /**
+ * 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 added
+ */
+ 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 added
+ */
+ 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 added
+ */
+ 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 added
+ */
+ 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
+ * entry with those values.
+ */
+ private static <K, V> Entry<K, V> entryOf(K key, V value) {
+ return Maps.immutableEntry(checkNotNull(key), checkNotNull(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.
+ */
+ public static class Builder<K, V> {
+ final List<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;
+ }
+
+ /**
+ * 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
+ */
+ 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;
+ }
+
+ // TODO: Should build() and the ImmutableBiMap version 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><b>Note:</b> Despite what the method name suggests, if {@code map} is an
+ * {@code ImmutableMap}, no copy will actually be performed, and the given map
+ * itself will be returned.
+ *
+ * @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) {
+ @SuppressWarnings("unchecked") // safe since map is not writable
+ ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
+ return kvMap;
+ }
+
+ int size = map.size();
+ switch (size) {
+ case 0:
+ return of();
+ case 1:
+ Map.Entry<? extends K, ? extends V> loneEntry
+ = getOnlyElement(map.entrySet());
+ /*
+ * Must cast next line to (K) and (V) to avoid returning an
+ * ImmutableMap<? extends K, ? extends V>, which is incompatible
+ * with the return type ImmutableMap<K, V>. (Eclipse will complain
+ * mightily about this line if there's no cast.)
+ */
+ return of((K) loneEntry.getKey(), (V) loneEntry.getValue());
+ default:
+ Entry<?, ?>[] array = new Entry<?, ?>[size];
+ int i = 0;
+ for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
+ /*
+ * See comment above re: <? extends K, ? extends V> to <K, V>.
+ */
+ array[i++] = entryOf((K) entry.getKey(), (V) entry.getValue());
+ }
+ return new RegularImmutableMap<K, V>(array);
+ }
+ }
+
+ ImmutableMap() {}
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final V put(K k, V v) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final V remove(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final V putIfAbsent(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final boolean remove(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final boolean replace(K key, V oldValue, V newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public final V replace(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the map unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ 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
+ */
+ public final void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ // Overriding to mark it Nullable
+ public abstract boolean containsKey(@Nullable Object key);
+
+ // Overriding to mark it Nullable
+ public abstract boolean containsValue(@Nullable Object value);
+
+ // Overriding to mark it Nullable
+ public abstract V get(@Nullable Object key);
+
+ /**
+ * 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.
+ */
+ public abstract ImmutableSet<Entry<K, V>> entrySet();
+
+ /**
+ * Returns an immutable set of the keys in this map. These keys are in
+ * the same order as the parameters used to build this map.
+ */
+ public abstract ImmutableSet<K> keySet();
+
+ /**
+ * Returns an immutable collection of the values in this map. The values are
+ * in the same order as the parameters used to build this map.
+ */
+ public abstract ImmutableCollection<V> values();
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Map) {
+ Map<?, ?> map = (Map<?, ?>) object;
+ return entrySet().equals(map.entrySet());
+ }
+ return false;
+ }
+
+ @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() {
+ StringBuilder result = new StringBuilder(size() * 16).append('{');
+ Join.join(result, ", ", entrySet());
+ return result.append('}').toString();
+ }
+
+ private static final class EmptyImmutableMap
+ extends ImmutableMap<Object, Object> {
+
+ @Override public Object get(Object key) {
+ return null;
+ }
+
+ public int size() {
+ return 0;
+ }
+
+ public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return false;
+ }
+
+ @Override public boolean containsValue(Object value) {
+ return false;
+ }
+
+ @Override public ImmutableSet<Entry<Object, Object>> entrySet() {
+ return ImmutableSet.of();
+ }
+
+ @Override public ImmutableSet<Object> keySet() {
+ return ImmutableSet.of();
+ }
+
+ @Override public ImmutableCollection<Object> values() {
+ return ImmutableCollection.EMPTY_IMMUTABLE_COLLECTION;
+ }
+
+ @Override public boolean equals(Object object) {
+ return object == this
+ || (object instanceof Map && ((Map<?, ?>) object).isEmpty());
+ }
+
+ @Override public int hashCode() {
+ return 0;
+ }
+
+ @Override public String toString() {
+ return "{}";
+ }
+ }
+
+ private static final class SingletonImmutableMap<K, V>
+ extends ImmutableMap<K, V> {
+ private transient final K singleKey;
+ private transient final V singleValue;
+ private transient Entry<K, V> entry;
+
+ private SingletonImmutableMap(K singleKey, V singleValue) {
+ this.singleKey = singleKey;
+ this.singleValue = singleValue;
+ }
+
+ private SingletonImmutableMap(Entry<K, V> entry) {
+ this.entry = entry;
+ this.singleKey = entry.getKey();
+ this.singleValue = entry.getValue();
+ }
+
+ private Entry<K, V> entry() {
+ Entry<K, V> e = entry;
+ return (e == null)
+ ? (entry = Maps.immutableEntry(singleKey, singleValue)) : e;
+ }
+
+ @Override public V get(Object key) {
+ return singleKey.equals(key) ? singleValue : null;
+ }
+
+ public int size() {
+ return 1;
+ }
+
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return singleKey.equals(key);
+ }
+
+ @Override public boolean containsValue(Object value) {
+ return singleValue.equals(value);
+ }
+
+ private transient ImmutableSet<Entry<K, V>> entrySet;
+
+ @Override public ImmutableSet<Entry<K, V>> entrySet() {
+ ImmutableSet<Entry<K, V>> es = entrySet;
+ return (es == null) ? (entrySet = ImmutableSet.of(entry())) : es;
+ }
+
+ private transient ImmutableSet<K> keySet;
+
+ @Override public ImmutableSet<K> keySet() {
+ ImmutableSet<K> ks = keySet;
+ return (ks == null) ? (keySet = ImmutableSet.of(singleKey)) : ks;
+ }
+
+ private transient ImmutableCollection<V> values;
+
+ @Override public ImmutableCollection<V> values() {
+ ImmutableCollection<V> v = values;
+ return (v == null) ? (values = new Values<V>(singleValue)) : v;
+ }
+
+ private static class Values<V> extends ImmutableCollection<V> {
+ final V singleValue;
+
+ Values(V singleValue) {
+ this.singleValue = singleValue;
+ }
+
+ @Override public boolean contains(Object object) {
+ return singleValue.equals(object);
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ public int size() {
+ return 1;
+ }
+
+ public Iterator<V> iterator() {
+ return Iterators.singletonIterator(singleValue);
+ }
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Map) {
+ Map<?, ?> map = (Map<?, ?>) object;
+ return map.size() == 1 && map.entrySet().contains(entry());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return singleKey.hashCode() ^ singleValue.hashCode();
+ }
+
+ @Override public String toString() {
+ return new StringBuilder()
+ .append('{')
+ .append(singleKey.toString())
+ .append('=')
+ .append(singleValue.toString())
+ .append('}')
+ .toString();
+ }
+ }
+
+ private static final class RegularImmutableMap<K, V>
+ extends ImmutableMap<K, V> {
+ private transient final Entry<K, V>[] entries; // entries in insertion order
+ private transient final Object[] table; // alternating keys and values
+ // 'and' with an int then shift to get a table index
+ private transient final int mask;
+ private transient final int keySetHashCode;
+
+ private RegularImmutableMap(Entry<?, ?>... entries) {
+ // each of our 6 callers carefully put only Entry<K, V>s into the array!
+ @SuppressWarnings("unchecked")
+ Entry<K, V>[] tmp = (Entry<K, V>[]) entries;
+ this.entries = tmp;
+
+ int tableSize = Hashing.chooseTableSize(entries.length);
+ table = new Object[tableSize * 2];
+ mask = tableSize - 1;
+
+ int keySetHashCodeMutable = 0;
+ for (Entry<K, V> entry : this.entries) {
+ K key = entry.getKey();
+ int keyHashCode = key.hashCode();
+ for (int i = Hashing.smear(keyHashCode); true; i++) {
+ int index = (i & mask) * 2;
+ Object existing = table[index];
+ if (existing == null) {
+ V value = entry.getValue();
+ table[index] = key;
+ table[index + 1] = value;
+ keySetHashCodeMutable += keyHashCode;
+ break;
+ } else if (existing.equals(key)) {
+ throw new IllegalArgumentException("duplicate key: " + key);
+ }
+ }
+ }
+ keySetHashCode = keySetHashCodeMutable;
+ }
+
+ @Override public V get(Object key) {
+ if (key == null) {
+ return null;
+ }
+ for (int i = Hashing.smear(key.hashCode()); true; i++) {
+ int index = (i & mask) * 2;
+ Object candidate = table[index];
+ if (candidate == null) {
+ return null;
+ }
+ if (candidate.equals(key)) {
+ // we're careful to store only V's at odd indices
+ @SuppressWarnings("unchecked")
+ V value = (V) table[index + 1];
+ return value;
+ }
+ }
+ }
+
+ public int size() {
+ return entries.length;
+ }
+
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return get(key) != null;
+ }
+
+ @Override public boolean containsValue(Object value) {
+ if (value == null) {
+ return false;
+ }
+ for (Entry<K, V> entry : entries) {
+ if (entry.getValue().equals(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // TODO: Serialization of the map views should serialize the map, and
+ // deserialization should call entrySet(), keySet(), or values() on the
+ // deserialized map. The views are serializable since the Immutable* classes
+ // are.
+
+ private transient ImmutableSet<Entry<K, V>> entrySet;
+
+ @Override public ImmutableSet<Entry<K, V>> entrySet() {
+ ImmutableSet<Entry<K, V>> es = entrySet;
+ return (es == null) ? (entrySet = new EntrySet<K, V>(this)) : es;
+ }
+
+ private static class EntrySet<K, V> extends ArrayImmutableSet<Entry<K, V>> {
+ final RegularImmutableMap<K, V> map;
+
+ EntrySet(RegularImmutableMap<K, V> map) {
+ super(map.entries);
+ this.map = map;
+ }
+
+ @Override public boolean contains(Object target) {
+ if (target instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) target;
+ V mappedValue = map.get(entry.getKey());
+ return mappedValue != null && mappedValue.equals(entry.getValue());
+ }
+ return false;
+ }
+ }
+
+ private transient ImmutableSet<K> keySet;
+
+ @Override public ImmutableSet<K> keySet() {
+ ImmutableSet<K> ks = keySet;
+ return (ks == null) ? (keySet = new KeySet<K, V>(this)) : ks;
+ }
+
+ private static class KeySet<K, V>
+ extends TransformedImmutableSet<Map.Entry<K, V>, K> {
+ final RegularImmutableMap<K, V> map;
+
+ KeySet(RegularImmutableMap<K, V> map) {
+ super(map.entries, map.keySetHashCode);
+ this.map = map;
+ }
+
+ @Override K transform(Entry<K, V> element) {
+ return element.getKey();
+ }
+
+ @Override public boolean contains(Object target) {
+ return map.containsKey(target);
+ }
+ }
+
+ private transient ImmutableCollection<V> values;
+
+ @Override public ImmutableCollection<V> values() {
+ ImmutableCollection<V> v = values;
+ return (v == null) ? (values = new Values<V>(this)) : v;
+ }
+
+ private static class Values<V> extends ImmutableCollection<V> {
+ final RegularImmutableMap<?, V> map;
+
+ Values(RegularImmutableMap<?, V> map) {
+ this.map = map;
+ }
+
+ public int size() {
+ return map.entries.length;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ public Iterator<V> iterator() {
+ return new AbstractIterator<V>() {
+ int index = 0;
+ @Override protected V computeNext() {
+ return (index < map.entries.length)
+ ? map.entries[index++].getValue()
+ : endOfData();
+ }
+ };
+ }
+
+ @Override public boolean contains(Object target) {
+ return map.containsValue(target);
+ }
+ }
+
+ @Override public String toString() {
+ StringBuilder result = new StringBuilder(size() * 16)
+ .append('{')
+ .append(entries[0]);
+ for (int e = 1; e < entries.length; e++) {
+ result.append(", ").append(entries[e].toString());
+ }
+ return result.append('}').toString();
+ }
+ }
+
+ /*
+ * 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.
+ */
+ private static class SerializedForm implements Serializable {
+ final Object[] keys;
+ 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>();
+ 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/plugins/com.google.collect/src/com/google/common/collect/ImmutableMultimap.java b/plugins/com.google.collect/src/com/google/common/collect/ImmutableMultimap.java
new file mode 100644
index 0000000..f47d628
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ImmutableMultimap.java
@@ -0,0 +1,591 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Nullable;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 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 map 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.
+ *
+ * @author Jared Levy
+ */
+public class ImmutableMultimap<K, V>
+ implements ListMultimap<K, V>, Serializable {
+
+ private static ImmutableMultimap<Object, Object> EMPTY_MULTIMAP
+ = new EmptyMultimap();
+
+ private static class EmptyMultimap extends ImmutableMultimap<Object, Object> {
+ EmptyMultimap() {
+ super(ImmutableMap.<Object, ImmutableList<Object>>of(), 0);
+ }
+ @Override public boolean isEmpty() {
+ return true;
+ }
+ Object readResolve() {
+ return EMPTY_MULTIMAP; // preserve singleton property
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /** Returns the empty multimap. */
+ // Casting is safe because the multimap will never hold any elements.
+ @SuppressWarnings("unchecked")
+ public static <K, V> ImmutableMultimap<K, V> empty() {
+ return (ImmutableMultimap<K, V>) EMPTY_MULTIMAP;
+ }
+
+ /**
+ * 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 Builder} that maintains key and value orderings, allows
+ * duplicate values, and performs better than {@link LinkedListMultimap}.
+ */
+ private static class BuilderMultimap<K, V> extends StandardMultimap<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>
+ *
+ * <p>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.
+ */
+ public static class Builder<K, V> {
+ private final Multimap<K, V> builderMultimap = new BuilderMultimap<K, V>();
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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. If a later
+ * value is null, earlier values may be added to the builder.
+ */
+ public Builder<K, V> putAll(K key, V... values) {
+ Collection<V> valueList = builderMultimap.get(checkNotNull(key));
+ for (V value : values) {
+ valueList.add(checkNotNull(value));
+ }
+ return this;
+ }
+
+ public ImmutableMultimap<K, V> build() {
+ 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><b>Note:</b> Despite what the method name suggests, if
+ * {@code multimap} is an {@code ImmutableMultimap}, no copy will actually be
+ * performed, and the given map itself will be returned.
+ *
+ * @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.isEmpty()) {
+ return empty();
+ }
+
+ if (multimap instanceof ImmutableMultimap) {
+ @SuppressWarnings("unchecked") // safe since multimap is not writable
+ ImmutableMultimap<K, V> kvMultimap = (ImmutableMultimap<K, V>) multimap;
+ return kvMultimap;
+ }
+
+ ImmutableMap.Builder<K, ImmutableList<V>> builder = ImmutableMap.builder();
+ int size = 0;
+
+ for (Map.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 ImmutableMultimap<K, V>(builder.build(), size);
+ }
+
+ private final transient ImmutableMap<K, ImmutableList<V>> map;
+ private final transient int size;
+
+ private ImmutableMultimap(ImmutableMap<K, ImmutableList<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
+ */
+ public List<V> removeAll(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public List<V> replaceValues(K key, Iterable<? extends V> values) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public boolean put(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the multimap unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ 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
+ */
+ 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
+ */
+ public boolean remove(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ // accessors
+
+ public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
+ Collection<V> valueList = map.get(key);
+ return (valueList != null) && valueList.contains(value);
+ }
+
+ public boolean containsKey(@Nullable Object key) {
+ return map.containsKey(key);
+ }
+
+ public boolean containsValue(@Nullable Object value) {
+ for (Collection<V> valueList : map.values()) {
+ if (valueList.contains(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isEmpty() {
+ return false;
+ }
+
+ public int size() {
+ return size;
+ }
+
+ @Override public boolean equals(@Nullable Object obj) {
+ if (obj instanceof Multimap) {
+ Multimap<?, ?> that = (Multimap<?, ?>) obj;
+ return map.equals(that.asMap());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return map.hashCode();
+ }
+
+ @Override public String toString() {
+ return map.toString();
+ }
+
+ // 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.
+ */
+ public ImmutableList<V> get(@Nullable K key) {
+ ImmutableList<V> list = map.get(key);
+ return (list == null) ? ImmutableList.<V>of() : list;
+ }
+
+ /**
+ * 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.
+ */
+ public ImmutableSet<K> keySet() {
+ return map.keySet();
+ }
+
+ /**
+ * Returns an immutable map that associates each key with its corresponding
+ * values in the multimap. Though the method signature doesn't say so
+ * explicitly, the returned map has {@link ImmutableList} values.
+ */
+ @SuppressWarnings("unchecked") // a widening cast
+ public ImmutableMap<K, Collection<V>> asMap() {
+ return (ImmutableMap) map;
+ }
+
+ private transient ImmutableCollection<Map.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.
+ */
+ public ImmutableCollection<Map.Entry<K, V>> entries() {
+ ImmutableCollection<Map.Entry<K, V>> result = entries;
+ return (result == null) ? (entries = new Entries<K, V>(this)) : result;
+ }
+
+ private static class Entries<K, V>
+ extends ImmutableCollection<Map.Entry<K, V>> {
+ final ImmutableMultimap<K, V> multimap;
+
+ Entries(ImmutableMultimap<K, V> multimap) {
+ this.multimap = multimap;
+ }
+
+ public Iterator<Map.Entry<K, V>> iterator() {
+ final Iterator<Map.Entry<K, ImmutableList<V>>> mapIterator
+ = multimap.map.entrySet().iterator();
+
+ return new UnmodifiableIterator<Map.Entry<K, V>>() {
+ Map.Entry<K, ImmutableList<V>> mapEntry;
+ int index;
+
+ public boolean hasNext() {
+ return ((mapEntry != null) && (index < mapEntry.getValue().size()))
+ || mapIterator.hasNext();
+ }
+
+ public Map.Entry<K, V> next() {
+ if ((mapEntry == null) || (index >= mapEntry.getValue().size())) {
+ mapEntry = mapIterator.next();
+ index = 0;
+ }
+ V value = mapEntry.getValue().get(index);
+ index++;
+ return Maps.immutableEntry(mapEntry.getKey(), value);
+ }
+ };
+ }
+
+ public int size() {
+ return multimap.size();
+ }
+
+ @Override public boolean contains(Object object) {
+ if (object instanceof Map.Entry) {
+ Map.Entry<?, ?> entry = (Map.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 of 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.
+ */
+ public ImmutableMultiset<K> keys() {
+ ImmutableMultiset<K> result = keys;
+ return (result == null)
+ ? (keys = new ImmutableMultiset<K>(new CountMap<K, V>(this), size))
+ : result;
+ }
+
+ /**
+ * Map from key to value count, used to create the {@link #keys} multiset.
+ * Methods that {@link ImmutableMultiset} doesn't require are unsupported.
+ */
+ private static class CountMap<K, V> extends ImmutableMap<K, Integer> {
+ final ImmutableMultimap<K, V> multimap;
+
+ CountMap(ImmutableMultimap<K, V> multimap) {
+ this.multimap = multimap;
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return multimap.containsKey(key);
+ }
+
+ @Override public boolean containsValue(Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public Integer get(Object key) {
+ Collection<?> valueList = multimap.map.get(key);
+ return (valueList == null) ? 0 : valueList.size();
+ }
+
+ @Override public ImmutableSet<K> keySet() {
+ return multimap.keySet();
+ }
+
+ @Override public ImmutableCollection<Integer> values() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isEmpty() {
+ return multimap.isEmpty();
+ }
+
+ public int size() {
+ return multimap.map.size();
+ }
+
+ transient ImmutableSet<Entry<K, Integer>> entrySet;
+
+ @Override public ImmutableSet<Entry<K, Integer>> entrySet() {
+ ImmutableSet<Entry<K, Integer>> result = entrySet;
+ return (result == null)
+ ? entrySet = new EntrySet<K, V>(multimap) : result;
+ }
+
+ private static class EntrySet<K, V>
+ extends ImmutableSet<Entry<K, Integer>> {
+ final ImmutableMultimap<K, V> multimap;
+
+ EntrySet(ImmutableMultimap<K, V> multimap) {
+ this.multimap = multimap;
+ }
+
+ public Iterator<Entry<K, Integer>> iterator() {
+ final Iterator<Entry<K, ImmutableList<V>>> mapIterator
+ = multimap.map.entrySet().iterator();
+ return new UnmodifiableIterator<Entry<K, Integer>>() {
+ public boolean hasNext() {
+ return mapIterator.hasNext();
+ }
+ public Entry<K, Integer> next() {
+ Entry<K, ImmutableList<V>> entry = mapIterator.next();
+ return Maps.immutableEntry(entry.getKey(), entry.getValue().size());
+ }
+ };
+ }
+
+ public int size() {
+ return multimap.map.size();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ 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.
+ */
+ public ImmutableCollection<V> values() {
+ ImmutableCollection<V> v = values;
+ return (v == null) ? (values = new Values<V>(this)) : v;
+ }
+
+ private static class Values<V> extends ImmutableCollection<V> {
+ final Multimap<?, V> multimap;
+
+ Values(Multimap<?, V> multimap) {
+ this.multimap = multimap;
+ }
+
+ public Iterator<V> iterator() {
+ final Iterator<? extends Map.Entry<?, V>> entryIterator
+ = multimap.entries().iterator();
+ return new UnmodifiableIterator<V>() {
+ public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+ public V next() {
+ return entryIterator.next().getValue();
+ }
+ };
+ }
+
+ public int size() {
+ return multimap.size();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * @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
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMultimap(this, stream);
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException, NoSuchFieldException {
+ stream.defaultReadObject();
+ int keyCount = stream.readInt();
+ if (keyCount < 0) {
+ throw new InvalidObjectException("Invalid key count " + keyCount);
+ }
+ ImmutableMap.Builder<K, ImmutableList<V>> builder = ImmutableMap.builder();
+ int tmpSize = 0;
+
+ for (int i = 0; i < keyCount; i++) {
+ @SuppressWarnings("unchecked") // reading data stored by writeMultimap
+ K key = (K) stream.readObject();
+ int valueCount = stream.readInt();
+ if (valueCount <= 0) {
+ throw new InvalidObjectException("Invalid value count " + valueCount);
+ }
+ @SuppressWarnings("unchecked") // casting a newly allocated array
+ V[] values = (V[]) new Object[valueCount];
+ for (int j = 0; j < valueCount; j++) {
+ @SuppressWarnings("unchecked") // reading data stored by writeMultimap
+ V value = (V) stream.readObject();
+ values[j] = value;
+ tmpSize += valueCount;
+ }
+ builder.put(key, ImmutableList.of(values));
+ }
+
+ Serialization.setFinalField(
+ ImmutableMultimap.class, this, "map", builder.build());
+ Serialization.setFinalField(ImmutableMultimap.class, this, "size", tmpSize);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ImmutableMultiset.java b/plugins/com.google.collect/src/com/google/common/collect/ImmutableMultiset.java
new file mode 100644
index 0000000..82b7bd4
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ImmutableMultiset.java
@@ -0,0 +1,360 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 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. When the multiset
+ * contains multiple instances of an element, those instances are consecutive in
+ * the iteration order.
+ *
+ * @author Jared Levy
+ */
+public class ImmutableMultiset<E> extends ImmutableCollection<E>
+ implements Multiset<E> {
+
+ private static final ImmutableMultiset<Object> EMPTY_MULTISET
+ = new EmptyMultiset();
+
+ private static class EmptyMultiset extends ImmutableMultiset<Object> {
+ EmptyMultiset() {
+ super(ImmutableMap.<Object, Integer>of(), 0);
+ }
+ Object readResolve() {
+ return EMPTY_MULTISET; // preserve singleton property
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * Returns the empty immutable multiset.
+ */
+ @SuppressWarnings("unchecked") // all supported methods are covariant
+ public static <E> ImmutableMultiset<E> of() {
+ return (ImmutableMultiset<E>) EMPTY_MULTISET;
+ }
+
+ /**
+ * Returns an immutable multiset containing the given elements.
+ *
+ * <p>The multiset is ordered by the first occurrence of each element. For
+ * example, {@code ImmutableMultiset.of(2, 3, 1, 3)} yields a multiset with
+ * elements in the order {@code 2, 3, 3, 1}.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableMultiset<E> of(E... elements) {
+ return copyOf(Arrays.asList(elements));
+ }
+
+ /**
+ * Returns an immutable multiset containing the given elements.
+ *
+ * <p>The multiset is ordered by the first occurrence of each element. For
+ * example, {@code ImmutableMultiset.copyOf(Arrays.asList(2, 3, 1, 3))} yields
+ * a multiset with elements in the order {@code 2, 3, 3, 1}.
+ *
+ * <p>Note that if {@code c} is a {@code Collection<String>}, then {@code
+ * ImmutableMultiset.copyOf(c)} returns an {@code ImmutableMultiset<String>}
+ * containing each of the strings in {@code c}, while
+ * {@code ImmutableMultiset.of(c)} returns an
+ * {@code ImmutableMultiset<Collection<String>>} containing one element (the
+ * given collection itself).
+ *
+ * <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;
+ return result;
+ }
+
+ @SuppressWarnings("unchecked") // the cast causes a warning
+ Multiset<? extends E> multiset = (elements instanceof Multiset)
+ ? (Multiset<? extends E>) elements
+ : new LinkedHashMultiset<E>(elements);
+
+ return copyOfInternal(multiset);
+ }
+
+
+ private static <E> ImmutableMultiset<E> copyOfInternal(
+ Multiset<? extends E> multiset) {
+ long size = 0;
+ ImmutableMap.Builder<E, Integer> builder = ImmutableMap.builder();
+
+ for (Entry<? extends E> entry : multiset.entrySet()) {
+ 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;
+ }
+ }
+
+ return new ImmutableMultiset<E>(
+ builder.build(), (int) Math.min(size, Integer.MAX_VALUE));
+ }
+
+ /**
+ * 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 = new LinkedHashMultiset<E>();
+ Iterators.addAll(multiset, elements);
+ return copyOfInternal(multiset);
+ }
+
+ private final transient ImmutableMap<E, Integer> map;
+ private final transient int size;
+
+ ImmutableMultiset(ImmutableMap<E, Integer> map, int size) {
+ this.map = map;
+ this.size = size;
+ }
+
+ public int count(@Nullable Object element) {
+ Integer value = map.get(element);
+ return (value == null) ? 0 : value;
+ }
+
+ public Iterator<E> iterator() {
+ final Iterator<Map.Entry<E, Integer>> mapIterator
+ = map.entrySet().iterator();
+
+ return new Iterator<E>() {
+ int remaining;
+ E element;
+
+ public boolean hasNext() {
+ return (remaining > 0) || mapIterator.hasNext();
+ }
+
+ public E next() {
+ if (remaining <= 0) {
+ Map.Entry<E, Integer> entry = mapIterator.next();
+ element = entry.getKey();
+ remaining = entry.getValue();
+ }
+ remaining--;
+ return element;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public int size() {
+ return size;
+ }
+
+ @Override public boolean contains(@Nullable Object element) {
+ return map.containsKey(element);
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public boolean add(E element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public int remove(Object element, int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Guaranteed to throw an exception and leave the collection unmodified.
+ *
+ * @throws UnsupportedOperationException always
+ */
+ public int removeAllOccurrences(Object element) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean equals(@Nullable Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (other instanceof Multiset) {
+ Multiset<?> that = (Multiset<?>) other;
+ 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() {
+ // could cache this, but not considered worthwhile to do so
+ return map.hashCode();
+ }
+
+ @Override public String toString() {
+ return entrySet().toString();
+ }
+
+ // TODO: Serialization of the element set should serialize the multiset, and
+ // deserialization should call multiset.elementSet(). Then
+ // reserialized(multiset).elementSet() == reserialized(multiset.elementSet())
+ // Currently, those object references differ.
+ public Set<E> elementSet() {
+ return map.keySet();
+ }
+
+ private transient ImmutableSet<Entry<E>> entrySet;
+
+ public Set<Entry<E>> entrySet() {
+ ImmutableSet<Entry<E>> es = entrySet;
+ return (es == null) ? (entrySet = new EntrySet<E>(this)) : es;
+ }
+
+ private static class EntrySet<E> extends ImmutableSet<Entry<E>> {
+ final ImmutableMultiset<E> multiset;
+
+ public EntrySet(ImmutableMultiset<E> multiset) {
+ this.multiset = multiset;
+ }
+
+ public Iterator<Entry<E>> iterator() {
+ final Iterator<Map.Entry<E, Integer>> mapIterator
+ = multiset.map.entrySet().iterator();
+ return new Iterator<Entry<E>>() {
+ public boolean hasNext() {
+ return mapIterator.hasNext();
+ }
+ public Entry<E> next() {
+ Map.Entry<E, Integer> mapEntry = mapIterator.next();
+ return
+ Multisets.immutableEntry(mapEntry.getKey(), mapEntry.getValue());
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public int size() {
+ return multiset.map.size();
+ }
+
+ @Override public boolean contains(Object o) {
+ if (o instanceof Entry) {
+ Entry<?> entry = (Entry<?>) o;
+ if (entry.getCount() <= 0) {
+ return false;
+ }
+ int count = multiset.count(entry.getElement());
+ return count == entry.getCount();
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return multiset.map.hashCode();
+ }
+
+ @Override Object writeReplace() {
+ return this;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * @serialData the number of distinct elements, the first element, its count,
+ * the second element, its count, and so on
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMultiset(this, stream);
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException, NoSuchFieldException {
+ stream.defaultReadObject();
+ int entryCount = stream.readInt();
+ ImmutableMap.Builder<E, Integer> builder = ImmutableMap.builder();
+ long tmpSize = 0;
+ for (int i = 0; i < entryCount; i++) {
+ @SuppressWarnings("unchecked") // reading data stored by writeMultiset
+ E element = (E) stream.readObject();
+ int count = stream.readInt();
+ if (count <= 0) {
+ throw new InvalidObjectException("Invalid count " + count);
+ }
+ builder.put(element, count);
+ tmpSize += count;
+ }
+
+ Serialization.setFinalField(ImmutableMultiset.class, this, "map",
+ builder.build());
+ Serialization.setFinalField(ImmutableMultiset.class, this, "size",
+ (int) Math.min(tmpSize, Integer.MAX_VALUE));
+ }
+
+ @Override Object writeReplace() {
+ return this;
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ImmutableSet.java b/plugins/com.google.collect/src/com/google/common/collect/ImmutableSet.java
new file mode 100644
index 0000000..e4b62f1
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ImmutableSet.java
@@ -0,0 +1,529 @@
+/*
+ * 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.collect;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 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.
+ *
+ * @see ImmutableList
+ * @see ImmutableMap
+ * @author Kevin Bourrillion
+ */
+@SuppressWarnings("serial") // we're overriding default serialization
+public abstract class ImmutableSet<E> extends ImmutableCollection<E>
+ implements Set<E> {
+ private static final ImmutableSet<?> EMPTY_IMMUTABLE_SET
+ = new EmptyImmutableSet();
+
+ /**
+ * 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>) EMPTY_IMMUTABLE_SET;
+ }
+
+ /**
+ * 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, element.hashCode());
+ }
+
+ /**
+ * 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 (but too many of these may result in the set being
+ * sized inappropriately).
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableSet<E> of(E... elements) {
+ switch (elements.length) {
+ case 0:
+ return of();
+ case 1:
+ return of(elements[0]);
+ default:
+ return create(Arrays.asList(elements), elements.length);
+ }
+ }
+
+ /**
+ * 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 (but too many of these may result in the set being
+ * sized inappropriately).
+ *
+ * <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, if {@code elements}
+ * is an {@code ImmutableSet}, no copy will actually be performed, and the
+ * given set itself will be returned.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
+ if (elements instanceof ImmutableSet) {
+ @SuppressWarnings("unchecked") // all supported methods are covariant
+ ImmutableSet<E> set = (ImmutableSet<E>) elements;
+ return set;
+ }
+ return copyOfInternal(Collections2.toCollection(elements));
+ }
+
+ /**
+ * 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) {
+ Collection<E> list = Lists.newArrayList(elements);
+ return copyOfInternal(list);
+ }
+
+ private static <E> ImmutableSet<E> copyOfInternal(
+ Collection<? extends E> collection) {
+ // TODO: Support concurrent collections that change while this method is
+ // running.
+ switch (collection.size()) {
+ case 0:
+ return of();
+ case 1:
+ // TODO: Remove "ImmutableSet.<E>" when eclipse bug is fixed.
+ return ImmutableSet.<E>of(collection.iterator().next());
+ default:
+ return create(collection, collection.size());
+ }
+ }
+
+ ImmutableSet() {}
+
+ /** Returns {@code true} if the {@code hashCode()} method runs quickly. */
+ boolean isHashCodeFast() {
+ return false;
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof ImmutableSet
+ && isHashCodeFast()
+ && ((ImmutableSet<?>) object).isHashCodeFast()
+ && hashCode() != object.hashCode()) {
+ return false;
+ }
+ if (object instanceof Set) {
+ Set<?> that = (Set<?>) object;
+ return size() == that.size() && containsAll(that);
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+
+ @Override public String toString() {
+ if (isEmpty()) {
+ return "[]";
+ }
+ Iterator<E> iterator = iterator();
+ StringBuilder result = new StringBuilder(size() * 16);
+ result.append('[').append(iterator.next().toString());
+ for (int i = 1; i < size(); i++) {
+ result.append(", ").append(iterator.next().toString());
+ }
+ return result.append(']').toString();
+ }
+
+ private static final class EmptyImmutableSet extends ImmutableSet<Object> {
+ public int size() {
+ return 0;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public boolean contains(Object target) {
+ return false;
+ }
+
+ public Iterator<Object> iterator() {
+ return Iterators.emptyIterator();
+ }
+
+ @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 boolean containsAll(Collection<?> targets) {
+ return targets.isEmpty();
+ }
+
+ @Override public boolean equals(Object object) {
+ return object == this
+ || (object instanceof Set && ((Set<?>) object).isEmpty());
+ }
+
+ @Override public final int hashCode() {
+ return 0;
+ }
+
+ @Override boolean isHashCodeFast() {
+ return true;
+ }
+
+ @Override public String toString() {
+ return "[]";
+ }
+ }
+
+ private static final class SingletonImmutableSet<E> extends ImmutableSet<E> {
+ final E element;
+ final int hashCode;
+
+ SingletonImmutableSet(E element, int hashCode) {
+ this.element = element;
+ this.hashCode = hashCode;
+ }
+
+ public int size() {
+ return 1;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ @Override public boolean contains(Object target) {
+ return element.equals(target);
+ }
+
+ public Iterator<E> iterator() {
+ return Iterators.singletonIterator(element);
+ }
+
+ @Override public Object[] toArray() {
+ return new Object[] { element };
+ }
+
+ @SuppressWarnings({"unchecked"})
+ @Override public <T> T[] toArray(T[] array) {
+ if (array.length == 0) {
+ array = ObjectArrays.newArray(array, 1);
+ } else if (array.length > 1) {
+ array[1] = null;
+ }
+ array[0] = (T) element;
+ return array;
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Set) {
+ Set<?> set = (Set<?>) object;
+ return set.size() == 1 && contains(set.iterator().next());
+ }
+ return false;
+ }
+
+ @Override public final int hashCode() {
+ return hashCode;
+ }
+
+ @Override boolean isHashCodeFast() {
+ return true;
+ }
+
+ @Override public String toString() {
+ String elementToString = element.toString();
+ return new StringBuilder(elementToString.length() + 2)
+ .append('[')
+ .append(elementToString)
+ .append(']')
+ .toString();
+ }
+ }
+
+ private static <E> ImmutableSet<E> create(
+ Iterable<? extends E> iterable, int count) {
+ // count is always the (nonzero) number of elements in the iterable
+ int tableSize = Hashing.chooseTableSize(count);
+ Object[] table = new Object[tableSize];
+ int mask = tableSize - 1;
+
+ List<E> elements = new ArrayList<E>(count);
+ int hashCode = 0;
+
+ for (E element : iterable) {
+ int hash = element.hashCode();
+ for (int i = Hashing.smear(hash); true; i++) {
+ int index = i & mask;
+ Object value = table[index];
+ if (value == null) {
+ // Came to an empty bucket. Put the element here.
+ table[index] = element;
+ elements.add(element);
+ hashCode += hash;
+ break;
+ } else if (value.equals(element)) {
+ break; // Found a duplicate. Nothing to do.
+ }
+ }
+ }
+
+ // The iterable might have contained only duplicates of the same element.
+ return (elements.size() == 1)
+ ? new SingletonImmutableSet<E>(elements.get(0), hashCode)
+ : new RegularImmutableSet<E>(elements.toArray(), hashCode, table, mask);
+ }
+
+ abstract static class ArrayImmutableSet<E> extends ImmutableSet<E> {
+ final Object[] elements; // the elements (two or more) in the desired order
+
+ ArrayImmutableSet(Object[] elements) {
+ this.elements = elements;
+ }
+
+ public int size() {
+ return elements.length;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ /*
+ * The cast is safe because the only way to create an instance is via the
+ * create() method above, which only permits elements of type E.
+ */
+ @SuppressWarnings("unchecked")
+ public Iterator<E> iterator() {
+ return (Iterator<E>) Iterators.forArray(elements);
+ }
+
+ @Override public Object[] toArray() {
+ Object[] array = new Object[size()];
+ System.arraycopy(elements, 0, array, 0, size());
+ return array;
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ int size = size();
+ if (array.length < size) {
+ array = ObjectArrays.newArray(array, size);
+ } else if (array.length > size) {
+ array[size] = null;
+ }
+ System.arraycopy(elements, 0, array, 0, size);
+ return 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;
+ }
+ }
+
+ private static final class RegularImmutableSet<E>
+ extends ArrayImmutableSet<E> {
+ final Object[] table; // the same elements in hashed positions (plus nulls)
+ final int mask; // 'and' with an int to get a valid table index
+ final 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;
+ }
+ }
+
+ /** such as ImmutableMap.keySet() */
+ abstract static class TransformedImmutableSet<D, E> extends ImmutableSet<E> {
+ final D[] source;
+ final int hashCode;
+
+ TransformedImmutableSet(D[] source, int hashCode) {
+ this.source = source;
+ this.hashCode = hashCode;
+ }
+
+ abstract E transform(D element);
+
+ public int size() {
+ return source.length;
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ public Iterator<E> iterator() {
+ return new AbstractIterator<E>() {
+ int index = 0;
+ @Override protected E computeNext() {
+ return index < source.length
+ ? transform(source[index++])
+ : endOfData();
+ }
+ };
+ }
+
+ @Override public Object[] toArray() {
+ return toArray(new Object[size()]);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public <T> T[] toArray(T[] array) {
+ int size = size();
+ if (array.length < size) {
+ array = ObjectArrays.newArray(array, size);
+ } else if (array.length > size) {
+ array[size] = null;
+ }
+
+ for (int i = 0; i < source.length; i++) {
+ array[i] = (T) transform(source[i]);
+ }
+ return array;
+ }
+
+ @Override public final int hashCode() {
+ return hashCode;
+ }
+
+ @Override boolean isHashCodeFast() {
+ return true;
+ }
+ }
+
+ /*
+ * This class is used to serialize all ImmutableSet instances, 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 of(elements);
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ @Override Object writeReplace() {
+ return new SerializedForm(toArray());
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ImmutableSortedSet.java b/plugins/com.google.collect/src/com/google/common/collect/ImmutableSortedSet.java
new file mode 100644
index 0000000..3af93d5
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ImmutableSortedSet.java
@@ -0,0 +1,832 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Objects;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+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;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedSet;
+
+/**
+ * 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 {@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.
+ *
+ * @see ImmutableSet
+ * @author Jared Levy
+ */
+@SuppressWarnings("serial") // we're overriding default serialization
+public abstract class ImmutableSortedSet<E> extends ImmutableSet<E>
+ implements SortedSet<E> {
+
+ // TODO: Can we find a way to remove these @SuppressWarnings?
+ @SuppressWarnings("unchecked")
+ private static final Comparator NATURAL_ORDER = Comparators.naturalOrder();
+ @SuppressWarnings("unchecked")
+ private static final ImmutableSortedSet<Object> NATURAL_EMPTY_SET =
+ new EmptyImmutableSortedSet<Object>(NATURAL_ORDER);
+
+ @SuppressWarnings("unchecked")
+ private static <E> ImmutableSortedSet<E> emptySet() {
+ return (ImmutableSortedSet<E>) NATURAL_EMPTY_SET;
+ }
+
+ private static <E> ImmutableSortedSet<E> emptySet(
+ Comparator<? super E> comparator) {
+ if (comparator == NATURAL_ORDER) {
+ 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.
+ *
+ * <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.
+ */
+ @SuppressWarnings("unchecked") // See method Javadoc
+ public static <E extends Comparable> ImmutableSortedSet<E> of(E element) {
+ Object[] array = { checkNotNull(element) };
+ return new RegularImmutableSortedSet<E>(array, NATURAL_ORDER);
+ }
+
+ // TODO: Consider adding factory methods that throw an exception when given
+ // duplicate elements.
+
+ /**
+ * 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.
+ *
+ * <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.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ @SuppressWarnings("unchecked") // See method Javadoc
+ public static <E extends Comparable> ImmutableSortedSet<E> of(E... elements) {
+ return ofInternal(Comparators.naturalOrder(), elements);
+ }
+
+ private static <E> ImmutableSortedSet<E> ofInternal(
+ Comparator<? super E> comparator, E... elements) {
+ switch (elements.length) {
+ case 0:
+ return emptySet(comparator);
+ default:
+ Object[] array = elements.clone();
+ for (Object element : array) {
+ checkNotNull(element);
+ }
+ sort(array, comparator);
+ array = removeDupes(array, comparator);
+ return new RegularImmutableSortedSet<E>(array, comparator);
+ }
+ }
+
+ /** Sort the array, according to the comparator. */
+ @SuppressWarnings("unchecked") // E comparator with Object array
+ private static <E> void sort(
+ Object[] array, Comparator<? super E> comparator) {
+ Arrays.sort(array, (Comparator<Object>) comparator);
+ }
+
+ /**
+ * Returns an array that removes duplicate consecutive elements, according to
+ * the provided comparator. Note that the input array is modified. This method
+ * does not support empty arrays.
+ */
+ private static <E> Object[] removeDupes(Object[] array,
+ Comparator<? super E> comparator) {
+ int size = 1;
+ for (int i = 1; i < array.length; i++) {
+ Object element = array[i];
+ if ((compare(comparator, array[size - 1], element) != 0)) {
+ array[size] = element;
+ size++;
+ }
+ }
+
+ // TODO: Move to ObjectArrays?
+ if (size == array.length) {
+ return array;
+ } else {
+ Object[] copy = new Object[size];
+ System.arraycopy(array, 0, copy, 0, size);
+ return copy;
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * <p>Note that if {@code s} is a {@code Set<String>}, then
+ * {@code ImmutableSortedSet.copyOf(s)} returns a
+ * {@code ImmutableSortedSet<String>} containing each of the strings in
+ * {@code s}, while {@code ImmutableSortedSet.of(s)} returns a
+ * {@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>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.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable> ImmutableSortedSet<E> copyOf(
+ Iterable<? extends E> elements) {
+ return copyOfInternal(Comparators.naturalOrder(), elements, false);
+ }
+
+ /**
+ * 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>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.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable> ImmutableSortedSet<E> copyOf(
+ Iterator<? extends E> elements) {
+ return copyOfInternal(Comparators.naturalOrder(), 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><b>Note:</b> Despite what the method name suggests, if {@code sortedSet}
+ * is an {@code ImmutableSortedSet}, it may be returned instead of a copy.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ @SuppressWarnings("unchecked")
+ public static <E> ImmutableSortedSet<E> copyOfSorted(SortedSet<E> sortedSet) {
+ Comparator<? super E> comparator = sortedSet.comparator();
+ if (comparator == null) {
+ comparator = NATURAL_ORDER;
+ }
+ return copyOfInternal(comparator, sortedSet, true);
+ }
+
+ private static <E> ImmutableSortedSet<E> copyOfInternal(
+ Comparator<? super E> comparator, Iterable<? extends E> elements,
+ boolean fromSortedSet) {
+ boolean hasSameComparator
+ = fromSortedSet || hasSameComparator(elements, comparator);
+
+ if (hasSameComparator && (elements instanceof ImmutableSortedSet)) {
+ @SuppressWarnings("unchecked")
+ ImmutableSortedSet<E> result = (ImmutableSortedSet<E>) elements;
+ if (!result.hasPartialArray()) {
+ return result;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ Object[] array
+ = Iterables.newArray((Iterable<Object>) elements, Object.class);
+ if (array.length == 0) {
+ return emptySet(comparator);
+ }
+
+ for (Object e : array) {
+ checkNotNull(e);
+ }
+ if (!hasSameComparator) {
+ sort(array, comparator);
+ array = removeDupes(array, comparator);
+ }
+ return new RegularImmutableSortedSet<E>(array, comparator);
+ }
+
+ private static <E> ImmutableSortedSet<E> copyOfInternal(
+ Comparator<? super E> comparator, Iterator<? extends E> elements) {
+ if (!elements.hasNext()) {
+ return emptySet(comparator);
+ }
+ List<E> list = Lists.newArrayList();
+ while (elements.hasNext()) {
+ list.add(checkNotNull(elements.next()));
+ }
+ Object[] array = list.toArray();
+ sort(array, comparator);
+ array = removeDupes(array, comparator);
+ return new RegularImmutableSortedSet<E>(array, comparator);
+ }
+
+ /**
+ * Returns {@code true} if {@code elements} is a {@code SortedSet} that uses
+ * {@code comparator} to order its elements. Note that equivalent comparators
+ * may still return {@code false}, if {@code equals} doesn't consider them
+ * equal. If one comparator is {@code null} and the other is
+ * {@link Comparators#naturalOrder()}, this method returns {@code true}.
+ */
+ private static boolean hasSameComparator(Object elements,
+ Comparator<?> comparator) {
+ if (elements instanceof SortedSet) {
+ SortedSet<?> sortedSet = (SortedSet<?>) elements;
+ Comparator<?> comparator2 = sortedSet.comparator();
+ return Objects.equal(comparator2, comparator)
+ || (comparator == null && comparator2 == Comparators.naturalOrder())
+ || (comparator2 == null && comparator == Comparators.naturalOrder());
+ }
+ return false;
+ }
+
+ /**
+ * Returns a factory 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 Factory#Factory(Comparator)}
+ * constructor instead.
+ *
+ * @throws NullPointerException if {@code comparator} is null
+ */
+ public static <E> Factory<E> orderedBy(Comparator<E> comparator) {
+ return new Factory<E>(comparator);
+ }
+
+ /**
+ * Returns a factory that creates immutable sorted sets whose elements are
+ * ordered by the reverse of their natural ordering. The sorted sets use
+ * {@link Collections#reverseOrder()} as the comparator.
+ *
+ * <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.
+ */
+ @SuppressWarnings("unchecked") // See method Javadoc
+ public static <E extends Comparable> Factory<E> reverseOrder() {
+ return new Factory<E>(Collections.reverseOrder());
+ }
+
+ /**
+ * A factory for creating immutable sorted sets with an explicit comparator.
+ *
+ * <p>The factory is immutable and may be used to create multiple
+ * {@code ImmutableSortedSet} instances.
+ */
+ public static class Factory<E> {
+ private final Comparator<? super E> comparator;
+
+ /**
+ * Creates a new factory. The returned factory is equivalent to the factory
+ * generated by {@link ImmutableSortedSet#orderedBy}.
+ *
+ * @throws NullPointerException if {@code comparator} is null
+ */
+ public Factory(Comparator<? super E> comparator) {
+ this.comparator = checkNotNull(comparator);
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * the factory's comparator. When multiple elements are equivalent according
+ * to the comparator, only the first one specified is included.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public ImmutableSortedSet<E> of(E... elements) {
+ return ofInternal(comparator, elements);
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * the factory's comparator. When multiple elements are equivalent according
+ * to the comparator, only the first one specified is included.
+ *
+ * <p><b>Note:</b> Despite what the method name suggests, if
+ * {@code elements} is an {@code ImmutableSortedSet} with an equivalent
+ * comparator, it may be returned instead of a copy.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public ImmutableSortedSet<E> copyOf(Iterable<? extends E> elements) {
+ return copyOfInternal(comparator, elements, false);
+ }
+
+ /**
+ * Returns an immutable sorted set containing the given elements sorted by
+ * the factory's comparator. When multiple elements are equivalent according
+ * to the comparator, only the first one specified is included.
+ *
+ * @throws NullPointerException if any of {@code elements} is null
+ */
+ public ImmutableSortedSet<E> copyOf(Iterator<? extends E> elements) {
+ return copyOfInternal(comparator, elements);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <E> int compare(Comparator<? super E> comparator, Object a,
+ Object b) {
+ return comparator.compare((E) a, (E) b);
+ }
+
+ final Comparator<? super E> comparator;
+
+ private ImmutableSortedSet(Comparator<? super E> comparator) {
+ this.comparator = comparator;
+ }
+
+ /**
+ * Returns the comparator that orders the elements, which is
+ * {@link Comparators#naturalOrder()} 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.
+ */
+ public Comparator<? super E> comparator() {
+ return comparator;
+ }
+
+ /**
+ * {@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}.
+ */
+ public ImmutableSortedSet<E> headSet(E toElement) {
+ return headSetImpl(checkNotNull(toElement));
+ }
+
+ /**
+ * {@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 toElement}. 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}.
+ */
+ public ImmutableSortedSet<E> subSet(E fromElement, E toElement) {
+ checkNotNull(fromElement);
+ checkNotNull(toElement);
+ checkArgument(compare(comparator, fromElement, toElement) <= 0);
+ return subSetImpl(fromElement, toElement);
+ }
+
+ /**
+ * {@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}.
+ */
+ public ImmutableSortedSet<E> tailSet(E fromElement) {
+ return tailSetImpl(checkNotNull(fromElement));
+ }
+
+ /*
+ * These methods perform most headSet, subSet, and tailSet logic, besides
+ * parameter validation.
+ */
+ abstract ImmutableSortedSet<E> headSetImpl(E toElement);
+ abstract ImmutableSortedSet<E> subSetImpl(E fromElement, E toElement);
+ abstract ImmutableSortedSet<E> tailSetImpl(E fromElement);
+
+ /** Returns whether the elements are stored in a subset of a larger array. */
+ abstract boolean hasPartialArray();
+
+ /** An empty immutable sorted set. */
+ private static class EmptyImmutableSortedSet<E>
+ extends ImmutableSortedSet<E> {
+
+ EmptyImmutableSortedSet(Comparator<? super E> comparator) {
+ super(comparator);
+ }
+
+ public int size() {
+ return 0;
+ }
+
+ @Override public boolean isEmpty() {
+ return true;
+ }
+
+ @Override public boolean contains(Object target) {
+ return false;
+ }
+
+ public Iterator<E> iterator() {
+ return Iterators.emptyIterator();
+ }
+
+ @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 boolean containsAll(Collection<?> targets) {
+ return targets.isEmpty();
+ }
+
+ @Override public boolean equals(Object object) {
+ return (object instanceof Set) && ((Set<?>) object).isEmpty();
+ }
+
+ @Override public int hashCode() {
+ return 0;
+ }
+
+ @Override public String toString() {
+ return "[]";
+ }
+
+ public E first() {
+ throw new NoSuchElementException();
+ }
+
+ public E last() {
+ throw new NoSuchElementException();
+ }
+
+ @Override ImmutableSortedSet<E> headSetImpl(E toElement) {
+ return this;
+ }
+
+ @Override ImmutableSortedSet<E> subSetImpl(E fromElement, E toElement) {
+ return this;
+ }
+
+ @Override ImmutableSortedSet<E> tailSetImpl(E fromElement) {
+ return this;
+ }
+
+ @Override boolean hasPartialArray() {
+ return false;
+ }
+ }
+
+ /**
+ * An empty immutable sorted set with one or more elements.
+ * TODO: Consider creating a separate class for a single-element sorted set.
+ */
+ @SuppressWarnings("serial")
+ private static final class RegularImmutableSortedSet<E>
+ extends ImmutableSortedSet<E> {
+
+ final Object[] elements;
+ /**
+ * The index of the first element that's in the sorted set (inclusive
+ * index).
+ */
+ final int fromIndex;
+ /**
+ * The index after the last element that's in the sorted set (exclusive
+ * index).
+ */
+ final int toIndex;
+
+ RegularImmutableSortedSet(Object[] elements,
+ Comparator<? super E> comparator) {
+ super(comparator);
+ this.elements = elements;
+ this.fromIndex = 0;
+ this.toIndex = elements.length;
+ }
+
+ RegularImmutableSortedSet(Object[] elements,
+ Comparator<? super E> comparator, int fromIndex, int toIndex) {
+ super(comparator);
+ this.elements = elements;
+ this.fromIndex = fromIndex;
+ this.toIndex = toIndex;
+ }
+
+ // The factory methods ensure that every element is an E.
+ @SuppressWarnings("unchecked")
+ public Iterator<E> iterator() {
+ return (Iterator<E>) Iterators.forArray(elements, fromIndex, size());
+ }
+
+ @Override public boolean isEmpty() {
+ return false;
+ }
+
+ public int size() {
+ return toIndex - fromIndex;
+ }
+
+ @Override public boolean contains(Object o) {
+ if (o == null) {
+ return false;
+ }
+ try {
+ return binarySearch(o) >= 0;
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+
+ @Override public boolean containsAll(Collection<?> targets) {
+ // TODO: For optimal performance, use a binary search when
+ // targets.size() < size() / log(size())
+ if (!hasSameComparator(targets, comparator()) || (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.
+ */
+ int i = fromIndex;
+ Iterator<?> iterator = targets.iterator();
+ Object target = iterator.next();
+
+ while (true) {
+ if (i >= toIndex) {
+ return false;
+ }
+
+ int cmp = compare(comparator, elements[i], target);
+
+ if (cmp < 0) {
+ i++;
+ } else if (cmp == 0) {
+ if (!iterator.hasNext()) {
+ return true;
+ }
+ target = iterator.next();
+ i++;
+ } else if (cmp > 0) {
+ return false;
+ }
+ }
+ }
+
+ int binarySearch(Object key) {
+ int lower = fromIndex;
+ int upper = toIndex - 1;
+
+ while (lower <= upper) {
+ int middle = lower + (upper - lower) / 2;
+ int c = compare(comparator, key, elements[middle]);
+ if (c < 0) {
+ upper = middle - 1;
+ } else if (c > 0) {
+ lower = middle + 1;
+ } else {
+ return middle;
+ }
+ }
+
+ return -lower - 1;
+ }
+
+ @Override public Object[] toArray() {
+ Object[] array = new Object[size()];
+ System.arraycopy(elements, fromIndex, array, 0, size());
+ return array;
+ }
+
+ // TODO: Move to ObjectArrays (same code in ImmutableList).
+ @Override public <T> T[] toArray(T[] array) {
+ int size = size();
+ if (array.length < size) {
+ array = ObjectArrays.newArray(array, size);
+ } else if (array.length > size) {
+ array[size] = null;
+ }
+ System.arraycopy(elements, fromIndex, array, 0, size);
+ return array;
+ }
+
+ @Override public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (!(object instanceof Set)) {
+ return false;
+ }
+ Set<?> set = (Set<?>) object;
+ if (size() != set.size()) {
+ return false;
+ }
+
+ if (hasSameComparator(object, comparator)) {
+ Iterator<?> iterator = set.iterator();
+ try {
+ for (int i = fromIndex; i < toIndex; i++) {
+ Object otherElement = iterator.next();
+ if ((otherElement == null)
+ || (compare(comparator, elements[i], otherElement) != 0)) {
+ return false;
+ }
+ }
+ return true;
+ } catch (ClassCastException e) {
+ return false;
+ } catch (NoSuchElementException e) {
+ return false; // concurrent change to other set
+ }
+ }
+
+ return containsAll(set);
+ }
+
+ @Override public int hashCode() {
+ // not caching hash code since it could change if the elements are mutable
+ // in a way that modifies their hash codes
+ int hash = 0;
+ for (int i = fromIndex; i < toIndex; i++) {
+ hash += elements[i].hashCode();
+ }
+ return hash;
+ }
+
+ @Override public String toString() {
+ StringBuilder result = new StringBuilder(size() * 16);
+ result.append('[').append(elements[fromIndex]);
+ for (int i = fromIndex + 1; i < toIndex; i++) {
+ result.append(", ").append(elements[i]);
+ }
+ return result.append(']').toString();
+ }
+
+ // The factory methods ensure that every element is an E.
+ @SuppressWarnings("unchecked")
+ public E first() {
+ return (E) elements[fromIndex];
+ }
+
+ // The factory methods ensure that every element is an E.
+ @SuppressWarnings("unchecked")
+ public E last() {
+ return (E) elements[toIndex - 1];
+ }
+
+ @Override ImmutableSortedSet<E> headSetImpl(E toElement) {
+ return createSubset(fromIndex, findSubsetIndex(toElement));
+ }
+
+ @Override ImmutableSortedSet<E> subSetImpl(E fromElement, E toElement) {
+ return createSubset(
+ findSubsetIndex(fromElement), findSubsetIndex(toElement));
+ }
+
+ @Override ImmutableSortedSet<E> tailSetImpl(E fromElement) {
+ return createSubset(findSubsetIndex(fromElement), toIndex);
+ }
+
+ int findSubsetIndex(E fromElement) {
+ int index = binarySearch(fromElement);
+ return (index >= 0) ? index : (-index - 1);
+ }
+
+ ImmutableSortedSet<E> createSubset(int newFromIndex, int newToIndex) {
+ if (newFromIndex < newToIndex) {
+ return new RegularImmutableSortedSet<E>(elements, comparator,
+ newFromIndex, newToIndex);
+ } else {
+ return emptySet(comparator);
+ }
+ }
+
+ @Override boolean hasPartialArray() {
+ return (fromIndex != 0) || (toIndex != elements.length);
+ }
+ }
+
+ /*
+ * 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 Factory<E>(comparator).of((E[]) 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<E>(comparator, toArray());
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Iterables.java b/plugins/com.google.collect/src/com/google/common/collect/Iterables.java
new file mode 100644
index 0000000..64aa914
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Iterables.java
@@ -0,0 +1,798 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Function;
+import com.google.common.base.Nullable;
+import com.google.common.base.Objects;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkContentsNotNull;
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.base.Predicate;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedSet;
+
+/**
+ * This class contains static utility methods that operate on or return objects
+ * of type {@code Iterable}. Also see the parallel implementations in {@link
+ * Iterators}.
+ *
+ * @author Kevin Bourrillion
+ * @author Scott Bonneau
+ */
+public final class Iterables {
+ private Iterables() {}
+
+ private static final Iterable<Object> EMPTY_ITERABLE = new Iterable<Object>()
+ {
+ public Iterator<Object> iterator() {
+ return Iterators.EMPTY_ITERATOR;
+ }
+ @Override public String toString() {
+ return "[]";
+ }
+ };
+
+ /** Returns the empty {@code Iterable}. */
+ // Casting to any type is safe since there are no actual elements.
+ @SuppressWarnings("unchecked")
+ public static <T> Iterable<T> emptyIterable() {
+ return (Iterable<T>) EMPTY_ITERABLE;
+ }
+
+ /** Returns an unmodifiable view of {@code iterable}. */
+ public static <T> Iterable<T> unmodifiableIterable(final Iterable<T> iterable)
+ {
+ checkNotNull(iterable);
+ return new Iterable<T>() {
+ 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 {@code element}; that is,
+ * any object for while {@code equals(element)} is true.
+ */
+ public static boolean contains(Iterable<?> iterable, @Nullable Object element)
+ {
+ if (element == null) {
+ return containsNull(iterable);
+ }
+ if (iterable instanceof Collection) {
+ Collection<?> collection = (Collection<?>) iterable;
+ try {
+ return collection.contains(element);
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+ return Iterators.contains(iterable.iterator(), element);
+ }
+
+ /**
+ * Returns {@code true} if {@code iterable} contains at least one null
+ * element.
+ */
+ public static boolean containsNull(Iterable<?> iterable) {
+ if (iterable instanceof Collection) {
+ Collection<?> collection = (Collection<?>) iterable;
+ try {
+ return collection.contains(null);
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+ return Iterators.containsNull(iterable.iterator());
+ }
+
+ /**
+ * 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 iterable the iterable to (potentially) remove elements from
+ * @param c the elements to remove
+ * @return {@code true} if any elements are removed from {@code iterable}
+ */
+ public static boolean removeAll(Iterable<?> iterable, Collection<?> c) {
+ return (iterable instanceof Collection)
+ ? ((Collection<?>) iterable).removeAll(checkNotNull(c))
+ : Iterators.removeAll(iterable.iterator(), c);
+ }
+
+ /**
+ * 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 iterable the iterable to (potentially) remove elements from
+ * @param c the elements to retain
+ * @return {@code true} if any elements are removed from {@code iterable}
+ */
+ public static boolean retainAll(Iterable<?> iterable, Collection<?> c) {
+ return (iterable instanceof Collection)
+ ? ((Collection<?>) iterable).retainAll(checkNotNull(c))
+ : Iterators.retainAll(iterable.iterator(), c);
+ }
+
+ /**
+ * 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<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
+ */
+ public static <T> T[] newArray(Iterable<T> iterable, Class<T> type) {
+ Collection<T> collection = (iterable instanceof Collection)
+ ? (Collection<T>) iterable
+ : Lists.newArrayList(iterable);
+ T[] array = ObjectArrays.newArray(type, collection.size());
+ return collection.toArray(array);
+ }
+
+ /**
+ * 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> collection, Iterable<? extends T> iterable) {
+ if (iterable instanceof Collection) {
+ @SuppressWarnings("unchecked")
+ Collection<? extends T> c = (Collection<? extends T>) iterable;
+ return collection.addAll(c);
+ }
+ return Iterators.addAll(collection, iterable.iterator());
+ }
+
+ /**
+ * Returns the number of elements in the specified iterable that equal the
+ * specified object.
+ *
+ * @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 iterator cycles 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 Iterable<T>() {
+ public Iterator<T> iterator() {
+ return Iterators.cycle(iterable);
+ }
+ @Override public String toString() {
+ return iterable.toString() + " (cycled)";
+ }
+ };
+ }
+
+ /**
+ * Returns an iterable whose iterator cycles indefinitely over the provided
+ * elements.
+ *
+ * <p>That iterator supports {@code remove()} if {@code iterable.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.
+ *
+ * <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 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(checkContentsNotNull(Arrays.asList(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 are null.
+ */
+ public static <T> Iterable<T> concat(
+ Iterable<? extends Iterable<? extends T>> inputs) {
+ /*
+ * Hint: if you let A represent Iterable<? extends T> and B represent
+ * Iterator<? extends T>, then this Function would look simply like:
+ *
+ * Function<A, B> function = new Function<A, B> {
+ * public B apply(A from) {
+ * return from.iterator();
+ * }
+ * }
+ *
+ * TODO: there may be a better way to do this.
+ */
+
+ Function<Iterable<? extends T>, Iterator<? extends T>> function
+ = new Function<Iterable<? extends T>, Iterator<? extends T>>() {
+ public Iterator<? extends T> apply(Iterable<? extends T> from) {
+ return from.iterator();
+ }
+ };
+ final Iterable<Iterator<? extends T>> iterators
+ = transform(inputs, function);
+ return new AbstractIterable<T>() {
+ public Iterator<T> iterator() {
+ return Iterators.concat(iterators.iterator());
+ }
+ };
+ }
+
+ /**
+ * Partition an iterable into sub-iterables of the given size. For example,
+ * <code>{A, B, C, D, E, F}</code> with partition size 3 yields
+ * <code>{A, B, C}</code> and <code>{D, E, F}</code>. The returned iterables
+ * have iterators that do not support {@code remove()}.
+ *
+ * <p>After {@code next()} is called on the returned iterable's iterator, the
+ * iterables from prior {@code next()} calls become invalid.
+ *
+ * @param iterable the iterable to partition
+ * @param partitionSize the size of each partition
+ * @param padToSize whether to pad the last partition to the partition size
+ * with {@code null}.
+ * @return an iterable across partitioned iterables
+ */
+ public static <T> Iterable<Iterable<T>> partition(
+ final Iterable<? extends T> iterable, final int partitionSize,
+ final boolean padToSize) {
+ checkNotNull(iterable);
+ return new AbstractIterable<Iterable<T>>() {
+ public Iterator<Iterable<T>> iterator() {
+ final Iterator<Iterator<T>> iterator = Iterators.partition(
+ iterable.iterator(), partitionSize, padToSize);
+ return new AbstractIterator<Iterable<T>>() {
+ int howFarIn;
+
+ @Override protected Iterable<T> computeNext() {
+ howFarIn++;
+ if (!iterator.hasNext()) {
+ return endOfData();
+ }
+ return new AbstractIterable<T>() {
+ Iterator<T> innerIter = iterator.next();
+ boolean firstIteratorRequest = true;
+
+ public Iterator<T> iterator() {
+ if (firstIteratorRequest) {
+ firstIteratorRequest = false;
+ return innerIter;
+ } else {
+ Iterator<Iterator<T>> partitionIter = Iterators.partition(
+ iterable.iterator(), partitionSize, padToSize);
+ for (int i = 0; i < howFarIn; i++) {
+ innerIter = partitionIter.next();
+ }
+ return innerIter;
+ }
+ }
+ };
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * 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 AbstractIterable<T>() {
+ 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
+ */
+ public static <T> Iterable<T> filter(
+ final Iterable<?> unfiltered, final Class<T> type) {
+ checkNotNull(unfiltered);
+ checkNotNull(type);
+ return new AbstractIterable<T>() {
+ public Iterator<T> iterator() {
+ return Iterators.filter(unfiltered.iterator(), type);
+ }
+ };
+ }
+
+ /**
+ * Returns {@code true} if one or more elements in {@code iterable} satisfy
+ * the predicate.
+ */
+ public static <T> boolean any(
+ Iterable<T> iterable, Predicate<? super T> predicate) {
+ 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.
+ *
+ * @throws NoSuchElementException if no element in {@code iterable} matches
+ * the given predicate
+ */
+ public static <E> E find(Iterable<E> iterable,
+ Predicate<? super E> predicate) {
+ return Iterators.find(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.
+ */
+ public static <F, T> Iterable<T> transform(final Iterable<F> fromIterable,
+ final Function<? super F, ? extends T> function) {
+ checkNotNull(fromIterable);
+ checkNotNull(function);
+ return new AbstractIterable<T>() {
+ 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 (position < 0) {
+ throw new IndexOutOfBoundsException(
+ "position cannot be negative: " + position);
+ }
+
+ if (iterable instanceof Collection) {
+ Collection<T> collection = (Collection<T>) iterable;
+ int size = collection.size();
+ if (position >= size) {
+ throw new IndexOutOfBoundsException(String.format(
+ "position %d must be less than the iterable size %d",
+ position, size));
+ }
+
+ if (iterable instanceof List) {
+ List<T> list = (List<T>) iterable;
+ return list.get(position);
+ }
+ }
+
+ return Iterators.get(iterable.iterator(), position);
+ }
+
+ /**
+ * Returns the last element of {@code iterable}.
+ *
+ * @return the last element of {@code iterable}
+ * @throws NoSuchElementException if the iterable has no elements
+ */
+ public static <T> T getLast(Iterable<T> iterable) {
+ if (iterable instanceof List) {
+ List<T> list = (List<T>) iterable;
+ // TODO: Support a concurrent list whose size changes while this method
+ // is running.
+ if (list.isEmpty()) {
+ throw new NoSuchElementException();
+ }
+ return list.get(list.size() - 1);
+ }
+
+ if (iterable instanceof SortedSet) {
+ SortedSet<T> sortedSet = (SortedSet<T>) iterable;
+ return sortedSet.last();
+ }
+
+ return Iterators.getLast(iterable.iterator());
+ }
+
+ /**
+ * 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}.
+ */
+ 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 AbstractIterable<T>() {
+ public Iterator<T> iterator() {
+ // TODO: Support a concurrent list whose size changes while this
+ // method is running.
+ return (numberToSkip >= list.size())
+ ? Iterators.<T>emptyIterator()
+ : list.subList(numberToSkip, list.size()).iterator();
+ }
+ };
+ }
+
+ return new AbstractIterable<T>() {
+ public Iterator<T> iterator() {
+ final Iterator<T> iterator = iterable.iterator();
+
+ Iterators.skip(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;
+
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ try {
+ return iterator.next();
+ } finally {
+ atStart = false;
+ }
+ }
+
+ 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
+ */
+ public static <T> Iterable<T> limit(
+ final Iterable<T> iterable, final int limitSize) {
+ checkNotNull(iterable);
+ checkArgument(limitSize >= 0, "limit is negative");
+ return new AbstractIterable<T>() {
+ public Iterator<T> iterator() {
+ return Iterators.limit(iterable.iterator(), limitSize);
+ }
+ };
+ }
+
+ // Methods only in Iterables, not in Iterators
+
+ /**
+ * Adapts a list to an iterable with reversed iteration order. It is
+ * especially useful in foreach-style loops:
+ * <pre>
+ * List<String> mylist = ...
+ * for (String str : Iterables.reverse(mylist)) {
+ * ...
+ * } </pre>
+ *
+ * @return an iterable with the same elements as the list, in reverse.
+ */
+ public static <T> Iterable<T> reverse(final List<T> list) {
+ checkNotNull(list);
+ return new AbstractIterable<T>() {
+ public Iterator<T> iterator() {
+ final ListIterator<T> listIter = list.listIterator(list.size());
+ return new Iterator<T>() {
+ public boolean hasNext() {
+ return listIter.hasPrevious();
+ }
+ public T next() {
+ return listIter.previous();
+ }
+ public void remove() {
+ listIter.remove();
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Provides a rotated view of a list. Differs from {@link Collections#rotate}
+ * in that it leaves the underlying list unchanged. Note that this is a
+ * "live" view of the list that will change as the list changes. However, the
+ * behavior of an {@link Iterator} retrieved from a rotated view of the list
+ * is undefined if the list is structurally changed after the iterator is
+ * retrieved.
+ *
+ * @param list the list to return a rotated view of
+ * @param distance the distance to rotate the list. There are no constraints
+ * on this value; it may be zero, negative, or greater than {@code
+ * list.size()}.
+ * @return a rotated view of the given list
+ */
+ public static <T> Iterable<T> rotate(final List<T> list, final int distance) {
+ checkNotNull(list);
+
+
+ // If no rotation is requested, just return the original list
+ if (distance == 0) {
+ return list;
+ }
+
+ return new AbstractIterable<T>() {
+ /**
+ * Determines the actual distance we need to rotate (distance provided
+ * might be larger than the size of the list or negative).
+ */
+ int calcActualDistance(int size) {
+ // we already know distance and size are non-zero
+ int actualDistance = distance % size;
+ if (actualDistance < 0) {
+ // distance must have been negative
+ actualDistance += size;
+ }
+ return actualDistance;
+ }
+
+ public Iterator<T> iterator() {
+ int size = list.size();
+ if (size <= 1) {
+ return list.iterator();
+ }
+
+ int actualDistance = calcActualDistance(size);
+ // lists of a size that go into the distance evenly don't need rotation
+ if (actualDistance == 0) {
+ return list.iterator();
+ }
+
+ @SuppressWarnings("unchecked")
+ Iterable<T> rotated = concat(list.subList(actualDistance, size),
+ list.subList(0, actualDistance));
+ return rotated.iterator();
+ }
+ };
+ }
+
+ /**
+ * Returns whether the given iterable contains no elements.
+ *
+ * @return {@code true} if the iterable has no elements, {@code false} if the
+ * iterable has one or more elements
+ */
+ public static <T> boolean isEmpty(Iterable<T> iterable) {
+ return !iterable.iterator().hasNext();
+ }
+
+ /**
+ * Removes the specified element from the specified iterable.
+ *
+ * <p>This method iterates over the iterable, checking each element returned
+ * by the iterator in turn to see if it equals the object {@code o}. If they
+ * are equal, it is removed from the iterable with the iterator's
+ * {@code remove} method. At most one element is removed, even if the iterable
+ * contains multiple members that equal {@code o}.
+ *
+ * <p><b>Warning</b>: Do not use this method for a collection, such as a
+ * {@link HashSet}, that has a fast {@code remove} method.
+ *
+ * @param iterable the iterable from which to remove
+ * @param o an element to remove from the collection
+ * @return {@code true} if the iterable changed as a result
+ * @throws UnsupportedOperationException if the iterator does not support the
+ * {@code remove} method and the iterable contains the object
+ */
+ static boolean remove(Iterable<?> iterable, @Nullable Object o) {
+ Iterator<?> i = iterable.iterator();
+ while (i.hasNext()) {
+ if (Objects.equal(i.next(), o)) {
+ i.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Iterators.java b/plugins/com.google.collect/src/com/google/common/collect/Iterators.java
new file mode 100644
index 0000000..ade0000
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Iterators.java
@@ -0,0 +1,950 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkContentsNotNull;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Function;
+import com.google.common.base.Join;
+import com.google.common.base.Nullable;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * This class contains static utility methods that operate on or return objects
+ * of type {@code Iterator}. Also see the parallel implementations in {@link
+ * Iterables}.
+ *
+ * @author Kevin Bourrillion
+ * @author Scott Bonneau
+ */
+public final class Iterators {
+ private Iterators() {}
+
+ static final Iterator<Object> EMPTY_ITERATOR = new Iterator<Object>() {
+ public boolean hasNext() {
+ return false;
+ }
+ public Object next() {
+ throw new NoSuchElementException();
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+
+ /** Returns the empty {@code Iterator}. */
+ // Casting to any type is safe since there are no actual elements.
+ @SuppressWarnings("unchecked")
+ public static <T> Iterator<T> emptyIterator() {
+ return (Iterator<T>) EMPTY_ITERATOR;
+ }
+
+ private static final ListIterator<Object> EMPTY_LIST_ITERATOR =
+ new ListIterator<Object>() {
+ public boolean hasNext() {
+ return false;
+ }
+ public boolean hasPrevious() {
+ return false;
+ }
+ public int nextIndex() {
+ return 0;
+ }
+ public int previousIndex() {
+ return -1;
+ }
+ public Object next() {
+ throw new NoSuchElementException();
+ }
+ public Object previous() {
+ throw new NoSuchElementException();
+ }
+ public void set(Object o) {
+ throw new UnsupportedOperationException();
+ }
+ public void add(Object o) {
+ throw new UnsupportedOperationException();
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ /** Returns the empty {@code ListIterator}. */
+ // Casting to any type is safe since there are no actual elements.
+ @SuppressWarnings("unchecked")
+ public static <T> ListIterator<T> emptyListIterator() {
+ return (ListIterator<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> Iterator<T> unmodifiableIterator(
+ final Iterator<T> iterator) {
+ checkNotNull(iterator);
+ return new Iterator<T>() {
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ public T next() {
+ return iterator.next();
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * 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) {
+ return containsNull(iterator);
+ }
+ while (iterator.hasNext()) {
+ if (element.equals(iterator.next())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns {@code true} if {@code iterator} contains at least one null
+ * element.
+ */
+ public static boolean containsNull(Iterator<?> iterator) {
+ while (iterator.hasNext()) {
+ if (iterator.next() == null) {
+ 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 iterator the iterator to (potentially) remove elements from
+ * @param c the elements to remove
+ * @return {@code true} if any elements are removed from {@code iterator}
+ */
+ public static boolean removeAll(Iterator<?> iterator, Collection<?> c) {
+ checkNotNull(c);
+ boolean modified = false;
+ while (iterator.hasNext()) {
+ if (c.contains(iterator.next())) {
+ iterator.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 iterator the iterator to (potentially) remove elements from
+ * @param c the elements to retain
+ * @return {@code true} if any elements are removed from {@code iterator}
+ */
+ public static boolean retainAll(Iterator<?> iterator, Collection<?> c) {
+ checkNotNull(c);
+ boolean modified = false;
+ while (iterator.hasNext()) {
+ if (!c.contains(iterator.next())) {
+ iterator.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) {
+ StringBuilder builder = new StringBuilder().append('[');
+ Join.join(builder, ", ", iterator);
+ return builder.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<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
+ */
+ public static <T> T[] newArray(
+ Iterator<? extends T> iterator, Class<T> type) {
+ List<T> list = Lists.newArrayList(iterator);
+ return Iterables.newArray(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> collection, Iterator<? extends T> iterator) {
+ checkNotNull(collection);
+ boolean wasModified = false;
+ while (iterator.hasNext()) {
+ wasModified |= collection.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;
+
+ public boolean hasNext() {
+ if (!iterator.hasNext()) {
+ iterator = iterable.iterator();
+ }
+ return iterator.hasNext();
+ }
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ removeFrom = iterator;
+ return iterator.next();
+ }
+ 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.
+ */
+ @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 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.
+ *
+ * @throws NullPointerException if any of the provided iterators is null
+ */
+ public static <T> Iterator<T> concat(Iterator<? extends T>... inputs) {
+ return concat(checkContentsNotNull(Arrays.asList(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 are null.
+ */
+ 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;
+
+ public boolean hasNext() {
+ while (!current.hasNext() && inputs.hasNext()) {
+ current = inputs.next();
+ }
+ return current.hasNext();
+ }
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ removeFrom = current;
+ return current.next();
+ }
+ public void remove() {
+ checkState(removeFrom != null,
+ "no calls to next() since last call to remove()");
+ removeFrom.remove();
+ removeFrom = null;
+ }
+ };
+ }
+
+ /**
+ * Partition an iterator into sub-iterators of the given size. For example,
+ * <code>{A, B, C, D, E, F}</code> with partition size 3 yields
+ * <code>{A, B, C}</code> and <code>{D, E, F}</code>. The returned
+ * iterators do not support {@code remove()}.
+ *
+ * <p>After {@code next()} is called on the returned iterator, the iterators
+ * from prior {@code next()} calls become invalid.
+ *
+ * @param iterator the iterator to partition
+ * @param partitionSize the size of each partition
+ * @param padToSize whether to pad the last partition to the partition size
+ * with {@code null}
+ * @return an iterator across partitioned iterators
+ */
+ public static <T> Iterator<Iterator<T>> partition(
+ final Iterator<? extends T> iterator,
+ final int partitionSize, final boolean padToSize) {
+ checkNotNull(iterator);
+ return new AbstractIterator<Iterator<T>>() {
+ Iterator<T> currentRow;
+
+ @Override protected Iterator<T> computeNext() {
+ if (currentRow != null) {
+ while (currentRow.hasNext()) {
+ currentRow.next();
+ }
+ }
+ if (!iterator.hasNext()) {
+ return endOfData();
+ }
+ currentRow = new AbstractIterator<T>() {
+ int count = partitionSize;
+
+ @Override protected T computeNext() {
+ if (count == 0) {
+ return endOfData();
+ }
+ count--;
+ if (iterator.hasNext()) {
+ return iterator.next();
+ } else {
+ if (!padToSize) {
+ endOfData();
+ }
+ return null;
+ }
+ }
+ };
+ return currentRow;
+ }
+ };
+ }
+
+ /**
+ * Returns the elements of {@code unfiltered} that satisfy a predicate. The
+ * resulting iterator does not support {@code remove()}.
+ */
+ public static <T> Iterator<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}. The returned iterator does not support {@code remove()}.
+ *
+ * @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")
+ public static <T> Iterator<T> filter(
+ Iterator<?> unfiltered, final Class<T> type) {
+ checkNotNull(type);
+ Predicate<Object> predicate = new Predicate<Object>() {
+ public boolean apply(Object object) {
+ return type.isInstance(object);
+ }
+ };
+ return (Iterator<T>) filter(unfiltered, predicate);
+ }
+
+ /**
+ * 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. If a matching element is found, the iterator will be left in a
+ * state such that calling {@code iterator.remove()} will remove the found
+ * item. If no such element is found, the iterator will be left exhausted: its
+ * {@code hasNext()} method will return {@code false}.
+ *
+ * @return the first matching element in {@code iterator}
+ * @throws NoSuchElementException if no element in {@code iterator} matches
+ * the given predicate
+ */
+ public static <E> E find(Iterator<E> iterator, Predicate<? super E> predicate)
+ {
+ return filter(iterator, predicate).next();
+ }
+
+ /**
+ * 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(fromIterator);
+ checkNotNull(function);
+ return new Iterator<T>() {
+ public boolean hasNext() {
+ return fromIterator.hasNext();
+ }
+ public T next() {
+ F from = fromIterator.next();
+ return function.apply(from);
+ }
+ public void remove() {
+ fromIterator.remove();
+ }
+ };
+ }
+
+ /**
+ * 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) {
+ checkNotNull(iterator);
+ if (position < 0) {
+ throw new IndexOutOfBoundsException(
+ "position cannot be negative: " + position);
+ }
+
+ int skipped = skip(iterator, position);
+ if (skipped < position || !iterator.hasNext()) {
+ throw new IndexOutOfBoundsException(String.format(
+ "position (%d) must be less than the number of elements that " +
+ "remained (%d)", position, skipped));
+ } else {
+ return iterator.next();
+ }
+ }
+
+ /**
+ * Advances {@code iterator} to the end, returning the last element.
+ *
+ * @return the last element of {@code iterator}
+ * @throws NoSuchElementException if the iterator has no remaining elements
+ */
+ public static <T> T getLast(Iterator<T> iterator) {
+ while (true) {
+ T current = iterator.next();
+ if (!iterator.hasNext()) {
+ return current;
+ }
+ }
+ }
+
+ /**
+ * 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
+ */
+ public static <T> int skip(Iterator<T> iterator, int numberToSkip) {
+ checkNotNull(iterator);
+ checkArgument(numberToSkip >= 0, "number to skip cannot be negative");
+
+ int i;
+ for (i = 0; i < numberToSkip && 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
+ */
+ 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;
+
+ public boolean hasNext() {
+ return count < limitSize && iterator.hasNext();
+ }
+
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ count++;
+ return iterator.next();
+ }
+
+ public void remove() {
+ iterator.remove();
+ }
+ };
+ }
+
+ // Methods only in Iterators, not in Iterables
+
+ /**
+ * Returns an iterator containing the elements of {@code array} in order. Note
+ * that you can also use the iterator of {@link Arrays#asList}.
+ */
+ static <T> Iterator<T> forArray(T[] array) {
+ return forArray(array, 0, array.length);
+ }
+
+ /**
+ * Returns an iterator containing the elements in the specified range of
+ * {@code array} in order.
+ *
+ * @param array array to read elements out of
+ * @param offset index of first array element to retrieve
+ * @length length number of elements in iteration
+ *
+ * @throws IndexOutOfBoundsException if {@code offset} is negative,
+ * {@code length} is negative, or {@code offset + length > array.length}
+ */
+ public static <T> Iterator<T> forArray(
+ final T[] array, final int offset, final int length) {
+ checkNotNull(array);
+ if (length < 0) {
+ throw new IndexOutOfBoundsException("Negative length " + length);
+ }
+ if (offset < 0) {
+ throw new IndexOutOfBoundsException("Negative offset " + offset);
+ }
+ if (offset + length > array.length) {
+ throw new IndexOutOfBoundsException(
+ "offset (" + offset + ") + length (" + length + ") > "
+ + "array.length (" + array.length + ")");
+ }
+ if (length == 0) {
+ return emptyIterator();
+ }
+ return new Iterator<T>() {
+ int i = offset;
+ public boolean hasNext() {
+ return i < offset + length;
+ }
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return array[i++];
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Returns an iterator containing only {@code value}.
+ */
+ static <T> Iterator<T> singletonIterator(final T value) {
+ return new Iterator<T>() {
+ boolean done;
+ public boolean hasNext() {
+ return !done;
+ }
+ public T next() {
+ if (done) {
+ throw new NoSuchElementException();
+ }
+ done = true;
+ return value;
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Adapts an {@code Enumeration} to the {@code Iterator} interface. The
+ * returned iterator does not support {@code remove()}.
+ */
+ public static <T> Iterator<T> forEnumeration(final Enumeration<T> enumeration)
+ {
+ checkNotNull(enumeration);
+ return new Iterator<T>() {
+ public boolean hasNext() {
+ return enumeration.hasMoreElements();
+ }
+ public T next() {
+ return enumeration.nextElement();
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Adapts an {@code Iterator} to the {@code Enumeration} interface.
+ *
+ * @see Collections#enumeration(Collection)
+ */
+ public static <T> Enumeration<T> asEnumeration(final Iterator<T> iterator) {
+ checkNotNull(iterator);
+ return new Enumeration<T>() {
+ public boolean hasMoreElements() {
+ return iterator.hasNext();
+ }
+ 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);
+ }
+
+ public boolean hasNext() {
+ return hasPeeked || iterator.hasNext();
+ }
+
+ public E next() {
+ if (!hasPeeked) {
+ return iterator.next();
+ }
+ E result = peekedElement;
+ hasPeeked = false;
+ peekedElement = null;
+ return result;
+ }
+
+ public void remove() {
+ checkState(!hasPeeked, "Can't remove after you've peeked at next");
+ iterator.remove();
+ }
+
+ public E peek() {
+ if (!hasPeeked) {
+ peekedElement = iterator.next();
+ hasPeeked = true;
+ }
+ return peekedElement;
+ }
+ }
+
+ /**
+ * Wraps the supplied iterator in a {@code PeekingIterator}. The
+ * {@link PeekingIterator} assumes ownership of the supplied iterator, so
+ * users should cease making direct calls to it after calling this method.
+ *
+ * <p>If the {@link PeekingIterator#peek()} method of the constructed
+ * {@code PeekingIterator} is never called, the returned iterator will
+ * behave exactly the same as the supplied iterator.
+ *
+ * <p>Subsequent calls to {@code peek()} with no intervening calls to
+ * {@code next()} do not affect the iteration, and hence return the same
+ * object each time. After a call to {@code peek()}, the next call to
+ * {@code next()} is guaranteed to return the same object that the
+ * {@code peek()} call returned. For example:
+ *
+ * <pre>
+ * PeekingIterator&lt;E&gt; peekingIterator = ...;
+ * // Either the next three calls will each throw
+ * // NoSuchElementExceptions, or...
+ * E e1 = peekingIterator.peek();
+ * E e2 = peekingIterator.peek(); // e2 is the same as e1
+ * E e3 = peekingIterator.next(); // e3 is the same as e1/e2
+ * </pre>
+ *
+ * <p>Calling {@link Iterator#remove()} after {@link PeekingIterator#peek()}
+ * is unsupported by the returned iterator and will throw an
+ * {@link IllegalStateException}.
+ */
+ public static <T> PeekingIterator<T> peekingIterator(
+ Iterator<? extends T> iterator) {
+ return new PeekingImpl<T>(iterator);
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/LinkedHashMultimap.java b/plugins/com.google.collect/src/com/google/common/collect/LinkedHashMultimap.java
new file mode 100644
index 0000000..d31ad84
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/LinkedHashMultimap.java
@@ -0,0 +1,326 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 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}.
+ *
+ * @author Jared Levy
+ */
+public final class LinkedHashMultimap<K, V> extends StandardSetMultimap<K, V> {
+ /**
+ * Map entries with an iteration order corresponding to the order in which the
+ * key-value pairs were added to the multimap.
+ */
+ private transient Collection<Map.Entry<K, V>> linkedEntries;
+
+ /** Constructs an empty {@code LinkedHashMultimap}. */
+ public LinkedHashMultimap() {
+ super(new LinkedHashMap<K, Collection<V>>());
+ linkedEntries = Sets.newLinkedHashSet();
+ }
+
+ /**
+ * Constructs a {@code LinkedHashMultimap} with the same mappings as the
+ * specified {@code 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.
+ */
+ public LinkedHashMultimap(Multimap<? extends K, ? extends V> multimap) {
+ super(new LinkedHashMap<K, Collection<V>>(
+ Maps.capacity(multimap.keySet().size())));
+ linkedEntries
+ = new LinkedHashSet<Map.Entry<K, V>>(Maps.capacity(multimap.size()));
+ putAll(multimap);
+ }
+
+ /**
+ * {@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>();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Creates a decorated {@code LinkedHashSet} that also keeps track of the
+ * order in which key-value pairs are added to the multimap.
+ *
+ * @param key key to associate with values in the collection
+ * @return a new decorated {@code LinkedHashSet} containing a collection of
+ * values for one key
+ */
+ @Override Collection<V> createCollection(@Nullable K key) {
+ return new SetDecorator(key, createCollection());
+ }
+
+ private class SetDecorator extends ForwardingSet<V> {
+ final Set<V> delegate;
+ final K key;
+
+ SetDecorator(K key, Set<V> delegate) {
+ this.delegate = delegate;
+ this.key = key;
+ }
+
+ @Override protected Set<V> delegate() {
+ return delegate;
+ }
+
+ <E> Map.Entry<K, E> createEntry(@Nullable E value) {
+ return Maps.immutableEntry(key, value);
+ }
+
+ <E> Collection<Map.Entry<K, E>> createEntries(Collection<E> values) {
+ // converts a collection of values into a list of key/value map entries
+ Collection<Map.Entry<K, E>> entries
+ = Lists.newArrayListWithExpectedSize(values.size());
+ for (E value : values) {
+ entries.add(createEntry(value));
+ }
+ return entries;
+ }
+
+ @Override public boolean add(@Nullable V value) {
+ boolean changed = delegate.add(value);
+ if (changed) {
+ linkedEntries.add(createEntry(value));
+ }
+ return changed;
+ }
+
+ @Override public boolean addAll(Collection<? extends V> values) {
+ boolean changed = delegate.addAll(values);
+ if (changed) {
+ linkedEntries.addAll(createEntries(delegate()));
+ }
+ return changed;
+ }
+
+ @Override public void clear() {
+ linkedEntries.removeAll(createEntries(delegate()));
+ delegate.clear();
+ }
+
+ @Override public Iterator<V> iterator() {
+ final Iterator<V> delegateIterator = delegate.iterator();
+ return new Iterator<V>() {
+ V value;
+
+ public boolean hasNext() {
+ return delegateIterator.hasNext();
+ }
+ public V next() {
+ value = delegateIterator.next();
+ return value;
+ }
+ public void remove() {
+ delegateIterator.remove();
+ linkedEntries.remove(createEntry(value));
+ }
+ };
+ }
+
+ @Override public boolean remove(@Nullable Object value) {
+ boolean changed = delegate.remove(value);
+ if (changed) {
+ /*
+ * linkedEntries.remove() will return false when this method is called
+ * by entries().iterator().remove()
+ */
+ linkedEntries.remove(createEntry(value));
+ }
+ return changed;
+ }
+
+ @Override public boolean removeAll(Collection<?> values) {
+ boolean changed = delegate.removeAll(values);
+ if (changed) {
+ linkedEntries.removeAll(createEntries(values));
+ }
+ return changed;
+ }
+
+ @Override public boolean retainAll(Collection<?> values) {
+ /*
+ * Calling linkedEntries.retainAll() would incorrectly remove values
+ * with other keys.
+ */
+ boolean changed = false;
+ Iterator<V> iterator = delegate.iterator();
+ while (iterator.hasNext()) {
+ V value = iterator.next();
+ if (!values.contains(value)) {
+ iterator.remove();
+ linkedEntries.remove(Maps.immutableEntry(key, value));
+ changed = true;
+ }
+ }
+ return changed;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Generates an iterator across map entries that follows the ordering in
+ * which the key-value pairs were added to the multimap.
+ *
+ * @return a key-value iterator with the correct ordering
+ */
+ @Override Iterator<Map.Entry<K, V>> createEntryIterator() {
+ final Iterator<Map.Entry<K, V>> delegateIterator = linkedEntries.iterator();
+
+ return new Iterator<Map.Entry<K, V>>() {
+ Map.Entry<K, V> entry;
+
+ public boolean hasNext() {
+ return delegateIterator.hasNext();
+ }
+
+ public Map.Entry<K, V> next() {
+ entry = delegateIterator.next();
+ return entry;
+ }
+
+ public void remove() {
+ // Remove from iterator first to keep iterator valid.
+ delegateIterator.remove();
+ LinkedHashMultimap.this.remove(entry.getKey(), entry.getValue());
+ }
+ };
+ }
+
+ /**
+ * {@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(
+ @Nullable 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.
+ */
+ @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();
+ }
+
+ // Unfortunately, the entries() ordering does not determine the key ordering;
+ // see the example in the LinkedListMultimap class Javadoc.
+
+ /**
+ * @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
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMultimap(this, stream);
+ for (Map.Entry<K, V> entry : linkedEntries) {
+ stream.writeObject(entry.getKey());
+ stream.writeObject(entry.getValue());
+ }
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ setMap(new LinkedHashMap<K, Collection<V>>());
+ linkedEntries = Sets.newLinkedHashSet();
+ Serialization.populateMultimap(this, stream);
+ linkedEntries.clear(); // will clear and repopulate entries
+ for (int i = 0; i < size(); i++) {
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ K key = (K) stream.readObject();
+ @SuppressWarnings("unchecked") // reading data stored by writeObject
+ V value = (V) stream.readObject();
+ linkedEntries.add(Maps.immutableEntry(key, value));
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/LinkedHashMultiset.java b/plugins/com.google.collect/src/com/google/common/collect/LinkedHashMultiset.java
new file mode 100644
index 0000000..c426bbd
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/LinkedHashMultiset.java
@@ -0,0 +1,86 @@
+/*
+ * 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.collect;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.LinkedHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 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.
+ *
+ * @author Kevin Bourrillion
+ * @author Jared Levy
+ */
+@SuppressWarnings("serial") // we're overriding default serialization
+public final class LinkedHashMultiset<E> extends AbstractMapBasedMultiset<E> {
+ /**
+ * Constructs a new empty {@code LinkedHashMultiset} using the default initial
+ * capacity (16 distinct elements) and load factor (0.75).
+ */
+ public LinkedHashMultiset() {
+ super(new LinkedHashMap<E, AtomicInteger>());
+ }
+
+ /**
+ * Constructs a new empty {@code LinkedHashMultiset} with the specified
+ * expected number of distinct elements and the default load factor (0.75).
+ *
+ * @param distinctElements the expected number of distinct elements
+ * @throws IllegalArgumentException if {@code distinctElements} is negative
+ */
+ public LinkedHashMultiset(int distinctElements) {
+ // Could use newLinkedHashMapWithExpectedSize() if it existed
+ super(new LinkedHashMap<E, AtomicInteger>(Maps.capacity(distinctElements)));
+ }
+
+ /**
+ * Constructs a new {@code LinkedHashMultiset} containing the specified
+ * elements.
+ *
+ * @param elements the elements that the multiset should contain
+ */
+ public LinkedHashMultiset(Iterable<? extends E> elements) {
+ this(Multisets.inferDistinctElements(elements));
+ Iterables.addAll(this, elements); // careful if we make this class non-final
+ }
+
+ /**
+ * @serialData the number of distinct elements, the first element, its count,
+ * the second element, its count, and so on
+ */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ Serialization.writeMultiset(this, stream);
+ }
+
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ setBackingMap(new LinkedHashMap<E, AtomicInteger>());
+ Serialization.populateMultiset(this, stream);
+ }
+
+ private static final long serialVersionUID = 0;
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/ListMultimap.java b/plugins/com.google.collect/src/com/google/common/collect/ListMultimap.java
new file mode 100644
index 0000000..5bf349b
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/ListMultimap.java
@@ -0,0 +1,79 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A {@code Multimap} that can hold duplicate key-value pairs and that maintains
+ * the insertion ordering of values for a given key.
+ *
+ * <p>The {@link #get}, {@link #removeAll}, and {@link #replaceValues} methods
+ * each return a {@link List} of values. Though the method signature doesn't say
+ * so explicitly, the map returned by {@link #asMap} has {@code List} values.
+ *
+ * @author Jared Levy
+ */
+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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ boolean equals(@Nullable Object obj);
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Lists.java b/plugins/com.google.collect/src/com/google/common/collect/Lists.java
new file mode 100644
index 0000000..cd9e21f
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Lists.java
@@ -0,0 +1,490 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Function;
+import com.google.common.base.Nullable;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+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.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.RandomAccess;
+
+/**
+ * Static utility methods pertaining to {@link List} instances. Also see this
+ * class's counterparts {@link Sets} and {@link Maps}.
+ *
+ * @author Kevin Bourrillion
+ * @author Mike Bostock
+ */
+public final class Lists {
+ private Lists() {}
+
+ // ArrayList
+
+ /**
+ * Creates an empty {@code ArrayList} instance.
+ *
+ * <p><b>Note:</b> if you need an immutable empty list, use {@link
+ * Collections#emptyList} instead.
+ *
+ * @return a newly-created, initially-empty {@code ArrayList}
+ */
+ public static <E> ArrayList<E> newArrayList() {
+ return new ArrayList<E>();
+ }
+
+ /**
+ * Creates an {@code ArrayList} instance containing the given elements.
+ *
+ * <p><b>Note:</b> if you need an immutable List, use {@link ImmutableList}
+ * instead.
+ *
+ * <p><b>Note:</b> due to a bug in javac 1.5.0_06, we cannot support the
+ * following:
+ *
+ * <p>{@code List<Base> list = Lists.newArrayList(sub1, sub2);}
+ *
+ * <p>where {@code sub1} and {@code sub2} are references to subtypes of {@code
+ * Base}, not of {@code Base} itself. To get around this, you must use:
+ *
+ * <p>{@code List<Base> list = Lists.<Base>newArrayList(sub1, sub2);}
+ *
+ * @param elements the elements that the list should contain, in order
+ * @return a newly-created {@code ArrayList} containing those elements
+ */
+ public static <E> ArrayList<E> newArrayList(E... elements) {
+ // 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;
+ }
+
+ static int computeArrayListCapacity(int arraySize) {
+ return (int) Math.min(5L + arraySize + (arraySize / 10), Integer.MAX_VALUE);
+ }
+
+ /**
+ * Creates an {@code ArrayList} instance containing the given elements.
+ *
+ * @param elements the elements that the list should contain, in order
+ * @return a newly-created {@code ArrayList} containing those elements
+ */
+ public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
+ // Let ArrayList's sizing logic work, if possible
+ if (elements instanceof Collection) {
+ @SuppressWarnings("unchecked")
+ Collection<? extends E> collection = (Collection<? extends E>) elements;
+ return new ArrayList<E>(collection);
+ } else {
+ return newArrayList(elements.iterator());
+ }
+ }
+
+ /**
+ * Creates an {@code ArrayList} instance containing the given elements.
+ *
+ * @param elements the elements that the list should contain, in order
+ * @return a newly-created {@code ArrayList} containing those elements
+ */
+ public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
+ ArrayList<E> list = newArrayList();
+ while (elements.hasNext()) {
+ list.add(elements.next());
+ }
+ return list;
+ }
+
+ /**
+ * Creates an {@code ArrayList} instance with the given expected size.
+ *
+ * @param expectedSize the expected size of the list
+ * @return a newly-created, initially empty {@code ArrayList} with enough
+ * capacity for the given expected size
+ * @throws IllegalArgumentException if the specified expected size is negative
+ */
+ public static <E> ArrayList<E> newArrayListWithExpectedSize(int expectedSize)
+ {
+ return new ArrayList<E>(computeArrayListCapacity(expectedSize));
+ }
+
+ // LinkedList
+
+ /**
+ * Creates an empty {@code LinkedList} instance.
+ *
+ * <p><b>Note:</b> if you need an immutable empty {@link List}, use
+ * {@link Collections#emptyList} instead.
+ *
+ * @return a newly-created, initially-empty {@code LinkedList}
+ */
+ 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 newly-created {@code LinkedList} containing those elements
+ */
+ public static <E> LinkedList<E> newLinkedList(
+ Iterable<? extends E> elements) {
+ return newLinkedList(elements.iterator());
+ }
+
+ /**
+ * Creates a {@code LinkedList} instance containing the given elements.
+ *
+ * @param elements the elements that the list should contain, in order
+ * @return a newly-created {@code LinkedList} containing those elements
+ */
+ private static <E> LinkedList<E> newLinkedList(
+ Iterator<? extends E> elements) {
+ LinkedList<E> list = newLinkedList();
+ while (elements.hasNext()) {
+ list.add(elements.next());
+ }
+ return list;
+ }
+
+ /**
+ * Returns a copy of the given iterable sorted by the natural ordering of its
+ * elements. The input is not modified. The returned list is modifiable,
+ * serializable, and implements {@link RandomAccess}.
+ *
+ * <p>Unlike {@link Sets#newTreeSet(Iterable)}, this method does not collapse
+ * equal elements, and the resulting collection does not maintain its own sort
+ * order.
+ *
+ * @param iterable the elements to be copied and sorted
+ * @return a new list containing the given elements in sorted order
+ * @throws ClassCastException if {@code iterable} contains elements that are
+ * not mutually comparable
+ */
+ @SuppressWarnings("unchecked")
+ public static <E extends Comparable> List<E> sortedCopy(Iterable<E> iterable)
+ {
+ List<E> list = Lists.newArrayList(iterable);
+ Collections.sort(list);
+ return list;
+ }
+
+ /**
+ * Returns a copy of the given iterable sorted by an explicit comparator. The
+ * input is not modified. The returned list is modifiable, serializable, and
+ * implements {@link RandomAccess}.
+ *
+ * <p>Unlike {@link Sets#newTreeSet(Comparator, Iterable)}, this method does
+ * not collapse elements that the comparator treats as equal, and the
+ * resulting collection does not maintain its own sort order.
+ *
+ * @param iterable the elements to be copied and sorted
+ * @param comparator a comparator capable of sorting the given elements
+ * @return a new list containing the given elements in sorted order
+ */
+ public static <E> List<E> sortedCopy(
+ Iterable<E> iterable, Comparator<? super E> comparator) {
+ List<E> list = Lists.newArrayList(iterable);
+ Collections.sort(list, checkNotNull(comparator));
+ return list;
+ }
+
+ /**
+ * 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) {
+ return (index == 0) ? first : rest[index - 1]; // allow IOOBE to throw
+ }
+ 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:
+ return rest[index - 2]; // allow IOOBE to throw
+ }
+ }
+ 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 always implements {@link Serializable},
+ * but serialization will succeed only when {@code fromList} and
+ * {@code function} are serializable. The returned list is threadsafe if the
+ * supplied list and function are.
+ */
+ 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>() {
+ public void add(T e) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean hasNext() {
+ return delegate.hasNext();
+ }
+
+ public boolean hasPrevious() {
+ return delegate.hasPrevious();
+ }
+
+ public T next() {
+ return function.apply(delegate.next());
+ }
+
+ public int nextIndex() {
+ return delegate.nextIndex();
+ }
+
+ public T previous() {
+ return function.apply(delegate.previous());
+ }
+
+ public int previousIndex() {
+ return delegate.previousIndex();
+ }
+
+ public void remove() {
+ delegate.remove();
+ }
+
+ public void set(T e) {
+ throw new UnsupportedOperationException("not supported");
+ }
+ };
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return super.removeAll(checkNotNull(c));
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ return super.retainAll(checkNotNull(c));
+ }
+ 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();
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return super.removeAll(checkNotNull(c));
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ return super.retainAll(checkNotNull(c));
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ private static class ImmutableArrayList<E> extends AbstractList<E>
+ implements RandomAccess, Serializable {
+ final E[] array;
+
+ /**
+ * @param array underlying array for this ImmutableArrayList. Note that the
+ * array is <b>not</b> cloned. The caller is responsible for ensuring
+ * that the array can't "escape".
+ */
+ ImmutableArrayList(E[] array) {
+ this.array = array;
+ }
+ @Override public E get(int index) {
+ return array[index];
+ }
+ @Override public int size() {
+ return array.length;
+ }
+
+ // optimizations
+
+ @Override public Object[] toArray() {
+ Object[] newArray = new Object[array.length];
+ System.arraycopy(array, 0, newArray, 0, array.length);
+ return newArray;
+ }
+ @Override public String toString() {
+ return Arrays.toString(array);
+ }
+ @Override public int hashCode() {
+ return Arrays.hashCode(array);
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/MapConstraint.java b/plugins/com.google.collect/src/com/google/common/collect/MapConstraint.java
new file mode 100644
index 0000000..5c649cc
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/MapConstraint.java
@@ -0,0 +1,58 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+/**
+ * A constraint on the keys and values that may be added to a {@code Map} or
+ * {@code Multimap}. For example, {@link MapConstraints#NOT_NULL}, 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
+ */
+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".
+ */
+ String toString();
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/MapConstraints.java b/plugins/com.google.collect/src/com/google/common/collect/MapConstraints.java
new file mode 100644
index 0000000..2013720
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/MapConstraints.java
@@ -0,0 +1,752 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+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.SortedSet;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Factory and utilities pertaining to the {@code MapConstraint} interface.
+ *
+ * @see Constraints
+ * @author Mike Bostock
+ */
+public final class MapConstraints {
+ private MapConstraints() {}
+
+ /**
+ * A constraint that verifies that neither the key nor the value is null. If
+ * either is null, a {@link NullPointerException} is thrown.
+ */
+ public static final MapConstraint<Object, Object> NOT_NULL =
+ NotNullMapConstraint.INSTANCE;
+
+ // enum singleton pattern
+ private enum NotNullMapConstraint implements MapConstraint<Object, Object> {
+ INSTANCE;
+
+ 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>() {
+ 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> {
+ final Map<K, V> delegate;
+ final MapConstraint<? super K, ? super V> constraint;
+ private transient volatile 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() {
+ if (entrySet == null) {
+ entrySet = constrainedEntrySet(delegate.entrySet(), constraint);
+ }
+ return entrySet;
+ }
+ @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> {
+ transient volatile BiMap<V, K> inverse;
+
+ ConstrainedBiMap(BiMap<K, V> delegate, BiMap<V, K> inverse,
+ MapConstraint<? super K, ? super V> constraint) {
+ super(delegate, constraint);
+ this.inverse = inverse;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override protected BiMap<K, V> delegate() {
+ return (BiMap<K, V>) super.delegate();
+ }
+
+ public V forcePut(K key, V value) {
+ constraint.checkKeyValue(key, value);
+ return delegate().forcePut(key, value);
+ }
+
+ 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);
+ }
+ 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 volatile Collection<Entry<K, V>> entries;
+ transient volatile 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() {
+ if (asMap == null) {
+ final Map<K, Collection<V>> asMapDelegate = delegate.asMap();
+
+ asMap = new ForwardingMap<K, Collection<V>>() {
+ volatile Set<Entry<K, Collection<V>>> entrySet;
+ volatile Collection<Collection<V>> values;
+
+ @Override protected Map<K, Collection<V>> delegate() {
+ return asMapDelegate;
+ }
+
+ @Override public Set<Entry<K, Collection<V>>> entrySet() {
+ if (entrySet == null) {
+ entrySet = constrainedAsMapEntries(
+ asMapDelegate.entrySet(), constraint);
+ }
+ return entrySet;
+ }
+
+
+ @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() {
+ if (values == null) {
+ values = new ConstrainedAsMapValues<K, V>(
+ delegate().values(), entrySet());
+ }
+ return values;
+ }
+
+ @Override public boolean containsValue(Object o) {
+ return values().contains(o);
+ }
+ };
+ }
+ return asMap;
+ }
+
+ @Override public Collection<Entry<K, V>> entries() {
+ if (entries == null) {
+ entries = constrainedEntries(delegate.entries(), constraint);
+ }
+ return entries;
+ }
+
+ @Override public Collection<V> get(final K key) {
+ return Constraints.constrainedTypePreservingCollection(
+ delegate.get(key), new Constraint<V>() {
+ 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) {
+ return delegate.putAll(checkMultimap(multimap, constraint));
+ }
+
+ @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>>() {
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ public Collection<V> next() {
+ return iterator.next().getValue();
+ }
+ public void remove() {
+ iterator.remove();
+ }
+ };
+ }
+
+ @Override public Object[] toArray() {
+ return ObjectArrays.toArrayImpl(this);
+ }
+ @Override public <T> T[] toArray(T[] array) {
+ return ObjectArrays.toArrayImpl(this, array);
+ }
+ @Override public boolean contains(Object o) {
+ return Iterators.contains(iterator(), o);
+ }
+ @Override public boolean containsAll(Collection<?> c) {
+ return Collections2.containsAll(this, c);
+ }
+ @Override public boolean remove(Object o) {
+ return Iterables.remove(this, o);
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return Iterators.removeAll(iterator(), c);
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ return Iterators.retainAll(iterator(), 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 ObjectArrays.toArrayImpl(this);
+ }
+ @Override public <T> T[] toArray(T[] array) {
+ return ObjectArrays.toArrayImpl(this, array);
+ }
+ @Override public boolean contains(Object o) {
+ return Maps.containsEntryImpl(delegate(), o);
+ }
+ @Override public boolean containsAll(Collection<?> c) {
+ return Collections2.containsAll(this, c);
+ }
+ @Override public boolean remove(Object o) {
+ return Maps.removeEntryImpl(delegate(), o);
+ }
+ @Override public boolean removeAll(Collection<?> c) {
+ return Iterators.removeAll(iterator(), c);
+ }
+ @Override public boolean retainAll(Collection<?> c) {
+ return Iterators.retainAll(iterator(), 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(Object o) {
+ return Sets.equalsImpl(this, o);
+ }
+
+ @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 ObjectArrays.toArrayImpl(this);
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return ObjectArrays.toArrayImpl(this, array);
+ }
+
+ @Override public boolean contains(Object o) {
+ return Maps.containsEntryImpl(delegate(), o);
+ }
+
+ @Override public boolean containsAll(Collection<?> c) {
+ return Collections2.containsAll(this, c);
+ }
+
+ @Override public boolean equals(Object o) {
+ return Sets.equalsImpl(this, o);
+ }
+
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+
+ @Override public boolean remove(Object o) {
+ return Maps.removeEntryImpl(delegate(), o);
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ return Iterators.removeAll(iterator(), c);
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ return Iterators.retainAll(iterator(), 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);
+ }
+ 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;
+ }
+
+ private static <K, V> Multimap<K, V> checkMultimap(
+ Multimap<? extends K, ? extends V> map,
+ MapConstraint<? super K, ? super V> constraint) {
+ Multimap<K, V> copy = new ArrayListMultimap<K, V>(map);
+ for (Entry<K, V> entry : copy.entries()) {
+ constraint.checkKeyValue(entry.getKey(), entry.getValue());
+ }
+ return copy;
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Maps.java b/plugins/com.google.collect/src/com/google/common/collect/Maps.java
new file mode 100644
index 0000000..46c6d36
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Maps.java
@@ -0,0 +1,597 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Function;
+import com.google.common.base.Nullable;
+import com.google.common.base.Objects;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.MapConstraints.ConstrainedMap;
+
+import java.io.Serializable;
+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.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Static utility methods pertaining to {@link Map} instances. Also see this
+ * class's counterparts {@link Lists} and {@link Sets}.
+ *
+ * @author Kevin Bourrillion
+ * @author Mike Bostock
+ */
+public final class Maps {
+ private Maps() {}
+
+ /**
+ * Creates a {@code HashMap} instance.
+ *
+ * <p><b>Note:</b> if {@code K} is an {@code enum} type, use {@link
+ * #newEnumMap} instead.
+ *
+ * <p><b>Note:</b> if you don't actually need the resulting map to be mutable,
+ * use {@link Collections#emptyMap} instead.
+ *
+ * @return a newly-created, initially-empty {@code HashMap}
+ */
+ public static <K, V> HashMap<K, V> newHashMap() {
+ return new HashMap<K, V>();
+ }
+
+ /**
+ * Creates a {@code HashMap} instance with enough capacity to hold the
+ * specified number of elements without rehashing.
+ *
+ * @param expectedSize the expected size
+ * @return a newly-created {@code HashMap}, initially empty, with enough
+ * capacity to hold {@code expectedSize} elements without rehashing
+ * @throws IllegalArgumentException if {@code expectedSize} is negative
+ */
+ public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(
+ int expectedSize) {
+ /*
+ * The HashMap is constructed with an initialCapacity that's greater than
+ * expectedSize. The larger value is necessary because HashMap resizes
+ * its internal array if the map size exceeds loadFactor * initialCapacity.
+ */
+ return new HashMap<K, V>(capacity(expectedSize));
+ }
+
+ /**
+ * Returns an appropriate value for the "capacity" (in reality, "minimum
+ * table size") parameter of a {@link HashMap} constructor, such that the
+ * resulting table will be between 25% and 50% full when it contains
+ * {@code expectedSize} entries.
+ *
+ * @throws IllegalArgumentException if {@code expectedSize} is negative
+ */
+ static int capacity(int expectedSize) {
+ checkArgument(expectedSize >= 0);
+ return Math.max(expectedSize * 2, 16);
+ }
+
+ /**
+ * Creates a {@code HashMap} instance with the same mappings as the specified
+ * map.
+ *
+ * <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 newly-created {@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 an insertion-ordered {@code LinkedHashMap} instance.
+ *
+ * @return a newly-created, initially-empty {@code LinkedHashMap}
+ */
+ public static <K, V> LinkedHashMap<K, V> newLinkedHashMap() {
+ return new LinkedHashMap<K, V>();
+ }
+
+ /**
+ * Creates an insertion-ordered {@code LinkedHashMap} instance with the same
+ * mappings as the specified map.
+ *
+ * @param map the mappings to be placed in the new map
+ * @return a newly-created, {@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);
+ }
+
+ /**
+ * Creates a {@code ConcurrentHashMap} instance.
+ *
+ * @return a newly-created, initially-empty {@code ConcurrentHashMap}
+ */
+ public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap() {
+ return new ConcurrentHashMap<K, V>();
+ }
+
+ /**
+ * Creates a {@code TreeMap} instance using the natural ordering of its
+ * elements.
+ *
+ * @return a newly-created, initially-empty {@code TreeMap}
+ */
+ @SuppressWarnings("unchecked") // allow ungenerified Comparable types
+ public static <K extends Comparable, V> TreeMap<K, V> newTreeMap() {
+ return new TreeMap<K, V>();
+ }
+
+ /**
+ * Creates a {@code TreeMap} instance using the given comparator.
+ *
+ * @param comparator the comparator to sort the keys with
+ * @return a newly-created, initially-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 newly-created, initially-empty {@code EnumMap}
+ */
+ public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(Class<K> type) {
+ return new EnumMap<K, V>(type);
+ }
+
+ /**
+ * Creates an {@code IdentityHashMap} instance.
+ *
+ * @return a newly-created, initially-empty {@code IdentityHashMap}
+ */
+ public static <K, V> IdentityHashMap<K, V> newIdentityHashMap() {
+ return new IdentityHashMap<K, V>();
+ }
+
+ /**
+ * Returns {@code true} if {@code map} contains an entry mapping {@code key}
+ * to {@code value}. If you are not concerned with null-safety you can simply
+ * use {@code map.get(key).equals(value)}.
+ */
+ public static boolean containsEntry(
+ Map<?, ?> map, @Nullable Object key, @Nullable Object value) {
+ Object valueForKey = map.get(key);
+ return (valueForKey == null)
+ ? value == null && map.containsKey(key)
+ : valueForKey.equals(value);
+ }
+
+ /**
+ * 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> Bimap&lt;K,V> m = Maps.synchronizedBiMap(
+ * new HashBiMap&lt;K,V>());
+ * ...
+ * Set&lt;K> s = m.keySet(); // Needn't be in synchronized block
+ * ...
+ * synchronized (m) { // Synchronizing on m, not s!
+ * Iterator&lt;K> i = s.iterator(); // Must be in synchronized block
+ * while (i.hasNext()) {
+ * foo(i.next());
+ * }
+ * }</pre>
+ *
+ * Failure to follow this advice may result in non-deterministic behavior.
+ *
+ * @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 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
+ */
+ // TODO: consider returning a bimap, whose inverse view does lookups by
+ // invoking the function.
+ public static <K, V> ImmutableMap<K, V> uniqueIndex(
+ Iterable<V> values, Function<? super V, K> keyFunction) {
+ checkNotNull(keyFunction);
+ ImmutableMap.Builder<K, V> builder = ImmutableMap.builder();
+ for (V value : values) {
+ builder.put(keyFunction.apply(value), value);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Creates a {@code Map<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}. The returned map won't
+ * include any null keys or values. The returned map is modifiable and
+ * serializable.
+ *
+ * @param properties a {@code Properties} object to be converted
+ * @return a map containing all the entries in {@code properties}
+ */
+ public static Map<String, String> fromProperties(Properties properties) {
+ Map<String, String> ret = newHashMapWithExpectedSize(properties.size());
+ for (Enumeration<?> e = properties.propertyNames(); e.hasMoreElements();) {
+ Object k = e.nextElement();
+ /*
+ * It is unlikely that a 'null' could be inserted into a Properties, but
+ * possible in a derived class.
+ */
+ String key = (k != null) ? k.toString() : null;
+ ret.put(key, properties.getProperty(key));
+ }
+ return ret;
+ }
+
+ /**
+ * 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
+ */
+ public static <K, V> Entry<K, V> immutableEntry(
+ @Nullable final K key, @Nullable final V value) {
+ return new ImmutableEntry<K, V>(key, value);
+ }
+
+ /** @see Maps#immutableEntry(Object,Object) */
+ private static class ImmutableEntry<K, V> extends AbstractMapEntry<K, V>
+ implements Serializable {
+ final K key;
+ final V value;
+
+ ImmutableEntry(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+ @Override public K getKey() {
+ return key;
+ }
+ @Override public V getValue() {
+ return value;
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * 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(
+ final 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
+ */
+ private 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 protected Iterator<Entry<K, V>> delegate() {
+ return delegate;
+ }
+ };
+ }
+
+ // See java.util.Collections.UnmodifiableEntrySet for details on attacks.
+
+ @Override public Object[] toArray() {
+ return ObjectArrays.toArrayImpl(this);
+ }
+
+ @Override public <T> T[] toArray(T[] array) {
+ return ObjectArrays.toArrayImpl(this, array);
+ }
+
+ @Override public boolean contains(Object o) {
+ return containsEntryImpl(delegate(), o);
+ }
+
+ @Override public boolean containsAll(Collection<?> c) {
+ return Collections2.containsAll(this, c);
+ }
+ }
+
+ /** @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(Object o) {
+ return Sets.equalsImpl(this, o);
+ }
+
+ @Override public int hashCode() {
+ return Sets.hashCodeImpl(this);
+ }
+ }
+
+ /**
+ * Returns a new empty {@code HashBiMap} with the default initial capacity
+ * (16).
+ */
+ public static <K, V> HashBiMap<K, V> newHashBiMap() {
+ return new HashBiMap<K, V>();
+ }
+
+ /**
+ * 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> newEnumHashBiMap(
+ Class<K> keyType) {
+ return new EnumHashBiMap<K, V>(keyType);
+ }
+
+ /**
+ * 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>
+ newEnumBiMap(Class<K> keyType, Class<V> valueType) {
+ return new EnumBiMap<K, V>(keyType, valueType);
+ }
+
+ /**
+ * 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
+ * attemps 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<K, 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<K, V> delegate;
+ transient BiMap<V, K> inverse;
+ transient Set<V> values;
+
+ UnmodifiableBiMap(BiMap<K, V> delegate, BiMap<V, K> inverse) {
+ unmodifiableMap = Collections.unmodifiableMap(delegate);
+ this.delegate = delegate;
+ this.inverse = inverse;
+ }
+ @Override protected Map<K, V> delegate() {
+ return unmodifiableMap;
+ }
+ public V forcePut(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+ 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 new {@code ClassToInstanceMap} instance backed by a {@link
+ * HashMap} using the default initial capacity and load factor.
+ */
+ public static <B> ClassToInstanceMap<B> newClassToInstanceMap() {
+ return newClassToInstanceMap(new HashMap<Class<? extends B>, B>());
+ }
+
+ /**
+ * Returns a new {@code ClassToInstanceMap} 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> ClassToInstanceMap<B> newClassToInstanceMap(
+ Map<Class<? extends B>, B> backingMap) {
+ return new SimpleClassToInstanceMap<B>(backingMap);
+ }
+
+ private static final MapConstraint<Class<?>, Object> VALUE_CAN_BE_CAST_TO_KEY
+ = new MapConstraint<Class<?>, Object>() {
+ public void checkKeyValue(Class<?> key, Object value) {
+ wrap(key).cast(value);
+ }
+ };
+
+ private static class SimpleClassToInstanceMap<B> extends
+ ConstrainedMap<Class<? extends B>, B> implements ClassToInstanceMap<B> {
+ SimpleClassToInstanceMap(Map<Class<? extends B>, B> delegate) {
+ super(delegate, VALUE_CAN_BE_CAST_TO_KEY);
+ }
+ public <T extends B> T putInstance(Class<T> type, T value) {
+ B oldValue = put(type, value);
+ return wrap(type).cast(oldValue);
+ }
+ public <T extends B> T getInstance(Class<T> type) {
+ B value = get(type);
+ return wrap(type).cast(value);
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> Class<T> wrap(Class<T> c) {
+ return c.isPrimitive() ? (Class<T>) PRIMITIVES_TO_WRAPPERS.get(c) : c;
+ }
+
+ private static final Map<Class<?>, Class<?>> PRIMITIVES_TO_WRAPPERS
+ = new ImmutableMap.Builder<Class<?>, Class<?>>()
+ .put(boolean.class, Boolean.class)
+ .put(byte.class, Byte.class)
+ .put(char.class, Character.class)
+ .put(double.class, Double.class)
+ .put(float.class, Float.class)
+ .put(int.class, Integer.class)
+ .put(long.class, Long.class)
+ .put(short.class, Short.class)
+ .put(void.class, Void.class)
+ .build();
+
+ /**
+ * 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));
+ }
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Multimap.java b/plugins/com.google.collect/src/com/google/common/collect/Multimap.java
new file mode 100644
index 0000000..030a3de
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Multimap.java
@@ -0,0 +1,259 @@
+/*
+ * 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.collect;
+
+import com.google.common.base.Nullable;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A collection similar to a {@code Map}, but which may associate multiple
+ * values with a single key. If you call {@link #put} twice, with the same key
+ * but different values, the multimap contains mappings from the key to both
+ * values.
+ *
+ * <p>The methods {@link #get}, {@link #keySet}, {@link #keys}, {@link #values},
+ * {@link #entries}, and {@link #asMap} return collections that are views of the
+ * multimap. If the multimap is modifiable, updating it can change the contents
+ * of those collections, and updating the collections will change the multimap.
+ * In contrast, {@link #replaceValues} and {@link #removeAll} return collections
+ * that are independent of subsequent multimap changes.
+ *
+ * <p>Depending on the implementation, a multimap may or may not allow duplicate
+ * key-value pairs. In other words, the multimap contents after adding the same
+ * key and value twice varies between implementations. In multimaps allowing
+ * duplicates, the multimap will contain two mappings, and {@code get} will
+ * return a collection that includes the value twice. In multimaps not
+ * supporting duplicates, the multimap will contain a single mapping from the
+ * key to the value, and {@code get} will return a collection that includes the
+ * value once.
+ *
+ * <p>All methods that alter the multimap are optional, and the views returned
+ * by the multimap may or may not be modifiable. When modification isn't
+ * supported, those methods will throw an {@link UnsupportedOperationException}.
+ *
+ * @author Jared Levy
+ * @param <K> the type of keys maintained by this multimap
+ * @param <V> the type of mapped values
+ */
+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(K key, V value);
+
+ /**
+ * Removes a key-value pair from the multimap.
+ *
+ * @param key key of entry to remove from the multimap
+ * @param value value of entry to remove the multimap
+ * @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(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>The collections returned by {@code asMap().get(Object)} have the same
+ * behavior as those returned by {@link #get}.
+ *
+ * @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.
+ */
+ 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}.
+ */
+ int hashCode();
+}
diff --git a/plugins/com.google.collect/src/com/google/common/collect/Multimaps.java b/plugins/com.google.collect/src/com/google/common/collect/Multimaps.java
new file mode 100644
index 0000000..22551ae
--- /dev/null
+++ b/plugins/com.google.collect/src/com/google/common/collect/Multimaps.java
@@ -0,0 +1,1400 @@
+/*
+ * 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.collect;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Function;
+import com.google.common.base.Nullable;
+import com.google.common.base.Supplier;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.AbstractSet;
+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.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.Map.Entry;
+
+/**
+ * Provides static methods acting on or generating a {@code Multimap}.
+ *
+ * @author Jared Levy
+ * @author Robert Konigsberg
+ * @author Mike Bostock
+ */
+public final class Multimaps {
+ private Multimaps() {}
+
+ /**
+ * Creates an empty {@code HashMultimap} instance.
+ *
+ * @return a newly-created, initially-empty {@code HashMultimap}
+ */
+ public static <K, V> HashMultimap<K, V> newHashMultimap() {
+ return new HashMultimap<K, V>();
+ }
+
+ /**
+ * Creates a {@code HashMultimap} instance initialized with all elements from
+ * the supplied {@code Multimap}. If the supplied multimap contains duplicate
+ * key-value pairs, those duplicate pairs will only be stored once in the new
+ * multimap.
+ *
+ * @param multimap the multimap whose contents are copied to this multimap.
+ * @return a newly-created and initialized {@code HashMultimap}
+ */
+ public static <K, V> HashMultimap<K, V> newHashMultimap(
+ Multimap<? extends K, ? extends V> multimap) {
+ return new HashMultimap<K, V>(multimap);
+ }
+
+ /**
+ * Creates an empty {@code ArrayListMultimap} instance.
+ *
+ * @return a newly-created, initially-empty {@code ArrayListMultimap}
+ */
+ public static <K, V> ArrayListMultimap<K, V> newArrayListMultimap() {
+ return new ArrayListMultimap<K, V>();
+ }
+
+ /**
+ * Creates an {@code ArrayListMultimap} instance initialized with all elements
+ * from the supplied {@code Multimap}.
+ *
+ * @param multimap the multimap whose contents are copied to this multimap.
+ * @return a newly-created and initialized {@code ArrayListMultimap}
+ */
+ public static <K, V> ArrayListMultimap<K, V> newArrayListMultimap(
+ Multimap<? extends K, ? extends V> multimap) {
+ return new ArrayListMultimap<K, V>(multimap);
+ }
+
+ /**
+ * Creates an empty {@code LinkedHashMultimap} instance.
+ *
+ * @return a newly-created, initially-empty {@code LinkedHashMultimap}
+ */
+ public static <K, V> LinkedHashMultimap<K, V> newLinkedHashMultimap() {
+ return new LinkedHashMultimap<K, V>();
+ }
+
+ /**
+ * Creates a {@code LinkedHashMultimap} instance initialized with all elements
+ * from the supplied {@code Multimap}. If the supplied multimap contains
+ * duplicate key-value pairs, those duplicate pairs will only be stored once
+ * in the new 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.
+ * @return a newly-created and initialized {@code LinkedHashMultimap}
+ */
+ public static <K, V> LinkedHashMultimap<K, V> newLinkedHashMultimap(
+ Multimap<? extends K, ? extends V> multimap) {
+ return new LinkedHashMultimap<K, V>(multimap);
+ }
+
+ /**
+ * Creates an empty {@code TreeMultimap} instance using the natural ordering
+ * of keys and values. If the supplied multimap contains duplicate key-value
+ * pairs, those duplicate pairs will only be stored once in the new multimap.
+ *
+ * @return a newly-created, initially-empty {@code TreeMultimap}
+ */
+ @SuppressWarnings("unchecked") // allow ungenerified Comparable types
+ public static <K extends Comparable, V extends Comparable>
+ TreeMultimap<K, V> newTreeMultimap() {
+ return new TreeMultimap<K, V>();
+ }
+
+ /**
+ * Constructs a {@code TreeMultimap} with the same mappings as the specified
+ * {@code Multimap}.
+ *
+ * <p>If the supplied multimap is an instance of {@code TreeMultimap}, the
+ * supplied multimap's comparators are copied to the new instance.
+ *
+ * <p>If the supplied multimap is not an instance of {@code TreeMultimap}, the
+ * new multimap is ordered using the natural ordering of the key and value
+ * classes. The key and value classes must satisfy the {@link Comparable}
+ * interface.
+ *
+ * @param multimap the multimap whose contents are copied to this multimap.
+ * @return a newly-created and initialized {@code TreeMultimap}
+ */
+ public static <K, V> TreeMultimap<K, V> newTreeMultimap(
+ Multimap<? extends K, ? extends V> multimap) {
+ return new TreeMultimap<K, V>(multimap);
+ }
+
+ /**
+ * Creates an empty {@code TreeMultimap} instance using explicit comparators.
+ *
+ * @param keyComparator the comparator that determines the key ordering. If
+ * it's {@code null}, the natural ordering of the keys is used.
+ * @param valueComparator the comparator that determines the value ordering.
+ * If it's {@code null}, the natural ordering of the values is used.
+ * @return a newly-created, initially-empty {@code TreeMultimap}
+ */
+ public static <K, V> TreeMultimap<K, V> newTreeMultimap(
+ @Nullable Comparator<? super K> keyComparator,
+ @Nullable Comparator<? super V> valueComparator) {
+ return new TreeMultimap<K, V>(keyComparator, valueComparator);
+ }
+
+ /**
+ * Creates a {@code TreeMultimap} instance using explicit comparators,
+ * initialized with all elements from the supplied {@code Multimap}.
+ *
+ * @param multimap the multimap whose contents are copied to this multimap.
+ * @return a newly-created and initialized {@code TreeMultimap}
+ */
+ public static <K, V> TreeMultimap<K, V> newTreeMultimap(
+ @Nullable Comparator<? super K> keyComparator,
+ @Nullable Comparator<? super V> valueComparator,
+ Multimap<? extends K, ? extends V> multimap) {
+ return new TreeMultimap<K, V>(keyComparator, valueComparator, multimap);
+ }
+
+ /**
+ * 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 multimaps'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 #newArrayListMultimap()}, {@link #newHashMultimap()},
+ * {@link #newLinkedHashMultimap()} and {@link #newTreeMultimap()} won't
+ * suffice.
+ *
+ * @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 StandardMultimap<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 */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(factory);
+ stream.writeObject(backingMap());
+ }
+
+ @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);
+ }
+
+ 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. However, the multimaps'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
+ * 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 method {@link
+ * #newArrayListMultimap()} won't suffice.
+ *
+ * @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 StandardListMultimap<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 */
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ stream.writeObject(factory);
+ stream.writeObject(backingMap());
+ }
+
+ @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);
+ }
+
+ 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 multimaps'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 #newHashMultimap()}, {@link #newLinkedHashMultimap()}, and
+ * {@link #newTreeMultimap()} won't suffice.
+ *
+ * @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 IllegalArgumentExcept