aboutsummaryrefslogtreecommitdiffstats
path: root/guava-gwt/src-super
diff options
context:
space:
mode:
Diffstat (limited to 'guava-gwt/src-super')
-rw-r--r--guava-gwt/src-super/com/google/common/base/super/com/google/common/base/CharMatcher.java1244
-rw-r--r--guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Charsets.java52
-rw-r--r--guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Enums.java108
-rw-r--r--guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Predicates.java22
-rw-r--r--guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Splitter.java136
-rw-r--r--guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Stopwatch.java40
-rw-r--r--guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheBuilder.java741
-rw-r--r--guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheLoader.java50
-rw-r--r--guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java829
-rw-r--r--guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LongAddables.java28
-rw-r--r--guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LongAdder.java40
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractBiMap.java76
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractMapBasedMultimap.java1259
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractMapBasedMultiset.java117
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractSortedMultiset.java142
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ArrayListMultimap.java6
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ArrayTable.java817
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ContiguousSet.java142
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/DescendingMultiset.java140
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyContiguousSet.java5
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableList.java15
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableMap.java (renamed from guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableBiMap.java)16
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSet.java7
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSortedMap.java42
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSortedSet.java2
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumBiMap.java15
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumHashBiMap.java13
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumMultiset.java17
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/FluentIterable.java508
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableList.java94
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableMap.java125
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableSet.java76
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/GenericMapMaker.java17
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashBiMap.java9
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashMultimap.java2
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableAsList.java38
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableAsList_CustomFieldSerializer.java50
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableBiMap.java23
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableCollection.java15
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumMap.java41
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumSet.java13
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableList.java102
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableListMultimap.java26
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMap.java200
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapEntrySet.java57
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapKeySet.java77
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapValues.java73
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMultimap.java280
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSet.java20
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimap.java85
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedAsList.java53
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedMap.java102
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedSet.java22
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterables.java146
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterators.java182
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultimap.java539
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultiset.java4
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedListMultimap.java452
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Lists.java1122
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/MapMaker.java28
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java919
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Multimaps.java834
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ObjectArrays.java15
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Platform.java42
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularContiguousSet.java52
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableList.java13
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableMap.java4
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSet.java2
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSortedSet.java4
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Sets.java420
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableList.java12
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableMap.java (renamed from guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableBiMap.java)31
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableSet.java23
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SortedMultiset.java57
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SortedMultisets.java93
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Synchronized.java67
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultimap.java42
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultiset.java1066
-rw-r--r--guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/UnmodifiableSortedMultiset.java112
-rw-r--r--guava-gwt/src-super/com/google/common/escape/super/com/google/common/escape/Platform.java (renamed from guava-gwt/src-super/java/nio/charset/IllegalCharsetNameException.java)24
-rw-r--r--guava-gwt/src-super/com/google/common/io/super/com/google/common/io/BaseEncoding.java794
-rw-r--r--guava-gwt/src-super/com/google/common/io/super/com/google/common/io/GwtWorkarounds.java118
-rw-r--r--guava-gwt/src-super/com/google/common/math/super/com/google/common/math/BigIntegerMath.java268
-rw-r--r--guava-gwt/src-super/com/google/common/math/super/com/google/common/math/IntMath.java292
-rw-r--r--guava-gwt/src-super/com/google/common/math/super/com/google/common/math/LongMath.java300
-rw-r--r--guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Chars.java9
-rw-r--r--guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Floats.java530
-rw-r--r--guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Ints.java20
-rw-r--r--guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Longs.java (renamed from guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Doubles.java)256
-rw-r--r--guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Shorts.java20
-rw-r--r--guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/UnsignedInteger.java312
-rw-r--r--guava-gwt/src-super/com/google/common/testing/super/com/google/common/testing/Platform.java (renamed from guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSortedMap.java)21
-rw-r--r--guava-gwt/src-super/java/nio/charset/Charset.gwt.xml4
-rw-r--r--guava-gwt/src-super/java/nio/charset/Charset.java101
-rw-r--r--guava-gwt/src-super/java/nio/charset/UnsupportedCharsetException.java35
-rw-r--r--guava-gwt/src-super/java/util/super/java/util/concurrent/Callable.java2
-rw-r--r--guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentHashMap.java2
-rw-r--r--guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentMap.java2
-rw-r--r--guava-gwt/src-super/java/util/super/java/util/concurrent/ExecutionException.java4
-rw-r--r--guava-gwt/src-super/java/util/super/java/util/concurrent/TimeUnit.java4
-rw-r--r--guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicInteger.java2
-rw-r--r--guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicLong.java2
102 files changed, 3315 insertions, 14317 deletions
diff --git a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/CharMatcher.java b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/CharMatcher.java
deleted file mode 100644
index ed30766..0000000
--- a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/CharMatcher.java
+++ /dev/null
@@ -1,1244 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.base;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Arrays;
-
-import javax.annotation.CheckReturnValue;
-
-/**
- * Determines a true or false value for any Java {@code char} value, just as {@link Predicate} does
- * for any {@link Object}. Also offers basic text processing methods based on this function.
- * Implementations are strongly encouraged to be side-effect-free and immutable.
- *
- * <p>Throughout the documentation of this class, the phrase "matching character" is used to mean
- * "any character {@code c} for which {@code this.matches(c)} returns {@code true}".
- *
- * <p><b>Note:</b> This class deals only with {@code char} values; it does not understand
- * supplementary Unicode code points in the range {@code 0x10000} to {@code 0x10FFFF}. Such logical
- * characters are encoded into a {@code String} using surrogate pairs, and a {@code CharMatcher}
- * treats these just as two separate characters.
- *
- * <p>Example usages: <pre>
- * String trimmed = {@link #WHITESPACE WHITESPACE}.{@link #trimFrom trimFrom}(userInput);
- * if ({@link #ASCII ASCII}.{@link #matchesAllOf matchesAllOf}(s)) { ... }</pre>
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#CharMatcher">
- * {@code CharMatcher}</a>.
- *
- * @author Kevin Bourrillion
- * @since 1.0
- */
-@Beta // Possibly change from chars to code points; decide constants vs. methods
-@GwtCompatible(emulated = true)
-public abstract class CharMatcher implements Predicate<Character> {
- // Constants
- /**
- * Determines whether a character is a breaking whitespace (that is, a whitespace which can be
- * interpreted as a break between words for formatting purposes). See {@link #WHITESPACE} for a
- * discussion of that term.
- *
- * @since 2.0
- */
- public static final CharMatcher BREAKING_WHITESPACE = new CharMatcher() {
- @Override
- public boolean matches(char c) {
- switch (c) {
- case '\t':
- case '\n':
- case '\013':
- case '\f':
- case '\r':
- case ' ':
- case '\u0085':
- case '\u1680':
- case '\u2028':
- case '\u2029':
- case '\u205f':
- case '\u3000':
- return true;
- case '\u2007':
- return false;
- default:
- return c >= '\u2000' && c <= '\u200a';
- }
- }
-
- @Override
- public String toString() {
- return "CharMatcher.BREAKING_WHITESPACE";
- }
- };
-
- /**
- * Determines whether a character is ASCII, meaning that its code point is less than 128.
- */
- public static final CharMatcher ASCII = inRange('\0', '\u007f', "CharMatcher.ASCII");
-
- private static class RangesMatcher extends CharMatcher {
- private final char[] rangeStarts;
- private final char[] rangeEnds;
-
- RangesMatcher(String description, char[] rangeStarts, char[] rangeEnds) {
- super(description);
- this.rangeStarts = rangeStarts;
- this.rangeEnds = rangeEnds;
- checkArgument(rangeStarts.length == rangeEnds.length);
- for (int i = 0; i < rangeStarts.length; i++) {
- checkArgument(rangeStarts[i] <= rangeEnds[i]);
- if (i + 1 < rangeStarts.length) {
- checkArgument(rangeEnds[i] < rangeStarts[i + 1]);
- }
- }
- }
-
- @Override
- public boolean matches(char c) {
- int index = Arrays.binarySearch(rangeStarts, c);
- if (index >= 0) {
- return true;
- } else {
- index = ~index - 1;
- return index >= 0 && c <= rangeEnds[index];
- }
- }
- }
-
- // Must be in ascending order.
- private static final String ZEROES = "0\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6"
- + "\u0c66\u0ce6\u0d66\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946\u19d0\u1b50\u1bb0"
- + "\u1c40\u1c50\ua620\ua8d0\ua900\uaa50\uff10";
-
- private static final String NINES;
- static {
- StringBuilder builder = new StringBuilder(ZEROES.length());
- for (int i = 0; i < ZEROES.length(); i++) {
- builder.append((char) (ZEROES.charAt(i) + 9));
- }
- NINES = builder.toString();
- }
-
- /**
- * Determines whether a character is a digit according to
- * <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bdigit%7D">Unicode</a>.
- */
- public static final CharMatcher DIGIT = new RangesMatcher(
- "CharMatcher.DIGIT", ZEROES.toCharArray(), NINES.toCharArray());
-
- /**
- * Determines whether a character is a digit according to {@link Character#isDigit(char) Java's
- * definition}. If you only care to match ASCII digits, you can use {@code inRange('0', '9')}.
- */
- public static final CharMatcher JAVA_DIGIT = new CharMatcher("CharMatcher.JAVA_DIGIT") {
- @Override public boolean matches(char c) {
- return Character.isDigit(c);
- }
- };
-
- /**
- * Determines whether a character is a letter according to {@link Character#isLetter(char) Java's
- * definition}. If you only care to match letters of the Latin alphabet, you can use {@code
- * inRange('a', 'z').or(inRange('A', 'Z'))}.
- */
- public static final CharMatcher JAVA_LETTER = new CharMatcher("CharMatcher.JAVA_LETTER") {
- @Override public boolean matches(char c) {
- return Character.isLetter(c);
- }
- };
-
- /**
- * Determines whether a character is a letter or digit according to {@link
- * Character#isLetterOrDigit(char) Java's definition}.
- */
- public static final CharMatcher JAVA_LETTER_OR_DIGIT =
- new CharMatcher("CharMatcher.JAVA_LETTER_OR_DIGIT") {
- @Override public boolean matches(char c) {
- return Character.isLetterOrDigit(c);
- }
- };
-
- /**
- * Determines whether a character is upper case according to {@link Character#isUpperCase(char)
- * Java's definition}.
- */
- public static final CharMatcher JAVA_UPPER_CASE =
- new CharMatcher("CharMatcher.JAVA_UPPER_CASE") {
- @Override public boolean matches(char c) {
- return Character.isUpperCase(c);
- }
- };
-
- /**
- * Determines whether a character is lower case according to {@link Character#isLowerCase(char)
- * Java's definition}.
- */
- public static final CharMatcher JAVA_LOWER_CASE =
- new CharMatcher("CharMatcher.JAVA_LOWER_CASE") {
- @Override public boolean matches(char c) {
- return Character.isLowerCase(c);
- }
- };
-
- /**
- * Determines whether a character is an ISO control character as specified by {@link
- * Character#isISOControl(char)}.
- */
- public static final CharMatcher JAVA_ISO_CONTROL =
- inRange('\u0000', '\u001f')
- .or(inRange('\u007f', '\u009f'))
- .withToString("CharMatcher.JAVA_ISO_CONTROL");
-
- /**
- * Determines whether a character is invisible; that is, if its Unicode category is any of
- * SPACE_SEPARATOR, LINE_SEPARATOR, PARAGRAPH_SEPARATOR, CONTROL, FORMAT, SURROGATE, and
- * PRIVATE_USE according to ICU4J.
- */
- public static final CharMatcher INVISIBLE = new RangesMatcher("CharMatcher.INVISIBLE", (
- "\u0000\u007f\u00ad\u0600\u06dd\u070f\u1680\u180e\u2000\u2028\u205f\u206a\u3000\ud800\ufeff"
- + "\ufff9\ufffa").toCharArray(), (
- "\u0020\u00a0\u00ad\u0604\u06dd\u070f\u1680\u180e\u200f\u202f\u2064\u206f\u3000\uf8ff\ufeff"
- + "\ufff9\ufffb").toCharArray());
-
- private static String showCharacter(char c) {
- String hex = "0123456789ABCDEF";
- char[] tmp = {'\\', 'u', '\0', '\0', '\0', '\0'};
- for (int i = 0; i < 4; i++) {
- tmp[5 - i] = hex.charAt(c & 0xF);
- c >>= 4;
- }
- return String.copyValueOf(tmp);
-
- }
-
- /**
- * Determines whether a character is single-width (not double-width). When in doubt, this matcher
- * errs on the side of returning {@code false} (that is, it tends to assume a character is
- * double-width).
- *
- * <p><b>Note:</b> as the reference file evolves, we will modify this constant to keep it up to
- * date.
- */
- public static final CharMatcher SINGLE_WIDTH = new RangesMatcher("CharMatcher.SINGLE_WIDTH",
- "\u0000\u05be\u05d0\u05f3\u0600\u0750\u0e00\u1e00\u2100\ufb50\ufe70\uff61".toCharArray(),
- "\u04f9\u05be\u05ea\u05f4\u06ff\u077f\u0e7f\u20af\u213a\ufdff\ufeff\uffdc".toCharArray());
-
- /** Matches any character. */
- public static final CharMatcher ANY =
- new FastMatcher("CharMatcher.ANY") {
- @Override public boolean matches(char c) {
- return true;
- }
-
- @Override public int indexIn(CharSequence sequence) {
- return (sequence.length() == 0) ? -1 : 0;
- }
-
- @Override public int indexIn(CharSequence sequence, int start) {
- int length = sequence.length();
- Preconditions.checkPositionIndex(start, length);
- return (start == length) ? -1 : start;
- }
-
- @Override public int lastIndexIn(CharSequence sequence) {
- return sequence.length() - 1;
- }
-
- @Override public boolean matchesAllOf(CharSequence sequence) {
- checkNotNull(sequence);
- return true;
- }
-
- @Override public boolean matchesNoneOf(CharSequence sequence) {
- return sequence.length() == 0;
- }
-
- @Override public String removeFrom(CharSequence sequence) {
- checkNotNull(sequence);
- return "";
- }
-
- @Override public String replaceFrom(CharSequence sequence, char replacement) {
- char[] array = new char[sequence.length()];
- Arrays.fill(array, replacement);
- return new String(array);
- }
-
- @Override public String replaceFrom(CharSequence sequence, CharSequence replacement) {
- StringBuilder retval = new StringBuilder(sequence.length() * replacement.length());
- for (int i = 0; i < sequence.length(); i++) {
- retval.append(replacement);
- }
- return retval.toString();
- }
-
- @Override public String collapseFrom(CharSequence sequence, char replacement) {
- return (sequence.length() == 0) ? "" : String.valueOf(replacement);
- }
-
- @Override public String trimFrom(CharSequence sequence) {
- checkNotNull(sequence);
- return "";
- }
-
- @Override public int countIn(CharSequence sequence) {
- return sequence.length();
- }
-
- @Override public CharMatcher and(CharMatcher other) {
- return checkNotNull(other);
- }
-
- @Override public CharMatcher or(CharMatcher other) {
- checkNotNull(other);
- return this;
- }
-
- @Override public CharMatcher negate() {
- return NONE;
- }
- };
-
- /** Matches no characters. */
- public static final CharMatcher NONE =
- new FastMatcher("CharMatcher.NONE") {
- @Override public boolean matches(char c) {
- return false;
- }
-
- @Override public int indexIn(CharSequence sequence) {
- checkNotNull(sequence);
- return -1;
- }
-
- @Override public int indexIn(CharSequence sequence, int start) {
- int length = sequence.length();
- Preconditions.checkPositionIndex(start, length);
- return -1;
- }
-
- @Override public int lastIndexIn(CharSequence sequence) {
- checkNotNull(sequence);
- return -1;
- }
-
- @Override public boolean matchesAllOf(CharSequence sequence) {
- return sequence.length() == 0;
- }
-
- @Override public boolean matchesNoneOf(CharSequence sequence) {
- checkNotNull(sequence);
- return true;
- }
-
- @Override public String removeFrom(CharSequence sequence) {
- return sequence.toString();
- }
-
- @Override public String replaceFrom(CharSequence sequence, char replacement) {
- return sequence.toString();
- }
-
- @Override public String replaceFrom(CharSequence sequence, CharSequence replacement) {
- checkNotNull(replacement);
- return sequence.toString();
- }
-
- @Override public String collapseFrom(CharSequence sequence, char replacement) {
- return sequence.toString();
- }
-
- @Override public String trimFrom(CharSequence sequence) {
- return sequence.toString();
- }
-
- @Override
- public String trimLeadingFrom(CharSequence sequence) {
- return sequence.toString();
- }
-
- @Override
- public String trimTrailingFrom(CharSequence sequence) {
- return sequence.toString();
- }
-
- @Override public int countIn(CharSequence sequence) {
- checkNotNull(sequence);
- return 0;
- }
-
- @Override public CharMatcher and(CharMatcher other) {
- checkNotNull(other);
- return this;
- }
-
- @Override public CharMatcher or(CharMatcher other) {
- return checkNotNull(other);
- }
-
- @Override public CharMatcher negate() {
- return ANY;
- }
- };
-
- // Static factories
-
- /**
- * Returns a {@code char} matcher that matches only one specified character.
- */
- public static CharMatcher is(final char match) {
- String description = "CharMatcher.is('" + showCharacter(match) + "')";
- return new FastMatcher(description) {
- @Override public boolean matches(char c) {
- return c == match;
- }
-
- @Override public String replaceFrom(CharSequence sequence, char replacement) {
- return sequence.toString().replace(match, replacement);
- }
-
- @Override public CharMatcher and(CharMatcher other) {
- return other.matches(match) ? this : NONE;
- }
-
- @Override public CharMatcher or(CharMatcher other) {
- return other.matches(match) ? other : super.or(other);
- }
-
- @Override public CharMatcher negate() {
- return isNot(match);
- }
- };
- }
-
- /**
- * Returns a {@code char} matcher that matches any character except the one specified.
- *
- * <p>To negate another {@code CharMatcher}, use {@link #negate()}.
- */
- public static CharMatcher isNot(final char match) {
- String description = "CharMatcher.isNot(" + Integer.toHexString(match) + ")";
- return new FastMatcher(description) {
- @Override public boolean matches(char c) {
- return c != match;
- }
-
- @Override public CharMatcher and(CharMatcher other) {
- return other.matches(match) ? super.and(other) : other;
- }
-
- @Override public CharMatcher or(CharMatcher other) {
- return other.matches(match) ? ANY : this;
- }
-
- @Override public CharMatcher negate() {
- return is(match);
- }
- };
- }
-
- /**
- * Returns a {@code char} matcher that matches any character present in the given character
- * sequence.
- */
- public static CharMatcher anyOf(final CharSequence sequence) {
- switch (sequence.length()) {
- case 0:
- return NONE;
- case 1:
- return is(sequence.charAt(0));
- case 2:
- return isEither(sequence.charAt(0), sequence.charAt(1));
- default:
- // continue below to handle the general case
- }
- // TODO(user): is it potentially worth just going ahead and building a precomputed matcher?
- final char[] chars = sequence.toString().toCharArray();
- Arrays.sort(chars);
- StringBuilder description = new StringBuilder("CharMatcher.anyOf(\"");
- for (char c : chars) {
- description.append(showCharacter(c));
- }
- description.append("\")");
- return new CharMatcher(description.toString()) {
- @Override public boolean matches(char c) {
- return Arrays.binarySearch(chars, c) >= 0;
- }
- };
- }
-
- private static CharMatcher isEither(
- final char match1,
- final char match2) {
- String description = "CharMatcher.anyOf(\"" +
- showCharacter(match1) + showCharacter(match2) + "\")";
- return new FastMatcher(description) {
- @Override public boolean matches(char c) {
- return c == match1 || c == match2;
- }
- };
- }
-
- /**
- * Returns a {@code char} matcher that matches any character not present in the given character
- * sequence.
- */
- public static CharMatcher noneOf(CharSequence sequence) {
- return anyOf(sequence).negate();
- }
-
- /**
- * Returns a {@code char} matcher that matches any character in a given range (both endpoints are
- * inclusive). For example, to match any lowercase letter of the English alphabet, use {@code
- * CharMatcher.inRange('a', 'z')}.
- *
- * @throws IllegalArgumentException if {@code endInclusive < startInclusive}
- */
- public static CharMatcher inRange(final char startInclusive, final char endInclusive) {
- checkArgument(endInclusive >= startInclusive);
- String description = "CharMatcher.inRange('" +
- showCharacter(startInclusive) + "', '" +
- showCharacter(endInclusive) + "')";
- return inRange(startInclusive, endInclusive, description);
- }
-
- static CharMatcher inRange(final char startInclusive, final char endInclusive,
- String description) {
- return new FastMatcher(description) {
- @Override public boolean matches(char c) {
- return startInclusive <= c && c <= endInclusive;
- }
- };
- }
-
- /**
- * Returns a matcher with identical behavior to the given {@link Character}-based predicate, but
- * which operates on primitive {@code char} instances instead.
- */
- public static CharMatcher forPredicate(final Predicate<? super Character> predicate) {
- checkNotNull(predicate);
- if (predicate instanceof CharMatcher) {
- return (CharMatcher) predicate;
- }
- String description = "CharMatcher.forPredicate(" + predicate + ")";
- return new CharMatcher(description) {
- @Override public boolean matches(char c) {
- return predicate.apply(c);
- }
-
- @Override public boolean apply(Character character) {
- return predicate.apply(checkNotNull(character));
- }
- };
- }
-
- // State
- final String description;
-
- // Constructors
-
- /**
- * Sets the {@code toString()} from the given description.
- */
- CharMatcher(String description) {
- this.description = description;
- }
-
- /**
- * Constructor for use by subclasses. When subclassing, you may want to override
- * {@code toString()} to provide a useful description.
- */
- protected CharMatcher() {
- description = super.toString();
- }
-
- // Abstract methods
-
- /** Determines a true or false value for the given character. */
- public abstract boolean matches(char c);
-
- // Non-static factories
-
- /**
- * Returns a matcher that matches any character not matched by this matcher.
- */
- public CharMatcher negate() {
- return new NegatedMatcher(this);
- }
-
- private static class NegatedMatcher extends CharMatcher {
- final CharMatcher original;
-
- NegatedMatcher(String toString, CharMatcher original) {
- super(toString);
- this.original = original;
- }
-
- NegatedMatcher(CharMatcher original) {
- this(original + ".negate()", original);
- }
-
- @Override public boolean matches(char c) {
- return !original.matches(c);
- }
-
- @Override public boolean matchesAllOf(CharSequence sequence) {
- return original.matchesNoneOf(sequence);
- }
-
- @Override public boolean matchesNoneOf(CharSequence sequence) {
- return original.matchesAllOf(sequence);
- }
-
- @Override public int countIn(CharSequence sequence) {
- return sequence.length() - original.countIn(sequence);
- }
-
- @Override public CharMatcher negate() {
- return original;
- }
-
- @Override
- CharMatcher withToString(String description) {
- return new NegatedMatcher(description, original);
- }
- }
-
- /**
- * Returns a matcher that matches any character matched by both this matcher and {@code other}.
- */
- public CharMatcher and(CharMatcher other) {
- return new And(this, checkNotNull(other));
- }
-
- private static class And extends CharMatcher {
- final CharMatcher first;
- final CharMatcher second;
-
- And(CharMatcher a, CharMatcher b) {
- this(a, b, "CharMatcher.and(" + a + ", " + b + ")");
- }
-
- And(CharMatcher a, CharMatcher b, String description) {
- super(description);
- first = checkNotNull(a);
- second = checkNotNull(b);
- }
-
- @Override
- public boolean matches(char c) {
- return first.matches(c) && second.matches(c);
- }
-
- @Override
- CharMatcher withToString(String description) {
- return new And(first, second, description);
- }
- }
-
- /**
- * Returns a matcher that matches any character matched by either this matcher or {@code other}.
- */
- public CharMatcher or(CharMatcher other) {
- return new Or(this, checkNotNull(other));
- }
-
- private static class Or extends CharMatcher {
- final CharMatcher first;
- final CharMatcher second;
-
- Or(CharMatcher a, CharMatcher b, String description) {
- super(description);
- first = checkNotNull(a);
- second = checkNotNull(b);
- }
-
- Or(CharMatcher a, CharMatcher b) {
- this(a, b, "CharMatcher.or(" + a + ", " + b + ")");
- }
-
- @Override
- public boolean matches(char c) {
- return first.matches(c) || second.matches(c);
- }
-
- @Override
- CharMatcher withToString(String description) {
- return new Or(first, second, description);
- }
- }
-
- /**
- * Returns a {@code char} matcher functionally equivalent to this one, but which may be faster to
- * query than the original; your mileage may vary. Precomputation takes time and is likely to be
- * worthwhile only if the precomputed matcher is queried many thousands of times.
- *
- * <p>This method has no effect (returns {@code this}) when called in GWT: it's unclear whether a
- * precomputed matcher is faster, but it certainly consumes more memory, which doesn't seem like a
- * worthwhile tradeoff in a browser.
- */
- public CharMatcher precomputed() {
- return Platform.precomputeCharMatcher(this);
- }
-
- /**
- * Subclasses should provide a new CharMatcher with the same characteristics as {@code this},
- * but with their {@code toString} method overridden with the new description.
- *
- * <p>This is unsupported by default.
- */
- CharMatcher withToString(String description) {
- throw new UnsupportedOperationException();
- }
-
- private static final int DISTINCT_CHARS = Character.MAX_VALUE - Character.MIN_VALUE + 1;
-
- /**
- * A matcher for which precomputation will not yield any significant benefit.
- */
- abstract static class FastMatcher extends CharMatcher {
- FastMatcher() {
- super();
- }
-
- FastMatcher(String description) {
- super(description);
- }
-
- @Override
- public final CharMatcher precomputed() {
- return this;
- }
-
- @Override
- public CharMatcher negate() {
- return new NegatedFastMatcher(this);
- }
- }
-
- static final class NegatedFastMatcher extends NegatedMatcher {
- NegatedFastMatcher(CharMatcher original) {
- super(original);
- }
-
- NegatedFastMatcher(String toString, CharMatcher original) {
- super(toString, original);
- }
-
- @Override
- public final CharMatcher precomputed() {
- return this;
- }
-
- @Override
- CharMatcher withToString(String description) {
- return new NegatedFastMatcher(description, original);
- }
- }
-
- private static boolean isSmall(int totalCharacters, int tableLength) {
- return totalCharacters <= SmallCharMatcher.MAX_SIZE
- && tableLength > (totalCharacters * Character.SIZE);
- }
-
- // Text processing routines
-
- /**
- * Returns {@code true} if a character sequence contains at least one matching character.
- * Equivalent to {@code !matchesNoneOf(sequence)}.
- *
- * <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
- * character, until this returns {@code true} or the end is reached.
- *
- * @param sequence the character sequence to examine, possibly empty
- * @return {@code true} if this matcher matches at least one character in the sequence
- * @since 8.0
- */
- public boolean matchesAnyOf(CharSequence sequence) {
- return !matchesNoneOf(sequence);
- }
-
- /**
- * Returns {@code true} if a character sequence contains only matching characters.
- *
- * <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
- * character, until this returns {@code false} or the end is reached.
- *
- * @param sequence the character sequence to examine, possibly empty
- * @return {@code true} if this matcher matches every character in the sequence, including when
- * the sequence is empty
- */
- public boolean matchesAllOf(CharSequence sequence) {
- for (int i = sequence.length() - 1; i >= 0; i--) {
- if (!matches(sequence.charAt(i))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Returns {@code true} if a character sequence contains no matching characters. Equivalent to
- * {@code !matchesAnyOf(sequence)}.
- *
- * <p>The default implementation iterates over the sequence, invoking {@link #matches} for each
- * character, until this returns {@code false} or the end is reached.
- *
- * @param sequence the character sequence to examine, possibly empty
- * @return {@code true} if this matcher matches every character in the sequence, including when
- * the sequence is empty
- */
- public boolean matchesNoneOf(CharSequence sequence) {
- return indexIn(sequence) == -1;
- }
-
- /**
- * Returns the index of the first matching character in a character sequence, or {@code -1} if no
- * matching character is present.
- *
- * <p>The default implementation iterates over the sequence in forward order calling {@link
- * #matches} for each character.
- *
- * @param sequence the character sequence to examine from the beginning
- * @return an index, or {@code -1} if no character matches
- */
- public int indexIn(CharSequence sequence) {
- int length = sequence.length();
- for (int i = 0; i < length; i++) {
- if (matches(sequence.charAt(i))) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Returns the index of the first matching character in a character sequence, starting from a
- * given position, or {@code -1} if no character matches after that position.
- *
- * <p>The default implementation iterates over the sequence in forward order, beginning at {@code
- * start}, calling {@link #matches} for each character.
- *
- * @param sequence the character sequence to examine
- * @param start the first index to examine; must be nonnegative and no greater than {@code
- * sequence.length()}
- * @return the index of the first matching character, guaranteed to be no less than {@code start},
- * or {@code -1} if no character matches
- * @throws IndexOutOfBoundsException if start is negative or greater than {@code
- * sequence.length()}
- */
- public int indexIn(CharSequence sequence, int start) {
- int length = sequence.length();
- Preconditions.checkPositionIndex(start, length);
- for (int i = start; i < length; i++) {
- if (matches(sequence.charAt(i))) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Returns the index of the last matching character in a character sequence, or {@code -1} if no
- * matching character is present.
- *
- * <p>The default implementation iterates over the sequence in reverse order calling {@link
- * #matches} for each character.
- *
- * @param sequence the character sequence to examine from the end
- * @return an index, or {@code -1} if no character matches
- */
- public int lastIndexIn(CharSequence sequence) {
- for (int i = sequence.length() - 1; i >= 0; i--) {
- if (matches(sequence.charAt(i))) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Returns the number of matching characters found in a character sequence.
- */
- public int countIn(CharSequence sequence) {
- int count = 0;
- for (int i = 0; i < sequence.length(); i++) {
- if (matches(sequence.charAt(i))) {
- count++;
- }
- }
- return count;
- }
-
- /**
- * Returns a string containing all non-matching characters of a character sequence, in order. For
- * example: <pre> {@code
- *
- * CharMatcher.is('a').removeFrom("bazaar")}</pre>
- *
- * ... returns {@code "bzr"}.
- */
- @CheckReturnValue
- public String removeFrom(CharSequence sequence) {
- String string = sequence.toString();
- int pos = indexIn(string);
- if (pos == -1) {
- return string;
- }
-
- char[] chars = string.toCharArray();
- int spread = 1;
-
- // This unusual loop comes from extensive benchmarking
- OUT: while (true) {
- pos++;
- while (true) {
- if (pos == chars.length) {
- break OUT;
- }
- if (matches(chars[pos])) {
- break;
- }
- chars[pos - spread] = chars[pos];
- pos++;
- }
- spread++;
- }
- return new String(chars, 0, pos - spread);
- }
-
- /**
- * Returns a string containing all matching characters of a character sequence, in order. For
- * example: <pre> {@code
- *
- * CharMatcher.is('a').retainFrom("bazaar")}</pre>
- *
- * ... returns {@code "aaa"}.
- */
- @CheckReturnValue
- public String retainFrom(CharSequence sequence) {
- return negate().removeFrom(sequence);
- }
-
- /**
- * Returns a string copy of the input character sequence, with each character that matches this
- * matcher replaced by a given replacement character. For example: <pre> {@code
- *
- * CharMatcher.is('a').replaceFrom("radar", 'o')}</pre>
- *
- * ... returns {@code "rodor"}.
- *
- * <p>The default implementation uses {@link #indexIn(CharSequence)} to find the first matching
- * character, then iterates the remainder of the sequence calling {@link #matches(char)} for each
- * character.
- *
- * @param sequence the character sequence to replace matching characters in
- * @param replacement the character to append to the result string in place of each matching
- * character in {@code sequence}
- * @return the new string
- */
- @CheckReturnValue
- public String replaceFrom(CharSequence sequence, char replacement) {
- String string = sequence.toString();
- int pos = indexIn(string);
- if (pos == -1) {
- return string;
- }
- char[] chars = string.toCharArray();
- chars[pos] = replacement;
- for (int i = pos + 1; i < chars.length; i++) {
- if (matches(chars[i])) {
- chars[i] = replacement;
- }
- }
- return new String(chars);
- }
-
- /**
- * Returns a string copy of the input character sequence, with each character that matches this
- * matcher replaced by a given replacement sequence. For example: <pre> {@code
- *
- * CharMatcher.is('a').replaceFrom("yaha", "oo")}</pre>
- *
- * ... returns {@code "yoohoo"}.
- *
- * <p><b>Note:</b> If the replacement is a fixed string with only one character, you are better
- * off calling {@link #replaceFrom(CharSequence, char)} directly.
- *
- * @param sequence the character sequence to replace matching characters in
- * @param replacement the characters to append to the result string in place of each matching
- * character in {@code sequence}
- * @return the new string
- */
- @CheckReturnValue
- public String replaceFrom(CharSequence sequence, CharSequence replacement) {
- int replacementLen = replacement.length();
- if (replacementLen == 0) {
- return removeFrom(sequence);
- }
- if (replacementLen == 1) {
- return replaceFrom(sequence, replacement.charAt(0));
- }
-
- String string = sequence.toString();
- int pos = indexIn(string);
- if (pos == -1) {
- return string;
- }
-
- int len = string.length();
- StringBuilder buf = new StringBuilder((len * 3 / 2) + 16);
-
- int oldpos = 0;
- do {
- buf.append(string, oldpos, pos);
- buf.append(replacement);
- oldpos = pos + 1;
- pos = indexIn(string, oldpos);
- } while (pos != -1);
-
- buf.append(string, oldpos, len);
- return buf.toString();
- }
-
- /**
- * Returns a substring of the input character sequence that omits all characters this matcher
- * matches from the beginning and from the end of the string. For example: <pre> {@code
- *
- * CharMatcher.anyOf("ab").trimFrom("abacatbab")}</pre>
- *
- * ... returns {@code "cat"}.
- *
- * <p>Note that: <pre> {@code
- *
- * CharMatcher.inRange('\0', ' ').trimFrom(str)}</pre>
- *
- * ... is equivalent to {@link String#trim()}.
- */
- @CheckReturnValue
- public String trimFrom(CharSequence sequence) {
- int len = sequence.length();
- int first;
- int last;
-
- for (first = 0; first < len; first++) {
- if (!matches(sequence.charAt(first))) {
- break;
- }
- }
- for (last = len - 1; last > first; last--) {
- if (!matches(sequence.charAt(last))) {
- break;
- }
- }
-
- return sequence.subSequence(first, last + 1).toString();
- }
-
- /**
- * Returns a substring of the input character sequence that omits all characters this matcher
- * matches from the beginning of the string. For example: <pre> {@code
- *
- * CharMatcher.anyOf("ab").trimLeadingFrom("abacatbab")}</pre>
- *
- * ... returns {@code "catbab"}.
- */
- @CheckReturnValue
- public String trimLeadingFrom(CharSequence sequence) {
- int len = sequence.length();
- for (int first = 0; first < len; first++) {
- if (!matches(sequence.charAt(first))) {
- return sequence.subSequence(first, len).toString();
- }
- }
- return "";
- }
-
- /**
- * Returns a substring of the input character sequence that omits all characters this matcher
- * matches from the end of the string. For example: <pre> {@code
- *
- * CharMatcher.anyOf("ab").trimTrailingFrom("abacatbab")}</pre>
- *
- * ... returns {@code "abacat"}.
- */
- @CheckReturnValue
- public String trimTrailingFrom(CharSequence sequence) {
- int len = sequence.length();
- for (int last = len - 1; last >= 0; last--) {
- if (!matches(sequence.charAt(last))) {
- return sequence.subSequence(0, last + 1).toString();
- }
- }
- return "";
- }
-
- /**
- * Returns a string copy of the input character sequence, with each group of consecutive
- * characters that match this matcher replaced by a single replacement character. For example:
- * <pre> {@code
- *
- * CharMatcher.anyOf("eko").collapseFrom("bookkeeper", '-')}</pre>
- *
- * ... returns {@code "b-p-r"}.
- *
- * <p>The default implementation uses {@link #indexIn(CharSequence)} to find the first matching
- * character, then iterates the remainder of the sequence calling {@link #matches(char)} for each
- * character.
- *
- * @param sequence the character sequence to replace matching groups of characters in
- * @param replacement the character to append to the result string in place of each group of
- * matching characters in {@code sequence}
- * @return the new string
- */
- @CheckReturnValue
- public String collapseFrom(CharSequence sequence, char replacement) {
- // This implementation avoids unnecessary allocation.
- int len = sequence.length();
- for (int i = 0; i < len; i++) {
- char c = sequence.charAt(i);
- if (matches(c)) {
- if (c == replacement
- && (i == len - 1 || !matches(sequence.charAt(i + 1)))) {
- // a no-op replacement
- i++;
- } else {
- StringBuilder builder = new StringBuilder(len)
- .append(sequence.subSequence(0, i))
- .append(replacement);
- return finishCollapseFrom(sequence, i + 1, len, replacement, builder, true);
- }
- }
- }
- // no replacement needed
- return sequence.toString();
- }
-
- /**
- * Collapses groups of matching characters exactly as {@link #collapseFrom} does, except that
- * groups of matching characters at the start or end of the sequence are removed without
- * replacement.
- */
- @CheckReturnValue
- public String trimAndCollapseFrom(CharSequence sequence, char replacement) {
- // This implementation avoids unnecessary allocation.
- int len = sequence.length();
- int first;
- int last;
-
- for (first = 0; first < len && matches(sequence.charAt(first)); first++) {}
- for (last = len - 1; last > first && matches(sequence.charAt(last)); last--) {}
-
- return (first == 0 && last == len - 1)
- ? collapseFrom(sequence, replacement)
- : finishCollapseFrom(
- sequence, first, last + 1, replacement,
- new StringBuilder(last + 1 - first),
- false);
- }
-
- private String finishCollapseFrom(
- CharSequence sequence, int start, int end, char replacement,
- StringBuilder builder, boolean inMatchingGroup) {
- for (int i = start; i < end; i++) {
- char c = sequence.charAt(i);
- if (matches(c)) {
- if (!inMatchingGroup) {
- builder.append(replacement);
- inMatchingGroup = true;
- }
- } else {
- builder.append(c);
- inMatchingGroup = false;
- }
- }
- return builder.toString();
- }
-
- // Predicate interface
-
- /**
- * Equivalent to {@link #matches}; provided only to satisfy the {@link Predicate} interface. When
- * using a reference of type {@code CharMatcher}, invoke {@link #matches} directly instead.
- */
- @Override public boolean apply(Character character) {
- return matches(character);
- }
-
- /**
- * Returns a string representation of this {@code CharMatcher}, such as
- * {@code CharMatcher.or(WHITESPACE, JAVA_DIGIT)}.
- */
- @Override
- public String toString() {
- return description;
- }
-
- /**
- * A special-case CharMatcher for Unicode whitespace characters that is extremely
- * efficient both in space required and in time to check for matches.
- *
- * Implementation details.
- * It turns out that all current (early 2012) Unicode characters are unique modulo 79:
- * so we can construct a lookup table of exactly 79 entries, and just check the character code
- * mod 79, and see if that character is in the table.
- *
- * There is a 1 at the beginning of the table so that the null character is not listed
- * as whitespace.
- *
- * Other things we tried that did not prove to be beneficial, mostly due to speed concerns:
- *
- * * Binary search into the sorted list of characters, i.e., what
- * CharMatcher.anyOf() does</li>
- * * Perfect hash function into a table of size 26 (using an offset table and a special
- * Jenkins hash function)</li>
- * * Perfect-ish hash function that required two lookups into a single table of size 26.</li>
- * * Using a power-of-2 sized hash table (size 64) with linear probing.</li>
- *
- * --Christopher Swenson, February 2012.
- */
- private static final String WHITESPACE_TABLE = "\u0001\u0000\u00a0\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0009\n\u000b\u000c\r\u0000\u0000\u2028\u2029\u0000\u0000\u0000\u0000\u0000\u202f"
- + "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0020\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0000\u0000\u0000\u0000\u3000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
- + "\u0000\u0000\u0085\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a"
- + "\u0000\u0000\u0000\u0000\u0000\u205f\u1680\u0000\u0000\u180e\u0000\u0000\u0000";
-
- /**
- * Determines whether a character is whitespace according to the latest Unicode standard, as
- * illustrated
- * <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bwhitespace%7D">here</a>.
- * This is not the same definition used by other Java APIs. (See a
- * <a href="http://spreadsheets.google.com/pub?key=pd8dAQyHbdewRsnE5x5GzKQ">comparison of several
- * definitions of "whitespace"</a>.)
- *
- * <p><b>Note:</b> as the Unicode definition evolves, we will modify this constant to keep it up
- * to date.
- */
- public static final CharMatcher WHITESPACE = new FastMatcher("CharMatcher.WHITESPACE") {
-
- @Override public boolean matches(char c) {
- return WHITESPACE_TABLE.charAt(c % 79) == c;
- }
- };
-}
diff --git a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Charsets.java b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Charsets.java
deleted file mode 100644
index 4c080be..0000000
--- a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Charsets.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.base;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.nio.charset.Charset;
-
-/**
- * Contains constant definitions for the six standard {@link Charset} instances, which are
- * guaranteed to be supported by all Java platform implementations.
- *
- * <p>Assuming you're free to choose, note that <b>{@link #UTF_8} is widely preferred</b>.
- *
- * <p>See the Guava User Guide article on <a
- * href="http://code.google.com/p/guava-libraries/wiki/StringsExplained#Charsets">
- * {@code Charsets}</a>.
- *
- * @author Mike Bostock
- * @since 1.0
- */
-@GwtCompatible(emulated = true)
-public final class Charsets {
- private Charsets() {}
-
- /**
- * UTF-8: eight-bit UCS Transformation Format.
- */
- public static final Charset UTF_8 = Charset.forName("UTF-8");
-
- /*
- * Please do not add new Charset references to this class, unless those character encodings are
- * part of the set required to be supported by all Java platform implementations! Any Charsets
- * initialized here may cause unexpected delays when this class is loaded. See the Charset
- * Javadocs for the list of built-in character encodings.
- */
-}
-
diff --git a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Enums.java b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Enums.java
deleted file mode 100644
index 61dd6e1..0000000
--- a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Enums.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.base;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-
-import java.io.Serializable;
-
-import javax.annotation.Nullable;
-
-/**
- * Utility methods for working with {@link Enum} instances.
- *
- * @author Steve McKay
- *
- * @since 9.0
- */
-@GwtCompatible(emulated = true)
-@Beta
-public final class Enums {
-
- private Enums() {}
-
- /**
- * Returns a {@link Function} that maps an {@link Enum} name to the associated
- * {@code Enum} constant. The {@code Function} will return {@code null} if the
- * {@code Enum} constant does not exist.
- *
- * @param enumClass the {@link Class} of the {@code Enum} declaring the
- * constant values.
- */
- public static <T extends Enum<T>> Function<String, T> valueOfFunction(Class<T> enumClass) {
- return new ValueOfFunction<T>(enumClass);
- }
-
- /**
- * A {@link Function} that maps an {@link Enum} name to the associated
- * constant, or {@code null} if the constant does not exist.
- */
- private static final class ValueOfFunction<T extends Enum<T>>
- implements Function<String, T>, Serializable {
-
- private final Class<T> enumClass;
-
- private ValueOfFunction(Class<T> enumClass) {
- this.enumClass = checkNotNull(enumClass);
- }
-
- @Override
- public T apply(String value) {
- try {
- return Enum.valueOf(enumClass, value);
- } catch (IllegalArgumentException e) {
- return null;
- }
- }
-
- @Override public boolean equals(@Nullable Object obj) {
- return obj instanceof ValueOfFunction &&
- enumClass.equals(((ValueOfFunction) obj).enumClass);
- }
-
- @Override public int hashCode() {
- return enumClass.hashCode();
- }
-
- @Override public String toString() {
- return "Enums.valueOf(" + enumClass + ")";
- }
-
- private static final long serialVersionUID = 0;
- }
-
- /**
- * Returns an optional enum constant for the given type, using {@link Enum#valueOf}. If the
- * constant does not exist, {@link Optional#absent} is returned. A common use case is for parsing
- * user input or falling back to a default enum constant. For example,
- * {@code Enums.getIfPresent(Country.class, countryInput).or(Country.DEFAULT);}
- *
- * @since 12.0
- */
- public static <T extends Enum<T>> Optional<T> getIfPresent(Class<T> enumClass, String value) {
- checkNotNull(enumClass);
- checkNotNull(value);
- try {
- return Optional.of(Enum.valueOf(enumClass, value));
- } catch (IllegalArgumentException iae) {
- return Optional.absent();
- }
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Predicates.java b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Predicates.java
index 04f088e..366ca0d 100644
--- a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Predicates.java
+++ b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Predicates.java
@@ -34,10 +34,6 @@ import javax.annotation.Nullable;
* <p>All methods returns serializable predicates as long as they're given
* serializable parameters.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the
- * use of {@code Predicate}</a>.
- *
* @author Kevin Bourrillion
* @since 2.0 (imported from Google Collections Library)
*/
@@ -230,7 +226,7 @@ public final class Predicates {
return o != null;
}
};
-
+
@SuppressWarnings("unchecked") // these Object predicates work for any T
<T> Predicate<T> withNarrowedType() {
return (Predicate<T>) this;
@@ -245,7 +241,7 @@ public final class Predicates {
this.predicate = checkNotNull(predicate);
}
@Override
- public boolean apply(@Nullable T t) {
+ public boolean apply(T t) {
return !predicate.apply(t);
}
@Override public int hashCode() {
@@ -274,8 +270,7 @@ public final class Predicates {
this.components = components;
}
@Override
- public boolean apply(@Nullable T t) {
- // Avoid using the Iterator to avoid generating garbage (issue 820).
+ public boolean apply(T t) {
for (int i = 0; i < components.size(); i++) {
if (!components.get(i).apply(t)) {
return false;
@@ -284,7 +279,7 @@ public final class Predicates {
return true;
}
@Override public int hashCode() {
- // add a random number to avoid collisions with OrPredicate
+ // 0x12472c2c is a random number to help avoid collisions with OrPredicate
return components.hashCode() + 0x12472c2c;
}
@Override public boolean equals(@Nullable Object obj) {
@@ -308,8 +303,7 @@ public final class Predicates {
this.components = components;
}
@Override
- public boolean apply(@Nullable T t) {
- // Avoid using the Iterator to avoid generating garbage (issue 820).
+ public boolean apply(T t) {
for (int i = 0; i < components.size(); i++) {
if (components.get(i).apply(t)) {
return true;
@@ -318,7 +312,7 @@ public final class Predicates {
return false;
}
@Override public int hashCode() {
- // add a random number to avoid collisions with AndPredicate
+ // 0x053c91cf is a random number to help avoid collisions with AndPredicate
return components.hashCode() + 0x053c91cf;
}
@Override public boolean equals(@Nullable Object obj) {
@@ -371,7 +365,7 @@ public final class Predicates {
}
@Override
- public boolean apply(@Nullable T t) {
+ public boolean apply(T t) {
try {
return target.contains(t);
} catch (NullPointerException e) {
@@ -411,7 +405,7 @@ public final class Predicates {
}
@Override
- public boolean apply(@Nullable A a) {
+ public boolean apply(A a) {
return p.apply(f.apply(a));
}
diff --git a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Splitter.java b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Splitter.java
index 458b5ad..142fbec 100644
--- a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Splitter.java
+++ b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Splitter.java
@@ -30,63 +30,60 @@ import java.util.Map;
import javax.annotation.CheckReturnValue;
/**
- * Extracts non-overlapping substrings from an input string, typically by
- * recognizing appearances of a <i>separator</i> sequence. This separator can be
- * specified as a single {@linkplain #on(char) character}, fixed {@linkplain
- * #on(String) string}, {@linkplain #onPattern regular expression} or {@link
- * #on(CharMatcher) CharMatcher} instance. Or, instead of using a separator at
- * all, a splitter can extract adjacent substrings of a given {@linkplain
- * #fixedLength fixed length}.
+ * An object that divides strings (or other instances of {@code CharSequence})
+ * into substrings, by recognizing a <i>separator</i> (a.k.a. "delimiter")
+ * which can be expressed as a single character, literal string, regular
+ * expression, {@code CharMatcher}, or by using a fixed substring length. This
+ * class provides the complementary functionality to {@link Joiner}.
*
- * <p>For example, this expression: <pre> {@code
+ * <p>Here is the most basic example of {@code Splitter} usage: <pre> {@code
*
- * Splitter.on(',').split("foo,bar,qux")}</pre>
+ * Splitter.on(',').split("foo,bar")}</pre>
*
- * ... produces an {@code Iterable} containing {@code "foo"}, {@code "bar"} and
- * {@code "qux"}, in that order.
+ * This invocation returns an {@code Iterable<String>} containing {@code "foo"}
+ * and {@code "bar"}, in that order.
*
- * <p>By default, {@code Splitter}'s behavior is simplistic and unassuming. The
- * following expression: <pre> {@code
+ * <p>By default {@code Splitter}'s behavior is very simplistic: <pre> {@code
*
- * Splitter.on(',').split(" foo,,, bar ,")}</pre>
+ * Splitter.on(',').split("foo,,bar, quux")}</pre>
*
- * ... yields the substrings {@code [" foo", "", "", " bar ", ""]}. If this
- * is not the desired behavior, use configuration methods to obtain a <i>new</i>
- * splitter instance with modified behavior: <pre> {@code
+ * This returns an iterable containing {@code ["foo", "", "bar", " quux"]}.
+ * Notice that the splitter does not assume that you want empty strings removed,
+ * or that you wish to trim whitespace. If you want features like these, simply
+ * ask for them: <pre> {@code
*
* private static final Splitter MY_SPLITTER = Splitter.on(',')
* .trimResults()
* .omitEmptyStrings();}</pre>
*
- * Now {@code MY_SPLITTER.split("foo,,, bar ,")} returns just {@code ["foo",
- * "bar"]}. Note that the order in which these configuration methods are called
- * is never significant.
+ * Now {@code MY_SPLITTER.split("foo, ,bar, quux,")} returns an iterable
+ * containing just {@code ["foo", "bar", "quux"]}. Note that the order in which
+ * the configuration methods are called is never significant; for instance,
+ * trimming is always applied first before checking for an empty result,
+ * regardless of the order in which the {@link #trimResults()} and
+ * {@link #omitEmptyStrings()} methods were invoked.
*
- * <p><b>Warning:</b> Splitter instances are immutable. Invoking a configuration
- * method has no effect on the receiving instance; you must store and use the
- * new splitter instance it returns instead. <pre> {@code
+ * <p><b>Warning: splitter instances are always immutable</b>; a configuration
+ * method such as {@code omitEmptyStrings} has no effect on the instance it
+ * is invoked on! You must store and use the new splitter instance returned by
+ * the method. This makes splitters thread-safe, and safe to store as {@code
+ * static final} constants (as illustrated above). <pre> {@code
*
- * // Do NOT do this
+ * // Bad! Do not do this!
* Splitter splitter = Splitter.on('/');
* splitter.trimResults(); // does nothing!
* return splitter.split("wrong / wrong / wrong");}</pre>
*
- * <p>For separator-based splitters that do not use {@code omitEmptyStrings}, an
- * input string containing {@code n} occurrences of the separator naturally
- * yields an iterable of size {@code n + 1}. So if the separator does not occur
- * anywhere in the input, a single substring is returned containing the entire
- * input. Consequently, all splitters split the empty string to {@code [""]}
- * (note: even fixed-length splitters).
+ * The separator recognized by the splitter does not have to be a single
+ * literal character as in the examples above. See the methods {@link
+ * #on(String)}, {@link #on(Pattern)} and {@link #on(CharMatcher)} for examples
+ * of other ways to specify separators.
*
- * <p>Splitter instances are thread-safe immutable, and are therefore safe to
- * store as {@code static final} constants.
- *
- * <p>The {@link Joiner} class provides the inverse operation to splitting, but
- * note that a round-trip between the two should be assumed to be lossy.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#Splitter">
- * {@code Splitter}</a>.
+ * <p><b>Note:</b> this class does not mimic any of the quirky behaviors of
+ * similar JDK methods; for instance, it does not silently discard trailing
+ * separators, as does {@link String#split(String)}, nor does it have a default
+ * behavior of using five particular whitespace characters as separators, like
+ * {@link java.util.StringTokenizer}.
*
* @author Julien Silland
* @author Jesse Wilson
@@ -156,8 +153,8 @@ public final class Splitter {
/**
* Returns a splitter that uses the given fixed string as a separator. For
- * example, {@code Splitter.on(", ").split("foo, bar,baz")} returns an
- * iterable containing {@code ["foo", "bar,baz"]}.
+ * example, {@code Splitter.on(", ").split("foo, bar, baz,qux")} returns an
+ * iterable containing {@code ["foo", "bar", "baz,qux"]}.
*
* @param separator the literal, nonempty string to recognize as a separator
* @return a splitter, with default settings, that recognizes that separator
@@ -200,18 +197,9 @@ public final class Splitter {
* iterable containing {@code ["ab", "cd", "e"]}. The last piece can be
* smaller than {@code length} but will never be empty.
*
- * <p><b>Exception:</b> for consistency with separator-based splitters, {@code
- * split("")} does not yield an empty iterable, but an iterable containing
- * {@code ""}. This is the only case in which {@code
- * Iterables.size(split(input))} does not equal {@code
- * IntMath.divide(input.length(), length, CEILING)}. To avoid this behavior,
- * use {@code omitEmptyStrings}.
- *
- * @param length the desired length of pieces after splitting, a positive
- * integer
+ * @param length the desired length of pieces after splitting
* @return a splitter, with default settings, that can split into fixed sized
* pieces
- * @throws IllegalArgumentException if {@code length} is zero or negative
*/
public static Splitter fixedLength(final int length) {
checkArgument(length > 0, "The length may not be less than 1");
@@ -328,12 +316,6 @@ public final class Splitter {
@Override public Iterator<String> iterator() {
return spliterator(sequence);
}
- @Override public String toString() {
- return Joiner.on(", ")
- .appendTo(new StringBuilder().append('['), this)
- .append(']')
- .toString();
- }
};
}
@@ -355,18 +337,6 @@ public final class Splitter {
/**
* Returns a {@code MapSplitter} which splits entries based on this splitter,
- * and splits entries into keys and values using the specified separator.
- *
- * @since 14.0
- */
- @CheckReturnValue
- @Beta
- public MapSplitter withKeyValueSeparator(char separator) {
- return withKeyValueSeparator(on(separator));
- }
-
- /**
- * Returns a {@code MapSplitter} which splits entries based on this splitter,
* and splits entries into keys and values using the specified key-value
* splitter.
*
@@ -435,7 +405,8 @@ public final class Splitter {
Iterator<String> iterator(Splitter splitter, CharSequence toSplit);
}
- private abstract static class SplittingIterator extends AbstractIterator<String> {
+ private abstract static class SplittingIterator
+ extends AbstractIterator<String> {
final CharSequence toSplit;
final CharMatcher trimmer;
final boolean omitEmptyStrings;
@@ -464,15 +435,8 @@ public final class Splitter {
}
@Override protected String computeNext() {
- /*
- * The returned string will be from the end of the last match to the
- * beginning of the next one. nextStart is the start position of the
- * returned substring, while offset is the place to start looking for a
- * separator.
- */
- int nextStart = offset;
while (offset != -1) {
- int start = nextStart;
+ int start = offset;
int end;
int separatorPosition = separatorStart(offset);
@@ -483,20 +447,6 @@ public final class Splitter {
end = separatorPosition;
offset = separatorEnd(separatorPosition);
}
- if (offset == nextStart) {
- /*
- * This occurs when some pattern has an empty match, even if it
- * doesn't match the empty string -- for example, if it requires
- * lookahead or the like. The offset must be increased to look for
- * separators beyond this point, without changing the start position
- * of the next returned substring -- so nextStart stays the same.
- */
- offset++;
- if (offset >= toSplit.length()) {
- offset = -1;
- }
- continue;
- }
while (start < end && trimmer.matches(toSplit.charAt(start))) {
start++;
@@ -506,8 +456,6 @@ public final class Splitter {
}
if (omitEmptyStrings && start == end) {
- // Don't include the (unused) separator in next split string.
- nextStart = offset;
continue;
}
diff --git a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Stopwatch.java b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Stopwatch.java
index d591f62..841362a 100644
--- a/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Stopwatch.java
+++ b/guava-gwt/src-super/com/google/common/base/super/com/google/common/base/Stopwatch.java
@@ -49,7 +49,7 @@ import java.util.concurrent.TimeUnit;
* doSomething();
* stopwatch.{@link #stop stop}(); // optional
*
- * long millis = stopwatch.elapsed(MILLISECONDS);
+ * long millis = stopwatch.{@link #elapsedMillis elapsedMillis}();
*
* log.info("that took: " + stopwatch); // formatted string like "12.3 ms"
* </pre>
@@ -68,7 +68,7 @@ import java.util.concurrent.TimeUnit;
* @since 10.0
*/
@Beta
-@GwtCompatible(emulated = true)
+@GwtCompatible(emulated=true)
public final class Stopwatch {
private final Ticker ticker;
private boolean isRunning;
@@ -88,7 +88,7 @@ public final class Stopwatch {
* source.
*/
public Stopwatch(Ticker ticker) {
- this.ticker = checkNotNull(ticker, "ticker");
+ this.ticker = checkNotNull(ticker);
}
/**
@@ -107,8 +107,7 @@ public final class Stopwatch {
* @throws IllegalStateException if the stopwatch is already running.
*/
public Stopwatch start() {
- checkState(!isRunning,
- "This stopwatch is already running; it cannot be started more than once.");
+ checkState(!isRunning);
isRunning = true;
startTick = ticker.read();
return this;
@@ -123,8 +122,7 @@ public final class Stopwatch {
*/
public Stopwatch stop() {
long tick = ticker.read();
- checkState(isRunning,
- "This stopwatch is already stopped; it cannot be stopped more than once.");
+ checkState(isRunning);
isRunning = false;
elapsedNanos += tick - startTick;
return this;
@@ -153,40 +151,18 @@ public final class Stopwatch {
* <p>Note that the overhead of measurement can be more than a microsecond, so
* it is generally not useful to specify {@link TimeUnit#NANOSECONDS}
* precision here.
- *
- * @since 14.0 (since 10.0 as {@code elapsedTime()})
*/
- public long elapsed(TimeUnit desiredUnit) {
- return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
- }
-
- /**
- * Returns the current elapsed time shown on this stopwatch, expressed
- * in the desired time unit, with any fraction rounded down.
- *
- * <p>Note that the overhead of measurement can be more than a microsecond, so
- * it is generally not useful to specify {@link TimeUnit#NANOSECONDS}
- * precision here.
- *
- * @deprecated Use {@link Stopwatch#elapsed(TimeUnit)} instead. This method is
- * scheduled to be removed in Guava release 16.0.
- */
- @Deprecated
public long elapsedTime(TimeUnit desiredUnit) {
- return elapsed(desiredUnit);
+ return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
}
/**
* Returns the current elapsed time shown on this stopwatch, expressed
* in milliseconds, with any fraction rounded down. This is identical to
- * {@code elapsed(TimeUnit.MILLISECONDS)}.
- *
- * @deprecated Use {@code stopwatch.elapsed(MILLISECONDS)} instead. This
- * method is scheduled to be removed in Guava release 16.0.
+ * {@code elapsedTime(TimeUnit.MILLISECONDS}.
*/
- @Deprecated
public long elapsedMillis() {
- return elapsed(MILLISECONDS);
+ return elapsedTime(MILLISECONDS);
}
private static TimeUnit chooseUnit(long nanos) {
diff --git a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheBuilder.java b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheBuilder.java
index 8b01a0e..4c30815 100644
--- a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheBuilder.java
+++ b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Guava Authors
+ * Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,251 +16,48 @@
package com.google.common.cache;
-import static com.google.common.base.Objects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Ascii;
-import com.google.common.base.Equivalence;
-import com.google.common.base.Objects;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.base.Ticker;
-import com.google.common.cache.AbstractCache.SimpleStatsCounter;
-import com.google.common.cache.AbstractCache.StatsCounter;
-import com.google.common.cache.LocalCache.Strength;
-
+import com.google.common.base.Function;
+import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ExecutionError;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+import com.google.gwt.user.client.Timer;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.annotation.CheckReturnValue;
+import javax.annotation.Nullable;
/**
- * <p>A builder of {@link LoadingCache} and {@link Cache} instances having any combination of the
- * following features:
- *
- * <ul>
- * <li>automatic loading of entries into the cache
- * <li>least-recently-used eviction when a maximum size is exceeded
- * <li>time-based expiration of entries, measured since last access or last write
- * <li>keys automatically wrapped in {@linkplain WeakReference weak} references
- * <li>values automatically wrapped in {@linkplain WeakReference weak} or
- * {@linkplain SoftReference soft} references
- * <li>notification of evicted (or otherwise removed) entries
- * <li>accumulation of cache access statistics
- * </ul>
- *
- * These features are all optional; caches can be created using all or none of them. By default
- * cache instances created by {@code CacheBuilder} will not perform any type of eviction.
- *
- * <p>Usage example: <pre> {@code
- *
- * LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
- * .maximumSize(10000)
- * .expireAfterWrite(10, TimeUnit.MINUTES)
- * .removalListener(MY_LISTENER)
- * .build(
- * new CacheLoader<Key, Graph>() {
- * public Graph load(Key key) throws AnyException {
- * return createExpensiveGraph(key);
- * }
- * });}</pre>
- *
- * Or equivalently, <pre> {@code
- *
- * // In real life this would come from a command-line flag or config file
- * String spec = "maximumSize=10000,expireAfterWrite=10m";
- *
- * LoadingCache<Key, Graph> graphs = CacheBuilder.from(spec)
- * .removalListener(MY_LISTENER)
- * .build(
- * new CacheLoader<Key, Graph>() {
- * public Graph load(Key key) throws AnyException {
- * return createExpensiveGraph(key);
- * }
- * });}</pre>
- *
- * <p>The returned cache is implemented as a hash table with similar performance characteristics to
- * {@link ConcurrentHashMap}. It implements all optional operations of the {@link LoadingCache} and
- * {@link Cache} interfaces. The {@code asMap} view (and its collection views) have <i>weakly
- * consistent iterators</i>. This means that they are safe for concurrent use, but if other threads
- * modify the cache after the iterator is created, it is undefined which of these changes, if any,
- * are reflected in that iterator. These iterators never throw {@link
- * ConcurrentModificationException}.
- *
- * <p><b>Note:</b> by default, the returned cache uses equality comparisons (the
- * {@link Object#equals equals} method) to determine equality for keys or values. However, if
- * {@link #weakKeys} was specified, the cache uses identity ({@code ==})
- * comparisons instead for keys. Likewise, if {@link #weakValues} or {@link #softValues} was
- * specified, the cache uses identity comparisons for values.
+ * CacheBuilder emulation.
*
- * <p>Entries are automatically evicted from the cache when any of
- * {@linkplain #maximumSize(long) maximumSize}, {@linkplain #maximumWeight(long) maximumWeight},
- * {@linkplain #expireAfterWrite expireAfterWrite},
- * {@linkplain #expireAfterAccess expireAfterAccess}, {@linkplain #weakKeys weakKeys},
- * {@linkplain #weakValues weakValues}, or {@linkplain #softValues softValues} are requested.
- *
- * <p>If {@linkplain #maximumSize(long) maximumSize} or
- * {@linkplain #maximumWeight(long) maximumWeight} is requested entries may be evicted on each cache
- * modification.
- *
- * <p>If {@linkplain #expireAfterWrite expireAfterWrite} or
- * {@linkplain #expireAfterAccess expireAfterAccess} is requested entries may be evicted on each
- * cache modification, on occasional cache accesses, or on calls to {@link Cache#cleanUp}. Expired
- * entries may be counted in {@link Cache#size}, but will never be visible to read or write
- * operations.
- *
- * <p>If {@linkplain #weakKeys weakKeys}, {@linkplain #weakValues weakValues}, or
- * {@linkplain #softValues softValues} are requested, it is possible for a key or value present in
- * the cache to be reclaimed by the garbage collector. Entries with reclaimed keys or values may be
- * removed from the cache on each cache modification, on occasional cache accesses, or on calls to
- * {@link Cache#cleanUp}; such entries may be counted in {@link Cache#size}, but will never be
- * visible to read or write operations.
- *
- * <p>Certain cache configurations will result in the accrual of periodic maintenance tasks which
- * will be performed during write operations, or during occasional read operations in the absense of
- * writes. The {@link Cache#cleanUp} method of the returned cache will also perform maintenance, but
- * calling it should not be necessary with a high throughput cache. Only caches built with
- * {@linkplain #removalListener removalListener}, {@linkplain #expireAfterWrite expireAfterWrite},
- * {@linkplain #expireAfterAccess expireAfterAccess}, {@linkplain #weakKeys weakKeys},
- * {@linkplain #weakValues weakValues}, or {@linkplain #softValues softValues} perform periodic
- * maintenance.
- *
- * <p>The caches produced by {@code CacheBuilder} are serializable, and the deserialized caches
- * retain all the configuration properties of the original cache. Note that the serialized form does
- * <i>not</i> include cache contents, but only configuration.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CachesExplained">caching</a> for a higher-level
- * explanation.
- *
- * @param <K> the base key type for all caches created by this builder
- * @param <V> the base value type for all caches created by this builder
* @author Charles Fry
- * @author Kevin Bourrillion
- * @since 10.0
*/
-@GwtCompatible(emulated = true)
-public final class CacheBuilder<K, V> {
+// TODO(fry): eventually we should emmulate LocalCache instead of CacheBuilder
+public class CacheBuilder<K, V> {
+ private static final int UNSET_INT = -1;
private static final int DEFAULT_INITIAL_CAPACITY = 16;
- private static final int DEFAULT_CONCURRENCY_LEVEL = 4;
private static final int DEFAULT_EXPIRATION_NANOS = 0;
- private static final int DEFAULT_REFRESH_NANOS = 0;
-
- static final Supplier<? extends StatsCounter> NULL_STATS_COUNTER = Suppliers.ofInstance(
- new StatsCounter() {
- @Override
- public void recordHits(int count) {}
- @Override
- public void recordMisses(int count) {}
-
- @Override
- public void recordLoadSuccess(long loadTime) {}
-
- @Override
- public void recordLoadException(long loadTime) {}
-
- @Override
- public void recordEviction() {}
-
- @Override
- public CacheStats snapshot() {
- return EMPTY_STATS;
- }
- });
- static final CacheStats EMPTY_STATS = new CacheStats(0, 0, 0, 0, 0, 0);
+ private int initialCapacity = -1;
+ private int concurrencyLevel = -1;
+ private long expirationMillis = -1;
+ private int maximumSize = -1;
- static final Supplier<StatsCounter> CACHE_STATS_COUNTER =
- new Supplier<StatsCounter>() {
- @Override
- public StatsCounter get() {
- return new SimpleStatsCounter();
- }
- };
-
- enum NullListener implements RemovalListener<Object, Object> {
- INSTANCE;
-
- @Override
- public void onRemoval(RemovalNotification<Object, Object> notification) {}
- }
-
- enum OneWeigher implements Weigher<Object, Object> {
- INSTANCE;
-
- @Override
- public int weigh(Object key, Object value) {
- return 1;
- }
- }
-
- static final Ticker NULL_TICKER = new Ticker() {
- @Override
- public long read() {
- return 0;
- }
- };
-
- private static final Logger logger = Logger.getLogger(CacheBuilder.class.getName());
-
- static final int UNSET_INT = -1;
-
- boolean strictParsing = true;
-
- int initialCapacity = UNSET_INT;
- int concurrencyLevel = UNSET_INT;
- long maximumSize = UNSET_INT;
- long maximumWeight = UNSET_INT;
- Weigher<? super K, ? super V> weigher;
-
- Strength keyStrength;
- Strength valueStrength;
-
- long expireAfterWriteNanos = UNSET_INT;
- long expireAfterAccessNanos = UNSET_INT;
- long refreshNanos = UNSET_INT;
-
- Equivalence<Object> keyEquivalence;
- Equivalence<Object> valueEquivalence;
-
- RemovalListener<? super K, ? super V> removalListener;
- Ticker ticker;
-
- Supplier<? extends StatsCounter> statsCounterSupplier = NULL_STATS_COUNTER;
-
- // TODO(fry): make constructor private and update tests to use newBuilder
CacheBuilder() {}
- /**
- * Constructs a new {@code CacheBuilder} instance with default settings, including strong keys,
- * strong values, and no automatic eviction of any kind.
- */
public static CacheBuilder<Object, Object> newBuilder() {
return new CacheBuilder<Object, Object>();
}
- Equivalence<Object> getKeyEquivalence() {
- return firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
- }
-
- Equivalence<Object> getValueEquivalence() {
- return firstNonNull(valueEquivalence, getValueStrength().defaultEquivalence());
- }
-
- /**
- * Sets the minimum total size for the internal hash tables. For example, if the initial capacity
- * is {@code 60}, and the concurrency level is {@code 8}, then eight segments are created, each
- * having a hash table of size eight. Providing a large enough estimate at construction time
- * avoids the need for expensive resizing operations later, but setting this value unnecessarily
- * high wastes memory.
- *
- * @throws IllegalArgumentException if {@code initialCapacity} is negative
- * @throws IllegalStateException if an initial capacity was already set
- */
public CacheBuilder<K, V> initialCapacity(int initialCapacity) {
checkState(this.initialCapacity == UNSET_INT, "initial capacity was already set to %s",
this.initialCapacity);
@@ -269,354 +66,258 @@ public final class CacheBuilder<K, V> {
return this;
}
- int getInitialCapacity() {
+ private int getInitialCapacity() {
return (initialCapacity == UNSET_INT) ? DEFAULT_INITIAL_CAPACITY : initialCapacity;
}
- /**
- * Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The
- * table is internally partitioned to try to permit the indicated number of concurrent updates
- * without contention. Because assignment of entries to these partitions is not necessarily
- * uniform, the actual concurrency observed may vary. Ideally, you should choose a value to
- * accommodate as many threads as will ever concurrently modify the table. Using a significantly
- * higher value than you need can waste space and time, and a significantly lower value can lead
- * to thread contention. But overestimates and underestimates within an order of magnitude do not
- * usually have much noticeable impact. A value of one permits only one thread to modify the cache
- * at a time, but since read operations and cache loading computations can proceed concurrently,
- * this still yields higher concurrency than full synchronization.
- *
- * <p> Defaults to 4. <b>Note:</b>The default may change in the future. If you care about this
- * value, you should always choose it explicitly.
- *
- * <p>The current implementation uses the concurrency level to create a fixed number of hashtable
- * segments, each governed by its own write lock. The segment lock is taken once for each explicit
- * write, and twice for each cache loading computation (once prior to loading the new value,
- * and once after loading completes). Much internal cache management is performed at the segment
- * granularity. For example, access queues and write queues are kept per segment when they are
- * required by the selected eviction algorithm. As such, when writing unit tests it is not
- * uncommon to specify {@code concurrencyLevel(1)} in order to achieve more deterministic eviction
- * behavior.
- *
- * <p>Note that future implementations may abandon segment locking in favor of more advanced
- * concurrency controls.
- *
- * @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive
- * @throws IllegalStateException if a concurrency level was already set
- */
public CacheBuilder<K, V> concurrencyLevel(int concurrencyLevel) {
checkState(this.concurrencyLevel == UNSET_INT, "concurrency level was already set to %s",
this.concurrencyLevel);
checkArgument(concurrencyLevel > 0);
+ // GWT technically only supports concurrencyLevel == 1, but we silently
+ // ignore other positive values.
this.concurrencyLevel = concurrencyLevel;
return this;
}
- int getConcurrencyLevel() {
- return (concurrencyLevel == UNSET_INT) ? DEFAULT_CONCURRENCY_LEVEL : concurrencyLevel;
+ public CacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
+ checkState(expirationMillis == UNSET_INT, "expireAfterWrite was already set to %s ms",
+ expirationMillis);
+ checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
+ this.expirationMillis = unit.toMillis(duration);
+ return this;
}
- /**
- * Specifies the maximum number of entries the cache may contain. Note that the cache <b>may evict
- * an entry before this limit is exceeded</b>. As the cache size grows close to the maximum, the
- * cache evicts entries that are less likely to be used again. For example, the cache may evict an
- * entry because it hasn't been used recently or very often.
- *
- * <p>When {@code size} is zero, elements will be evicted immediately after being loaded into the
- * cache. This can be useful in testing, or to disable caching temporarily without a code change.
- *
- * <p>This feature cannot be used in conjunction with {@link #maximumWeight}.
- *
- * @param size the maximum size of the cache
- * @throws IllegalArgumentException if {@code size} is negative
- * @throws IllegalStateException if a maximum size or weight was already set
- */
- public CacheBuilder<K, V> maximumSize(long size) {
- checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
- this.maximumSize);
- checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s",
- this.maximumWeight);
- checkState(this.weigher == null, "maximum size can not be combined with weigher");
- checkArgument(size >= 0, "maximum size must not be negative");
- this.maximumSize = size;
- return this;
+ private long getExpirationMillis() {
+ return (expirationMillis == UNSET_INT) ? DEFAULT_EXPIRATION_NANOS : expirationMillis;
}
- long getMaximumWeight() {
- if (expireAfterWriteNanos == 0 || expireAfterAccessNanos == 0) {
- return 0;
+ public CacheBuilder<K, V> maximumSize(int maximumSize) {
+ if (this.maximumSize != -1) {
+ throw new IllegalStateException("maximum size of " + maximumSize + " was already set");
+ }
+ if (maximumSize < 0) {
+ throw new IllegalArgumentException("invalid maximum size: " + maximumSize);
}
- return (weigher == null) ? maximumSize : maximumWeight;
+ this.maximumSize = maximumSize;
+ return this;
}
- // Make a safe contravariant cast now so we don't have to do it over and over.
- @SuppressWarnings("unchecked")
- <K1 extends K, V1 extends V> Weigher<K1, V1> getWeigher() {
- return (Weigher<K1, V1>) Objects.firstNonNull(weigher, OneWeigher.INSTANCE);
+ public <K1 extends K, V1 extends V> Cache<K1, V1> build() {
+ return new LocalManualCache<K1, V1>(this);
}
- CacheBuilder<K, V> setKeyStrength(Strength strength) {
- checkState(keyStrength == null, "Key strength was already set to %s", keyStrength);
- keyStrength = checkNotNull(strength);
- return this;
+ public <K1 extends K, V1 extends V> LoadingCache<K1, V1> build(
+ CacheLoader<? super K1, V1> loader) {
+ return new LocalLoadingCache<K1, V1>(this, loader);
}
- Strength getKeyStrength() {
- return firstNonNull(keyStrength, Strength.STRONG);
- }
+ private static class LocalManualCache<K, V>
+ extends AbstractCache<K, V> implements Function<K, V> {
+ final LocalCache<K, V> localCache;
- CacheBuilder<K, V> setValueStrength(Strength strength) {
- checkState(valueStrength == null, "Value strength was already set to %s", valueStrength);
- valueStrength = checkNotNull(strength);
- return this;
- }
+ LocalManualCache(CacheBuilder<? super K, ? super V> builder) {
+ this(builder, null);
+ }
- Strength getValueStrength() {
- return firstNonNull(valueStrength, Strength.STRONG);
- }
+ protected LocalManualCache(CacheBuilder<? super K, ? super V> builder,
+ CacheLoader<? super K, V> loader) {
+ this.localCache = new LocalCache<K, V>(builder, loader);
+ }
- /**
- * Specifies that each entry should be automatically removed from the cache once a fixed duration
- * has elapsed after the entry's creation, or the most recent replacement of its value.
- *
- * <p>When {@code duration} is zero, this method hands off to
- * {@link #maximumSize(long) maximumSize}{@code (0)}, ignoring any otherwise-specificed maximum
- * size or weight. This can be useful in testing, or to disable caching temporarily without a code
- * change.
- *
- * <p>Expired entries may be counted in {@link Cache#size}, but will never be visible to read or
- * write operations. Expired entries are cleaned up as part of the routine maintenance described
- * in the class javadoc.
- *
- * @param duration the length of time after an entry is created that it should be automatically
- * removed
- * @param unit the unit that {@code duration} is expressed in
- * @throws IllegalArgumentException if {@code duration} is negative
- * @throws IllegalStateException if the time to live or time to idle was already set
- */
- public CacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
- checkState(expireAfterWriteNanos == UNSET_INT, "expireAfterWrite was already set to %s ns",
- expireAfterWriteNanos);
- checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
- this.expireAfterWriteNanos = unit.toNanos(duration);
- return this;
- }
+ // Cache methods
- long getExpireAfterWriteNanos() {
- return (expireAfterWriteNanos == UNSET_INT) ? DEFAULT_EXPIRATION_NANOS : expireAfterWriteNanos;
- }
+ @Override
+ public V get(K key) throws ExecutionException {
+ return localCache.getOrLoad(key);
+ }
- /**
- * Specifies that each entry should be automatically removed from the cache once a fixed duration
- * has elapsed after the entry's creation, the most recent replacement of its value, or its last
- * access. Access time is reset by all cache read and write operations (including
- * {@code Cache.asMap().get(Object)} and {@code Cache.asMap().put(K, V)}), but not by operations
- * on the collection-views of {@link Cache#asMap}.
- *
- * <p>When {@code duration} is zero, this method hands off to
- * {@link #maximumSize(long) maximumSize}{@code (0)}, ignoring any otherwise-specificed maximum
- * size or weight. This can be useful in testing, or to disable caching temporarily without a code
- * change.
- *
- * <p>Expired entries may be counted in {@link Cache#size}, but will never be visible to read or
- * write operations. Expired entries are cleaned up as part of the routine maintenance described
- * in the class javadoc.
- *
- * @param duration the length of time after an entry is last accessed that it should be
- * automatically removed
- * @param unit the unit that {@code duration} is expressed in
- * @throws IllegalArgumentException if {@code duration} is negative
- * @throws IllegalStateException if the time to idle or time to live was already set
- */
- public CacheBuilder<K, V> expireAfterAccess(long duration, TimeUnit unit) {
- checkState(expireAfterAccessNanos == UNSET_INT, "expireAfterAccess was already set to %s ns",
- expireAfterAccessNanos);
- checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
- this.expireAfterAccessNanos = unit.toNanos(duration);
- return this;
- }
+ @Override
+ public V getUnchecked(K key) {
+ try {
+ return get(key);
+ } catch (ExecutionException e) {
+ throw new UncheckedExecutionException(e.getCause());
+ }
+ }
- long getExpireAfterAccessNanos() {
- return (expireAfterAccessNanos == UNSET_INT)
- ? DEFAULT_EXPIRATION_NANOS : expireAfterAccessNanos;
- }
+ @Override
+ public final V apply(K key) {
+ return getUnchecked(key);
+ }
- long getRefreshNanos() {
- return (refreshNanos == UNSET_INT) ? DEFAULT_REFRESH_NANOS : refreshNanos;
- }
+ @Override
+ @Nullable
+ public V getIfPresent(K key) {
+ return localCache.get(key);
+ }
- /**
- * Specifies a nanosecond-precision time source for use in determining when entries should be
- * expired. By default, {@link System#nanoTime} is used.
- *
- * <p>The primary intent of this method is to facilitate testing of caches which have been
- * configured with {@link #expireAfterWrite} or {@link #expireAfterAccess}.
- *
- * @throws IllegalStateException if a ticker was already set
- */
- public CacheBuilder<K, V> ticker(Ticker ticker) {
- checkState(this.ticker == null);
- this.ticker = checkNotNull(ticker);
- return this;
- }
+ @Override
+ public void put(K key, V value) {
+ localCache.put(key, value);
+ }
- Ticker getTicker(boolean recordsTime) {
- if (ticker != null) {
- return ticker;
+ @Override
+ public void invalidate(Object key) {
+ checkNotNull(key);
+ localCache.remove(key);
}
- return recordsTime ? Ticker.systemTicker() : NULL_TICKER;
- }
- /**
- * Specifies a listener instance that caches should notify each time an entry is removed for any
- * {@linkplain RemovalCause reason}. Each cache created by this builder will invoke this listener
- * as part of the routine maintenance described in the class documentation above.
- *
- * <p><b>Warning:</b> after invoking this method, do not continue to use <i>this</i> cache
- * builder reference; instead use the reference this method <i>returns</i>. At runtime, these
- * point to the same instance, but only the returned reference has the correct generic type
- * information so as to ensure type safety. For best results, use the standard method-chaining
- * idiom illustrated in the class documentation above, configuring a builder and building your
- * cache in a single statement. Failure to heed this advice can result in a {@link
- * ClassCastException} being thrown by a cache operation at some <i>undefined</i> point in the
- * future.
- *
- * <p><b>Warning:</b> any exception thrown by {@code listener} will <i>not</i> be propagated to
- * the {@code Cache} user, only logged via a {@link Logger}.
- *
- * @return the cache builder reference that should be used instead of {@code this} for any
- * remaining configuration and cache building
- * @throws IllegalStateException if a removal listener was already set
- */
- @CheckReturnValue
- public <K1 extends K, V1 extends V> CacheBuilder<K1, V1> removalListener(
- RemovalListener<? super K1, ? super V1> listener) {
- checkState(this.removalListener == null);
-
- // safely limiting the kinds of caches this can produce
- @SuppressWarnings("unchecked")
- CacheBuilder<K1, V1> me = (CacheBuilder<K1, V1>) this;
- me.removalListener = checkNotNull(listener);
- return me;
- }
+ @Override
+ public void invalidateAll() {
+ localCache.clear();
+ }
- // Make a safe contravariant cast now so we don't have to do it over and over.
- @SuppressWarnings("unchecked")
- <K1 extends K, V1 extends V> RemovalListener<K1, V1> getRemovalListener() {
- return (RemovalListener<K1, V1>) Objects.firstNonNull(removalListener, NullListener.INSTANCE);
- }
+ @Override
+ public long size() {
+ return localCache.size();
+ }
- /**
- * Enable the accumulation of {@link CacheStats} during the operation of the cache. Without this
- * {@link Cache#stats} will return zero for all statistics. Note that recording stats requires
- * bookkeeping to be performed with each operation, and thus imposes a performance penalty on
- * cache operation.
- *
- * @since 12.0 (previously, stats collection was automatic)
- */
- public CacheBuilder<K, V> recordStats() {
- statsCounterSupplier = CACHE_STATS_COUNTER;
- return this;
+ @Override
+ public ConcurrentMap<K, V> asMap() {
+ return localCache;
+ }
}
- Supplier<? extends StatsCounter> getStatsCounterSupplier() {
- return statsCounterSupplier;
- }
+ private static class LocalLoadingCache<K, V>
+ extends LocalManualCache<K, V> implements LoadingCache<K, V> {
- /**
- * Builds a cache, which either returns an already-loaded value for a given key or atomically
- * computes or retrieves it using the supplied {@code CacheLoader}. If another thread is currently
- * loading the value for this key, simply waits for that thread to finish and returns its
- * loaded value. Note that multiple threads can concurrently load values for distinct keys.
- *
- * <p>This method does not alter the state of this {@code CacheBuilder} instance, so it can be
- * invoked again to create multiple independent caches.
- *
- * @param loader the cache loader used to obtain new values
- * @return a cache having the requested features
- */
- public <K1 extends K, V1 extends V> LoadingCache<K1, V1> build(
- CacheLoader<? super K1, V1> loader) {
- checkWeightWithWeigher();
- return new LocalCache.LocalLoadingCache<K1, V1>(this, loader);
- }
+ LocalLoadingCache(CacheBuilder<? super K, ? super V> builder,
+ CacheLoader<? super K, V> loader) {
+ super(builder, checkNotNull(loader));
+ }
- /**
- * Builds a cache which does not automatically load values when keys are requested.
- *
- * <p>Consider {@link #build(CacheLoader)} instead, if it is feasible to implement a
- * {@code CacheLoader}.
- *
- * <p>This method does not alter the state of this {@code CacheBuilder} instance, so it can be
- * invoked again to create multiple independent caches.
- *
- * @return a cache having the requested features
- * @since 11.0
- */
- public <K1 extends K, V1 extends V> Cache<K1, V1> build() {
- checkWeightWithWeigher();
- checkNonLoadingCache();
- return new LocalCache.LocalManualCache<K1, V1>(this);
- }
+ // Cache methods
- private void checkNonLoadingCache() {
- checkState(refreshNanos == UNSET_INT, "refreshAfterWrite requires a LoadingCache");
- }
+ @Override
+ public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
+ throw new UnsupportedOperationException();
+ }
- private void checkWeightWithWeigher() {
- if (weigher == null) {
- checkState(maximumWeight == UNSET_INT, "maximumWeight requires weigher");
- } else {
- if (strictParsing) {
- checkState(maximumWeight != UNSET_INT, "weigher requires maximumWeight");
- } else {
- if (maximumWeight == UNSET_INT) {
- logger.log(Level.WARNING, "ignoring weigher specified without maximumWeight");
- }
- }
+ @Override
+ public void refresh(K key) {
+ throw new UnsupportedOperationException();
}
}
- /**
- * Returns a string representation for this CacheBuilder instance. The exact form of the returned
- * string is not specified.
- */
- @Override
- public String toString() {
- Objects.ToStringHelper s = Objects.toStringHelper(this);
- if (initialCapacity != UNSET_INT) {
- s.add("initialCapacity", initialCapacity);
+ // TODO(fry,user): ConcurrentHashMap never throws a CME when mutating the map during iteration, but
+ // this implementation (based on a LHM) does. This will all be replaced soon anyways, so leaving
+ // it as is for now.
+ private static class LocalCache<K, V> extends LinkedHashMap<K, V>
+ implements ConcurrentMap<K, V> {
+ private final CacheLoader<? super K, V> loader;
+ private final long expirationMillis;
+ private final int maximumSize;
+
+ LocalCache(CacheBuilder<? super K, ? super V> builder, CacheLoader<? super K, V> loader) {
+ super(builder.getInitialCapacity(), 0.75f, (builder.maximumSize != UNSET_INT));
+ this.loader = loader;
+ this.expirationMillis = builder.getExpirationMillis();
+ this.maximumSize = builder.maximumSize;
}
- if (concurrencyLevel != UNSET_INT) {
- s.add("concurrencyLevel", concurrencyLevel);
- }
- if (maximumSize != UNSET_INT) {
- s.add("maximumSize", maximumSize);
+
+ @Override
+ public V put(K key, V value) {
+ V result = super.put(key, value);
+ if (expirationMillis > 0) {
+ scheduleRemoval(key, value);
+ }
+ return result;
}
- if (maximumWeight != UNSET_INT) {
- s.add("maximumWeight", maximumWeight);
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K, V> ignored) {
+ return (maximumSize == -1) ? false : size() > maximumSize;
}
- if (expireAfterWriteNanos != UNSET_INT) {
- s.add("expireAfterWrite", expireAfterWriteNanos + "ns");
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ if (!containsKey(key)) {
+ return put(key, value);
+ } else {
+ return get(key);
+ }
}
- if (expireAfterAccessNanos != UNSET_INT) {
- s.add("expireAfterAccess", expireAfterAccessNanos + "ns");
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ if (containsKey(key) && get(key).equals(value)) {
+ remove(key);
+ return true;
+ }
+ return false;
}
- if (keyStrength != null) {
- s.add("keyStrength", Ascii.toLowerCase(keyStrength.toString()));
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ if (containsKey(key) && get(key).equals(oldValue)) {
+ put(key, newValue);
+ return true;
+ }
+ return false;
}
- if (valueStrength != null) {
- s.add("valueStrength", Ascii.toLowerCase(valueStrength.toString()));
+
+ @Override
+ public V replace(K key, V value) {
+ return containsKey(key) ? put(key, value) : null;
}
- if (keyEquivalence != null) {
- s.addValue("keyEquivalence");
+
+ private void scheduleRemoval(final K key, final V value) {
+ /*
+ * TODO: Keep weak reference to map, too. Build a priority queue out of the entries themselves
+ * instead of creating a task per entry. Then, we could have one recurring task per map (which
+ * would clean the entire map and then reschedule itself depending upon when the next
+ * expiration comes). We also want to avoid removing an entry prematurely if the entry was set
+ * to the same value again.
+ */
+ Timer timer = new Timer() {
+ @Override
+ public void run() {
+ remove(key, value);
+ }
+ };
+ timer.schedule((int) expirationMillis);
}
- if (valueEquivalence != null) {
- s.addValue("valueEquivalence");
+
+ public V getOrLoad(Object k) throws ExecutionException {
+ // from CustomConcurrentHashMap
+ V result = super.get(k);
+ if (result == null) {
+ /*
+ * This cast isn't safe, but we can rely on the fact that K is almost always passed to
+ * Map.get(), and tools like IDEs and Findbugs can catch situations where this isn't the
+ * case.
+ *
+ * The alternative is to add an overloaded method, but the chances of a user calling get()
+ * instead of the new API and the risks inherent in adding a new API outweigh this little
+ * hole.
+ */
+ @SuppressWarnings("unchecked")
+ K key = (K) k;
+ result = compute(key);
+ }
+ return result;
}
- if (removalListener != null) {
- s.addValue("removalListener");
+
+ private V compute(K key) throws ExecutionException {
+ V value;
+ try {
+ value = loader.load(key);
+ } catch (RuntimeException e) {
+ throw new UncheckedExecutionException(e);
+ } catch (Exception e) {
+ throw new ExecutionException(e);
+ } catch (Error e) {
+ throw new ExecutionError(e);
+ }
+
+ if (value == null) {
+ String message = loader + " returned null for key " + key + ".";
+ throw new InvalidCacheLoadException(message);
+ }
+ put(key, value);
+ return value;
}
- return s.toString();
}
-}
+}
diff --git a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheLoader.java b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheLoader.java
index c345553..c0815dd 100644
--- a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheLoader.java
+++ b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/CacheLoader.java
@@ -18,7 +18,6 @@ package com.google.common.cache;
import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
@@ -27,20 +26,11 @@ import java.io.Serializable;
import java.util.Map;
/**
- * Computes or retrieves values, based on a key, for use in populating a {@link LoadingCache}.
+ * Computes or retrieves values, based on a key, for use in populating a {@code Cache}.
*
* <p>Most implementations will only need to implement {@link #load}. Other methods may be
* overridden as desired.
*
- * <p>Usage example: <pre> {@code
- *
- * CacheLoader<Key, Graph> loader = new CacheLoader<Key, Graph>() {
- * public Graph load(Key key) throws AnyException {
- * return createExpensiveGraph(key);
- * }
- * };
- * LoadingCache<Key, Graph> cache = CacheBuilder.newBuilder().build(loader);}</pre>
- *
* @author Charles Fry
* @since 10.0
*/
@@ -56,16 +46,12 @@ public abstract class CacheLoader<K, V> {
*
* @param key the non-null key whose value should be loaded
* @return the value associated with {@code key}; <b>must not be null</b>
- * @throws Exception if unable to load the result
- * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
- * treated like any other {@code Exception} in all respects except that, when it is caught,
- * the thread's interrupt status is set
*/
public abstract V load(K key) throws Exception;
/**
* Computes or retrieves the values corresponding to {@code keys}. This method is called by
- * {@link LoadingCache#getAll}.
+ * {@link Cache#getAll}.
*
* <p>If the returned map doesn't contain all requested {@code keys} then the entries it does
* contain will be cached, but {@code getAll} will throw an exception. If the returned map
@@ -73,33 +59,22 @@ public abstract class CacheLoader<K, V> {
* but only the entries for {@code keys} will be returned from {@code getAll}.
*
* <p>This method should be overriden when bulk retrieval is significantly more efficient than
- * many individual lookups. Note that {@link LoadingCache#getAll} will defer to individual calls
- * to {@link LoadingCache#get} if this method is not overriden.
+ * many individual lookups. Note that {@link Cache#getAll} will defer to individual calls to
+ * {@link Cache#get} if this method is not overriden.
*
* @param keys the unique, non-null keys whose values should be loaded
* @return a map from each key in {@code keys} to the value associated with that key;
* <b>may not contain null values</b>
- * @throws Exception if unable to load the result
- * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
- * treated like any other {@code Exception} in all respects except that, when it is caught,
- * the thread's interrupt status is set
* @since 11.0
*/
public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
- // This will be caught by getAll(), causing it to fall back to multiple calls to
- // LoadingCache.get
+ // This will be caught by getAll(), causing it to fall back to multiple calls to Cache.get
throw new UnsupportedLoadingOperationException();
}
/**
- * Returns a cache loader based on an <i>existing</i> function instance. Note that there's no need
- * to create a <i>new</i> function just to pass it in here; just subclass {@code CacheLoader} and
- * implement {@link #load load} instead.
- *
- * @param function the function to be used for loading values; must never return {@code null}
- * @return a cache loader that loads values by passing each key to {@code function}
+ * Returns a {@code CacheLoader} which creates values by applying a {@code Function} to the key.
*/
- @Beta
public static <K, V> CacheLoader<K, V> from(Function<K, V> function) {
return new FunctionToCacheLoader<K, V>(function);
}
@@ -114,22 +89,16 @@ public abstract class CacheLoader<K, V> {
@Override
public V load(K key) {
- return computingFunction.apply(checkNotNull(key));
+ return computingFunction.apply(key);
}
private static final long serialVersionUID = 0;
}
/**
- * Returns a cache loader based on an <i>existing</i> supplier instance. Note that there's no need
- * to create a <i>new</i> supplier just to pass it in here; just subclass {@code CacheLoader} and
- * implement {@link #load load} instead.
- *
- * @param supplier the supplier to be used for loading values; must never return {@code null}
- * @return a cache loader that loads values by calling {@link Supplier#get}, irrespective of the
- * key
+ * Returns a {@code CacheLoader} which obtains values from a {@code Supplier} (independent of the
+ * key).
*/
- @Beta
public static <V> CacheLoader<Object, V> from(Supplier<V> supplier) {
return new SupplierToCacheLoader<V>(supplier);
}
@@ -144,7 +113,6 @@ public abstract class CacheLoader<K, V> {
@Override
public V load(Object key) {
- checkNotNull(key);
return computingSupplier.get();
}
diff --git a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java
deleted file mode 100644
index 44528bf..0000000
--- a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LocalCache.java
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.cache;
-
-import static com.google.common.base.Objects.firstNonNull;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.base.Equivalence;
-import com.google.common.base.Ticker;
-import com.google.common.cache.AbstractCache.StatsCounter;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ExecutionError;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-
-import java.util.AbstractSet;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-
-import javax.annotation.Nullable;
-
-/**
- * LocalCache emulation for GWT.
- *
- * @param <K> the base key type
- * @param <V> the base value type
- * @author Charles Fry
- * @author Jon Donovan
- */
-public class LocalCache<K, V> implements ConcurrentMap<K, V> {
- private static final int UNSET_INT = CacheBuilder.UNSET_INT;
-
- private final LinkedHashMap<K, Timestamped<V>> cachingHashMap;
- private final CacheLoader<? super K, V> loader;
- private final RemovalListener removalListener;
- private final StatsCounter statsCounter;
- private final Ticker ticker;
- private final long expireAfterWrite;
- private final long expireAfterAccess;
-
- LocalCache(CacheBuilder<? super K, ? super V> builder, CacheLoader<? super K, V> loader) {
- this.loader = loader;
- this.removalListener = builder.removalListener;
- this.expireAfterAccess = builder.expireAfterAccessNanos;
- this.expireAfterWrite = builder.expireAfterWriteNanos;
- this.statsCounter = builder.getStatsCounterSupplier().get();
-
- /* Implements size-capped LinkedHashMap */
- final long maximumSize = builder.maximumSize;
- this.cachingHashMap = new CapacityEnforcingLinkedHashMap<K, V>(
- builder.getInitialCapacity(),
- 0.75f,
- (builder.maximumSize != UNSET_INT),
- builder.maximumSize,
- statsCounter,
- removalListener);
-
- this.ticker = firstNonNull(builder.ticker, Ticker.systemTicker());
- }
-
- @Override
- public int size() {
- return cachingHashMap.size();
- }
-
- @Override
- public boolean isEmpty() {
- return cachingHashMap.isEmpty();
- }
-
- @Override
- public V get(Object key) {
- key = checkNotNull(key);
- Timestamped<V> value = cachingHashMap.get(key);
-
- if (value == null) {
- statsCounter.recordMisses(1);
- return null;
- } else if (!isExpired(value)) {
- statsCounter.recordHits(1);
- value.updateTimestamp();
- return value.getValue();
- } else {
- statsCounter.recordEviction();
- statsCounter.recordMisses(1);
- alertListenerIfPresent(key, value.getValue(), RemovalCause.EXPIRED);
- cachingHashMap.remove(key);
- return null;
- }
- }
-
- @Override
- public V put(K key, V value) {
- key = checkNotNull(key);
- value = checkNotNull(value);
- Timestamped<V> oldValue = cachingHashMap.put(key, new Timestamped<V>(value, ticker));
- if (oldValue == null) {
- return null;
- }
- alertListenerIfPresent(key, oldValue.getValue(), RemovalCause.REPLACED);
- return oldValue.getValue();
- }
-
- @Override
- public V remove(Object key) {
- Timestamped<V> stamped = cachingHashMap.remove(key);
- if (stamped != null) {
- V value = stamped.getValue();
-
- if (!isExpired(stamped)) {
- alertListenerIfPresent(key, value, RemovalCause.EXPLICIT);
- return value;
- }
-
- alertListenerIfPresent(key, value, RemovalCause.EXPIRED);
- }
- return null;
- }
-
- @Override
- public void putAll(Map<? extends K, ? extends V> m) {
- for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
- put(entry.getKey(), entry.getValue());
- }
- }
-
- @Override
- public void clear() {
- if (removalListener != null) {
- for (Map.Entry<K, Timestamped<V>> entry : cachingHashMap.entrySet()) {
- alertListenerIfPresent(entry.getKey(), entry.getValue().getValue(), RemovalCause.EXPLICIT);
- }
- }
- cachingHashMap.clear();
- }
-
- @Override
- public V putIfAbsent(K key, V value) {
- V currentValue = get(key);
- if (currentValue != null) {
- return currentValue;
- }
- return put(key, value);
- }
-
- @Override
- public boolean remove(Object key, Object value) {
- if (value.equals(get(key))) {
- alertListenerIfPresent(key, value, RemovalCause.EXPLICIT);
- remove(key);
- return true;
- }
- return false;
- }
-
- @Override
- public boolean replace(K key, V oldValue, V newValue) {
- if (oldValue.equals(get(key))) {
- alertListenerIfPresent(key, oldValue, RemovalCause.REPLACED);
- put(key, newValue);
- return true;
- }
- return false;
- }
-
- @Override
- public V replace(K key, V value) {
- V currentValue = get(key);
- if (currentValue != null) {
- alertListenerIfPresent(key, currentValue, RemovalCause.REPLACED);
- return put(key, value);
- }
- return null;
- }
-
- @Override
- public boolean containsKey(Object key) {
- return cachingHashMap.containsKey(key) && !isExpired(cachingHashMap.get(key));
- }
-
- @Override
- public boolean containsValue(Object value) {
- for (Timestamped<V> val : cachingHashMap.values()) {
- if (val.getValue().equals(value)) {
- if (!isExpired(val)) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean isExpired(Timestamped<V> stamped) {
- if ((expireAfterAccess == UNSET_INT) && (expireAfterWrite == UNSET_INT)) {
- return false;
- }
-
- boolean expireWrite = (stamped.getWriteTimestamp() + expireAfterWrite <= currentTimeNanos());
- boolean expireAccess = (stamped.getAccessTimestamp() + expireAfterAccess <= currentTimeNanos());
-
- if (expireAfterAccess == UNSET_INT) {
- return expireWrite;
- }
- if (expireAfterWrite == UNSET_INT) {
- return expireAccess;
- }
-
- return expireWrite || expireAccess;
- }
-
- private long currentTimeNanos() {
- return ticker.read();
- }
-
- private void alertListenerIfPresent(Object key, Object value, RemovalCause cause) {
- if (removalListener != null) {
- removalListener.onRemoval(new RemovalNotification(key, value, cause));
- }
- }
-
- private V load(Object key) throws ExecutionException {
- long startTime = ticker.read();
- V calculatedValue;
- try {
- /*
- * This cast isn't safe, but we can rely on the fact that K is almost always passed to
- * Map.get(), and tools like IDEs and Findbugs can catch situations where this isn't the
- * case.
- *
- * The alternative is to add an overloaded method, but the chances of a user calling get()
- * instead of the new API and the risks inherent in adding a new API outweigh this little
- * hole.
- */
- K castKey = (K) key;
- calculatedValue = loader.load(castKey);
- put(castKey, calculatedValue);
- } catch (RuntimeException e) {
- statsCounter.recordLoadException(ticker.read() - startTime);
- throw new UncheckedExecutionException(e);
- } catch (Exception e) {
- statsCounter.recordLoadException(ticker.read() - startTime);
- throw new ExecutionException(e);
- } catch (Error e) {
- statsCounter.recordLoadException(ticker.read() - startTime);
- throw new ExecutionError(e);
- }
-
- if (calculatedValue == null) {
- String message = loader + " returned null for key " + key + ".";
- throw new CacheLoader.InvalidCacheLoadException(message);
- }
- statsCounter.recordLoadSuccess(ticker.read() - startTime);
- return calculatedValue;
- }
-
- private V getIfPresent(Object key) {
- key = checkNotNull(key);
- Timestamped<V> value = cachingHashMap.get(key);
-
- if (value == null) {
- return null;
- } else if (!isExpired(value)) {
- value.updateTimestamp();
- return value.getValue();
- } else {
- alertListenerIfPresent(key, value.getValue(), RemovalCause.EXPIRED);
- cachingHashMap.remove(key);
- return null;
- }
- }
-
- private V getOrLoad(K key) throws ExecutionException{
- V value = get(key);
- if (value != null) {
- return value;
- }
- return load(key);
- }
-
- private static class Timestamped<V> {
- private final V value;
- private final Ticker ticker;
- private long writeTimestamp;
- private long accessTimestamp;
-
- public Timestamped(V value, Ticker ticker) {
- this.value = checkNotNull(value);
- this.ticker = checkNotNull(ticker);
- this.writeTimestamp = ticker.read();
- this.accessTimestamp = this.writeTimestamp;
- }
-
- public V getValue() {
- return value;
- }
-
- public void updateTimestamp() {
- accessTimestamp = ticker.read();
- }
-
- public long getAccessTimestamp() {
- return accessTimestamp;
- }
-
- public long getWriteTimestamp() {
- return writeTimestamp;
- }
-
- public boolean equals(Object o) {
- return value.equals(o);
- }
-
- public int hashCode() {
- return value.hashCode();
- }
- }
-
- /**
- * LocalManualCache is a wrapper around LocalCache for a cache without loading.
- *
- * @param <K> the base key type
- * @param <V> the base value type
- */
- public static class LocalManualCache<K, V> extends AbstractCache<K, V> {
- final LocalCache<K, V> localCache;
-
- LocalManualCache(CacheBuilder<? super K, ? super V> builder) {
- this(builder, null);
- }
-
- protected LocalManualCache(CacheBuilder<? super K, ? super V> builder,
- CacheLoader<? super K, V> loader) {
- this.localCache = new LocalCache<K, V>(builder, loader);
- }
-
- // Cache methods
-
- @Override
- public V get(K key, Callable<? extends V> valueLoader) throws ExecutionException {
- V value = localCache.get(key);
- if (value != null) {
- return value;
- }
-
- try {
- V newValue = valueLoader.call();
- localCache.put(key, newValue);
- return newValue;
- } catch (Exception e) {
- throw new ExecutionException(e);
- }
- }
-
- @Override
- @Nullable
- public V getIfPresent(Object key) {
- return localCache.getIfPresent(key);
- }
-
- @Override
- public void put(K key, V value) {
- localCache.put(key, value);
- }
-
- @Override
- public void invalidate(Object key) {
- key = checkNotNull(key);
- localCache.remove(key);
- }
-
- @Override
- public void invalidateAll() {
- localCache.clear();
- }
-
- @Override
- public long size() {
- return localCache.size();
- }
-
- @Override
- public ConcurrentMap<K, V> asMap() {
- return localCache;
- }
- }
-
- /**
- * LocalLoadingCache is a wrapper around LocalCache for a cache with loading.
- *
- * @param <K> the base key type
- * @param <V> the base value type
- */
- public static class LocalLoadingCache<K, V>
- extends LocalManualCache<K, V> implements LoadingCache<K, V> {
-
- LocalLoadingCache(CacheBuilder<? super K, ? super V> builder,
- CacheLoader<? super K, V> loader) {
- super(builder, checkNotNull(loader));
- }
-
- // Cache methods
-
- @Override
- public V get(K key) throws ExecutionException {
- return localCache.getOrLoad(key);
- }
-
- @Override
- public V getUnchecked(K key) {
- try {
- return get(key);
- } catch (ExecutionException e) {
- throw new UncheckedExecutionException(e.getCause());
- }
- }
-
- @Override
- public final V apply(K key) {
- return getUnchecked(key);
- }
-
- @Override
- public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
- Map<K, V> map = new HashMap<K, V>();
- for (K key : keys) {
- map.put(key, localCache.getOrLoad(key));
- }
- return ImmutableMap.copyOf(map);
- }
-
- @Override
- public void refresh(K key) {
- throw new UnsupportedOperationException();
- }
- }
-
- /**
- * LinkedHashMap that enforces it's maximum size and logs events in a StatsCounter object
- * and an optional RemovalListener.
- *
- * @param <K> the base key type
- * @param <V> the base value type
- */
- private class CapacityEnforcingLinkedHashMap<K, V> extends LinkedHashMap<K, Timestamped<V>> {
-
- private final StatsCounter statsCounter;
- private final RemovalListener removalListener;
- private final long maximumSize;
-
- public CapacityEnforcingLinkedHashMap(
- int initialCapacity,
- float loadFactor,
- boolean accessOrder,
- long maximumSize,
- StatsCounter statsCounter,
- @Nullable RemovalListener removalListener) {
- super(initialCapacity, loadFactor, accessOrder);
- this.maximumSize = maximumSize;
- this.statsCounter = statsCounter;
- this.removalListener = removalListener;
- }
-
- @Override
- protected boolean removeEldestEntry(Map.Entry<K, Timestamped<V>> ignored) {
- boolean removal = (maximumSize == UNSET_INT) ? false : (size() > maximumSize);
- if ((removalListener != null) && removal) {
- removalListener.onRemoval(new RemovalNotification(
- ignored.getKey(),
- ignored.getValue().getValue(),
- RemovalCause.SIZE));
- }
- statsCounter.recordEviction();
- return removal;
- }
- }
-
- /**
- * Any updates to LocalCache.Strength used in CacheBuilder need to be matched in this class for
- * compilation purposes.
- */
- enum Strength {
- /*
- * TODO(kevinb): If we strongly reference the value and aren't loading, we needn't wrap the
- * value. This could save ~8 bytes per entry.
- */
-
- STRONG {
- @Override
- Equivalence<Object> defaultEquivalence() {
- return Equivalence.equals();
- }
- },
-
- SOFT {
- @Override
- Equivalence<Object> defaultEquivalence() {
- return Equivalence.identity();
- }
- },
-
- WEAK {
- @Override
- Equivalence<Object> defaultEquivalence() {
- return Equivalence.identity();
- }
- };
-
- abstract Equivalence<Object> defaultEquivalence();
- }
-
- /**
- * <p>Implementation for the EntryIterator, which is used to build Key and Value iterators.
- *
- * <p>Expiration is only checked on hasNext(), so as to ensure that a next() call never returns
- * null when hasNext() has already been called.
- */
- class EntryIterator implements Iterator<Entry<K, V>> {
- Iterator<Entry<K, Timestamped<V>>> iterator;
- Entry<K, Timestamped<V>> lastEntry;
- Entry<K, Timestamped<V>> nextEntry;
-
- EntryIterator() {
- this.iterator = LocalCache.this.cachingHashMap.entrySet().iterator();
- }
-
- @Override
- public Entry<K, V> next(){
- if (nextEntry == null) {
- hasNext();
-
- if (nextEntry == null) {
- throw new NoSuchElementException();
- }
- }
-
- lastEntry = nextEntry;
- nextEntry = null;
- return new WriteThroughEntry(lastEntry.getKey(), lastEntry.getValue().getValue());
- }
-
- @Override
- public boolean hasNext() {
- if (nextEntry == null) {
- while (iterator.hasNext()) {
- Entry<K, Timestamped<V>> next = iterator.next();
- if (!isExpired(next.getValue())) {
- nextEntry = next;
- return true;
- }
- }
- return false;
- }
- return true;
- }
-
- @Override
- public void remove() {
- checkState(lastEntry != null);
- LocalCache.this.remove(lastEntry.getKey(), lastEntry.getValue());
- lastEntry = null;
- }
- }
-
- /**
- * KeyIterator build on top of EntryIterator.
- */
- final class KeyIterator implements Iterator<K> {
- private EntryIterator iterator;
-
- KeyIterator() {
- iterator = new EntryIterator();
- }
-
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
-
- @Override
- public K next() {
- return iterator.next().getKey();
- }
-
- @Override
- public void remove() {
- iterator.remove();
- }
- }
-
- /**
- * ValueIterator build on top of EntryIterator.
- */
- final class ValueIterator implements Iterator<V> {
- private EntryIterator iterator;
-
- ValueIterator() {
- iterator = new EntryIterator();
- }
-
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
-
- @Override
- public V next() {
- return iterator.next().getValue();
- }
-
- @Override
- public void remove() {
- iterator.remove();
- }
- }
-
- Set<K> keySet;
-
- @Override
- public Set<K> keySet() {
- // does not impact recency ordering
- Set<K> ks = keySet;
- return (ks != null) ? ks : (keySet = new KeySet(this));
- }
-
- Collection<V> values;
-
- @Override
- public Collection<V> values() {
- // does not impact recency ordering
- Collection<V> vs = values;
- return (vs != null) ? vs : (values = new Values(this));
- }
-
- Set<Entry<K, V>> entrySet;
-
- @Override
- public Set<Entry<K, V>> entrySet() {
- // does not impact recency ordering
- Set<Entry<K, V>> es = entrySet;
- return (es != null) ? es : (entrySet = new EntrySet(this));
- }
-
- /**
- * Custom Entry class used by EntryIterator.next(), that relays setValue changes to the
- * underlying map.
- */
- private final class WriteThroughEntry implements Entry<K, V> {
- final K key;
- V value;
-
- WriteThroughEntry(K key, V value) {
- this.key = checkNotNull(key);
- this.value = checkNotNull(value);
- }
-
- @Override
- public K getKey() {
- return key;
- }
-
- @Override
- public V getValue() {
- return value;
- }
-
- @Override
- public boolean equals(@Nullable Object object) {
- // Cannot use key and value equivalence
- if (object instanceof Entry) {
- Entry<?, ?> that = (Entry<?, ?>) object;
- return key.equals(that.getKey()) && value.equals(that.getValue());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- // Cannot use key and value equivalence
- return key.hashCode() ^ value.hashCode();
- }
-
- @Override
- public V setValue(V newValue) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Returns a string representation of the form <code>{key}={value}</code>.
- */
- @Override
- public String toString() {
- return getKey() + "=" + getValue();
- }
- }
-
- // TODO(fry): Separate logic for consistency between emul and nonemul implementation.
- // TODO(fry): Look into Maps.KeySet and Maps.Values, which can ideally be reused here but are
- // currently only package visible.
- abstract class AbstractCacheSet<T> extends AbstractSet<T> {
- final ConcurrentMap<?, ?> map;
-
- AbstractCacheSet(ConcurrentMap<?, ?> map) {
- this.map = map;
- }
-
- @Override
- public int size() {
- return map.size();
- }
-
- @Override
- public boolean isEmpty() {
- return map.isEmpty();
- }
-
- @Override
- public void clear() {
- map.clear();
- }
- }
-
- /**
- * Abstraction layer for the KeySet, which redirects to cache methods.
- */
- private final class KeySet extends AbstractCacheSet<K> {
-
- KeySet(ConcurrentMap<?, ?> map) {
- super(map);
- }
-
- @Override
- public Iterator<K> iterator() {
- return new KeyIterator();
- }
-
- @Override
- public boolean contains(Object o) {
- return map.containsKey(o);
- }
-
- @Override
- public boolean remove(Object o) {
- return map.remove(o) != null;
- }
- }
-
- /**
- * Abstraction layer for the Values set, which redirects to cache methods.
- */
- private final class Values extends AbstractCacheSet<V> {
-
- Values(ConcurrentMap<?, ?> map) {
- super(map);
- }
-
- @Override
- public Iterator<V> iterator() {
- return new ValueIterator();
- }
-
- @Override
- public boolean contains(Object o) {
- return map.containsValue(o);
- }
- }
-
- /**
- * Abstraction layer for the EntrySet, which redirects to cache methods.
- */
- private final class EntrySet extends AbstractCacheSet<Entry<K, V>> {
-
- EntrySet(ConcurrentMap<?, ?> map) {
- super(map);
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return new EntryIterator();
- }
-
- @Override
- public boolean contains(Object o) {
- if (!(o instanceof Entry)) {
- return false;
- }
- Entry<?, ?> e = (Entry<?, ?>) o;
- Object key = e.getKey();
- if (key == null) {
- return false;
- }
- V v = LocalCache.this.get(key);
-
- return (v != null) && e.getValue().equals(v);
- }
-
- @Override
- public boolean remove(Object o) {
- if (!(o instanceof Entry)) {
- return false;
- }
- Entry<?, ?> e = (Entry<?, ?>) o;
- Object key = e.getKey();
- return (key != null) && LocalCache.this.remove(key, e.getValue());
- }
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LongAddables.java b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LongAddables.java
deleted file mode 100644
index a911ef3..0000000
--- a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LongAddables.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.cache;
-
-/**
- * GWT emulation for LongAddables.
- *
- * @author Louis Wasserman
- */
-final class LongAddables {
- public static LongAddable create() {
- return new LongAdder();
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LongAdder.java b/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LongAdder.java
deleted file mode 100644
index 34b6f37..0000000
--- a/guava-gwt/src-super/com/google/common/cache/super/com/google/common/cache/LongAdder.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.cache;
-
-/**
- * GWT emulated version of LongAdder.
- *
- * @author Charles Fry
- */
-class LongAdder implements LongAddable {
-
- private long value;
-
- public void increment() {
- value++;
- }
-
- public void add(long x) {
- value += x;
- }
-
- public long sum() {
- return value;
- }
-
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractBiMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractBiMap.java
index 7c882fe..a6cec16 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractBiMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractBiMap.java
@@ -45,7 +45,7 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
implements BiMap<K, V>, Serializable {
private transient Map<K, V> delegate;
- transient AbstractBiMap<V, K> inverse;
+ private transient AbstractBiMap<V, K> inverse;
/** Package-private constructor for creating a map-backed bimap. */
AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
@@ -63,20 +63,6 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
}
/**
- * Returns its input, or throws an exception if this is not a valid key.
- */
- K checkKey(@Nullable K key) {
- return key;
- }
-
- /**
- * Returns its input, or throws an exception if this is not a valid value.
- */
- V checkValue(@Nullable V value) {
- return value;
- }
-
- /**
* Specifies the delegate maps going in each direction. Called by the
* constructor and by subclasses during deserialization.
*/
@@ -96,24 +82,22 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
// Query Operations (optimizations)
- @Override public boolean containsValue(@Nullable Object value) {
+ @Override public boolean containsValue(Object value) {
return inverse.containsKey(value);
}
// Modification Operations
- @Override public V put(@Nullable K key, @Nullable V value) {
+ @Override public V put(K key, V value) {
return putInBothMaps(key, value, false);
}
@Override
- public V forcePut(@Nullable K key, @Nullable V value) {
+ public V forcePut(K key, V value) {
return putInBothMaps(key, value, true);
}
private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) {
- checkKey(key);
- checkValue(value);
boolean containedKey = containsKey(key);
if (containedKey && Objects.equal(value, get(key))) {
return value;
@@ -136,7 +120,7 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
inverse.delegate.put(newValue, key);
}
- @Override public V remove(@Nullable Object key) {
+ @Override public V remove(Object key) {
return containsKey(key) ? removeFromBothMaps(key) : null;
}
@@ -203,7 +187,27 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
}
@Override public Iterator<K> iterator() {
- return Maps.keyIterator(entrySet().iterator());
+ final Iterator<Entry<K, V>> iterator = delegate.entrySet().iterator();
+ return new Iterator<K>() {
+ Entry<K, V> entry;
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+ @Override
+ public K next() {
+ entry = iterator.next();
+ return entry.getKey();
+ }
+ @Override
+ public void remove() {
+ checkState(entry != null);
+ V value = entry.getValue();
+ iterator.remove();
+ removeFromInverseMap(value);
+ }
+ };
}
}
@@ -226,7 +230,23 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
}
@Override public Iterator<V> iterator() {
- return Maps.valueIterator(entrySet().iterator());
+ final Iterator<V> iterator = delegate.values().iterator();
+ return new Iterator<V>() {
+ V valueToRemove;
+
+ @Override public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override public V next() {
+ return valueToRemove = iterator.next();
+ }
+
+ @Override public void remove() {
+ iterator.remove();
+ removeFromInverseMap(valueToRemove);
+ }
+ };
}
@Override public Object[] toArray() {
@@ -358,16 +378,6 @@ abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
* If a bimap and its inverse are serialized together, the deserialized
* instances have inverse() methods that return the other.
*/
-
- @Override
- K checkKey(K key) {
- return inverse.checkValue(key);
- }
-
- @Override
- V checkValue(V value) {
- return inverse.checkKey(value);
- }
}
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractMapBasedMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractMapBasedMultimap.java
deleted file mode 100644
index 2cfb3ef..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractMapBasedMultimap.java
+++ /dev/null
@@ -1,1259 +0,0 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.io.Serializable;
-import java.util.AbstractCollection;
-import java.util.AbstractMap;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.RandomAccess;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.SortedSet;
-
-import javax.annotation.Nullable;
-
-/**
- * Basic implementation of the {@link Multimap} interface. This class represents
- * a multimap as a map that associates each key with a collection of values. All
- * methods of {@link Multimap} are supported, including those specified as
- * optional in the interface.
- *
- * <p>To implement a multimap, a subclass must define the method {@link
- * #createCollection()}, which creates an empty collection of values for a key.
- *
- * <p>The multimap constructor takes a map that has a single entry for each
- * distinct key. When you insert a key-value pair with a key that isn't already
- * in the multimap, {@code AbstractMapBasedMultimap} calls {@link #createCollection()}
- * to create the collection of values for that key. The subclass should not call
- * {@link #createCollection()} directly, and a new instance should be created
- * every time the method is called.
- *
- * <p>For example, the subclass could pass a {@link java.util.TreeMap} during
- * construction, and {@link #createCollection()} could return a {@link
- * java.util.TreeSet}, in which case the multimap's iterators would propagate
- * through the keys and values in sorted order.
- *
- * <p>Keys and values may be null, as long as the underlying collection classes
- * support null elements.
- *
- * <p>The collections created by {@link #createCollection()} may or may not
- * allow duplicates. If the collection, such as a {@link Set}, does not support
- * duplicates, an added key-value pair will replace an existing pair with the
- * same key and value, if such a pair is present. With collections like {@link
- * List} that allow duplicates, the collection will keep the existing key-value
- * pairs while adding a new pair.
- *
- * <p>This class is not threadsafe when any concurrent operations update the
- * multimap, even if the underlying map and {@link #createCollection()} method
- * return threadsafe classes. Concurrent read operations will work correctly. To
- * allow concurrent update operations, wrap your multimap with a call to {@link
- * Multimaps#synchronizedMultimap}.
- *
- * <p>For serialization to work, the subclass must specify explicit
- * {@code readObject} and {@code writeObject} methods.
- *
- * @author Jared Levy
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-abstract class AbstractMapBasedMultimap<K, V> extends AbstractMultimap<K, V>
- implements Serializable {
- /*
- * Here's an outline of the overall design.
- *
- * The map variable contains the collection of values associated with each
- * key. When a key-value pair is added to a multimap that didn't previously
- * contain any values for that key, a new collection generated by
- * createCollection is added to the map. That same collection instance
- * remains in the map as long as the multimap has any values for the key. If
- * all values for the key are removed, the key and collection are removed
- * from the map.
- *
- * The get method returns a WrappedCollection, which decorates the collection
- * in the map (if the key is present) or an empty collection (if the key is
- * not present). When the collection delegate in the WrappedCollection is
- * empty, the multimap may contain subsequently added values for that key. To
- * handle that situation, the WrappedCollection checks whether map contains
- * an entry for the provided key, and if so replaces the delegate.
- */
-
- private transient Map<K, Collection<V>> map;
- private transient int totalSize;
-
- /**
- * Creates a new multimap that uses the provided map.
- *
- * @param map place to store the mapping from each key to its corresponding
- * values
- * @throws IllegalArgumentException if {@code map} is not empty
- */
- protected AbstractMapBasedMultimap(Map<K, Collection<V>> map) {
- checkArgument(map.isEmpty());
- this.map = map;
- }
-
- /** Used during deserialization only. */
- final void setMap(Map<K, Collection<V>> map) {
- this.map = map;
- totalSize = 0;
- for (Collection<V> values : map.values()) {
- checkArgument(!values.isEmpty());
- totalSize += values.size();
- }
- }
-
- /**
- * Creates an unmodifiable, empty collection of values.
- *
- * <p>This is used in {@link #removeAll} on an empty key.
- */
- Collection<V> createUnmodifiableEmptyCollection() {
- return unmodifiableCollectionSubclass(createCollection());
- }
-
- /**
- * Creates the collection of values for a single key.
- *
- * <p>Collections with weak, soft, or phantom references are not supported.
- * Each call to {@code createCollection} should create a new instance.
- *
- * <p>The returned collection class determines whether duplicate key-value
- * pairs are allowed.
- *
- * @return an empty collection of values
- */
- abstract Collection<V> createCollection();
-
- /**
- * Creates the collection of values for an explicitly provided key. By
- * default, it simply calls {@link #createCollection()}, which is the correct
- * behavior for most implementations. The {@link LinkedHashMultimap} class
- * overrides it.
- *
- * @param key key to associate with values in the collection
- * @return an empty collection of values
- */
- Collection<V> createCollection(@Nullable K key) {
- return createCollection();
- }
-
- Map<K, Collection<V>> backingMap() {
- return map;
- }
-
- // Query Operations
-
- @Override
- public int size() {
- return totalSize;
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return map.containsKey(key);
- }
-
- // Modification Operations
-
- @Override
- public boolean put(@Nullable K key, @Nullable V value) {
- Collection<V> collection = map.get(key);
- if (collection == null) {
- collection = createCollection(key);
- if (collection.add(value)) {
- totalSize++;
- map.put(key, collection);
- return true;
- } else {
- throw new AssertionError("New Collection violated the Collection spec");
- }
- } else if (collection.add(value)) {
- totalSize++;
- return true;
- } else {
- return false;
- }
- }
-
- private Collection<V> getOrCreateCollection(@Nullable K key) {
- Collection<V> collection = map.get(key);
- if (collection == null) {
- collection = createCollection(key);
- map.put(key, collection);
- }
- return collection;
- }
-
- // Bulk Operations
-
- /**
- * {@inheritDoc}
- *
- * <p>The returned collection is immutable.
- */
- @Override
- public Collection<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
- Iterator<? extends V> iterator = values.iterator();
- if (!iterator.hasNext()) {
- return removeAll(key);
- }
-
- // TODO(user): investigate atomic failure?
- Collection<V> collection = getOrCreateCollection(key);
- Collection<V> oldValues = createCollection();
- oldValues.addAll(collection);
-
- totalSize -= collection.size();
- collection.clear();
-
- while (iterator.hasNext()) {
- if (collection.add(iterator.next())) {
- totalSize++;
- }
- }
-
- return unmodifiableCollectionSubclass(oldValues);
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>The returned collection is immutable.
- */
- @Override
- public Collection<V> removeAll(@Nullable Object key) {
- Collection<V> collection = map.remove(key);
-
- if (collection == null) {
- return createUnmodifiableEmptyCollection();
- }
-
- Collection<V> output = createCollection();
- output.addAll(collection);
- totalSize -= collection.size();
- collection.clear();
-
- return unmodifiableCollectionSubclass(output);
- }
-
- Collection<V> unmodifiableCollectionSubclass(Collection<V> collection) {
- // We don't deal with NavigableSet here yet for GWT reasons -- instead,
- // non-GWT TreeMultimap explicitly overrides this and uses NavigableSet.
- if (collection instanceof SortedSet) {
- return Collections.unmodifiableSortedSet((SortedSet<V>) collection);
- } else if (collection instanceof Set) {
- return Collections.unmodifiableSet((Set<V>) collection);
- } else if (collection instanceof List) {
- return Collections.unmodifiableList((List<V>) collection);
- } else {
- return Collections.unmodifiableCollection(collection);
- }
- }
-
- @Override
- public void clear() {
- // Clear each collection, to make previously returned collections empty.
- for (Collection<V> collection : map.values()) {
- collection.clear();
- }
- map.clear();
- totalSize = 0;
- }
-
- // Views
-
- /**
- * {@inheritDoc}
- *
- * <p>The returned collection is not serializable.
- */
- @Override
- public Collection<V> get(@Nullable K key) {
- Collection<V> collection = map.get(key);
- if (collection == null) {
- collection = createCollection(key);
- }
- return wrapCollection(key, collection);
- }
-
- /**
- * Generates a decorated collection that remains consistent with the values in
- * the multimap for the provided key. Changes to the multimap may alter the
- * returned collection, and vice versa.
- */
- Collection<V> wrapCollection(@Nullable K key, Collection<V> collection) {
- // We don't deal with NavigableSet here yet for GWT reasons -- instead,
- // non-GWT TreeMultimap explicitly overrides this and uses NavigableSet.
- if (collection instanceof SortedSet) {
- return new WrappedSortedSet(key, (SortedSet<V>) collection, null);
- } else if (collection instanceof Set) {
- return new WrappedSet(key, (Set<V>) collection);
- } else if (collection instanceof List) {
- return wrapList(key, (List<V>) collection, null);
- } else {
- return new WrappedCollection(key, collection, null);
- }
- }
-
- private List<V> wrapList(
- @Nullable K key, List<V> list, @Nullable WrappedCollection ancestor) {
- return (list instanceof RandomAccess)
- ? new RandomAccessWrappedList(key, list, ancestor)
- : new WrappedList(key, list, ancestor);
- }
-
- /**
- * Collection decorator that stays in sync with the multimap values for a key.
- * There are two kinds of wrapped collections: full and subcollections. Both
- * have a delegate pointing to the underlying collection class.
- *
- * <p>Full collections, identified by a null ancestor field, contain all
- * multimap values for a given key. Its delegate is a value in {@link
- * AbstractMapBasedMultimap#map} whenever the delegate is non-empty. The {@code
- * refreshIfEmpty}, {@code removeIfEmpty}, and {@code addToMap} methods ensure
- * that the {@code WrappedCollection} and map remain consistent.
- *
- * <p>A subcollection, such as a sublist, contains some of the values for a
- * given key. Its ancestor field points to the full wrapped collection with
- * all values for the key. The subcollection {@code refreshIfEmpty}, {@code
- * removeIfEmpty}, and {@code addToMap} methods call the corresponding methods
- * of the full wrapped collection.
- */
- private class WrappedCollection extends AbstractCollection<V> {
- final K key;
- Collection<V> delegate;
- final WrappedCollection ancestor;
- final Collection<V> ancestorDelegate;
-
- WrappedCollection(@Nullable K key, Collection<V> delegate,
- @Nullable WrappedCollection ancestor) {
- this.key = key;
- this.delegate = delegate;
- this.ancestor = ancestor;
- this.ancestorDelegate
- = (ancestor == null) ? null : ancestor.getDelegate();
- }
-
- /**
- * If the delegate collection is empty, but the multimap has values for the
- * key, replace the delegate with the new collection for the key.
- *
- * <p>For a subcollection, refresh its ancestor and validate that the
- * ancestor delegate hasn't changed.
- */
- void refreshIfEmpty() {
- if (ancestor != null) {
- ancestor.refreshIfEmpty();
- if (ancestor.getDelegate() != ancestorDelegate) {
- throw new ConcurrentModificationException();
- }
- } else if (delegate.isEmpty()) {
- Collection<V> newDelegate = map.get(key);
- if (newDelegate != null) {
- delegate = newDelegate;
- }
- }
- }
-
- /**
- * If collection is empty, remove it from {@code AbstractMapBasedMultimap.this.map}.
- * For subcollections, check whether the ancestor collection is empty.
- */
- void removeIfEmpty() {
- if (ancestor != null) {
- ancestor.removeIfEmpty();
- } else if (delegate.isEmpty()) {
- map.remove(key);
- }
- }
-
- K getKey() {
- return key;
- }
-
- /**
- * Add the delegate to the map. Other {@code WrappedCollection} methods
- * should call this method after adding elements to a previously empty
- * collection.
- *
- * <p>Subcollection add the ancestor's delegate instead.
- */
- void addToMap() {
- if (ancestor != null) {
- ancestor.addToMap();
- } else {
- map.put(key, delegate);
- }
- }
-
- @Override public int size() {
- refreshIfEmpty();
- return delegate.size();
- }
-
- @Override public boolean equals(@Nullable Object object) {
- if (object == this) {
- return true;
- }
- refreshIfEmpty();
- return delegate.equals(object);
- }
-
- @Override public int hashCode() {
- refreshIfEmpty();
- return delegate.hashCode();
- }
-
- @Override public String toString() {
- refreshIfEmpty();
- return delegate.toString();
- }
-
- Collection<V> getDelegate() {
- return delegate;
- }
-
- @Override public Iterator<V> iterator() {
- refreshIfEmpty();
- return new WrappedIterator();
- }
-
- /** Collection iterator for {@code WrappedCollection}. */
- class WrappedIterator implements Iterator<V> {
- final Iterator<V> delegateIterator;
- final Collection<V> originalDelegate = delegate;
-
- WrappedIterator() {
- delegateIterator = iteratorOrListIterator(delegate);
- }
-
- WrappedIterator(Iterator<V> delegateIterator) {
- this.delegateIterator = delegateIterator;
- }
-
- /**
- * If the delegate changed since the iterator was created, the iterator is
- * no longer valid.
- */
- void validateIterator() {
- refreshIfEmpty();
- if (delegate != originalDelegate) {
- throw new ConcurrentModificationException();
- }
- }
-
- @Override
- public boolean hasNext() {
- validateIterator();
- return delegateIterator.hasNext();
- }
-
- @Override
- public V next() {
- validateIterator();
- return delegateIterator.next();
- }
-
- @Override
- public void remove() {
- delegateIterator.remove();
- totalSize--;
- removeIfEmpty();
- }
-
- Iterator<V> getDelegateIterator() {
- validateIterator();
- return delegateIterator;
- }
- }
-
- @Override public boolean add(V value) {
- refreshIfEmpty();
- boolean wasEmpty = delegate.isEmpty();
- boolean changed = delegate.add(value);
- if (changed) {
- totalSize++;
- if (wasEmpty) {
- addToMap();
- }
- }
- return changed;
- }
-
- WrappedCollection getAncestor() {
- return ancestor;
- }
-
- // The following methods are provided for better performance.
-
- @Override public boolean addAll(Collection<? extends V> collection) {
- if (collection.isEmpty()) {
- return false;
- }
- int oldSize = size(); // calls refreshIfEmpty
- boolean changed = delegate.addAll(collection);
- if (changed) {
- int newSize = delegate.size();
- totalSize += (newSize - oldSize);
- if (oldSize == 0) {
- addToMap();
- }
- }
- return changed;
- }
-
- @Override public boolean contains(Object o) {
- refreshIfEmpty();
- return delegate.contains(o);
- }
-
- @Override public boolean containsAll(Collection<?> c) {
- refreshIfEmpty();
- return delegate.containsAll(c);
- }
-
- @Override public void clear() {
- int oldSize = size(); // calls refreshIfEmpty
- if (oldSize == 0) {
- return;
- }
- delegate.clear();
- totalSize -= oldSize;
- removeIfEmpty(); // maybe shouldn't be removed if this is a sublist
- }
-
- @Override public boolean remove(Object o) {
- refreshIfEmpty();
- boolean changed = delegate.remove(o);
- if (changed) {
- totalSize--;
- removeIfEmpty();
- }
- return changed;
- }
-
- @Override public boolean removeAll(Collection<?> c) {
- if (c.isEmpty()) {
- return false;
- }
- int oldSize = size(); // calls refreshIfEmpty
- boolean changed = delegate.removeAll(c);
- if (changed) {
- int newSize = delegate.size();
- totalSize += (newSize - oldSize);
- removeIfEmpty();
- }
- return changed;
- }
-
- @Override public boolean retainAll(Collection<?> c) {
- checkNotNull(c);
- int oldSize = size(); // calls refreshIfEmpty
- boolean changed = delegate.retainAll(c);
- if (changed) {
- int newSize = delegate.size();
- totalSize += (newSize - oldSize);
- removeIfEmpty();
- }
- return changed;
- }
- }
-
- private Iterator<V> iteratorOrListIterator(Collection<V> collection) {
- return (collection instanceof List)
- ? ((List<V>) collection).listIterator()
- : collection.iterator();
- }
-
- /** Set decorator that stays in sync with the multimap values for a key. */
- private class WrappedSet extends WrappedCollection implements Set<V> {
- WrappedSet(@Nullable K key, Set<V> delegate) {
- super(key, delegate, null);
- }
-
- @Override
- public boolean removeAll(Collection<?> c) {
- if (c.isEmpty()) {
- return false;
- }
- int oldSize = size(); // calls refreshIfEmpty
-
- // Guava issue 1013: AbstractSet and most JDK set implementations are
- // susceptible to quadratic removeAll performance on lists;
- // use a slightly smarter implementation here
- boolean changed = Sets.removeAllImpl((Set<V>) delegate, c);
- if (changed) {
- int newSize = delegate.size();
- totalSize += (newSize - oldSize);
- removeIfEmpty();
- }
- return changed;
- }
- }
-
- /**
- * SortedSet decorator that stays in sync with the multimap values for a key.
- */
- private class WrappedSortedSet extends WrappedCollection
- implements SortedSet<V> {
- WrappedSortedSet(@Nullable K key, SortedSet<V> delegate,
- @Nullable WrappedCollection ancestor) {
- super(key, delegate, ancestor);
- }
-
- SortedSet<V> getSortedSetDelegate() {
- return (SortedSet<V>) getDelegate();
- }
-
- @Override
- public Comparator<? super V> comparator() {
- return getSortedSetDelegate().comparator();
- }
-
- @Override
- public V first() {
- refreshIfEmpty();
- return getSortedSetDelegate().first();
- }
-
- @Override
- public V last() {
- refreshIfEmpty();
- return getSortedSetDelegate().last();
- }
-
- @Override
- public SortedSet<V> headSet(V toElement) {
- refreshIfEmpty();
- return new WrappedSortedSet(
- getKey(), getSortedSetDelegate().headSet(toElement),
- (getAncestor() == null) ? this : getAncestor());
- }
-
- @Override
- public SortedSet<V> subSet(V fromElement, V toElement) {
- refreshIfEmpty();
- return new WrappedSortedSet(
- getKey(), getSortedSetDelegate().subSet(fromElement, toElement),
- (getAncestor() == null) ? this : getAncestor());
- }
-
- @Override
- public SortedSet<V> tailSet(V fromElement) {
- refreshIfEmpty();
- return new WrappedSortedSet(
- getKey(), getSortedSetDelegate().tailSet(fromElement),
- (getAncestor() == null) ? this : getAncestor());
- }
- }
-
- /** List decorator that stays in sync with the multimap values for a key. */
- private class WrappedList extends WrappedCollection implements List<V> {
- WrappedList(@Nullable K key, List<V> delegate,
- @Nullable WrappedCollection ancestor) {
- super(key, delegate, ancestor);
- }
-
- List<V> getListDelegate() {
- return (List<V>) getDelegate();
- }
-
- @Override
- public boolean addAll(int index, Collection<? extends V> c) {
- if (c.isEmpty()) {
- return false;
- }
- int oldSize = size(); // calls refreshIfEmpty
- boolean changed = getListDelegate().addAll(index, c);
- if (changed) {
- int newSize = getDelegate().size();
- totalSize += (newSize - oldSize);
- if (oldSize == 0) {
- addToMap();
- }
- }
- return changed;
- }
-
- @Override
- public V get(int index) {
- refreshIfEmpty();
- return getListDelegate().get(index);
- }
-
- @Override
- public V set(int index, V element) {
- refreshIfEmpty();
- return getListDelegate().set(index, element);
- }
-
- @Override
- public void add(int index, V element) {
- refreshIfEmpty();
- boolean wasEmpty = getDelegate().isEmpty();
- getListDelegate().add(index, element);
- totalSize++;
- if (wasEmpty) {
- addToMap();
- }
- }
-
- @Override
- public V remove(int index) {
- refreshIfEmpty();
- V value = getListDelegate().remove(index);
- totalSize--;
- removeIfEmpty();
- return value;
- }
-
- @Override
- public int indexOf(Object o) {
- refreshIfEmpty();
- return getListDelegate().indexOf(o);
- }
-
- @Override
- public int lastIndexOf(Object o) {
- refreshIfEmpty();
- return getListDelegate().lastIndexOf(o);
- }
-
- @Override
- public ListIterator<V> listIterator() {
- refreshIfEmpty();
- return new WrappedListIterator();
- }
-
- @Override
- public ListIterator<V> listIterator(int index) {
- refreshIfEmpty();
- return new WrappedListIterator(index);
- }
-
- @Override
- public List<V> subList(int fromIndex, int toIndex) {
- refreshIfEmpty();
- return wrapList(getKey(),
- getListDelegate().subList(fromIndex, toIndex),
- (getAncestor() == null) ? this : getAncestor());
- }
-
- /** ListIterator decorator. */
- private class WrappedListIterator extends WrappedIterator
- implements ListIterator<V> {
- WrappedListIterator() {}
-
- public WrappedListIterator(int index) {
- super(getListDelegate().listIterator(index));
- }
-
- private ListIterator<V> getDelegateListIterator() {
- return (ListIterator<V>) getDelegateIterator();
- }
-
- @Override
- public boolean hasPrevious() {
- return getDelegateListIterator().hasPrevious();
- }
-
- @Override
- public V previous() {
- return getDelegateListIterator().previous();
- }
-
- @Override
- public int nextIndex() {
- return getDelegateListIterator().nextIndex();
- }
-
- @Override
- public int previousIndex() {
- return getDelegateListIterator().previousIndex();
- }
-
- @Override
- public void set(V value) {
- getDelegateListIterator().set(value);
- }
-
- @Override
- public void add(V value) {
- boolean wasEmpty = isEmpty();
- getDelegateListIterator().add(value);
- totalSize++;
- if (wasEmpty) {
- addToMap();
- }
- }
- }
- }
-
- /**
- * List decorator that stays in sync with the multimap values for a key and
- * supports rapid random access.
- */
- private class RandomAccessWrappedList extends WrappedList
- implements RandomAccess {
- RandomAccessWrappedList(@Nullable K key, List<V> delegate,
- @Nullable WrappedCollection ancestor) {
- super(key, delegate, ancestor);
- }
- }
-
- @Override
- Set<K> createKeySet() {
- // TreeMultimap uses NavigableKeySet explicitly, but we don't handle that here for GWT
- // compatibility reasons
- return (map instanceof SortedMap)
- ? new SortedKeySet((SortedMap<K, Collection<V>>) map) : new KeySet(map);
- }
-
- private class KeySet extends Maps.KeySet<K, Collection<V>> {
-
- /**
- * This is usually the same as map, except when someone requests a
- * subcollection of a {@link SortedKeySet}.
- */
- final Map<K, Collection<V>> subMap;
-
- KeySet(final Map<K, Collection<V>> subMap) {
- this.subMap = subMap;
- }
-
- @Override
- Map<K, Collection<V>> map() {
- return subMap;
- }
-
- @Override public Iterator<K> iterator() {
- final Iterator<Map.Entry<K, Collection<V>>> entryIterator
- = subMap.entrySet().iterator();
- return new Iterator<K>() {
- Map.Entry<K, Collection<V>> entry;
-
- @Override
- public boolean hasNext() {
- return entryIterator.hasNext();
- }
- @Override
- public K next() {
- entry = entryIterator.next();
- return entry.getKey();
- }
- @Override
- public void remove() {
- Iterators.checkRemove(entry != null);
- Collection<V> collection = entry.getValue();
- entryIterator.remove();
- totalSize -= collection.size();
- collection.clear();
- }
- };
- }
-
- // The following methods are included for better performance.
-
- @Override public boolean remove(Object key) {
- int count = 0;
- Collection<V> collection = subMap.remove(key);
- if (collection != null) {
- count = collection.size();
- collection.clear();
- totalSize -= count;
- }
- return count > 0;
- }
-
- @Override
- public void clear() {
- Iterators.clear(iterator());
- }
-
- @Override public boolean containsAll(Collection<?> c) {
- return subMap.keySet().containsAll(c);
- }
-
- @Override public boolean equals(@Nullable Object object) {
- return this == object || this.subMap.keySet().equals(object);
- }
-
- @Override public int hashCode() {
- return subMap.keySet().hashCode();
- }
- }
-
- private class SortedKeySet extends KeySet implements SortedSet<K> {
-
- SortedKeySet(SortedMap<K, Collection<V>> subMap) {
- super(subMap);
- }
-
- SortedMap<K, Collection<V>> sortedMap() {
- return (SortedMap<K, Collection<V>>) subMap;
- }
-
- @Override
- public Comparator<? super K> comparator() {
- return sortedMap().comparator();
- }
-
- @Override
- public K first() {
- return sortedMap().firstKey();
- }
-
- @Override
- public SortedSet<K> headSet(K toElement) {
- return new SortedKeySet(sortedMap().headMap(toElement));
- }
-
- @Override
- public K last() {
- return sortedMap().lastKey();
- }
-
- @Override
- public SortedSet<K> subSet(K fromElement, K toElement) {
- return new SortedKeySet(sortedMap().subMap(fromElement, toElement));
- }
-
- @Override
- public SortedSet<K> tailSet(K fromElement) {
- return new SortedKeySet(sortedMap().tailMap(fromElement));
- }
- }
-
- /**
- * Removes all values for the provided key. Unlike {@link #removeAll}, it
- * returns the number of removed mappings.
- */
- private int removeValuesForKey(Object key) {
- Collection<V> collection = Maps.safeRemove(map, key);
-
- int count = 0;
- if (collection != null) {
- count = collection.size();
- collection.clear();
- totalSize -= count;
- }
- return count;
- }
-
- /**
- * {@inheritDoc}
- *
- * <p>The iterator generated by the returned collection traverses the values
- * for one key, followed by the values of a second key, and so on.
- */
- @Override public Collection<V> values() {
- return super.values();
- }
-
- /*
- * TODO(kevinb): should we copy this javadoc to each concrete class, so that
- * classes like LinkedHashMultimap that need to say something different are
- * still able to {@inheritDoc} all the way from Multimap?
- */
-
- /**
- * {@inheritDoc}
- *
- * <p>The iterator generated by the returned collection traverses the values
- * for one key, followed by the values of a second key, and so on.
- *
- * <p>Each entry is an immutable snapshot of a key-value mapping in the
- * multimap, taken at the time the entry is returned by a method call to the
- * collection or its iterator.
- */
- @Override
- public Collection<Map.Entry<K, V>> entries() {
- return super.entries();
- }
-
- /**
- * Returns an iterator across all key-value map entries, used by {@code
- * entries().iterator()} and {@code values().iterator()}. The default
- * behavior, which traverses the values for one key, the values for a second
- * key, and so on, suffices for most {@code AbstractMapBasedMultimap} implementations.
- *
- * @return an iterator across map entries
- */
- @Override
- Iterator<Map.Entry<K, V>> entryIterator() {
- return new EntryIterator();
- }
-
- /** Iterator across all key-value pairs. */
- private class EntryIterator implements Iterator<Map.Entry<K, V>> {
- final Iterator<Map.Entry<K, Collection<V>>> keyIterator;
- K key;
- Collection<V> collection;
- Iterator<V> valueIterator;
-
- EntryIterator() {
- keyIterator = map.entrySet().iterator();
- if (keyIterator.hasNext()) {
- findValueIteratorAndKey();
- } else {
- valueIterator = Iterators.emptyModifiableIterator();
- }
- }
-
- void findValueIteratorAndKey() {
- Map.Entry<K, Collection<V>> entry = keyIterator.next();
- key = entry.getKey();
- collection = entry.getValue();
- valueIterator = collection.iterator();
- }
-
- @Override
- public boolean hasNext() {
- return keyIterator.hasNext() || valueIterator.hasNext();
- }
-
- @Override
- public Map.Entry<K, V> next() {
- if (!valueIterator.hasNext()) {
- findValueIteratorAndKey();
- }
- return Maps.immutableEntry(key, valueIterator.next());
- }
-
- @Override
- public void remove() {
- valueIterator.remove();
- if (collection.isEmpty()) {
- keyIterator.remove();
- }
- totalSize--;
- }
- }
-
- @Override
- Map<K, Collection<V>> createAsMap() {
- // TreeMultimap uses NavigableAsMap explicitly, but we don't handle that here for GWT
- // compatibility reasons
- return (map instanceof SortedMap)
- ? new SortedAsMap((SortedMap<K, Collection<V>>) map) : new AsMap(map);
- }
-
- private class AsMap extends AbstractMap<K, Collection<V>> {
- /**
- * Usually the same as map, but smaller for the headMap(), tailMap(), or
- * subMap() of a SortedAsMap.
- */
- final transient Map<K, Collection<V>> submap;
-
- AsMap(Map<K, Collection<V>> submap) {
- this.submap = submap;
- }
-
- transient Set<Map.Entry<K, Collection<V>>> entrySet;
-
- @Override public Set<Map.Entry<K, Collection<V>>> entrySet() {
- Set<Map.Entry<K, Collection<V>>> result = entrySet;
- return (result == null) ? entrySet = new AsMapEntries() : result;
- }
-
- // The following methods are included for performance.
-
- @Override public boolean containsKey(Object key) {
- return Maps.safeContainsKey(submap, key);
- }
-
- @Override public Collection<V> get(Object key) {
- Collection<V> collection = Maps.safeGet(submap, key);
- if (collection == null) {
- return null;
- }
- @SuppressWarnings("unchecked")
- K k = (K) key;
- return wrapCollection(k, collection);
- }
-
- @Override public Set<K> keySet() {
- return AbstractMapBasedMultimap.this.keySet();
- }
-
- @Override
- public int size() {
- return submap.size();
- }
-
- @Override public Collection<V> remove(Object key) {
- Collection<V> collection = submap.remove(key);
- if (collection == null) {
- return null;
- }
-
- Collection<V> output = createCollection();
- output.addAll(collection);
- totalSize -= collection.size();
- collection.clear();
- return output;
- }
-
- @Override public boolean equals(@Nullable Object object) {
- return this == object || submap.equals(object);
- }
-
- @Override public int hashCode() {
- return submap.hashCode();
- }
-
- @Override public String toString() {
- return submap.toString();
- }
-
- @Override
- public void clear() {
- if (submap == map) {
- AbstractMapBasedMultimap.this.clear();
- } else {
-
- Iterators.clear(new AsMapIterator());
- }
- }
-
- Entry<K, Collection<V>> wrapEntry(Entry<K, Collection<V>> entry) {
- K key = entry.getKey();
- return Maps.immutableEntry(key, wrapCollection(key, entry.getValue()));
- }
-
- class AsMapEntries extends Maps.EntrySet<K, Collection<V>> {
- @Override
- Map<K, Collection<V>> map() {
- return AsMap.this;
- }
-
- @Override public Iterator<Map.Entry<K, Collection<V>>> iterator() {
- return new AsMapIterator();
- }
-
- // The following methods are included for performance.
-
- @Override public boolean contains(Object o) {
- return Collections2.safeContains(submap.entrySet(), o);
- }
-
- @Override public boolean remove(Object o) {
- if (!contains(o)) {
- return false;
- }
- Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
- removeValuesForKey(entry.getKey());
- return true;
- }
- }
-
- /** Iterator across all keys and value collections. */
- class AsMapIterator implements Iterator<Map.Entry<K, Collection<V>>> {
- final Iterator<Map.Entry<K, Collection<V>>> delegateIterator
- = submap.entrySet().iterator();
- Collection<V> collection;
-
- @Override
- public boolean hasNext() {
- return delegateIterator.hasNext();
- }
-
- @Override
- public Map.Entry<K, Collection<V>> next() {
- Map.Entry<K, Collection<V>> entry = delegateIterator.next();
- collection = entry.getValue();
- return wrapEntry(entry);
- }
-
- @Override
- public void remove() {
- delegateIterator.remove();
- totalSize -= collection.size();
- collection.clear();
- }
- }
- }
-
- private class SortedAsMap extends AsMap
- implements SortedMap<K, Collection<V>> {
- SortedAsMap(SortedMap<K, Collection<V>> submap) {
- super(submap);
- }
-
- SortedMap<K, Collection<V>> sortedMap() {
- return (SortedMap<K, Collection<V>>) submap;
- }
-
- @Override
- public Comparator<? super K> comparator() {
- return sortedMap().comparator();
- }
-
- @Override
- public K firstKey() {
- return sortedMap().firstKey();
- }
-
- @Override
- public K lastKey() {
- return sortedMap().lastKey();
- }
-
- @Override
- public SortedMap<K, Collection<V>> headMap(K toKey) {
- return new SortedAsMap(sortedMap().headMap(toKey));
- }
-
- @Override
- public SortedMap<K, Collection<V>> subMap(K fromKey, K toKey) {
- return new SortedAsMap(sortedMap().subMap(fromKey, toKey));
- }
-
- @Override
- public SortedMap<K, Collection<V>> tailMap(K fromKey) {
- return new SortedAsMap(sortedMap().tailMap(fromKey));
- }
-
- SortedSet<K> sortedKeySet;
-
- // returns a SortedSet, even though returning a Set would be sufficient to
- // satisfy the SortedMap.keySet() interface
- @Override public SortedSet<K> keySet() {
- SortedSet<K> result = sortedKeySet;
- return (result == null) ? sortedKeySet = createKeySet() : result;
- }
-
- SortedSet<K> createKeySet() {
- return new SortedKeySet(sortedMap());
- }
- }
-
- private static final long serialVersionUID = 2447537837011683357L;
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractMapBasedMultiset.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractMapBasedMultiset.java
index 3c0f05d..6bccc6d 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractMapBasedMultiset.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractMapBasedMultiset.java
@@ -25,6 +25,7 @@ import com.google.common.annotations.GwtCompatible;
import com.google.common.primitives.Ints;
import java.io.Serializable;
+import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
@@ -34,7 +35,7 @@ import javax.annotation.Nullable;
/**
* Basic implementation of {@code Multiset<E>} backed by an instance of {@code
- * Map<E, Count>}.
+ * Map<E, AtomicInteger>}.
*
* <p>For serialization to work, the subclass must specify explicit {@code
* readObject} and {@code writeObject} methods.
@@ -60,6 +61,10 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
this.size = super.size();
}
+ Map<E, Count> backingMap() {
+ return backingMap;
+ }
+
/** Used during deserialization only. The backing map must be empty. */
void setBackingMap(Map<E, Count> backingMap) {
this.backingMap = backingMap;
@@ -116,7 +121,8 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
@Override
public void remove() {
- Iterators.checkRemove(toRemove != null);
+ checkState(toRemove != null,
+ "no calls to next() since the last call to remove()");
size -= toRemove.getValue().getAndSet(0);
backingEntries.remove();
toRemove = null;
@@ -150,7 +156,7 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
/*
* Not subclassing AbstractMultiset$MultisetIterator because next() needs to
- * retrieve the Map.Entry<E, Count> entry, which can then be used for
+ * retrieve the Map.Entry<E, AtomicInteger> entry, which can then be used for
* a more efficient remove() call.
*/
private class MapBasedMultisetIterator implements Iterator<E> {
@@ -196,8 +202,14 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
}
@Override public int count(@Nullable Object element) {
- Count frequency = Maps.safeGet(backingMap, element);
- return (frequency == null) ? 0 : frequency.get();
+ try {
+ Count frequency = backingMap.get(element);
+ return (frequency == null) ? 0 : frequency.get();
+ } catch (NullPointerException e) {
+ return 0;
+ } catch (ClassCastException e) {
+ return 0;
+ }
}
// Optional Operations - Modification Operations
@@ -258,7 +270,7 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
}
// Roughly a 33% performance improvement over AbstractMultiset.setCount().
- @Override public int setCount(@Nullable E element, int count) {
+ @Override public int setCount(E element, int count) {
checkNonnegative(count, "count");
Count existingCounter;
@@ -287,6 +299,97 @@ abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E>
return i.getAndSet(count);
}
+ private int removeAllOccurrences(@Nullable Object element,
+ Map<E, Count> map) {
+ Count frequency = map.remove(element);
+ if (frequency == null) {
+ return 0;
+ }
+ int numberRemoved = frequency.getAndSet(0);
+ size -= numberRemoved;
+ return numberRemoved;
+ }
+
+ // Views
+
+ @Override Set<E> createElementSet() {
+ return new MapBasedElementSet(backingMap);
+ }
+
+ // TODO(user): once TreeMultiset is replaced with a SortedMultiset
+ // implementation, replace this with a subclass of Multisets.ElementSet.
+ class MapBasedElementSet extends ForwardingSet<E> {
+
+ // This mapping is the usually the same as 'backingMap', but can be a
+ // submap in some implementations.
+ private final Map<E, Count> map;
+ private final Set<E> delegate;
+
+ MapBasedElementSet(Map<E, Count> map) {
+ this.map = map;
+ delegate = map.keySet();
+ }
+
+ @Override protected Set<E> delegate() {
+ return delegate;
+ }
+
+ @Override public Iterator<E> iterator() {
+ final Iterator<Map.Entry<E, Count>> entries
+ = map.entrySet().iterator();
+ return new Iterator<E>() {
+ Map.Entry<E, Count> toRemove;
+
+ @Override
+ public boolean hasNext() {
+ return entries.hasNext();
+ }
+
+ @Override
+ public E next() {
+ toRemove = entries.next();
+ return toRemove.getKey();
+ }
+
+ @Override
+ public void remove() {
+ checkState(toRemove != null,
+ "no calls to next() since the last call to remove()");
+ size -= toRemove.getValue().getAndSet(0);
+ entries.remove();
+ toRemove = null;
+ }
+ };
+ }
+
+ @Override public boolean remove(Object element) {
+ return removeAllOccurrences(element, map) != 0;
+ }
+
+ @Override public boolean removeAll(Collection<?> elementsToRemove) {
+ return Iterators.removeAll(iterator(), elementsToRemove);
+ }
+
+ @Override public boolean retainAll(Collection<?> elementsToRetain) {
+ return Iterators.retainAll(iterator(), elementsToRetain);
+ }
+
+ @Override public void clear() {
+ if (map == backingMap) {
+ AbstractMapBasedMultiset.this.clear();
+ } else {
+ Iterator<E> i = iterator();
+ while (i.hasNext()) {
+ i.next();
+ i.remove();
+ }
+ }
+ }
+
+ public Map<E, Count> getMap() {
+ return map;
+ }
+ }
+
// Don't allow default serialization.
}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractSortedMultiset.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractSortedMultiset.java
deleted file mode 100644
index 3eea734..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/AbstractSortedMultiset.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.SortedSet;
-
-import javax.annotation.Nullable;
-
-/**
- * This class provides a skeletal implementation of the {@link SortedMultiset} interface.
- *
- * <p>The {@link #count} and {@link #size} implementations all iterate across the set returned by
- * {@link Multiset#entrySet()}, as do many methods acting on the set returned by
- * {@link #elementSet()}. Override those methods for better performance.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-abstract class AbstractSortedMultiset<E> extends AbstractMultiset<E> implements SortedMultiset<E> {
- @GwtTransient final Comparator<? super E> comparator;
-
- // needed for serialization
- @SuppressWarnings("unchecked")
- AbstractSortedMultiset() {
- this((Comparator) Ordering.natural());
- }
-
- AbstractSortedMultiset(Comparator<? super E> comparator) {
- this.comparator = checkNotNull(comparator);
- }
-
- @Override
- public SortedSet<E> elementSet() {
- return (SortedSet<E>) super.elementSet();
- }
-
- @Override
- SortedSet<E> createElementSet() {
- return new SortedMultisets.ElementSet<E>(this);
- }
-
- @Override
- public Comparator<? super E> comparator() {
- return comparator;
- }
-
- @Override
- public Entry<E> firstEntry() {
- Iterator<Entry<E>> entryIterator = entryIterator();
- return entryIterator.hasNext() ? entryIterator.next() : null;
- }
-
- @Override
- public Entry<E> lastEntry() {
- Iterator<Entry<E>> entryIterator = descendingEntryIterator();
- return entryIterator.hasNext() ? entryIterator.next() : null;
- }
-
- @Override
- public Entry<E> pollFirstEntry() {
- Iterator<Entry<E>> entryIterator = entryIterator();
- if (entryIterator.hasNext()) {
- Entry<E> result = entryIterator.next();
- result = Multisets.immutableEntry(result.getElement(), result.getCount());
- entryIterator.remove();
- return result;
- }
- return null;
- }
-
- @Override
- public Entry<E> pollLastEntry() {
- Iterator<Entry<E>> entryIterator = descendingEntryIterator();
- if (entryIterator.hasNext()) {
- Entry<E> result = entryIterator.next();
- result = Multisets.immutableEntry(result.getElement(), result.getCount());
- entryIterator.remove();
- return result;
- }
- return null;
- }
-
- @Override
- public SortedMultiset<E> subMultiset(@Nullable E fromElement, BoundType fromBoundType,
- @Nullable E toElement, BoundType toBoundType) {
- // These are checked elsewhere, but NullPointerTester wants them checked eagerly.
- checkNotNull(fromBoundType);
- checkNotNull(toBoundType);
- return tailMultiset(fromElement, fromBoundType).headMultiset(toElement, toBoundType);
- }
-
- abstract Iterator<Entry<E>> descendingEntryIterator();
-
- Iterator<E> descendingIterator() {
- return Multisets.iteratorImpl(descendingMultiset());
- }
-
- private transient SortedMultiset<E> descendingMultiset;
-
- @Override
- public SortedMultiset<E> descendingMultiset() {
- SortedMultiset<E> result = descendingMultiset;
- return (result == null) ? descendingMultiset = createDescendingMultiset() : result;
- }
-
- SortedMultiset<E> createDescendingMultiset() {
- return new DescendingMultiset<E>() {
- @Override
- SortedMultiset<E> forwardMultiset() {
- return AbstractSortedMultiset.this;
- }
-
- @Override
- Iterator<Entry<E>> entryIterator() {
- return descendingEntryIterator();
- }
-
- @Override
- public Iterator<E> iterator() {
- return descendingIterator();
- }
- };
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ArrayListMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ArrayListMultimap.java
index 59d4e77..da5478c 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ArrayListMultimap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ArrayListMultimap.java
@@ -50,10 +50,6 @@ import java.util.List;
* multimap. Concurrent read operations will work correctly. To allow concurrent
* update operations, wrap your multimap with a call to {@link
* Multimaps#synchronizedListMultimap}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
*
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
@@ -61,7 +57,7 @@ import java.util.List;
@GwtCompatible(serializable = true, emulated = true)
public final class ArrayListMultimap<K, V> extends AbstractListMultimap<K, V> {
// Default from ArrayList
- private static final int DEFAULT_VALUES_PER_KEY = 3;
+ private static final int DEFAULT_VALUES_PER_KEY = 10;
@VisibleForTesting transient int expectedValuesPerKey;
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ArrayTable.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ArrayTable.java
deleted file mode 100644
index bde92c5..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ArrayTable.java
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * Copyright (C) 2009 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkElementIndex;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Objects;
-
-import java.io.Serializable;
-import java.util.AbstractCollection;
-import java.util.AbstractSet;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * Fixed-size {@link Table} implementation backed by a two-dimensional array.
- *
- * <p>The allowed row and column keys must be supplied when the table is
- * created. The table always contains a mapping for every row key / column pair.
- * The value corresponding to a given row and column is null unless another
- * value is provided.
- *
- * <p>The table's size is constant: the product of the number of supplied row
- * keys and the number of supplied column keys. The {@code remove} and {@code
- * clear} methods are not supported by the table or its views. The {@link
- * #erase} and {@link #eraseAll} methods may be used instead.
- *
- * <p>The ordering of the row and column keys provided when the table is
- * constructed determines the iteration ordering across rows and columns in the
- * table's views. None of the view iterators support {@link Iterator#remove}.
- * If the table is modified after an iterator is created, the iterator remains
- * valid.
- *
- * <p>This class requires less memory than the {@link HashBasedTable} and {@link
- * TreeBasedTable} implementations, except when the table is sparse.
- *
- * <p>Null row keys or column keys are not permitted.
- *
- * <p>This class provides methods involving the underlying array structure,
- * where the array indices correspond to the position of a row or column in the
- * lists of allowed keys and values. See the {@link #at}, {@link #set}, {@link
- * #toArray}, {@link #rowKeyList}, and {@link #columnKeyList} methods for more
- * details.
- *
- * <p>Note that this implementation is not synchronized. If multiple threads
- * access the same cell of an {@code ArrayTable} concurrently and one of the
- * threads modifies its value, there is no guarantee that the new value will be
- * fully visible to the other threads. To guarantee that modifications are
- * visible, synchronize access to the table. Unlike other {@code Table}
- * implementations, synchronization is unnecessary between a thread that writes
- * to one cell and a thread that reads from another.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table">
- * {@code Table}</a>.
- *
- * @author Jared Levy
- * @since 10.0
- */
-@Beta
-@GwtCompatible(emulated = true)
-public final class ArrayTable<R, C, V> implements Table<R, C, V>, Serializable {
-
- /**
- * Creates an empty {@code ArrayTable}.
- *
- * @param rowKeys row keys that may be stored in the generated table
- * @param columnKeys column keys that may be stored in the generated table
- * @throws NullPointerException if any of the provided keys is null
- * @throws IllegalArgumentException if {@code rowKeys} or {@code columnKeys}
- * contains duplicates or is empty
- */
- public static <R, C, V> ArrayTable<R, C, V> create(
- Iterable<? extends R> rowKeys, Iterable<? extends C> columnKeys) {
- return new ArrayTable<R, C, V>(rowKeys, columnKeys);
- }
-
- /*
- * TODO(jlevy): Add factory methods taking an Enum class, instead of an
- * iterable, to specify the allowed row keys and/or column keys. Note that
- * custom serialization logic is needed to support different enum sizes during
- * serialization and deserialization.
- */
-
- /**
- * Creates an {@code ArrayTable} with the mappings in the provided table.
- *
- * <p>If {@code table} includes a mapping with row key {@code r} and a
- * separate mapping with column key {@code c}, the returned table contains a
- * mapping with row key {@code r} and column key {@code c}. If that row key /
- * column key pair in not in {@code table}, the pair maps to {@code null} in
- * the generated table.
- *
- * <p>The returned table allows subsequent {@code put} calls with the row keys
- * in {@code table.rowKeySet()} and the column keys in {@code
- * table.columnKeySet()}. Calling {@link #put} with other keys leads to an
- * {@code IllegalArgumentException}.
- *
- * <p>The ordering of {@code table.rowKeySet()} and {@code
- * table.columnKeySet()} determines the row and column iteration ordering of
- * the returned table.
- *
- * @throws NullPointerException if {@code table} has a null key
- * @throws IllegalArgumentException if the provided table is empty
- */
- public static <R, C, V> ArrayTable<R, C, V> create(Table<R, C, V> table) {
- return new ArrayTable<R, C, V>(table);
- }
-
- /**
- * Creates an {@code ArrayTable} with the same mappings, allowed keys, and
- * iteration ordering as the provided {@code ArrayTable}.
- */
- public static <R, C, V> ArrayTable<R, C, V> create(
- ArrayTable<R, C, V> table) {
- return new ArrayTable<R, C, V>(table);
- }
-
- private final ImmutableList<R> rowList;
- private final ImmutableList<C> columnList;
-
- // TODO(jlevy): Add getters returning rowKeyToIndex and columnKeyToIndex?
- private final ImmutableMap<R, Integer> rowKeyToIndex;
- private final ImmutableMap<C, Integer> columnKeyToIndex;
- private final V[][] array;
-
- private ArrayTable(Iterable<? extends R> rowKeys,
- Iterable<? extends C> columnKeys) {
- this.rowList = ImmutableList.copyOf(rowKeys);
- this.columnList = ImmutableList.copyOf(columnKeys);
- checkArgument(!rowList.isEmpty());
- checkArgument(!columnList.isEmpty());
-
- /*
- * TODO(jlevy): Support empty rowKeys or columnKeys? If we do, when
- * columnKeys is empty but rowKeys isn't, the table is empty but
- * containsRow() can return true and rowKeySet() isn't empty.
- */
- rowKeyToIndex = index(rowList);
- columnKeyToIndex = index(columnList);
-
- @SuppressWarnings("unchecked")
- V[][] tmpArray
- = (V[][]) new Object[rowList.size()][columnList.size()];
- array = tmpArray;
- // Necessary because in GWT the arrays are initialized with "undefined" instead of null.
- eraseAll();
- }
-
- private static <E> ImmutableMap<E, Integer> index(List<E> list) {
- ImmutableMap.Builder<E, Integer> columnBuilder = ImmutableMap.builder();
- for (int i = 0; i < list.size(); i++) {
- columnBuilder.put(list.get(i), i);
- }
- return columnBuilder.build();
- }
-
- private ArrayTable(Table<R, C, V> table) {
- this(table.rowKeySet(), table.columnKeySet());
- putAll(table);
- }
-
- private ArrayTable(ArrayTable<R, C, V> table) {
- rowList = table.rowList;
- columnList = table.columnList;
- rowKeyToIndex = table.rowKeyToIndex;
- columnKeyToIndex = table.columnKeyToIndex;
- @SuppressWarnings("unchecked")
- V[][] copy = (V[][]) new Object[rowList.size()][columnList.size()];
- array = copy;
- // Necessary because in GWT the arrays are initialized with "undefined" instead of null.
- eraseAll();
- for (int i = 0; i < rowList.size(); i++) {
- System.arraycopy(table.array[i], 0, copy[i], 0, table.array[i].length);
- }
- }
-
- private abstract static class ArrayMap<K, V> extends Maps.ImprovedAbstractMap<K, V> {
- private final ImmutableMap<K, Integer> keyIndex;
-
- private ArrayMap(ImmutableMap<K, Integer> keyIndex) {
- this.keyIndex = keyIndex;
- }
-
- @Override
- public Set<K> keySet() {
- return keyIndex.keySet();
- }
-
- K getKey(int index) {
- return keyIndex.keySet().asList().get(index);
- }
-
- abstract String getKeyRole();
-
- @Nullable abstract V getValue(int index);
-
- @Nullable abstract V setValue(int index, V newValue);
-
- @Override
- public int size() {
- return keyIndex.size();
- }
-
- @Override
- public boolean isEmpty() {
- return keyIndex.isEmpty();
- }
-
- @Override
- protected Set<Entry<K, V>> createEntrySet() {
- return new Maps.EntrySet<K, V>() {
- @Override
- Map<K, V> map() {
- return ArrayMap.this;
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return new AbstractIndexedListIterator<Entry<K, V>>(size()) {
- @Override
- protected Entry<K, V> get(final int index) {
- return new AbstractMapEntry<K, V>() {
- @Override
- public K getKey() {
- return ArrayMap.this.getKey(index);
- }
-
- @Override
- public V getValue() {
- return ArrayMap.this.getValue(index);
- }
-
- @Override
- public V setValue(V value) {
- return ArrayMap.this.setValue(index, value);
- }
- };
- }
- };
- }
- };
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return keyIndex.containsKey(key);
- }
-
- @Override
- public V get(@Nullable Object key) {
- Integer index = keyIndex.get(key);
- if (index == null) {
- return null;
- } else {
- return getValue(index);
- }
- }
-
- @Override
- public V put(K key, V value) {
- Integer index = keyIndex.get(key);
- if (index == null) {
- throw new IllegalArgumentException(
- getKeyRole() + " " + key + " not in " + keyIndex.keySet());
- }
- return setValue(index, value);
- }
-
- @Override
- public V remove(Object key) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clear() {
- throw new UnsupportedOperationException();
- }
- }
-
- /**
- * Returns, as an immutable list, the row keys provided when the table was
- * constructed, including those that are mapped to null values only.
- */
- public ImmutableList<R> rowKeyList() {
- return rowList;
- }
-
- /**
- * Returns, as an immutable list, the column keys provided when the table was
- * constructed, including those that are mapped to null values only.
- */
- public ImmutableList<C> columnKeyList() {
- return columnList;
- }
-
- /**
- * Returns the value corresponding to the specified row and column indices.
- * The same value is returned by {@code
- * get(rowKeyList().get(rowIndex), columnKeyList().get(columnIndex))}, but
- * this method runs more quickly.
- *
- * @param rowIndex position of the row key in {@link #rowKeyList()}
- * @param columnIndex position of the row key in {@link #columnKeyList()}
- * @return the value with the specified row and column
- * @throws IndexOutOfBoundsException if either index is negative, {@code
- * rowIndex} is greater then or equal to the number of allowed row keys,
- * or {@code columnIndex} is greater then or equal to the number of
- * allowed column keys
- */
- public V at(int rowIndex, int columnIndex) {
- // In GWT array access never throws IndexOutOfBoundsException.
- checkElementIndex(rowIndex, rowList.size());
- checkElementIndex(columnIndex, columnList.size());
- return array[rowIndex][columnIndex];
- }
-
- /**
- * Associates {@code value} with the specified row and column indices. The
- * logic {@code
- * put(rowKeyList().get(rowIndex), columnKeyList().get(columnIndex), value)}
- * has the same behavior, but this method runs more quickly.
- *
- * @param rowIndex position of the row key in {@link #rowKeyList()}
- * @param columnIndex position of the row key in {@link #columnKeyList()}
- * @param value value to store in the table
- * @return the previous value with the specified row and column
- * @throws IndexOutOfBoundsException if either index is negative, {@code
- * rowIndex} is greater then or equal to the number of allowed row keys,
- * or {@code columnIndex} is greater then or equal to the number of
- * allowed column keys
- */
- public V set(int rowIndex, int columnIndex, @Nullable V value) {
- // In GWT array access never throws IndexOutOfBoundsException.
- checkElementIndex(rowIndex, rowList.size());
- checkElementIndex(columnIndex, columnList.size());
- V oldValue = array[rowIndex][columnIndex];
- array[rowIndex][columnIndex] = value;
- return oldValue;
- }
-
- /**
- * Not supported. Use {@link #eraseAll} instead.
- *
- * @throws UnsupportedOperationException always
- * @deprecated Use {@link #eraseAll}
- */
- @Override
- @Deprecated public void clear() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Associates the value {@code null} with every pair of allowed row and column
- * keys.
- */
- public void eraseAll() {
- for (V[] row : array) {
- Arrays.fill(row, null);
- }
- }
-
- /**
- * Returns {@code true} if the provided keys are among the keys provided when
- * the table was constructed.
- */
- @Override
- public boolean contains(@Nullable Object rowKey, @Nullable Object columnKey) {
- return containsRow(rowKey) && containsColumn(columnKey);
- }
-
- /**
- * Returns {@code true} if the provided column key is among the column keys
- * provided when the table was constructed.
- */
- @Override
- public boolean containsColumn(@Nullable Object columnKey) {
- return columnKeyToIndex.containsKey(columnKey);
- }
-
- /**
- * Returns {@code true} if the provided row key is among the row keys
- * provided when the table was constructed.
- */
- @Override
- public boolean containsRow(@Nullable Object rowKey) {
- return rowKeyToIndex.containsKey(rowKey);
- }
-
- @Override
- public boolean containsValue(@Nullable Object value) {
- for (V[] row : array) {
- for (V element : row) {
- if (Objects.equal(value, element)) {
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public V get(@Nullable Object rowKey, @Nullable Object columnKey) {
- Integer rowIndex = rowKeyToIndex.get(rowKey);
- Integer columnIndex = columnKeyToIndex.get(columnKey);
- return (rowIndex == null || columnIndex == null)
- ? null : at(rowIndex, columnIndex);
- }
-
- /**
- * Always returns {@code false}.
- */
- @Override
- public boolean isEmpty() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- *
- * @throws IllegalArgumentException if {@code rowKey} is not in {@link
- * #rowKeySet()} or {@code columnKey} is not in {@link #columnKeySet()}.
- */
- @Override
- public V put(R rowKey, C columnKey, @Nullable V value) {
- checkNotNull(rowKey);
- checkNotNull(columnKey);
- Integer rowIndex = rowKeyToIndex.get(rowKey);
- checkArgument(rowIndex != null, "Row %s not in %s", rowKey, rowList);
- Integer columnIndex = columnKeyToIndex.get(columnKey);
- checkArgument(columnIndex != null,
- "Column %s not in %s", columnKey, columnList);
- return set(rowIndex, columnIndex, value);
- }
-
- /*
- * TODO(jlevy): Consider creating a merge() method, similar to putAll() but
- * copying non-null values only.
- */
-
- /**
- * {@inheritDoc}
- *
- * <p>If {@code table} is an {@code ArrayTable}, its null values will be
- * stored in this table, possibly replacing values that were previously
- * non-null.
- *
- * @throws NullPointerException if {@code table} has a null key
- * @throws IllegalArgumentException if any of the provided table's row keys or
- * column keys is not in {@link #rowKeySet()} or {@link #columnKeySet()}
- */
- @Override
- public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
- for (Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) {
- put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
- }
- }
-
- /**
- * Not supported. Use {@link #erase} instead.
- *
- * @throws UnsupportedOperationException always
- * @deprecated Use {@link #erase}
- */
- @Override
- @Deprecated public V remove(Object rowKey, Object columnKey) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Associates the value {@code null} with the specified keys, assuming both
- * keys are valid. If either key is null or isn't among the keys provided
- * during construction, this method has no effect.
- *
- * <p>This method is equivalent to {@code put(rowKey, columnKey, null)} when
- * both provided keys are valid.
- *
- * @param rowKey row key of mapping to be erased
- * @param columnKey column key of mapping to be erased
- * @return the value previously associated with the keys, or {@code null} if
- * no mapping existed for the keys
- */
- public V erase(@Nullable Object rowKey, @Nullable Object columnKey) {
- Integer rowIndex = rowKeyToIndex.get(rowKey);
- Integer columnIndex = columnKeyToIndex.get(columnKey);
- if (rowIndex == null || columnIndex == null) {
- return null;
- }
- return set(rowIndex, columnIndex, null);
- }
-
- // TODO(jlevy): Add eraseRow and eraseColumn methods?
-
- @Override
- public int size() {
- return rowList.size() * columnList.size();
- }
-
- @Override public boolean equals(@Nullable Object obj) {
- if (obj instanceof Table) {
- Table<?, ?, ?> other = (Table<?, ?, ?>) obj;
- return cellSet().equals(other.cellSet());
- }
- return false;
- }
-
- @Override public int hashCode() {
- return cellSet().hashCode();
- }
-
- /**
- * Returns the string representation {@code rowMap().toString()}.
- */
- @Override public String toString() {
- return rowMap().toString();
- }
-
- private transient CellSet cellSet;
-
- /**
- * Returns an unmodifiable set of all row key / column key / value
- * triplets. Changes to the table will update the returned set.
- *
- * <p>The returned set's iterator traverses the mappings with the first row
- * key, the mappings with the second row key, and so on.
- *
- * <p>The value in the returned cells may change if the table subsequently
- * changes.
- *
- * @return set of table cells consisting of row key / column key / value
- * triplets
- */
- @Override
- public Set<Cell<R, C, V>> cellSet() {
- CellSet set = cellSet;
- return (set == null) ? cellSet = new CellSet() : set;
- }
-
- private class CellSet extends AbstractSet<Cell<R, C, V>> {
-
- @Override public Iterator<Cell<R, C, V>> iterator() {
- return new AbstractIndexedListIterator<Cell<R, C, V>>(size()) {
- @Override protected Cell<R, C, V> get(final int index) {
- return new Tables.AbstractCell<R, C, V>() {
- final int rowIndex = index / columnList.size();
- final int columnIndex = index % columnList.size();
- @Override
- public R getRowKey() {
- return rowList.get(rowIndex);
- }
- @Override
- public C getColumnKey() {
- return columnList.get(columnIndex);
- }
- @Override
- public V getValue() {
- return at(rowIndex, columnIndex);
- }
- };
- }
- };
- }
-
- @Override public int size() {
- return ArrayTable.this.size();
- }
-
- @Override public boolean contains(Object obj) {
- if (obj instanceof Cell) {
- Cell<?, ?, ?> cell = (Cell<?, ?, ?>) obj;
- Integer rowIndex = rowKeyToIndex.get(cell.getRowKey());
- Integer columnIndex = columnKeyToIndex.get(cell.getColumnKey());
- return rowIndex != null
- && columnIndex != null
- && Objects.equal(at(rowIndex, columnIndex), cell.getValue());
- }
- return false;
- }
- }
-
- /**
- * Returns a view of all mappings that have the given column key. If the
- * column key isn't in {@link #columnKeySet()}, an empty immutable map is
- * returned.
- *
- * <p>Otherwise, for each row key in {@link #rowKeySet()}, the returned map
- * associates the row key with the corresponding value in the table. Changes
- * to the returned map will update the underlying table, and vice versa.
- *
- * @param columnKey key of column to search for in the table
- * @return the corresponding map from row keys to values
- */
- @Override
- public Map<R, V> column(C columnKey) {
- checkNotNull(columnKey);
- Integer columnIndex = columnKeyToIndex.get(columnKey);
- return (columnIndex == null)
- ? ImmutableMap.<R, V>of() : new Column(columnIndex);
- }
-
- private class Column extends ArrayMap<R, V> {
- final int columnIndex;
-
- Column(int columnIndex) {
- super(rowKeyToIndex);
- this.columnIndex = columnIndex;
- }
-
- @Override
- String getKeyRole() {
- return "Row";
- }
-
- @Override
- V getValue(int index) {
- return at(index, columnIndex);
- }
-
- @Override
- V setValue(int index, V newValue) {
- return set(index, columnIndex, newValue);
- }
- }
-
- /**
- * Returns an immutable set of the valid column keys, including those that
- * are associated with null values only.
- *
- * @return immutable set of column keys
- */
- @Override
- public ImmutableSet<C> columnKeySet() {
- return columnKeyToIndex.keySet();
- }
-
- private transient ColumnMap columnMap;
-
- @Override
- public Map<C, Map<R, V>> columnMap() {
- ColumnMap map = columnMap;
- return (map == null) ? columnMap = new ColumnMap() : map;
- }
-
- private class ColumnMap extends ArrayMap<C, Map<R, V>> {
- private ColumnMap() {
- super(columnKeyToIndex);
- }
-
- @Override
- String getKeyRole() {
- return "Column";
- }
-
- @Override
- Map<R, V> getValue(int index) {
- return new Column(index);
- }
-
- @Override
- Map<R, V> setValue(int index, Map<R, V> newValue) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Map<R, V> put(C key, Map<R, V> value) {
- throw new UnsupportedOperationException();
- }
- }
-
- /**
- * Returns a view of all mappings that have the given row key. If the
- * row key isn't in {@link #rowKeySet()}, an empty immutable map is
- * returned.
- *
- * <p>Otherwise, for each column key in {@link #columnKeySet()}, the returned
- * map associates the column key with the corresponding value in the
- * table. Changes to the returned map will update the underlying table, and
- * vice versa.
- *
- * @param rowKey key of row to search for in the table
- * @return the corresponding map from column keys to values
- */
- @Override
- public Map<C, V> row(R rowKey) {
- checkNotNull(rowKey);
- Integer rowIndex = rowKeyToIndex.get(rowKey);
- return (rowIndex == null) ? ImmutableMap.<C, V>of() : new Row(rowIndex);
- }
-
- private class Row extends ArrayMap<C, V> {
- final int rowIndex;
-
- Row(int rowIndex) {
- super(columnKeyToIndex);
- this.rowIndex = rowIndex;
- }
-
- @Override
- String getKeyRole() {
- return "Column";
- }
-
- @Override
- V getValue(int index) {
- return at(rowIndex, index);
- }
-
- @Override
- V setValue(int index, V newValue) {
- return set(rowIndex, index, newValue);
- }
- }
-
- /**
- * Returns an immutable set of the valid row keys, including those that are
- * associated with null values only.
- *
- * @return immutable set of row keys
- */
- @Override
- public ImmutableSet<R> rowKeySet() {
- return rowKeyToIndex.keySet();
- }
-
- private transient RowMap rowMap;
-
- @Override
- public Map<R, Map<C, V>> rowMap() {
- RowMap map = rowMap;
- return (map == null) ? rowMap = new RowMap() : map;
- }
-
- private class RowMap extends ArrayMap<R, Map<C, V>> {
- private RowMap() {
- super(rowKeyToIndex);
- }
-
- @Override
- String getKeyRole() {
- return "Row";
- }
-
- @Override
- Map<C, V> getValue(int index) {
- return new Row(index);
- }
-
- @Override
- Map<C, V> setValue(int index, Map<C, V> newValue) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Map<C, V> put(R key, Map<C, V> value) {
- throw new UnsupportedOperationException();
- }
- }
-
- private transient Collection<V> values;
-
- /**
- * Returns an unmodifiable collection of all values, which may contain
- * duplicates. Changes to the table will update the returned collection.
- *
- * <p>The returned collection's iterator traverses the values of the first row
- * key, the values of the second row key, and so on.
- *
- * @return collection of values
- */
- @Override
- public Collection<V> values() {
- Collection<V> v = values;
- return (v == null) ? values = new Values() : v;
- }
-
- private class Values extends AbstractCollection<V> {
- @Override public Iterator<V> iterator() {
- return new TransformedIterator<Cell<R, C, V>, V>(cellSet().iterator()) {
- @Override
- V transform(Cell<R, C, V> cell) {
- return cell.getValue();
- }
- };
- }
-
- @Override public int size() {
- return ArrayTable.this.size();
- }
- }
-
- private static final long serialVersionUID = 0;
-}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ContiguousSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ContiguousSet.java
deleted file mode 100644
index 5cebc98..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ContiguousSet.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2010 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.NoSuchElementException;
-
-/**
- * A sorted set of contiguous values in a given {@link DiscreteDomain}.
- *
- * <p><b>Warning:</b> Be extremely careful what you do with conceptually large instances (such as
- * {@code ContiguousSet.create(Range.greaterThan(0), DiscreteDomains.integers()}). Certain
- * operations on such a set can be performed efficiently, but others (such as {@link Set#hashCode}
- * or {@link Collections#frequency}) can cause major performance problems.
- *
- * @author Gregory Kick
- * @since 10.0
- */
-@Beta
-@GwtCompatible(emulated = true)
-@SuppressWarnings("rawtypes") // allow ungenerified Comparable types
-public abstract class ContiguousSet<C extends Comparable> extends ImmutableSortedSet<C> {
- /**
- * Returns a {@code ContiguousSet} containing the same values in the given domain
- * {@linkplain Range#contains contained} by the range.
- *
- * @throws IllegalArgumentException if neither range nor the domain has a lower bound, or if
- * neither has an upper bound
- *
- * @since 13.0
- */
- public static <C extends Comparable> ContiguousSet<C> create(
- Range<C> range, DiscreteDomain<C> domain) {
- checkNotNull(range);
- checkNotNull(domain);
- Range<C> effectiveRange = range;
- try {
- if (!range.hasLowerBound()) {
- effectiveRange = effectiveRange.intersection(Range.atLeast(domain.minValue()));
- }
- if (!range.hasUpperBound()) {
- effectiveRange = effectiveRange.intersection(Range.atMost(domain.maxValue()));
- }
- } catch (NoSuchElementException e) {
- throw new IllegalArgumentException(e);
- }
-
- // Per class spec, we are allowed to throw CCE if necessary
- boolean empty = effectiveRange.isEmpty()
- || Range.compareOrThrow(
- range.lowerBound.leastValueAbove(domain),
- range.upperBound.greatestValueBelow(domain)) > 0;
-
- return empty
- ? new EmptyContiguousSet<C>(domain)
- : new RegularContiguousSet<C>(effectiveRange, domain);
- }
-
- final DiscreteDomain<C> domain;
-
- ContiguousSet(DiscreteDomain<C> domain) {
- super(Ordering.natural());
- this.domain = domain;
- }
-
- @Override public ContiguousSet<C> headSet(C toElement) {
- return headSetImpl(checkNotNull(toElement), false);
- }
-
- @Override public ContiguousSet<C> subSet(C fromElement, C toElement) {
- checkNotNull(fromElement);
- checkNotNull(toElement);
- checkArgument(comparator().compare(fromElement, toElement) <= 0);
- return subSetImpl(fromElement, true, toElement, false);
- }
-
- @Override public ContiguousSet<C> tailSet(C fromElement) {
- return tailSetImpl(checkNotNull(fromElement), true);
- }
-
- /*
- * These methods perform most headSet, subSet, and tailSet logic, besides parameter validation.
- */
- /*@Override*/ abstract ContiguousSet<C> headSetImpl(C toElement, boolean inclusive);
-
- /*@Override*/ abstract ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive,
- C toElement, boolean toInclusive);
-
- /*@Override*/ abstract ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive);
-
- /**
- * Returns the set of values that are contained in both this set and the other.
- *
- * <p>This method should always be used instead of
- * {@link Sets#intersection} for {@link ContiguousSet} instances.
- */
- public abstract ContiguousSet<C> intersection(ContiguousSet<C> other);
-
- /**
- * Returns a range, closed on both ends, whose endpoints are the minimum and maximum values
- * contained in this set. This is equivalent to {@code range(CLOSED, CLOSED)}.
- *
- * @throws NoSuchElementException if this set is empty
- */
- public abstract Range<C> range();
-
- /**
- * Returns the minimal range with the given boundary types for which all values in this set are
- * {@linkplain Range#contains(Comparable) contained} within the range.
- *
- * <p>Note that this method will return ranges with unbounded endpoints if {@link BoundType#OPEN}
- * is requested for a domain minimum or maximum. For example, if {@code set} was created from the
- * range {@code [1..Integer.MAX_VALUE]} then {@code set.range(CLOSED, OPEN)} must return
- * {@code [1..∞)}.
- *
- * @throws NoSuchElementException if this set is empty
- */
- public abstract Range<C> range(BoundType lowerBoundType, BoundType upperBoundType);
-
- /** Returns a short-hand representation of the contents such as {@code "[1..100]"}. */
- @Override public String toString() {
- return range().toString();
- }
-}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/DescendingMultiset.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/DescendingMultiset.java
deleted file mode 100644
index a708d9c..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/DescendingMultiset.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.SortedSet;
-
-/**
- * A skeleton implementation of a descending multiset. Only needs
- * {@code forwardMultiset()} and {@code entryIterator()}.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-abstract class DescendingMultiset<E> extends ForwardingMultiset<E>
- implements SortedMultiset<E> {
- abstract SortedMultiset<E> forwardMultiset();
-
- private transient Comparator<? super E> comparator;
-
- @Override public Comparator<? super E> comparator() {
- Comparator<? super E> result = comparator;
- if (result == null) {
- return comparator =
- Ordering.from(forwardMultiset().comparator()).<E>reverse();
- }
- return result;
- }
-
- private transient SortedSet<E> elementSet;
-
- @Override public SortedSet<E> elementSet() {
- SortedSet<E> result = elementSet;
- if (result == null) {
- return elementSet = new SortedMultisets.ElementSet<E>(this);
- }
- return result;
- }
-
- @Override public Entry<E> pollFirstEntry() {
- return forwardMultiset().pollLastEntry();
- }
-
- @Override public Entry<E> pollLastEntry() {
- return forwardMultiset().pollFirstEntry();
- }
-
- @Override public SortedMultiset<E> headMultiset(E toElement,
- BoundType boundType) {
- return forwardMultiset().tailMultiset(toElement, boundType)
- .descendingMultiset();
- }
-
- @Override public SortedMultiset<E> subMultiset(E fromElement,
- BoundType fromBoundType, E toElement, BoundType toBoundType) {
- return forwardMultiset().subMultiset(toElement, toBoundType, fromElement,
- fromBoundType).descendingMultiset();
- }
-
- @Override public SortedMultiset<E> tailMultiset(E fromElement,
- BoundType boundType) {
- return forwardMultiset().headMultiset(fromElement, boundType)
- .descendingMultiset();
- }
-
- @Override protected Multiset<E> delegate() {
- return forwardMultiset();
- }
-
- @Override public SortedMultiset<E> descendingMultiset() {
- return forwardMultiset();
- }
-
- @Override public Entry<E> firstEntry() {
- return forwardMultiset().lastEntry();
- }
-
- @Override public Entry<E> lastEntry() {
- return forwardMultiset().firstEntry();
- }
-
- abstract Iterator<Entry<E>> entryIterator();
-
- private transient Set<Entry<E>> entrySet;
-
- @Override public Set<Entry<E>> entrySet() {
- Set<Entry<E>> result = entrySet;
- return (result == null) ? entrySet = createEntrySet() : result;
- }
-
- Set<Entry<E>> createEntrySet() {
- return new Multisets.EntrySet<E>() {
- @Override Multiset<E> multiset() {
- return DescendingMultiset.this;
- }
-
- @Override public Iterator<Entry<E>> iterator() {
- return entryIterator();
- }
-
- @Override public int size() {
- return forwardMultiset().entrySet().size();
- }
- };
- }
-
- @Override public Iterator<E> iterator() {
- return Multisets.iteratorImpl(this);
- }
-
- @Override public Object[] toArray() {
- return standardToArray();
- }
-
- @Override public <T> T[] toArray(T[] array) {
- return standardToArray(array);
- }
-
- @Override public String toString() {
- return entrySet().toString();
- }
-} \ No newline at end of file
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyContiguousSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyContiguousSet.java
index 368e856..f8fbe59 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyContiguousSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyContiguousSet.java
@@ -69,6 +69,11 @@ final class EmptyContiguousSet<C extends Comparable> extends ContiguousSet<C> {
return this;
}
+ //Abstract method doesn't exist in GWT emulation
+ /* @Override */ int indexOf(Object target) {
+ return -1;
+ }
+
@Override public UnmodifiableIterator<C> iterator() {
return Iterators.emptyIterator();
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableList.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableList.java
index 24b1151..435fc26 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableList.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableList.java
@@ -13,25 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.google.common.collect;
-import static java.util.Collections.emptyList;
-
-import java.util.List;
-
/**
* GWT emulated version of EmptyImmutableList.
*
* @author Hayward Chan
*/
-final class EmptyImmutableList extends ForwardingImmutableList<Object> {
- static final EmptyImmutableList INSTANCE = new EmptyImmutableList();
-
- private EmptyImmutableList() {
- }
+final class EmptyImmutableList extends ImmutableList<Object> {
- @Override List<Object> delegateList() {
- return emptyList();
- }
+ static final EmptyImmutableList INSTANCE = new EmptyImmutableList();
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableBiMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableMap.java
index 1520d58..dc3fecf 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableBiMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableMap.java
@@ -16,21 +16,13 @@
package com.google.common.collect;
-import java.util.Collections;
-
/**
- * GWT emulation of {@link EmptyImmutableBiMap}.
+ * GWT emulation of {@link EmptyImmutableMap}. In GWT, it is a thin wrapper
+ * around {@link java.util.Collections#emptyMap()}.
*
* @author Hayward Chan
*/
-@SuppressWarnings("serial")
-final class EmptyImmutableBiMap extends ImmutableBiMap<Object, Object> {
- static final EmptyImmutableBiMap INSTANCE = new EmptyImmutableBiMap();
+final class EmptyImmutableMap extends ImmutableMap<Object, Object> {
- private EmptyImmutableBiMap() {
- super(Collections.emptyMap());
- }
- @Override public ImmutableBiMap<Object, Object> inverse() {
- return this;
- }
+ static final EmptyImmutableMap INSTANCE = new EmptyImmutableMap();
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSet.java
index ae3b3f3..6166c36 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSet.java
@@ -16,17 +16,12 @@
package com.google.common.collect;
-import java.util.Collections;
-
/**
* GWT emulation of {@link EmptyImmutableSet}.
*
* @author Hayward Chan
*/
-final class EmptyImmutableSet extends ForwardingImmutableSet<Object> {
- private EmptyImmutableSet() {
- super(Collections.emptySet());
- }
+final class EmptyImmutableSet extends ImmutableSet<Object> {
static final EmptyImmutableSet INSTANCE = new EmptyImmutableSet();
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSortedMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSortedMap.java
deleted file mode 100644
index 4159cd4..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSortedMap.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import java.util.Comparator;
-import java.util.TreeMap;
-
-/**
- * GWT emulated version of {@link EmptyImmutableSortedMap}.
- *
- * @author Chris Povirk
- */
-final class EmptyImmutableSortedMap<K, V> extends ImmutableSortedMap<K, V> {
- private EmptyImmutableSortedMap(Comparator<? super K> comparator) {
- super(new TreeMap<K, V>(comparator), comparator);
- }
-
- @SuppressWarnings("unchecked")
- private static final ImmutableSortedMap<Object, Object> NATURAL_EMPTY_MAP =
- new EmptyImmutableSortedMap<Object, Object>(NATURAL_ORDER);
-
- static <K, V> ImmutableSortedMap<K, V> forComparator(Comparator<? super K> comparator) {
- if (comparator == NATURAL_ORDER) {
- return (ImmutableSortedMap) NATURAL_EMPTY_MAP;
- }
- return new EmptyImmutableSortedMap<K, V>(comparator);
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSortedSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSortedSet.java
index ff45a39..b21896b 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSortedSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EmptyImmutableSortedSet.java
@@ -25,6 +25,6 @@ import java.util.Comparator;
*/
class EmptyImmutableSortedSet<E> extends ImmutableSortedSet<E> {
EmptyImmutableSortedSet(Comparator<? super E> comparator) {
- super(Sets.newTreeSet(comparator));
+ super(comparator);
}
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumBiMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumBiMap.java
index 46fa641..f6d7e90 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumBiMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumBiMap.java
@@ -17,7 +17,6 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
@@ -28,10 +27,6 @@ import java.util.Map;
* A {@code BiMap} backed by two {@code EnumMap} instances. Null keys and values
* are not permitted. An {@code EnumBiMap} and its inverse are both
* serializable.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
- * {@code BiMap}</a>.
*
* @author Mike Bostock
* @since 2.0 (imported from Google Collections Library)
@@ -106,15 +101,5 @@ public final class EnumBiMap<K extends Enum<K>, V extends Enum<V>>
public Class<V> valueType() {
return valueType;
}
-
- @Override
- K checkKey(K key) {
- return checkNotNull(key);
- }
-
- @Override
- V checkValue(V value) {
- return checkNotNull(value);
- }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumHashBiMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumHashBiMap.java
index 3d9503f..dce8d66 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumHashBiMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumHashBiMap.java
@@ -16,8 +16,6 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.common.annotations.GwtCompatible;
import java.util.EnumMap;
@@ -30,10 +28,6 @@ import javax.annotation.Nullable;
* a {@code HashMap} instance for values-to-keys. Null keys are not permitted,
* but null values are. An {@code EnumHashBiMap} and its inverse are both
* serializable.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
- * {@code BiMap}</a>.
*
* @author Mike Bostock
* @since 2.0 (imported from Google Collections Library)
@@ -78,12 +72,7 @@ public final class EnumHashBiMap<K extends Enum<K>, V>
this.keyType = keyType;
}
- // Overriding these 3 methods to show that values may be null (but not keys)
-
- @Override
- K checkKey(K key) {
- return checkNotNull(key);
- }
+ // Overriding these two methods to show that values may be null (but not keys)
@Override public V put(K key, @Nullable V value) {
return super.put(key, value);
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumMultiset.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumMultiset.java
index 4e769fb..589706b 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumMultiset.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/EnumMultiset.java
@@ -23,10 +23,6 @@ import java.util.Iterator;
/**
* Multiset implementation backed by an {@link EnumMap}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
- * {@code Multiset}</a>.
*
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
@@ -54,19 +50,6 @@ public final class EnumMultiset<E extends Enum<E>> extends AbstractMapBasedMulti
Iterables.addAll(multiset, elements);
return multiset;
}
-
- /**
- * Returns a new {@code EnumMultiset} instance containing the given elements. Unlike
- * {@link EnumMultiset#create(Iterable)}, this method does not produce an exception on an empty
- * iterable.
- *
- * @since 14.0
- */
- public static <E extends Enum<E>> EnumMultiset<E> create(Iterable<E> elements, Class<E> type) {
- EnumMultiset<E> result = create(type);
- Iterables.addAll(result, elements);
- return result;
- }
private transient Class<E> type;
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/FluentIterable.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/FluentIterable.java
deleted file mode 100644
index 7c08944..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/FluentIterable.java
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedSet;
-
-import javax.annotation.Nullable;
-
-/**
- * {@code FluentIterable} provides a rich interface for manipulating {@code Iterable} instances in a
- * chained fashion. A {@code FluentIterable} can be created from an {@code Iterable}, or from a set
- * of elements. The following types of methods are provided on {@code FluentIterable}:
- * <ul>
- * <li>chained methods which return a new {@code FluentIterable} based in some way on the contents
- * of the current one (for example {@link #transform})
- * <li>conversion methods which copy the {@code FluentIterable}'s contents into a new collection or
- * array (for example {@link #toList})
- * <li>element extraction methods which facilitate the retrieval of certain elements (for example
- * {@link #last})
- * <li>query methods which answer questions about the {@code FluentIterable}'s contents (for example
- * {@link #anyMatch})
- * </ul>
- *
- * <p>Here is an example that merges the lists returned by two separate database calls, transforms
- * it by invoking {@code toString()} on each element, and returns the first 10 elements as an
- * {@code ImmutableList}: <pre> {@code
- *
- * FluentIterable
- * .from(database.getClientList())
- * .filter(activeInLastMonth())
- * .transform(Functions.toStringFunction())
- * .limit(10)
- * .toList();}</pre>
- *
- * Anything which can be done using {@code FluentIterable} could be done in a different fashion
- * (often with {@link Iterables}), however the use of {@code FluentIterable} makes many sets of
- * operations significantly more concise.
- *
- * @author Marcin Mikosik
- * @since 12.0
- */
-@GwtCompatible(emulated = true)
-public abstract class FluentIterable<E> implements Iterable<E> {
- // We store 'iterable' and use it instead of 'this' to allow Iterables to perform instanceof
- // checks on the _original_ iterable when FluentIterable.from is used.
- private final Iterable<E> iterable;
-
- /** Constructor for use by subclasses. */
- protected FluentIterable() {
- this.iterable = this;
- }
-
- FluentIterable(Iterable<E> iterable) {
- this.iterable = checkNotNull(iterable);
- }
-
- /**
- * Returns a fluent iterable that wraps {@code iterable}, or {@code iterable} itself if it
- * is already a {@code FluentIterable}.
- */
- public static <E> FluentIterable<E> from(final Iterable<E> iterable) {
- return (iterable instanceof FluentIterable) ? (FluentIterable<E>) iterable
- : new FluentIterable<E>(iterable) {
- @Override
- public Iterator<E> iterator() {
- return iterable.iterator();
- }
- };
- }
-
- /**
- * Construct a fluent iterable from another fluent iterable. This is obviously never necessary,
- * but is intended to help call out cases where one migration from {@code Iterable} to
- * {@code FluentIterable} has obviated the need to explicitly convert to a {@code FluentIterable}.
- *
- * @deprecated instances of {@code FluentIterable} don't need to be converted to
- * {@code FluentIterable}
- */
- @Deprecated
- public static <E> FluentIterable<E> from(FluentIterable<E> iterable) {
- return checkNotNull(iterable);
- }
-
- /**
- * Returns a string representation of this fluent iterable, with the format
- * {@code [e1, e2, ..., en]}.
- */
- @Override
- public String toString() {
- return Iterables.toString(iterable);
- }
-
- /**
- * Returns the number of elements in this fluent iterable.
- */
- public final int size() {
- return Iterables.size(iterable);
- }
-
- /**
- * Returns {@code true} if this fluent iterable contains any object for which
- * {@code equals(element)} is true.
- */
- public final boolean contains(@Nullable Object element) {
- return Iterables.contains(iterable, element);
- }
-
- /**
- * Returns a fluent iterable whose {@code Iterator} cycles indefinitely over the elements of
- * this fluent iterable.
- *
- * <p>That iterator supports {@code remove()} if {@code iterable.iterator()} does. After
- * {@code remove()} is called, subsequent cycles omit the removed element, which is no longer in
- * this fluent iterable. The iterator's {@code hasNext()} method returns {@code true} until
- * this fluent iterable is empty.
- *
- * <p><b>Warning:</b> Typical uses of the resulting iterator may produce an infinite loop. You
- * should use an explicit {@code break} or be certain that you will eventually remove all the
- * elements.
- */
- public final FluentIterable<E> cycle() {
- return from(Iterables.cycle(iterable));
- }
-
- /**
- * Returns the elements from this fluent iterable that satisfy a predicate. The
- * resulting fluent iterable's iterator does not support {@code remove()}.
- */
- public final FluentIterable<E> filter(Predicate<? super E> predicate) {
- return from(Iterables.filter(iterable, predicate));
- }
-
- /**
- * Returns {@code true} if any element in this fluent iterable satisfies the predicate.
- */
- public final boolean anyMatch(Predicate<? super E> predicate) {
- return Iterables.any(iterable, predicate);
- }
-
- /**
- * Returns {@code true} if every element in this fluent iterable satisfies the predicate.
- * If this fluent iterable is empty, {@code true} is returned.
- */
- public final boolean allMatch(Predicate<? super E> predicate) {
- return Iterables.all(iterable, predicate);
- }
-
- /**
- * Returns an {@link Optional} containing the first element in this fluent iterable that
- * satisfies the given predicate, if such an element exists.
- *
- * <p><b>Warning:</b> avoid using a {@code predicate} that matches {@code null}. If {@code null}
- * is matched in this fluent iterable, a {@link NullPointerException} will be thrown.
- */
- public final Optional<E> firstMatch(Predicate<? super E> predicate) {
- return Iterables.tryFind(iterable, predicate);
- }
-
- /**
- * Returns a fluent iterable that applies {@code function} to each element of this
- * fluent iterable.
- *
- * <p>The returned fluent iterable's iterator supports {@code remove()} if this iterable's
- * iterator does. After a successful {@code remove()} call, this fluent iterable no longer
- * contains the corresponding element.
- */
- public final <T> FluentIterable<T> transform(Function<? super E, T> function) {
- return from(Iterables.transform(iterable, function));
- }
-
- /**
- * Applies {@code function} to each element of this fluent iterable and returns
- * a fluent iterable with the concatenated combination of results. {@code function}
- * returns an Iterable of results.
- *
- * <p>The returned fluent iterable's iterator supports {@code remove()} if this
- * function-returned iterables' iterator does. After a successful {@code remove()} call,
- * the returned fluent iterable no longer contains the corresponding element.
- *
- * @since 13.0 (required {@code Function<E, Iterable<T>>} until 14.0)
- */
- public <T> FluentIterable<T> transformAndConcat(
- Function<? super E, ? extends Iterable<? extends T>> function) {
- return from(Iterables.concat(transform(function)));
- }
-
- /**
- * Returns an {@link Optional} containing the first element in this fluent iterable.
- * If the iterable is empty, {@code Optional.absent()} is returned.
- *
- * @throws NullPointerException if the first element is null; if this is a possibility, use
- * {@code iterator().next()} or {@link Iterables#getFirst} instead.
- */
- public final Optional<E> first() {
- Iterator<E> iterator = iterable.iterator();
- return iterator.hasNext()
- ? Optional.of(iterator.next())
- : Optional.<E>absent();
- }
-
- /**
- * Returns an {@link Optional} containing the last element in this fluent iterable.
- * If the iterable is empty, {@code Optional.absent()} is returned.
- *
- * @throws NullPointerException if the last element is null; if this is a possibility, use
- * {@link Iterables#getLast} instead.
- */
- public final Optional<E> last() {
- // Iterables#getLast was inlined here so we don't have to throw/catch a NSEE
-
- // TODO(kevinb): Support a concurrently modified collection?
- if (iterable instanceof List) {
- List<E> list = (List<E>) iterable;
- if (list.isEmpty()) {
- return Optional.absent();
- }
- return Optional.of(list.get(list.size() - 1));
- }
- Iterator<E> iterator = iterable.iterator();
- if (!iterator.hasNext()) {
- return Optional.absent();
- }
-
- /*
- * TODO(kevinb): consider whether this "optimization" is worthwhile. Users
- * with SortedSets tend to know they are SortedSets and probably would not
- * call this method.
- */
- if (iterable instanceof SortedSet) {
- SortedSet<E> sortedSet = (SortedSet<E>) iterable;
- return Optional.of(sortedSet.last());
- }
-
- while (true) {
- E current = iterator.next();
- if (!iterator.hasNext()) {
- return Optional.of(current);
- }
- }
- }
-
- /**
- * Returns a view of this fluent iterable that skips its first {@code numberToSkip}
- * elements. If this fluent iterable contains fewer than {@code numberToSkip} elements,
- * the returned fluent iterable skips all of its elements.
- *
- * <p>Modifications to this fluent iterable before a call to {@code iterator()} are
- * reflected in the returned fluent iterable. That is, the its iterator skips the first
- * {@code numberToSkip} elements that exist when the iterator is created, not when {@code skip()}
- * is called.
- *
- * <p>The returned fluent iterable's iterator supports {@code remove()} if the
- * {@code Iterator} of this fluent iterable supports it. Note that it is <i>not</i>
- * possible to delete the last skipped element by immediately calling {@code remove()} on the
- * returned fluent iterable's iterator, as the {@code Iterator} contract states that a call
- * to {@code * remove()} before a call to {@code next()} will throw an
- * {@link IllegalStateException}.
- */
- public final FluentIterable<E> skip(int numberToSkip) {
- return from(Iterables.skip(iterable, numberToSkip));
- }
-
- /**
- * Creates a fluent iterable with the first {@code size} elements of this
- * fluent iterable. If this fluent iterable does not contain that many elements,
- * the returned fluent iterable will have the same behavior as this fluent iterable.
- * The returned fluent iterable's iterator supports {@code remove()} if this
- * fluent iterable's iterator does.
- *
- * @param size the maximum number of elements in the returned fluent iterable
- * @throws IllegalArgumentException if {@code size} is negative
- */
- public final FluentIterable<E> limit(int size) {
- return from(Iterables.limit(iterable, size));
- }
-
- /**
- * Determines whether this fluent iterable is empty.
- */
- public final boolean isEmpty() {
- return !iterable.iterator().hasNext();
- }
-
- /**
- * Returns an {@code ImmutableList} containing all of the elements from this fluent iterable in
- * proper sequence.
- *
- * @since 14.0 (since 12.0 as {@code toImmutableList()}).
- */
- public final ImmutableList<E> toList() {
- return ImmutableList.copyOf(iterable);
- }
-
- /**
- * Returns an {@code ImmutableList} containing all of the elements from this {@code
- * FluentIterable} in the order specified by {@code comparator}. To produce an {@code
- * ImmutableList} sorted by its natural ordering, use {@code toSortedList(Ordering.natural())}.
- *
- * @param comparator the function by which to sort list elements
- * @throws NullPointerException if any element is null
- * @since 14.0 (since 13.0 as {@code toSortedImmutableList()}).
- */
- @Beta
- public final ImmutableList<E> toSortedList(Comparator<? super E> comparator) {
- return Ordering.from(comparator).immutableSortedCopy(iterable);
- }
-
- /**
- * Returns an {@code ImmutableSet} containing all of the elements from this fluent iterable with
- * duplicates removed.
- *
- * @since 14.0 (since 12.0 as {@code toImmutableSet()}).
- */
- public final ImmutableSet<E> toSet() {
- return ImmutableSet.copyOf(iterable);
- }
-
- /**
- * Returns an {@code ImmutableSortedSet} containing all of the elements from this {@code
- * FluentIterable} in the order specified by {@code comparator}, with duplicates (determined by
- * {@code comparator.compare(x, y) == 0}) removed. To produce an {@code ImmutableSortedSet} sorted
- * by its natural ordering, use {@code toSortedSet(Ordering.natural())}.
- *
- * @param comparator the function by which to sort set elements
- * @throws NullPointerException if any element is null
- * @since 14.0 (since 12.0 as {@code toImmutableSortedSet()}).
- */
- public final ImmutableSortedSet<E> toSortedSet(Comparator<? super E> comparator) {
- return ImmutableSortedSet.copyOf(comparator, iterable);
- }
-
- /**
- * Returns an immutable map for which the elements of this {@code FluentIterable} are the keys in
- * the same order, mapped to values by the given function. If this iterable contains duplicate
- * elements, the returned map will contain each distinct element once in the order it first
- * appears.
- *
- * @throws NullPointerException if any element of this iterable is {@code null}, or if {@code
- * valueFunction} produces {@code null} for any key
- * @since 14.0
- */
- public final <V> ImmutableMap<E, V> toMap(Function<? super E, V> valueFunction) {
- return Maps.toMap(iterable, valueFunction);
- }
-
- /**
- * Creates an index {@code ImmutableListMultimap} that contains the results of applying a
- * specified function to each item in this {@code FluentIterable} of values. Each element of this
- * iterable will be stored as a value in the resulting multimap, yielding a multimap with the same
- * size as this iterable. The key used to store that value in the multimap will be the result of
- * calling the function on that value. The resulting multimap is created as an immutable snapshot.
- * In the returned multimap, keys appear in the order they are first encountered, and the values
- * corresponding to each key appear in the same order as they are encountered.
- *
- * @param keyFunction the function used to produce the key for each value
- * @throws NullPointerException if any of the following cases is true:
- * <ul>
- * <li>{@code keyFunction} is null
- * <li>An element in this fluent iterable is null
- * <li>{@code keyFunction} returns {@code null} for any element of this iterable
- * </ul>
- * @since 14.0
- */
- public final <K> ImmutableListMultimap<K, E> index(Function<? super E, K> keyFunction) {
- return Multimaps.index(iterable, keyFunction);
- }
-
- /**
- * Returns an immutable map for which the {@link java.util.Map#values} are the elements of this
- * {@code FluentIterable} in the given order, and each key is the product of invoking a supplied
- * function on its corresponding value.
- *
- * @param keyFunction the function used to produce the key for each value
- * @throws IllegalArgumentException if {@code keyFunction} produces the same key for more than one
- * value in this fluent iterable
- * @throws NullPointerException if any element of this fluent iterable is null, or if
- * {@code keyFunction} produces {@code null} for any value
- * @since 14.0
- */
- public final <K> ImmutableMap<K, E> uniqueIndex(Function<? super E, K> keyFunction) {
- return Maps.uniqueIndex(iterable, keyFunction);
- }
-
- /**
- * Returns an {@code ImmutableList} containing all of the elements from this
- * fluent iterable in proper sequence.
- *
- * @deprecated Use {@link #toList()} instead. This method is scheduled for removal in Guava 15.0.
- */
- @Deprecated
- public final ImmutableList<E> toImmutableList() {
- return toList();
- }
-
- /**
- * Returns an {@code ImmutableList} containing all of the elements from this
- * {@code FluentIterable} in the order specified by {@code comparator}. To produce an
- * {@code ImmutableList} sorted by its natural ordering, use
- * {@code toSortedImmutableList(Ordering.natural())}.
- *
- * @param comparator the function by which to sort list elements
- * @throws NullPointerException if any element is null
- * @since 13.0
- * @deprecated Use {@link #toSortedList(Comparator)} instead. This method is scheduled for removal
- * in Guava 15.0.
- */
- @Deprecated
- public final ImmutableList<E> toSortedImmutableList(Comparator<? super E> comparator) {
- return toSortedList(comparator);
- }
-
- /**
- * Returns an {@code ImmutableSet} containing all of the elements from this
- * fluent iterable with duplicates removed.
- *
- * @deprecated Use {@link #toSet()} instead. This method is scheduled for removal in Guava 15.0.
- */
- @Deprecated
- public final ImmutableSet<E> toImmutableSet() {
- return toSet();
- }
-
- /**
- * Returns an {@code ImmutableSortedSet} containing all of the elements from this
- * {@code FluentIterable} in the order specified by {@code comparator}, with duplicates
- * (determined by {@code comparator.compare(x, y) == 0}) removed. To produce an
- * {@code ImmutableSortedSet} sorted by its natural ordering, use
- * {@code toImmutableSortedSet(Ordering.natural())}.
- *
- * @param comparator the function by which to sort set elements
- * @throws NullPointerException if any element is null
- * @deprecated Use {@link #toSortedSet(Comparator)} instead. This method is scheduled for removal
- * in Guava 15.0.
- */
- @Deprecated
- public final ImmutableSortedSet<E> toImmutableSortedSet(Comparator<? super E> comparator) {
- return toSortedSet(comparator);
- }
-
- /**
- * Copies all the elements from this fluent iterable to {@code collection}. This is equivalent to
- * calling {@code Iterables.addAll(collection, this)}.
- *
- * @param collection the collection to copy elements to
- * @return {@code collection}, for convenience
- * @since 14.0
- */
- public final <C extends Collection<? super E>> C copyInto(C collection) {
- checkNotNull(collection);
- if (iterable instanceof Collection) {
- collection.addAll(Collections2.cast(iterable));
- } else {
- for (E item : iterable) {
- collection.add(item);
- }
- }
- return collection;
- }
-
- /**
- * Returns the element at the specified position in this fluent iterable.
- *
- * @param position position of the element to return
- * @return the element at the specified position in this fluent iterable
- * @throws IndexOutOfBoundsException if {@code position} is negative or greater than or equal to
- * the size of this fluent iterable
- */
- public final E get(int position) {
- return Iterables.get(iterable, position);
- }
-
- /**
- * Function that transforms {@code Iterable<E>} into a fluent iterable.
- */
- private static class FromIterableFunction<E>
- implements Function<Iterable<E>, FluentIterable<E>> {
- @Override
- public FluentIterable<E> apply(Iterable<E> fromObject) {
- return FluentIterable.from(fromObject);
- }
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableList.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableList.java
deleted file mode 100644
index 1327ba0..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableList.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2009 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import java.util.Collection;
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-/**
- * GWT emulated version of {@link ImmutableList}.
- * TODO(cpovirk): more doc
- *
- * @author Hayward Chan
- */
-abstract class ForwardingImmutableList<E> extends ImmutableList<E> {
-
- ForwardingImmutableList() {
- }
-
- abstract List<E> delegateList();
-
- public int indexOf(@Nullable Object object) {
- return delegateList().indexOf(object);
- }
-
- public int lastIndexOf(@Nullable Object object) {
- return delegateList().lastIndexOf(object);
- }
-
- public E get(int index) {
- return delegateList().get(index);
- }
-
- public ImmutableList<E> subList(int fromIndex, int toIndex) {
- return unsafeDelegateList(delegateList().subList(fromIndex, toIndex));
- }
-
- @Override public Object[] toArray() {
- // Note that ArrayList.toArray() doesn't work here because it returns E[]
- // instead of Object[].
- return delegateList().toArray(new Object[size()]);
- }
-
- @Override public boolean equals(Object obj) {
- return delegateList().equals(obj);
- }
-
- @Override public int hashCode() {
- return delegateList().hashCode();
- }
-
- @Override public UnmodifiableIterator<E> iterator() {
- return Iterators.unmodifiableIterator(delegateList().iterator());
- }
-
- @Override public boolean contains(@Nullable Object object) {
- return object != null && delegateList().contains(object);
- }
-
- @Override public boolean containsAll(Collection<?> targets) {
- return delegateList().containsAll(targets);
- }
-
- public int size() {
- return delegateList().size();
- }
-
- @Override public boolean isEmpty() {
- return delegateList().isEmpty();
- }
-
- @Override public <T> T[] toArray(T[] other) {
- return delegateList().toArray(other);
- }
-
- @Override public String toString() {
- return delegateList().toString();
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableMap.java
deleted file mode 100644
index 9ef0d96..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableMap.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2009 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * GWT implementation of {@link ImmutableMap} that forwards to another map.
- *
- * @author Hayward Chan
- */
-public abstract class ForwardingImmutableMap<K, V> extends ImmutableMap<K, V> {
-
- final transient Map<K, V> delegate;
-
- ForwardingImmutableMap(Map<? extends K, ? extends V> delegate) {
- this.delegate = Collections.unmodifiableMap(delegate);
- }
-
- @SuppressWarnings("unchecked")
- ForwardingImmutableMap(Entry<? extends K, ? extends V>... entries) {
- Map<K, V> delegate = Maps.newLinkedHashMap();
- for (Entry<? extends K, ? extends V> entry : entries) {
- K key = checkNotNull(entry.getKey());
- V previous = delegate.put(key, checkNotNull(entry.getValue()));
- if (previous != null) {
- throw new IllegalArgumentException("duplicate key: " + key);
- }
- }
- this.delegate = Collections.unmodifiableMap(delegate);
- }
-
- boolean isPartialView() {
- return false;
- }
-
- public final boolean isEmpty() {
- return delegate.isEmpty();
- }
-
- public final boolean containsKey(@Nullable Object key) {
- return Maps.safeContainsKey(delegate, key);
- }
-
- public final boolean containsValue(@Nullable Object value) {
- return delegate.containsValue(value);
- }
-
- public V get(@Nullable Object key) {
- return (key == null) ? null : Maps.safeGet(delegate, key);
- }
-
- @Override ImmutableSet<Entry<K, V>> createEntrySet() {
- return ImmutableSet.unsafeDelegate(
- new ForwardingSet<Entry<K, V>>() {
- @Override protected Set<Entry<K, V>> delegate() {
- return delegate.entrySet();
- }
- @Override public boolean contains(Object object) {
- if (object instanceof Entry<?, ?>
- && ((Entry<?, ?>) object).getKey() == null) {
- return false;
- }
- try {
- return super.contains(object);
- } catch (ClassCastException e) {
- return false;
- }
- }
- @Override public <T> T[] toArray(T[] array) {
- T[] result = super.toArray(array);
- if (size() < result.length) {
- // It works around a GWT bug where elements after last is not
- // properly null'ed.
- result[size()] = null;
- }
- return result;
- }
- });
- }
-
- @Override ImmutableSet<K> createKeySet() {
- return ImmutableSet.unsafeDelegate(delegate.keySet());
- }
-
- @Override ImmutableCollection<V> createValues() {
- return ImmutableCollection.unsafeDelegate(delegate.values());
- }
-
- @Override public int size() {
- return delegate.size();
- }
-
- @Override public boolean equals(@Nullable Object object) {
- return delegate.equals(object);
- }
-
- @Override public int hashCode() {
- return delegate.hashCode();
- }
-
- @Override public String toString() {
- return delegate.toString();
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableSet.java
deleted file mode 100644
index 6db3339..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ForwardingImmutableSet.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2009 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-/**
- * GWT implementation of {@link ImmutableSet} that forwards to another {@code Set} implementation.
- *
- * @author Hayward Chan
- */
-@SuppressWarnings("serial") // Serialization only done in GWT.
-public abstract class ForwardingImmutableSet<E> extends ImmutableSet<E> {
- private final transient Set<E> delegate;
-
- ForwardingImmutableSet(Set<E> delegate) {
- // TODO(cpovirk): are we over-wrapping?
- this.delegate = Collections.unmodifiableSet(delegate);
- }
-
- @Override public UnmodifiableIterator<E> iterator() {
- return Iterators.unmodifiableIterator(delegate.iterator());
- }
-
- @Override public boolean contains(@Nullable Object object) {
- return object != null && delegate.contains(object);
- }
-
- @Override public boolean containsAll(Collection<?> targets) {
- return delegate.containsAll(targets);
- }
-
- @Override public int size() {
- return delegate.size();
- }
-
- @Override public boolean isEmpty() {
- return delegate.isEmpty();
- }
-
- @Override public Object[] toArray() {
- return delegate.toArray();
- }
-
- @Override public <T> T[] toArray(T[] other) {
- return delegate.toArray(other);
- }
-
- @Override public String toString() {
- return delegate.toString();
- }
-
- // TODO(cpovirk): equals(), as well, in case it's any faster than Sets.equalsImpl?
-
- @Override public int hashCode() {
- return delegate.hashCode();
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/GenericMapMaker.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/GenericMapMaker.java
index b3b4319..b75f4bf 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/GenericMapMaker.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/GenericMapMaker.java
@@ -52,11 +52,28 @@ public abstract class GenericMapMaker<K0, V0> {
abstract GenericMapMaker<K0, V0> maximumSize(int maximumSize);
/**
+ * See {@link MapMaker#strongKeys}.
+ */
+ abstract GenericMapMaker<K0, V0> strongKeys();
+
+ /**
* See {@link MapMaker#concurrencyLevel}.
*/
public abstract GenericMapMaker<K0, V0> concurrencyLevel(int concurrencyLevel);
/**
+ * See {@link MapMaker#strongValues}.
+ */
+ abstract GenericMapMaker<K0, V0> strongValues();
+
+ /**
+ * See {@link MapMaker#expiration}.
+ */
+ @Deprecated
+ public
+ abstract GenericMapMaker<K0, V0> expiration(long duration, TimeUnit unit);
+
+ /**
* See {@link MapMaker#expireAfterWrite}.
*/
abstract GenericMapMaker<K0, V0> expireAfterWrite(long duration, TimeUnit unit);
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashBiMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashBiMap.java
index 10e4e35..15c3f9e 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashBiMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashBiMap.java
@@ -16,16 +16,22 @@
package com.google.common.collect;
+import com.google.common.annotations.GwtCompatible;
+
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
/**
- * GWT emulation of {@code HashBiMap} that just delegates to two HashMaps.
+ * 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
+ * @since 2.0 (imported from Google Collections Library)
*/
+@GwtCompatible(emulated = true)
public final class HashBiMap<K, V> extends AbstractBiMap<K, V> {
/**
@@ -79,3 +85,4 @@ public final class HashBiMap<K, V> extends AbstractBiMap<K, V> {
return super.forcePut(key, value);
}
}
+
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashMultimap.java
index 582c2f7..55ecd46 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashMultimap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/HashMultimap.java
@@ -43,7 +43,7 @@ import java.util.Set;
*/
@GwtCompatible(serializable = true, emulated = true)
public final class HashMultimap<K, V> extends AbstractSetMultimap<K, V> {
- private static final int DEFAULT_VALUES_PER_KEY = 2;
+ private static final int DEFAULT_VALUES_PER_KEY = 8;
@VisibleForTesting
transient int expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableAsList.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableAsList.java
index 1279bee..a790487 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableAsList.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableAsList.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Guava Authors
+ * Copyright (C) 2010 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,39 +16,15 @@
package com.google.common.collect;
-import com.google.common.annotations.GwtCompatible;
+import java.util.List;
/**
- * List returned by {@link ImmutableCollection#asList} that delegates {@code contains} checks
- * to the backing collection.
+ * GWT emulation of {@link ImmutableAsList}.
*
- * @author Jared Levy
- * @author Louis Wasserman
+ * @author Hayward Chan
*/
-@GwtCompatible(serializable = true, emulated = true)
-@SuppressWarnings("serial")
-abstract class ImmutableAsList<E> extends ImmutableList<E> {
- abstract ImmutableCollection<E> delegateCollection();
-
- @Override public boolean contains(Object target) {
- // The collection's contains() is at least as fast as ImmutableList's
- // and is often faster.
- return delegateCollection().contains(target);
- }
-
- @Override
- public int size() {
- return delegateCollection().size();
- }
-
- @Override
- public boolean isEmpty() {
- return delegateCollection().isEmpty();
- }
-
- @Override
- boolean isPartialView() {
- return delegateCollection().isPartialView();
+final class ImmutableAsList<E> extends RegularImmutableList<E> {
+ ImmutableAsList(List<E> delegate) {
+ super(delegate);
}
}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableAsList_CustomFieldSerializer.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableAsList_CustomFieldSerializer.java
new file mode 100644
index 0000000..1712f5a
--- /dev/null
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableAsList_CustomFieldSerializer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.common.collect;
+
+import com.google.gwt.user.client.rpc.SerializationException;
+import com.google.gwt.user.client.rpc.SerializationStreamReader;
+import com.google.gwt.user.client.rpc.SerializationStreamWriter;
+import com.google.gwt.user.client.rpc.core.java.util.Collection_CustomFieldSerializerBase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class implements the client-side GWT serialization of
+ * {@link ImmutableAsList}.
+ *
+ * @author Hayward Chan
+ */
+public class ImmutableAsList_CustomFieldSerializer {
+
+ public static void deserialize(SerializationStreamReader reader,
+ RegularImmutableList<?> instance) {
+ }
+
+ public static ImmutableAsList<Object> instantiate(
+ SerializationStreamReader reader) throws SerializationException {
+ List<Object> elements = new ArrayList<Object>();
+ Collection_CustomFieldSerializerBase.deserialize(reader, elements);
+ return new ImmutableAsList<Object>(elements);
+ }
+
+ public static void serialize(SerializationStreamWriter writer,
+ ImmutableAsList<?> instance) throws SerializationException {
+ Collection_CustomFieldSerializerBase.serialize(writer, instance);
+ }
+}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableBiMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableBiMap.java
index c8cdebb..59cb788 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableBiMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableBiMap.java
@@ -16,8 +16,7 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkNotNull;
-
+import java.util.Collections;
import java.util.Map;
/**
@@ -25,18 +24,20 @@ import java.util.Map;
*
* @author Hayward Chan
*/
-public abstract class ImmutableBiMap<K, V> extends ForwardingImmutableMap<K, V>
+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();
+
// Casting to any type is safe because the set will never hold any elements.
@SuppressWarnings("unchecked")
public static <K, V> ImmutableBiMap<K, V> of() {
- return (ImmutableBiMap<K, V>) EmptyImmutableBiMap.INSTANCE;
+ return (ImmutableBiMap<K, V>) EMPTY_IMMUTABLE_BIMAP;
}
public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {
- return new SingletonImmutableBiMap<K, V>(
- checkNotNull(k1), checkNotNull(v1));
+ return new RegularImmutableBiMap<K, V>(ImmutableMap.of(k1, v1));
}
public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) {
@@ -117,4 +118,14 @@ public abstract class ImmutableBiMap<K, V> extends ForwardingImmutableMap<K, V>
public final V forcePut(K key, V value) {
throw new UnsupportedOperationException();
}
+
+ @SuppressWarnings("serial")
+ static class EmptyBiMap extends ImmutableBiMap<Object, Object> {
+ EmptyBiMap() {
+ super(Collections.emptyMap());
+ }
+ @Override public ImmutableBiMap<Object, Object> inverse() {
+ return this;
+ }
+ }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableCollection.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableCollection.java
index 936f900..04bd060 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableCollection.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableCollection.java
@@ -16,15 +16,16 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import java.io.Serializable;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import javax.annotation.Nullable;
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* GWT emulated version of {@link ImmutableCollection}.
*
@@ -88,10 +89,6 @@ public abstract class ImmutableCollection<E>
return size() == 0;
}
- @Override public String toString() {
- return Collections2.toStringImpl(this);
- }
-
public final boolean add(E e) {
throw new UnsupportedOperationException();
}
@@ -130,13 +127,15 @@ public abstract class ImmutableCollection<E>
case 1:
return ImmutableList.of(iterator().next());
default:
- return new RegularImmutableAsList<E>(this, toArray());
+ @SuppressWarnings("unchecked")
+ E[] castedArray = (E[]) toArray();
+ return new ImmutableAsList<E>(Arrays.asList(castedArray));
}
}
static <E> ImmutableCollection<E> unsafeDelegate(Collection<E> delegate) {
return new ForwardingImmutableCollection<E>(delegate);
}
-
+
boolean isPartialView(){
return false;
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumMap.java
deleted file mode 100644
index 86f0c26..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumMap.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2009 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Map;
-
-/**
- * GWT emulation of {@link ImmutableEnumMap}. The type parameter is not bounded
- * by {@code Enum<E>} to avoid code-size bloat.
- *
- * @author Hayward Chan
- */
-final class ImmutableEnumMap<K, V> extends ForwardingImmutableMap<K, V> {
- static <K, V> ImmutableMap<K, V> asImmutable(Map<K, V> map) {
- for (Map.Entry<K, V> entry : checkNotNull(map).entrySet()) {
- checkNotNull(entry.getKey());
- checkNotNull(entry.getValue());
- }
- return new ImmutableEnumMap<K, V>(map);
- }
-
- ImmutableEnumMap(Map<? extends K, ? extends V> delegate) {
- super(WellBehavedMap.wrap(delegate));
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumSet.java
index a9c21c8..14506c2 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableEnumSet.java
@@ -24,18 +24,7 @@ import java.util.Set;
*
* @author Hayward Chan
*/
-final class ImmutableEnumSet<E> extends ForwardingImmutableSet<E> {
- static <E> ImmutableSet<E> asImmutable(Set<E> delegate) {
- switch (delegate.size()) {
- case 0:
- return ImmutableSet.of();
- case 1:
- return ImmutableSet.of(Iterables.getOnlyElement(delegate));
- default:
- return new ImmutableEnumSet<E>(delegate);
- }
- }
-
+final class ImmutableEnumSet<E> extends ImmutableSet<E> {
public ImmutableEnumSet(Set<E> delegate) {
super(delegate);
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableList.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableList.java
index ca5a95a..db67daa 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableList.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableList.java
@@ -26,20 +26,30 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.ListIterator;
import java.util.RandomAccess;
import javax.annotation.Nullable;
/**
* GWT emulated version of {@link ImmutableList}.
- * TODO(cpovirk): more doc
*
* @author Hayward Chan
*/
@SuppressWarnings("serial") // we're overriding default serialization
-public abstract class ImmutableList<E> extends ImmutableCollection<E>
+public abstract class ImmutableList<E> extends ForwardingImmutableCollection<E>
implements List<E>, RandomAccess {
- ImmutableList() {}
+
+ private transient final List<E> delegate;
+
+ ImmutableList(List<E> delegate) {
+ super(delegate);
+ this.delegate = Collections.unmodifiableList(delegate);
+ }
+
+ ImmutableList() {
+ this(Collections.<E>emptyList());
+ }
// Casting to any type is safe because the list will never hold any elements.
@SuppressWarnings("unchecked")
@@ -116,6 +126,19 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
return new RegularImmutableList<E>(ImmutableList.<E>nullCheckedList(array));
}
+ public static <E> ImmutableList<E> of(E[] elements) {
+ checkNotNull(elements); // for GWT
+ switch (elements.length) {
+ case 0:
+ return ImmutableList.of();
+ case 1:
+ return new SingletonImmutableList<E>(elements[0]);
+ default:
+ return new RegularImmutableList<E>(
+ ImmutableList.<E>nullCheckedList(elements));
+ }
+ }
+
private static void arrayCopy(Object[] dest, int pos, Object... source) {
System.arraycopy(source, 0, dest, pos, source.length);
}
@@ -165,7 +188,7 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
}
// Factory method that skips the null checks. Used only when the elements
- // are guaranteed to be non-null.
+ // are guaranteed to be null.
static <E> ImmutableList<E> unsafeDelegateList(List<? extends E> list) {
switch (list.size()) {
case 0:
@@ -179,14 +202,8 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
}
}
- /**
- * Views the array as an immutable list. The array must have only {@code E} elements.
- *
- * <p>The array must be internally created.
- */
- @SuppressWarnings("unchecked") // caller is reponsible for getting this right
- static <E> ImmutableList<E> asImmutableList(Object[] elements) {
- return unsafeDelegateList((List) Arrays.asList(elements));
+ static <E> ImmutableList<E> backedBy(E[] elements) {
+ return unsafeDelegateList(Arrays.asList(elements));
}
private static <E> List<E> nullCheckedList(Object... array) {
@@ -200,14 +217,12 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
return Arrays.asList(castedArray);
}
- @Override
public int indexOf(@Nullable Object object) {
- return (object == null) ? -1 : Lists.indexOfImpl(this, object);
+ return delegate.indexOf(object);
}
- @Override
public int lastIndexOf(@Nullable Object object) {
- return (object == null) ? -1 : Lists.lastIndexOfImpl(this, object);
+ return delegate.lastIndexOf(object);
}
public final boolean addAll(int index, Collection<? extends E> newElements) {
@@ -226,45 +241,44 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
throw new UnsupportedOperationException();
}
- @Override public UnmodifiableIterator<E> iterator() {
- return listIterator();
+ public E get(int index) {
+ return delegate.get(index);
}
- @Override public ImmutableList<E> subList(int fromIndex, int toIndex) {
- return unsafeDelegateList(Lists.subListImpl(this, fromIndex, toIndex));
+ public ImmutableList<E> subList(int fromIndex, int toIndex) {
+ return unsafeDelegateList(delegate.subList(fromIndex, toIndex));
}
- @Override public UnmodifiableListIterator<E> listIterator() {
- return listIterator(0);
+ public ListIterator<E> listIterator() {
+ return delegate.listIterator();
}
- @Override public UnmodifiableListIterator<E> listIterator(int index) {
- return new AbstractIndexedListIterator<E>(size(), index) {
- @Override
- protected E get(int index) {
- return ImmutableList.this.get(index);
- }
- };
+ public ListIterator<E> listIterator(int index) {
+ return delegate.listIterator(index);
}
@Override public ImmutableList<E> asList() {
return this;
}
+
+ public ImmutableList<E> reverse(){
+ List<E> list = Lists.newArrayList(this);
+ Collections.reverse(list);
+ return unsafeDelegateList(list);
+ }
- @Override
- public boolean equals(@Nullable Object obj) {
- return Lists.equalsImpl(this, obj);
+ @Override public Object[] toArray() {
+ // Note that ArrayList.toArray() doesn't work here because it returns E[]
+ // instead of Object[].
+ return delegate.toArray(new Object[size()]);
}
- @Override
- public int hashCode() {
- return Lists.hashCodeImpl(this);
+ @Override public boolean equals(Object obj) {
+ return delegate.equals(obj);
}
- public ImmutableList<E> reverse() {
- List<E> list = Lists.newArrayList(this);
- Collections.reverse(list);
- return unsafeDelegateList(list);
+ @Override public int hashCode() {
+ return delegate.hashCode();
}
public static <E> Builder<E> builder() {
@@ -272,15 +286,9 @@ public abstract class ImmutableList<E> extends ImmutableCollection<E>
}
public static final class Builder<E> extends ImmutableCollection.Builder<E> {
- private final ArrayList<E> contents;
+ private final ArrayList<E> contents = Lists.newArrayList();
- public Builder() {
- contents = Lists.newArrayList();
- }
-
- Builder(int capacity) {
- contents = Lists.newArrayListWithCapacity(capacity);
- }
+ public Builder() {}
@Override public Builder<E> add(E element) {
contents.add(checkNotNull(element));
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableListMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableListMultimap.java
index 5803848..fe445d9 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableListMultimap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableListMultimap.java
@@ -16,6 +16,7 @@
package com.google.common.collect;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
@@ -40,10 +41,6 @@ import javax.annotation.Nullable;
* it has no public or protected constructors. Thus, instances of this class
* are guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
*/
@@ -195,7 +192,7 @@ public class ImmutableListMultimap<K, V>
*
* @since 8.0
*/
- @Override
+ @Beta @Override
public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
super.orderKeysBy(keyComparator);
return this;
@@ -206,7 +203,7 @@ public class ImmutableListMultimap<K, V>
*
* @since 8.0
*/
- @Override
+ @Beta @Override
public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
super.orderValuesBy(valueComparator);
return this;
@@ -286,14 +283,13 @@ public class ImmutableListMultimap<K, V>
/**
* {@inheritDoc}
*
- * <p>Because an inverse of a list multimap can contain multiple pairs with
- * the same key and value, this method returns an {@code
- * ImmutableListMultimap} rather than the {@code ImmutableMultimap} specified
- * in the {@code ImmutableMultimap} class.
+ * <p>Because an inverse of a list multimap can contain multiple pairs with the same key and
+ * value, this method returns an {@code ImmutableListMultimap} rather than the
+ * {@code ImmutableMultimap} specified in the {@code ImmutableMultimap} class.
*
- * @since 11.0
+ * @since 11
*/
- @Override
+ @Beta
public ImmutableListMultimap<V, K> inverse() {
ImmutableListMultimap<V, K> result = inverse;
return (result == null) ? (inverse = invert()) : result;
@@ -313,9 +309,8 @@ public class ImmutableListMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public ImmutableList<V> removeAll(Object key) {
+ @Override public ImmutableList<V> removeAll(Object key) {
throw new UnsupportedOperationException();
}
@@ -323,9 +318,8 @@ public class ImmutableListMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public ImmutableList<V> replaceValues(
+ @Override public ImmutableList<V> replaceValues(
K key, Iterable<? extends V> values) {
throw new UnsupportedOperationException();
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMap.java
index 410538c..84896b5 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMap.java
@@ -21,10 +21,9 @@ import static com.google.common.collect.Iterables.getOnlyElement;
import java.io.Serializable;
import java.util.Collections;
-import java.util.EnumMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import javax.annotation.Nullable;
@@ -40,15 +39,39 @@ import javax.annotation.Nullable;
* @author Hayward Chan
*/
public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
+
+ private transient final Map<K, V> delegate;
- ImmutableMap() {}
+ ImmutableMap() {
+ this.delegate = Collections.emptyMap();
+ }
+
+ ImmutableMap(Map<? extends K, ? extends V> delegate) {
+ this.delegate = Collections.unmodifiableMap(delegate);
+ }
+
+ @SuppressWarnings("unchecked")
+ ImmutableMap(Entry<? extends K, ? extends V>... entries) {
+ Map<K, V> delegate = Maps.newLinkedHashMap();
+ for (Entry<? extends K, ? extends V> entry : entries) {
+ K key = checkNotNull(entry.getKey());
+ V previous = delegate.put(key, checkNotNull(entry.getValue()));
+ if (previous != null) {
+ throw new IllegalArgumentException("duplicate key: " + key);
+ }
+ }
+ this.delegate = Collections.unmodifiableMap(delegate);
+ }
+ // Casting to any type is safe because the set will never hold any elements.
+ @SuppressWarnings("unchecked")
public static <K, V> ImmutableMap<K, V> of() {
- return ImmutableBiMap.of();
+ return (ImmutableMap<K, V>) EmptyImmutableMap.INSTANCE;
}
public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
- return ImmutableBiMap.of(k1, v1);
+ return new SingletonImmutableMap<K, V>(
+ checkNotNull(k1), checkNotNull(v1));
}
public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) {
@@ -94,7 +117,7 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
}
public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
- if (entry instanceof ImmutableEntry) {
+ if (entry instanceof ImmutableEntry<?, ?>) {
checkNotNull(entry.getKey());
checkNotNull(entry.getValue());
@SuppressWarnings("unchecked") // all supported methods are covariant
@@ -125,7 +148,8 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
return of();
case 1:
Entry<K, V> entry = getOnlyElement(entries);
- return of(entry.getKey(), entry.getValue());
+ return new SingletonImmutableMap<K, V>(
+ entry.getKey(), entry.getValue());
default:
@SuppressWarnings("unchecked")
Entry<K, V>[] entryArray
@@ -141,16 +165,6 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
@SuppressWarnings("unchecked") // safe since map is not writable
ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
return kvMap;
- } else if (map instanceof EnumMap) {
- EnumMap<?, ?> enumMap = (EnumMap<?, ?>) map;
- for (Map.Entry<?, ?> entry : enumMap.entrySet()) {
- checkNotNull(entry.getKey());
- checkNotNull(entry.getValue());
- }
- @SuppressWarnings("unchecked")
- // immutable collections are safe for covariant casts
- ImmutableMap<K, V> result = ImmutableEnumMap.asImmutable(new EnumMap(enumMap));
- return result;
}
int size = map.size();
@@ -170,8 +184,10 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
return new RegularImmutableMap<K, V>(orderPreservingCopy);
}
}
-
- abstract boolean isPartialView();
+
+ boolean isPartialView(){
+ return false;
+ }
public final V put(K k, V v) {
throw new UnsupportedOperationException();
@@ -189,19 +205,20 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
throw new UnsupportedOperationException();
}
- @Override
- public boolean isEmpty() {
- return size() == 0;
+ public final boolean isEmpty() {
+ return delegate.isEmpty();
}
- @Override
- public boolean containsKey(@Nullable Object key) {
- return get(key) != null;
+ public final boolean containsKey(@Nullable Object key) {
+ return Maps.safeContainsKey(delegate, key);
}
- @Override
- public boolean containsValue(@Nullable Object value) {
- return value != null && Maps.containsValueImpl(this, value);
+ public final boolean containsValue(@Nullable Object value) {
+ return delegate.containsValue(value);
+ }
+
+ public final V get(@Nullable Object key) {
+ return (key == null) ? null : Maps.safeGet(delegate, key);
}
private transient ImmutableSet<Entry<K, V>> cachedEntrySet = null;
@@ -210,22 +227,41 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
if (cachedEntrySet != null) {
return cachedEntrySet;
}
- return cachedEntrySet = createEntrySet();
+ return cachedEntrySet = ImmutableSet.unsafeDelegate(
+ new ForwardingSet<Entry<K, V>>() {
+ @Override protected Set<Entry<K, V>> delegate() {
+ return delegate.entrySet();
+ }
+ @Override public boolean contains(Object object) {
+ if (object instanceof Entry<?, ?>
+ && ((Entry<?, ?>) object).getKey() == null) {
+ return false;
+ }
+ try {
+ return super.contains(object);
+ } catch (ClassCastException e) {
+ return false;
+ }
+ }
+ @Override public <T> T[] toArray(T[] array) {
+ T[] result = super.toArray(array);
+ if (size() < result.length) {
+ // It works around a GWT bug where elements after last is not
+ // properly null'ed.
+ result[size()] = null;
+ }
+ return result;
+ }
+ });
}
- abstract ImmutableSet<Entry<K, V>> createEntrySet();
-
private transient ImmutableSet<K> cachedKeySet = null;
public ImmutableSet<K> keySet() {
if (cachedKeySet != null) {
return cachedKeySet;
}
- return cachedKeySet = createKeySet();
- }
-
- ImmutableSet<K> createKeySet() {
- return new ImmutableMapKeySet<K, V>(this);
+ return cachedKeySet = ImmutableSet.unsafeDelegate(delegate.keySet());
}
private transient ImmutableCollection<V> cachedValues = null;
@@ -234,102 +270,22 @@ public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
if (cachedValues != null) {
return cachedValues;
}
- return cachedValues = createValues();
- }
-
- // esnickell is editing here
-
- // cached so that this.multimapView().inverse() only computes inverse once
- private transient ImmutableSetMultimap<K, V> multimapView;
-
- public ImmutableSetMultimap<K, V> asMultimap() {
- ImmutableSetMultimap<K, V> result = multimapView;
- return (result == null) ? (multimapView = createMultimapView()) : result;
- }
-
- private ImmutableSetMultimap<K, V> createMultimapView() {
- ImmutableMap<K, ImmutableSet<V>> map = viewValuesAsImmutableSet();
- return new ImmutableSetMultimap<K, V>(map, map.size(), null);
- }
-
- private ImmutableMap<K, ImmutableSet<V>> viewValuesAsImmutableSet() {
- final Map<K, V> outer = this;
- return new ImmutableMap<K, ImmutableSet<V>>() {
- @Override
- public int size() {
- return outer.size();
- }
-
- @Override
- public ImmutableSet<V> get(@Nullable Object key) {
- V outerValue = outer.get(key);
- return outerValue == null ? null : ImmutableSet.of(outerValue);
- }
-
- @Override
- ImmutableSet<Entry<K, ImmutableSet<V>>> createEntrySet() {
- return new ImmutableSet<Entry<K, ImmutableSet<V>>>() {
- @Override
- public UnmodifiableIterator<Entry<K, ImmutableSet<V>>> iterator() {
- final Iterator<Entry<K,V>> outerEntryIterator = outer.entrySet().iterator();
- return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() {
- @Override
- public boolean hasNext() {
- return outerEntryIterator.hasNext();
- }
-
- @Override
- public Entry<K, ImmutableSet<V>> next() {
- final Entry<K, V> outerEntry = outerEntryIterator.next();
- return new AbstractMapEntry<K, ImmutableSet<V>>() {
- @Override
- public K getKey() {
- return outerEntry.getKey();
- }
-
- @Override
- public ImmutableSet<V> getValue() {
- return ImmutableSet.of(outerEntry.getValue());
- }
- };
- }
- };
- }
-
- @Override
- boolean isPartialView() {
- return false;
- }
-
- @Override
- public int size() {
- return outer.size();
- }
- };
- }
-
- @Override
- boolean isPartialView() {
- return false;
- }
- };
+ return cachedValues = ImmutableCollection.unsafeDelegate(delegate.values());
}
- ImmutableCollection<V> createValues() {
- return new ImmutableMapValues<K, V>(this);
+ public int size() {
+ return delegate.size();
}
@Override public boolean equals(@Nullable Object object) {
- return Maps.equalsImpl(this, object);
+ return delegate.equals(object);
}
@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();
+ return delegate.hashCode();
}
@Override public String toString() {
- return Maps.toStringImpl(this);
+ return delegate.toString();
}
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapEntrySet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapEntrySet.java
deleted file mode 100644
index 7a5e580..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapEntrySet.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Map.Entry;
-
-import javax.annotation.Nullable;
-
-/**
- * {@code entrySet()} implementation for {@link ImmutableMap}.
- *
- * @author Jesse Wilson
- * @author Kevin Bourrillion
- */
-@GwtCompatible(emulated = true)
-abstract class ImmutableMapEntrySet<K, V> extends ImmutableSet<Entry<K, V>> {
- ImmutableMapEntrySet() {}
-
- abstract ImmutableMap<K, V> map();
-
- @Override
- public int size() {
- return map().size();
- }
-
- @Override
- public boolean contains(@Nullable Object object) {
- if (object instanceof Entry) {
- Entry<?, ?> entry = (Entry<?, ?>) object;
- V value = map().get(entry.getKey());
- return value != null && value.equals(entry.getValue());
- }
- return false;
- }
-
- @Override
- boolean isPartialView() {
- return map().isPartialView();
- }
-}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapKeySet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapKeySet.java
deleted file mode 100644
index 78508f4..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapKeySet.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Map.Entry;
-
-import javax.annotation.Nullable;
-
-/**
- * {@code keySet()} implementation for {@link ImmutableMap}.
- *
- * @author Jesse Wilson
- * @author Kevin Bourrillion
- */
-@GwtCompatible(emulated = true)
-final class ImmutableMapKeySet<K, V> extends ImmutableSet<K> {
- private final ImmutableMap<K, V> map;
-
- ImmutableMapKeySet(ImmutableMap<K, V> map) {
- this.map = map;
- }
-
- @Override
- public int size() {
- return map.size();
- }
-
- @Override
- public UnmodifiableIterator<K> iterator() {
- return asList().iterator();
- }
-
- @Override
- public boolean contains(@Nullable Object object) {
- return map.containsKey(object);
- }
-
- @Override
- ImmutableList<K> createAsList() {
- final ImmutableList<Entry<K, V>> entryList = map.entrySet().asList();
- return new ImmutableAsList<K>() {
-
- @Override
- public K get(int index) {
- return entryList.get(index).getKey();
- }
-
- @Override
- ImmutableCollection<K> delegateCollection() {
- return ImmutableMapKeySet.this;
- }
-
- };
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
-}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapValues.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapValues.java
deleted file mode 100644
index ccf4b7d..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMapValues.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Map.Entry;
-
-/**
- * {@code values()} implementation for {@link ImmutableMap}.
- *
- * @author Jesse Wilson
- * @author Kevin Bourrillion
- */
-@GwtCompatible(emulated = true)
-final class ImmutableMapValues<K, V> extends ImmutableCollection<V> {
- private final ImmutableMap<K, V> map;
-
- ImmutableMapValues(ImmutableMap<K, V> map) {
- this.map = map;
- }
-
- @Override
- public int size() {
- return map.size();
- }
-
- @Override
- public UnmodifiableIterator<V> iterator() {
- return Maps.valueIterator(map.entrySet().iterator());
- }
-
- @Override
- public boolean contains(Object object) {
- return map.containsValue(object);
- }
-
- @Override
- boolean isPartialView() {
- return true;
- }
-
- @Override
- ImmutableList<V> createAsList() {
- final ImmutableList<Entry<K, V>> entryList = map.entrySet().asList();
- return new ImmutableAsList<V>() {
- @Override
- public V get(int index) {
- return entryList.get(index).getValue();
- }
-
- @Override
- ImmutableCollection<V> delegateCollection() {
- return ImmutableMapValues.this;
- }
- };
- }
-}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMultimap.java
index f02ea43..a971129 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMultimap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableMultimap.java
@@ -18,8 +18,8 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Function;
import java.io.Serializable;
import java.util.Arrays;
@@ -29,9 +29,8 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
+import java.util.TreeMap;
import javax.annotation.Nullable;
@@ -53,16 +52,13 @@ import javax.annotation.Nullable;
* <p>In addition to methods defined by {@link Multimap}, an {@link #inverse}
* method is also supported.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(emulated = true)
-public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
- implements Serializable {
+// TODO(user): If BiMultimap graduates from labs, this class should implement it.
+public abstract class ImmutableMultimap<K, V>
+ implements Multimap<K, V>, Serializable {
/** Returns an empty multimap. */
public static <K, V> ImmutableMultimap<K, V> of() {
@@ -122,7 +118,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* value orderings, allows duplicate values, and performs better than
* {@link LinkedListMultimap}.
*/
- private static class BuilderMultimap<K, V> extends AbstractMapBasedMultimap<K, V> {
+ private static class BuilderMultimap<K, V> extends AbstractMultimap<K, V> {
BuilderMultimap() {
super(new LinkedHashMap<K, Collection<V>>());
}
@@ -133,6 +129,23 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
}
/**
+ * Multimap for {@link ImmutableMultimap.Builder} that sorts key and allows
+ * duplicate values,
+ */
+ private static class SortedKeyBuilderMultimap<K, V>
+ extends AbstractMultimap<K, V> {
+ SortedKeyBuilderMultimap(
+ Comparator<? super K> keyComparator, Multimap<K, V> multimap) {
+ super(new TreeMap<K, Collection<V>>(keyComparator));
+ putAll(multimap);
+ }
+ @Override Collection<V> createCollection() {
+ return Lists.newArrayList();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
* A builder for creating immutable multimap instances, especially
* {@code public static final} multimaps ("constant multimaps"). Example:
* <pre> {@code
@@ -152,7 +165,6 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*/
public static class Builder<K, V> {
Multimap<K, V> builderMultimap = new BuilderMultimap<K, V>();
- Comparator<? super K> keyComparator;
Comparator<? super V> valueComparator;
/**
@@ -227,8 +239,10 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*
* @since 8.0
*/
+ @Beta
public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
- this.keyComparator = checkNotNull(keyComparator);
+ builderMultimap = new SortedKeyBuilderMultimap<K, V>(
+ checkNotNull(keyComparator), builderMultimap);
return this;
}
@@ -237,6 +251,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*
* @since 8.0
*/
+ @Beta
public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
this.valueComparator = checkNotNull(valueComparator);
return this;
@@ -252,23 +267,6 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
Collections.sort(list, valueComparator);
}
}
- if (keyComparator != null) {
- Multimap<K, V> sortedCopy = new BuilderMultimap<K, V>();
- List<Map.Entry<K, Collection<V>>> entries = Lists.newArrayList(
- builderMultimap.asMap().entrySet());
- Collections.sort(
- entries,
- Ordering.from(keyComparator).onResultOf(new Function<Entry<K, Collection<V>>, K>() {
- @Override
- public K apply(Entry<K, Collection<V>> entry) {
- return entry.getKey();
- }
- }));
- for (Map.Entry<K, Collection<V>> entry : entries) {
- sortedCopy.putAll(entry.getKey(), entry.getValue());
- }
- builderMultimap = sortedCopy;
- }
return copyOf(builderMultimap);
}
}
@@ -317,9 +315,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public ImmutableCollection<V> removeAll(Object key) {
throw new UnsupportedOperationException();
@@ -329,9 +325,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public ImmutableCollection<V> replaceValues(K key,
Iterable<? extends V> values) {
@@ -342,9 +336,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public void clear() {
throw new UnsupportedOperationException();
@@ -364,17 +356,16 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* key-value mapping in the original, the result will have a mapping with
* key and value reversed.
*
- * @since 11.0
+ * @since 11
*/
+ @Beta
public abstract ImmutableMultimap<V, K> inverse();
/**
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public boolean put(K key, V value) {
throw new UnsupportedOperationException();
@@ -384,9 +375,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public boolean putAll(K key, Iterable<? extends V> values) {
throw new UnsupportedOperationException();
@@ -396,9 +385,7 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
throw new UnsupportedOperationException();
@@ -408,30 +395,65 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated
@Override
public boolean remove(Object key, Object value) {
throw new UnsupportedOperationException();
}
- boolean isPartialView() {
+ boolean isPartialView(){
return map.isPartialView();
}
// accessors
@Override
+ public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
+ Collection<V> values = map.get(key);
+ return values != null && values.contains(value);
+ }
+
+ @Override
public boolean containsKey(@Nullable Object key) {
return map.containsKey(key);
}
@Override
+ public boolean containsValue(@Nullable Object value) {
+ for (Collection<V> valueCollection : map.values()) {
+ if (valueCollection.contains(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ @Override
public int size() {
return size;
}
+ @Override public boolean equals(@Nullable Object object) {
+ if (object instanceof Multimap) {
+ Multimap<?, ?> that = (Multimap<?, ?>) object;
+ return this.map.equals(that.asMap());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return map.hashCode();
+ }
+
+ @Override public String toString() {
+ return map.toString();
+ }
+
// views
/**
@@ -453,11 +475,8 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
public ImmutableMap<K, Collection<V>> asMap() {
return (ImmutableMap) map;
}
-
- @Override
- Map<K, Collection<V>> createAsMap() {
- throw new AssertionError("should never be called");
- }
+
+ private transient ImmutableCollection<Entry<K, V>> entries;
/**
* Returns an immutable collection of all key-value pairs in the multimap. Its
@@ -466,12 +485,9 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*/
@Override
public ImmutableCollection<Entry<K, V>> entries() {
- return (ImmutableCollection<Entry<K, V>>) super.entries();
- }
-
- @Override
- ImmutableCollection<Entry<K, V>> createEntries() {
- return new EntryCollection<K, V>(this);
+ ImmutableCollection<Entry<K, V>> result = entries;
+ return (result == null)
+ ? (entries = new EntryCollection<K, V>(this)) : result;
}
private static class EntryCollection<K, V>
@@ -483,7 +499,30 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
}
@Override public UnmodifiableIterator<Entry<K, V>> iterator() {
- return multimap.entryIterator();
+ final Iterator<? extends Entry<K, ? extends ImmutableCollection<V>>>
+ mapIterator = this.multimap.map.entrySet().iterator();
+
+ return new UnmodifiableIterator<Entry<K, V>>() {
+ K key;
+ Iterator<V> valueIterator;
+
+ @Override
+ public boolean hasNext() {
+ return (key != null && valueIterator.hasNext())
+ || mapIterator.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ if (key == null || !valueIterator.hasNext()) {
+ Entry<K, ? extends ImmutableCollection<V>> entry
+ = mapIterator.next();
+ key = entry.getKey();
+ valueIterator = entry.getValue().iterator();
+ }
+ return Maps.immutableEntry(key, valueIterator.next());
+ }
+ };
}
@Override boolean isPartialView() {
@@ -505,34 +544,8 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
private static final long serialVersionUID = 0;
}
-
- @Override
- UnmodifiableIterator<Entry<K, V>> entryIterator() {
- final Iterator<? extends Entry<K, ? extends ImmutableCollection<V>>>
- mapIterator = map.entrySet().iterator();
-
- return new UnmodifiableIterator<Entry<K, V>>() {
- K key;
- Iterator<V> valueIterator;
-
- @Override
- public boolean hasNext() {
- return (key != null && valueIterator.hasNext())
- || mapIterator.hasNext();
- }
- @Override
- public Entry<K, V> next() {
- if (key == null || !valueIterator.hasNext()) {
- Entry<K, ? extends ImmutableCollection<V>> entry
- = mapIterator.next();
- key = entry.getKey();
- valueIterator = entry.getValue().iterator();
- }
- return Maps.immutableEntry(key, valueIterator.next());
- }
- };
- }
+ private transient ImmutableMultiset<K> keys;
/**
* Returns a collection, which may contain duplicates, of all keys. The number
@@ -542,78 +555,21 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*/
@Override
public ImmutableMultiset<K> keys() {
- return (ImmutableMultiset<K>) super.keys();
+ ImmutableMultiset<K> result = keys;
+ return (result == null) ? (keys = createKeys()) : result;
}
- @Override
- ImmutableMultiset<K> createKeys() {
- return new Keys();
- }
-
- @SuppressWarnings("serial") // Uses writeReplace, not default serialization
- class Keys extends ImmutableMultiset<K> {
- @Override
- public boolean contains(@Nullable Object object) {
- return containsKey(object);
- }
-
- @Override
- public int count(@Nullable Object element) {
- Collection<V> values = map.get(element);
- return (values == null) ? 0 : values.size();
- }
-
- @Override
- public Set<K> elementSet() {
- return keySet();
- }
-
- @Override
- public int size() {
- return ImmutableMultimap.this.size();
- }
-
- @Override
- ImmutableSet<Entry<K>> createEntrySet() {
- return new KeysEntrySet();
- }
-
- private class KeysEntrySet extends ImmutableMultiset<K>.EntrySet {
- @Override
- public int size() {
- return keySet().size();
- }
-
- @Override
- public UnmodifiableIterator<Entry<K>> iterator() {
- return asList().iterator();
- }
-
- @Override
- ImmutableList<Entry<K>> createAsList() {
- final ImmutableList<? extends Map.Entry<K, ? extends Collection<V>>> mapEntries =
- map.entrySet().asList();
- return new ImmutableAsList<Entry<K>>() {
- @Override
- public Entry<K> get(int index) {
- Map.Entry<K, ? extends Collection<V>> entry = mapEntries.get(index);
- return Multisets.immutableEntry(entry.getKey(), entry.getValue().size());
- }
-
- @Override
- ImmutableCollection<Entry<K>> delegateCollection() {
- return KeysEntrySet.this;
- }
- };
- }
- }
-
- @Override
- boolean isPartialView() {
- return true;
+ private ImmutableMultiset<K> createKeys() {
+ ImmutableMultiset.Builder<K> builder = ImmutableMultiset.builder();
+ for (Entry<K, ? extends ImmutableCollection<V>> entry
+ : map.entrySet()) {
+ builder.addCopies(entry.getKey(), entry.getValue().size());
}
+ return builder.build();
}
+ private transient ImmutableCollection<V> values;
+
/**
* Returns an immutable collection of the values in this multimap. Its
* iterator traverses the values for the first key, the values for the second
@@ -621,12 +577,8 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
*/
@Override
public ImmutableCollection<V> values() {
- return (ImmutableCollection<V>) super.values();
- }
-
- @Override
- ImmutableCollection<V> createValues() {
- return new Values<V>(this);
+ ImmutableCollection<V> result = values;
+ return (result == null) ? (values = new Values<V>(this)) : result;
}
private static class Values<V> extends ImmutableCollection<V> {
@@ -637,7 +589,18 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
}
@Override public UnmodifiableIterator<V> iterator() {
- return Maps.valueIterator(multimap.entries().iterator());
+ final Iterator<? extends Entry<?, V>> entryIterator
+ = multimap.entries().iterator();
+ return new UnmodifiableIterator<V>() {
+ @Override
+ public boolean hasNext() {
+ return entryIterator.hasNext();
+ }
+ @Override
+ public V next() {
+ return entryIterator.next().getValue();
+ }
+ };
}
@Override
@@ -654,4 +617,3 @@ public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
private static final long serialVersionUID = 0;
}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSet.java
index 97d9dd1..26bc57f 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSet.java
@@ -37,8 +37,16 @@ import java.util.Set;
* @author Hayward Chan
*/
@SuppressWarnings("serial") // Serialization only done in GWT.
-public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements Set<E> {
- ImmutableSet() {}
+public abstract class ImmutableSet<E> extends ForwardingImmutableCollection<E>
+ implements Set<E> {
+
+ ImmutableSet(Set<E> delegate) {
+ super(Collections.unmodifiableSet(delegate));
+ }
+
+ ImmutableSet() {
+ this(Collections.<E>emptySet());
+ }
// Casting to any type is safe because the set will never hold any elements.
@SuppressWarnings({"unchecked"})
@@ -71,7 +79,8 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements
}
@SuppressWarnings("unchecked")
- public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E... others) {
+ public static <E> ImmutableSet<E> of(E e1, E e2, E e3, E e4, E e5, E e6,
+ E... others) {
int size = others.length + 6;
List<E> all = new ArrayList<E>(size);
Collections.addAll(all, e1, e2, e3, e4, e5, e6);
@@ -102,7 +111,8 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements
}
public static <E> ImmutableSet<E> copyOf(Iterable<? extends E> elements) {
- if (elements instanceof ImmutableSet && !(elements instanceof ImmutableSortedSet)) {
+ if (elements instanceof ImmutableSet
+ && !(elements instanceof ImmutableSortedSet)) {
@SuppressWarnings("unchecked") // all supported methods are covariant
ImmutableSet<E> set = (ImmutableSet<E>) elements;
return set;
@@ -165,7 +175,7 @@ public abstract class ImmutableSet<E> extends ImmutableCollection<E> implements
}
@Override public int hashCode() {
- return Sets.hashCodeImpl(this);
+ return delegate.hashCode();
}
public static <E> Builder<E> builder() {
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimap.java
index 43e701e..b5eaabf 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSetMultimap.java
@@ -18,17 +18,15 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Function;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
import java.util.Map.Entry;
+import java.util.TreeMap;
import javax.annotation.Nullable;
@@ -48,10 +46,6 @@ import javax.annotation.Nullable;
* it has no public or protected constructors. Thus, instances of this class
* are guaranteed to be immutable.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
- * immutable collections</a>.
- *
* @author Mike Ward
* @since 2.0 (imported from Google Collections Library)
*/
@@ -146,7 +140,7 @@ public class ImmutableSetMultimap<K, V>
* Multimap for {@link ImmutableSetMultimap.Builder} that maintains key
* and value orderings and performs better than {@link LinkedHashMultimap}.
*/
- private static class BuilderMultimap<K, V> extends AbstractMapBasedMultimap<K, V> {
+ private static class BuilderMultimap<K, V> extends AbstractMultimap<K, V> {
BuilderMultimap() {
super(new LinkedHashMap<K, Collection<V>>());
}
@@ -157,6 +151,23 @@ public class ImmutableSetMultimap<K, V>
}
/**
+ * Multimap for {@link ImmutableSetMultimap.Builder} that sorts keys and
+ * maintains value orderings.
+ */
+ private static class SortedKeyBuilderMultimap<K, V>
+ extends AbstractMultimap<K, V> {
+ SortedKeyBuilderMultimap(
+ Comparator<? super K> keyComparator, Multimap<K, V> multimap) {
+ super(new TreeMap<K, Collection<V>>(keyComparator));
+ putAll(multimap);
+ }
+ @Override Collection<V> createCollection() {
+ return Sets.newLinkedHashSet();
+ }
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
* A builder for creating immutable {@code SetMultimap} instances, especially
* {@code public static final} multimaps ("constant multimaps"). Example:
* <pre> {@code
@@ -181,7 +192,7 @@ public class ImmutableSetMultimap<K, V>
* generated by {@link ImmutableSetMultimap#builder}.
*/
public Builder() {
- builderMultimap = new BuilderMultimap<K, V>();
+ builderMultimap = new BuilderMultimap<K, V>();
}
/**
@@ -230,25 +241,26 @@ public class ImmutableSetMultimap<K, V>
*
* @since 8.0
*/
- @Override
+ @Beta @Override
public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
- this.keyComparator = checkNotNull(keyComparator);
+ builderMultimap = new SortedKeyBuilderMultimap<K, V>(
+ checkNotNull(keyComparator), builderMultimap);
return this;
}
/**
* Specifies the ordering of the generated multimap's values for each key.
- *
- * <p>If this method is called, the sets returned by the {@code get()}
+ *
+ * <p>If this method is called, the sets returned by the {@code get()}
* method of the generated multimap and its {@link Multimap#asMap()} view
* are {@link ImmutableSortedSet} instances. However, serialization does not
* preserve that property, though it does maintain the key and value
* ordering.
- *
+ *
* @since 8.0
*/
// TODO: Make serialization behavior consistent.
- @Override
+ @Beta @Override
public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
super.orderValuesBy(valueComparator);
return this;
@@ -258,23 +270,6 @@ public class ImmutableSetMultimap<K, V>
* Returns a newly-created immutable set multimap.
*/
@Override public ImmutableSetMultimap<K, V> build() {
- if (keyComparator != null) {
- Multimap<K, V> sortedCopy = new BuilderMultimap<K, V>();
- List<Map.Entry<K, Collection<V>>> entries = Lists.newArrayList(
- builderMultimap.asMap().entrySet());
- Collections.sort(
- entries,
- Ordering.from(keyComparator).onResultOf(new Function<Entry<K, Collection<V>>, K>() {
- @Override
- public K apply(Entry<K, Collection<V>> entry) {
- return entry.getKey();
- }
- }));
- for (Map.Entry<K, Collection<V>> entry : entries) {
- sortedCopy.putAll(entry.getKey(), entry.getValue());
- }
- builderMultimap = sortedCopy;
- }
return copyOf(builderMultimap, valueComparator);
}
}
@@ -297,7 +292,7 @@ public class ImmutableSetMultimap<K, V>
Multimap<? extends K, ? extends V> multimap) {
return copyOf(multimap, null);
}
-
+
private static <K, V> ImmutableSetMultimap<K, V> copyOf(
Multimap<? extends K, ? extends V> multimap,
Comparator<? super V> valueComparator) {
@@ -323,7 +318,7 @@ public class ImmutableSetMultimap<K, V>
K key = entry.getKey();
Collection<? extends V> values = entry.getValue();
ImmutableSet<V> set = (valueComparator == null)
- ? ImmutableSet.copyOf(values)
+ ? ImmutableSet.copyOf(values)
: ImmutableSortedSet.copyOf(valueComparator, values);
if (!set.isEmpty()) {
builder.put(key, set);
@@ -338,10 +333,10 @@ public class ImmutableSetMultimap<K, V>
// Returned by get() when values are sorted and a missing key is provided.
private final transient ImmutableSortedSet<V> emptySet;
- ImmutableSetMultimap(ImmutableMap<K, ImmutableSet<V>> map, int size,
+ ImmutableSetMultimap(ImmutableMap<K, ImmutableSet<V>> map, int size,
@Nullable Comparator<? super V> valueComparator) {
super(map, size);
- this.emptySet = (valueComparator == null)
+ this.emptySet = (valueComparator == null)
? null : ImmutableSortedSet.<V>emptySet(valueComparator);
}
@@ -370,13 +365,13 @@ public class ImmutableSetMultimap<K, V>
/**
* {@inheritDoc}
*
- * <p>Because an inverse of a set multimap cannot contain multiple pairs with
- * the same key and value, this method returns an {@code ImmutableSetMultimap}
- * rather than the {@code ImmutableMultimap} specified in the {@code
- * ImmutableMultimap} class.
+ * <p>Because an inverse of a set multimap cannot contain multiple pairs with the same key and
+ * value, this method returns an {@code ImmutableSetMultimap} rather than the
+ * {@code ImmutableMultimap} specified in the {@code ImmutableMultimap} class.
*
- * @since 11.0
+ * @since 11
*/
+ @Beta
public ImmutableSetMultimap<V, K> inverse() {
ImmutableSetMultimap<V, K> result = inverse;
return (result == null) ? (inverse = invert()) : result;
@@ -396,9 +391,8 @@ public class ImmutableSetMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public ImmutableSet<V> removeAll(Object key) {
+ @Override public ImmutableSet<V> removeAll(Object key) {
throw new UnsupportedOperationException();
}
@@ -406,9 +400,8 @@ public class ImmutableSetMultimap<K, V>
* Guaranteed to throw an exception and leave the multimap unmodified.
*
* @throws UnsupportedOperationException always
- * @deprecated Unsupported operation.
*/
- @Deprecated @Override public ImmutableSet<V> replaceValues(
+ @Override public ImmutableSet<V> replaceValues(
K key, Iterable<? extends V> values) {
throw new UnsupportedOperationException();
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedAsList.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedAsList.java
deleted file mode 100644
index c94e88e..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedAsList.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2009 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.util.Comparator;
-
-/**
- * List returned by {@code ImmutableSortedSet.asList()} when the set isn't empty.
- *
- * @author Jared Levy
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-@SuppressWarnings("serial")
-final class ImmutableSortedAsList<E> extends RegularImmutableAsList<E>
- implements SortedIterable<E> {
- ImmutableSortedAsList(
- ImmutableSortedSet<E> backingSet, ImmutableList<E> backingList) {
- super(backingSet, backingList);
- }
-
- @Override
- ImmutableSortedSet<E> delegateCollection() {
- return (ImmutableSortedSet<E>) super.delegateCollection();
- }
-
- @Override public Comparator<? super E> comparator() {
- return delegateCollection().comparator();
- }
-
- // Override indexOf() and lastIndexOf() to be O(log N) instead of O(N).
-
- @Override
- public boolean contains(Object target) {
- // Necessary for ISS's with comparators inconsistent with equals.
- return indexOf(target) >= 0;
- }
-}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedMap.java
index 19139d1..89624d8 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedMap.java
@@ -18,11 +18,10 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Maps.newTreeMap;
-import static java.util.Collections.unmodifiableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
+import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
@@ -34,49 +33,60 @@ import java.util.SortedMap;
*
* @author Hayward Chan
*/
-public abstract class ImmutableSortedMap<K, V>
- extends ForwardingImmutableMap<K, V> implements SortedMap<K, V> {
+public class ImmutableSortedMap<K, V>
+ extends ImmutableMap<K, V> implements SortedMap<K, V> {
+
+ // TODO: Confirm that ImmutableSortedMap is faster to construct and uses less
+ // memory than TreeMap; then say so in the class Javadoc.
+
+ // TODO: Create separate subclasses for empty, single-entry, and
+ // multiple-entry instances.
+
+ @SuppressWarnings("unchecked")
+ private static final Comparator NATURAL_ORDER = Ordering.natural();
@SuppressWarnings("unchecked")
- static final Comparator NATURAL_ORDER = Ordering.natural();
+ private static final ImmutableSortedMap<Object, Object> NATURAL_EMPTY_MAP
+ = create(NATURAL_ORDER);
// This reference is only used by GWT compiler to infer the keys and values
// of the map that needs to be serialized.
- private Comparator<? super K> unusedComparatorForSerialization;
+ private Comparator<K> unusedComparatorForSerialization;
private K unusedKeyForSerialization;
private V unusedValueForSerialization;
- private final transient SortedMap<K, V> sortedDelegate;
+ private transient final SortedMap<K, V> sortedDelegate;
// The comparator used by this map. It's the same as that of sortedDelegate,
// except that when sortedDelegate's comparator is null, it points to a
// non-null instance of Ordering.natural().
- // (cpovirk: Is sortedDelegate's comparator really ever null?)
- // The comparator will likely also differ because of our nullAccepting hack.
- // See the bottom of the file for more information about it.
- private final transient Comparator<? super K> comparator;
+ private transient final Comparator<K> comparator;
- ImmutableSortedMap(SortedMap<K, V> delegate, Comparator<? super K> comparator) {
+ // If map has a null comparator, the keys should have a natural ordering,
+ // even though K doesn't explicitly implement Comparable.
+ @SuppressWarnings("unchecked")
+ ImmutableSortedMap(SortedMap<K, ? extends V> delegate) {
super(delegate);
- this.comparator = comparator;
- this.sortedDelegate = delegate;
+ this.comparator = (delegate.comparator() == null)
+ ? NATURAL_ORDER : delegate.comparator();
+ this.sortedDelegate = Collections.unmodifiableSortedMap(delegate);
}
private static <K, V> ImmutableSortedMap<K, V> create(
Comparator<? super K> comparator,
Entry<? extends K, ? extends V>... entries) {
checkNotNull(comparator);
- SortedMap<K, V> delegate = newModifiableDelegate(comparator);
+ SortedMap<K, V> delegate = Maps.newTreeMap(comparator);
for (Entry<? extends K, ? extends V> entry : entries) {
delegate.put(entry.getKey(), entry.getValue());
}
- return newView(unmodifiableSortedMap(delegate), comparator);
+ return new ImmutableSortedMap<K, V>(delegate);
}
// Casting to any type is safe because the set will never hold any elements.
@SuppressWarnings("unchecked")
public static <K, V> ImmutableSortedMap<K, V> of() {
- return EmptyImmutableSortedMap.forComparator(NATURAL_ORDER);
+ return (ImmutableSortedMap) NATURAL_EMPTY_MAP;
}
public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V>
@@ -145,11 +155,11 @@ public abstract class ImmutableSortedMap<K, V>
}
}
- SortedMap<K, V> delegate = newModifiableDelegate(comparator);
+ SortedMap<K, V> delegate = Maps.newTreeMap(comparator);
for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
putEntryWithChecks(delegate, entry);
}
- return newView(unmodifiableSortedMap(delegate), comparator);
+ return new ImmutableSortedMap<K, V>(delegate);
}
private static <K, V> void putEntryWithChecks(
@@ -169,7 +179,7 @@ public abstract class ImmutableSortedMap<K, V>
map.put(key, value);
}
- public static <K extends Comparable<?>, V> Builder<K, V> naturalOrder() {
+ public static <K extends Comparable<K>, V> Builder<K, V> naturalOrder() {
return new Builder<K, V>(Ordering.natural());
}
@@ -177,7 +187,7 @@ public abstract class ImmutableSortedMap<K, V>
return new Builder<K, V>(comparator);
}
- public static <K extends Comparable<?>, V> Builder<K, V> reverseOrder() {
+ public static <K extends Comparable<K>, V> Builder<K, V> reverseOrder() {
return new Builder<K, V>(Ordering.natural().reverse());
}
@@ -206,11 +216,11 @@ public abstract class ImmutableSortedMap<K, V>
}
@Override public ImmutableSortedMap<K, V> build() {
- SortedMap<K, V> delegate = newModifiableDelegate(comparator);
+ SortedMap<K, V> delegate = Maps.newTreeMap(comparator);
for (Entry<? extends K, ? extends V> entry : entries) {
putEntryWithChecks(delegate, entry);
}
- return newView(unmodifiableSortedMap(delegate), comparator);
+ return new ImmutableSortedMap<K, V>(delegate);
}
}
@@ -221,7 +231,7 @@ public abstract class ImmutableSortedMap<K, V>
return (ks == null) ? (keySet = createKeySet()) : ks;
}
- @Override ImmutableSortedSet<K> createKeySet() {
+ private ImmutableSortedSet<K> createKeySet() {
// the keySet() of the delegate is only a Set and TreeMap.navigatableKeySet
// is not available in GWT yet. To keep the code simple and code size more,
// we make a copy here, instead of creating a view of it.
@@ -256,7 +266,7 @@ public abstract class ImmutableSortedMap<K, V>
public ImmutableSortedMap<K, V> headMap(K toKey) {
checkNotNull(toKey);
- return newView(sortedDelegate.headMap(toKey));
+ return new ImmutableSortedMap<K, V>(sortedDelegate.headMap(toKey));
}
ImmutableSortedMap<K, V> headMap(K toKey, boolean inclusive) {
@@ -275,7 +285,7 @@ public abstract class ImmutableSortedMap<K, V>
checkNotNull(fromKey);
checkNotNull(toKey);
checkArgument(comparator.compare(fromKey, toKey) <= 0);
- return newView(sortedDelegate.subMap(fromKey, toKey));
+ return new ImmutableSortedMap<K, V>(sortedDelegate.subMap(fromKey, toKey));
}
ImmutableSortedMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive){
@@ -284,10 +294,10 @@ public abstract class ImmutableSortedMap<K, V>
checkArgument(comparator.compare(fromKey, toKey) <= 0);
return tailMap(fromKey, fromInclusive).headMap(toKey, toInclusive);
}
-
+
public ImmutableSortedMap<K, V> tailMap(K fromKey) {
checkNotNull(fromKey);
- return newView(sortedDelegate.tailMap(fromKey));
+ return new ImmutableSortedMap<K, V>(sortedDelegate.tailMap(fromKey));
}
public ImmutableSortedMap<K, V> tailMap(K fromKey, boolean inclusive) {
@@ -295,42 +305,16 @@ public abstract class ImmutableSortedMap<K, V>
if (!inclusive) {
fromKey = higher(fromKey);
if (fromKey == null) {
- return EmptyImmutableSortedMap.forComparator(comparator());
+ return emptyMap(comparator());
}
}
return tailMap(fromKey);
}
- private ImmutableSortedMap<K, V> newView(SortedMap<K, V> delegate) {
- return newView(delegate, comparator);
- }
-
- private static <K, V> ImmutableSortedMap<K, V> newView(
- SortedMap<K, V> delegate, Comparator<? super K> comparator) {
- if (delegate.isEmpty()) {
- return EmptyImmutableSortedMap.forComparator(comparator);
+ static <K, V> ImmutableSortedMap<K, V> emptyMap(Comparator<? super K> comparator) {
+ if (comparator == NATURAL_ORDER) {
+ return (ImmutableSortedMap) NATURAL_EMPTY_MAP;
}
- return new RegularImmutableSortedMap<K, V>(delegate, comparator);
- }
-
- /*
- * We don't permit nulls, but we wrap every comparator with nullsFirst().
- * Why? We want for queries like containsKey(null) to return false, but the
- * GWT SortedMap implementation that we delegate to throws
- * NullPointerException if the comparator does. Since our construction
- * methods ensure that null is never present in the map, it's OK for the
- * comparator to look for it wherever it wants.
- *
- * Note that we do NOT touch the comparator returned by comparator(), which
- * should be identical to the one the user passed in. We touch only the
- * "secret" comparator used by the delegate implementation.
- */
-
- private static <K, V> SortedMap<K, V> newModifiableDelegate(Comparator<? super K> comparator) {
- return newTreeMap(nullAccepting(comparator));
- }
-
- private static <E> Comparator<E> nullAccepting(Comparator<E> comparator) {
- return Ordering.from(comparator).nullsFirst();
+ return create(comparator);
}
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedSet.java
index c3cb7aa..cfb1da2 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ImmutableSortedSet.java
@@ -16,8 +16,8 @@
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.checkArgument;
import java.util.ArrayList;
import java.util.Collection;
@@ -36,8 +36,7 @@ import javax.annotation.Nullable;
* @author Hayward Chan
*/
public abstract class ImmutableSortedSet<E>
- extends ForwardingImmutableSet<E> implements SortedSet<E>, SortedIterable<E> {
- // TODO(cpovirk): split into ImmutableSortedSet/ForwardingImmutableSortedSet?
+ extends ImmutableSet<E> implements SortedSet<E>, SortedIterable<E> {
// In the non-emulated source, this is in ImmutableSortedSetFauxverideShim,
// which overrides ImmutableSet & which ImmutableSortedSet extends.
@@ -247,19 +246,6 @@ public abstract class ImmutableSortedSet<E>
private transient final SortedSet<E> sortedDelegate;
- /**
- * Scary constructor for ContiguousSet. This constructor (in this file, the
- * GWT emulation of ImmutableSortedSet) creates an empty sortedDelegate,
- * which, in a vacuum, sets this object's contents to empty. By contrast,
- * the non-GWT constructor with the same signature uses the comparator only
- * as a comparator. It does NOT assume empty contents. (It requires an
- * implementation of iterator() to define its contents, and methods like
- * contains() are implemented in terms of that method (though they will
- * likely be overridden by subclasses for performance reasons).) This means
- * that a call to this method have can different behavior in GWT and non-GWT
- * environments UNLESS subclasses are careful to always override all methods
- * implemented in terms of sortedDelegate (except comparator()).
- */
ImmutableSortedSet(Comparator<? super E> comparator) {
this(Sets.newTreeSet(comparator));
}
@@ -385,11 +371,11 @@ public abstract class ImmutableSortedSet<E>
return new Builder<E>(comparator);
}
- public static <E extends Comparable<?>> Builder<E> reverseOrder() {
+ public static <E extends Comparable<E>> Builder<E> reverseOrder() {
return new Builder<E>(Ordering.natural().reverse());
}
- public static <E extends Comparable<?>> Builder<E> naturalOrder() {
+ public static <E extends Comparable<E>> Builder<E> naturalOrder() {
return new Builder<E>(Ordering.natural());
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterables.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterables.java
index 330c5bf..1299a62 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterables.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterables.java
@@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Function;
+import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
@@ -48,10 +49,6 @@ import javax.annotation.Nullable;
* produced in this class are <i>lazy</i>, which means that their iterators
* only advance the backing iteration when absolutely necessary.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Iterables">
- * {@code Iterables}</a>.
- *
* @author Kevin Bourrillion
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
@@ -82,7 +79,7 @@ public final class Iterables {
return checkNotNull(iterable);
}
- private static final class UnmodifiableIterable<T> extends FluentIterable<T> {
+ private static final class UnmodifiableIterable<T> implements Iterable<T> {
private final Iterable<T> iterable;
private UnmodifiableIterable(Iterable<T> iterable) {
@@ -111,14 +108,20 @@ public final class Iterables {
}
/**
- * Returns {@code true} if {@code iterable} contains any object for which {@code equals(element)}
- * is true.
+ * Returns {@code true} if {@code iterable} contains {@code element}; that is,
+ * any object for which {@code equals(element)} is true.
*/
public static boolean contains(Iterable<?> iterable, @Nullable Object element)
{
if (iterable instanceof Collection) {
Collection<?> collection = (Collection<?>) iterable;
- return Collections2.safeContains(collection, element);
+ try {
+ return collection.contains(element);
+ } catch (NullPointerException e) {
+ return false;
+ } catch (ClassCastException e) {
+ return false;
+ }
}
return Iterators.contains(iterable.iterator(), element);
}
@@ -240,13 +243,6 @@ public final class Iterables {
*/
public static boolean elementsEqual(
Iterable<?> iterable1, Iterable<?> iterable2) {
- if (iterable1 instanceof Collection && iterable2 instanceof Collection) {
- Collection<?> collection1 = (Collection<?>) iterable1;
- Collection<?> collection2 = (Collection<?>) iterable2;
- if (collection1.size() != collection2.size()) {
- return false;
- }
- }
return Iterators.elementsEqual(iterable1.iterator(), iterable2.iterator());
}
@@ -276,9 +272,8 @@ public final class Iterables {
* @throws IllegalArgumentException if the iterator contains multiple
* elements
*/
- @Nullable
public static <T> T getOnlyElement(
- Iterable<? extends T> iterable, @Nullable T defaultValue) {
+ Iterable<T> iterable, @Nullable T defaultValue) {
return Iterators.getOnlyElement(iterable.iterator(), defaultValue);
}
@@ -355,7 +350,7 @@ public final class Iterables {
*/
public static <T> Iterable<T> cycle(final Iterable<T> iterable) {
checkNotNull(iterable);
- return new FluentIterable<T>() {
+ return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.cycle(iterable);
@@ -470,7 +465,7 @@ public final class Iterables {
public static <T> Iterable<T> concat(
final Iterable<? extends Iterable<? extends T>> inputs) {
checkNotNull(inputs);
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.concat(iterators(inputs));
@@ -521,7 +516,7 @@ public final class Iterables {
final Iterable<T> iterable, final int size) {
checkNotNull(iterable);
checkArgument(size > 0);
- return new FluentIterable<List<T>>() {
+ return new IterableWithToString<List<T>>() {
@Override
public Iterator<List<T>> iterator() {
return Iterators.partition(iterable.iterator(), size);
@@ -550,7 +545,7 @@ public final class Iterables {
final Iterable<T> iterable, final int size) {
checkNotNull(iterable);
checkArgument(size > 0);
- return new FluentIterable<List<T>>() {
+ return new IterableWithToString<List<T>>() {
@Override
public Iterator<List<T>> iterator() {
return Iterators.paddedPartition(iterable.iterator(), size);
@@ -566,7 +561,7 @@ public final class Iterables {
final Iterable<T> unfiltered, final Predicate<? super T> predicate) {
checkNotNull(unfiltered);
checkNotNull(predicate);
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.filter(unfiltered.iterator(), predicate);
@@ -575,7 +570,8 @@ public final class Iterables {
}
/**
- * Returns {@code true} if any element in {@code iterable} satisfies the predicate.
+ * Returns {@code true} if one or more elements in {@code iterable} satisfy
+ * the predicate.
*/
public static <T> boolean any(
Iterable<T> iterable, Predicate<? super T> predicate) {
@@ -594,8 +590,8 @@ public final class Iterables {
/**
* Returns the first element in {@code iterable} that satisfies the given
* predicate; use this method only when such an element is known to exist. If
- * it is possible that <i>no</i> element will match, use {@link #tryFind} or
- * {@link #find(Iterable, Predicate, Object)} instead.
+ * it is possible that <i>no</i> element will match, use {@link
+ * #tryFind)} or {@link #find(Iterable, Predicate, T)} instead.
*
* @throws NoSuchElementException if no element in {@code iterable} matches
* the given predicate
@@ -613,8 +609,7 @@ public final class Iterables {
*
* @since 7.0
*/
- @Nullable
- public static <T> T find(Iterable<? extends T> iterable,
+ public static <T> T find(Iterable<T> iterable,
Predicate<? super T> predicate, @Nullable T defaultValue) {
return Iterators.find(iterable.iterator(), predicate, defaultValue);
}
@@ -666,7 +661,7 @@ public final class Iterables {
final Function<? super F, ? extends T> function) {
checkNotNull(fromIterable);
checkNotNull(function);
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.transform(fromIterable.iterator(), function);
@@ -719,8 +714,8 @@ public final class Iterables {
* @throws IndexOutOfBoundsException if {@code position} is negative
* @since 4.0
*/
- @Nullable
- public static <T> T get(Iterable<? extends T> iterable, int position, @Nullable T defaultValue) {
+ public static <T> T get(Iterable<T> iterable, int position,
+ @Nullable T defaultValue) {
checkNotNull(iterable);
checkNonnegativeIndex(position);
@@ -736,16 +731,11 @@ public final class Iterables {
* the iterable is empty. The {@link Iterators} analog to this method is
* {@link Iterators#getNext}.
*
- * <p>If no default value is desired (and the caller instead wants a
- * {@link NoSuchElementException} to be thrown), it is recommended that
- * {@code iterable.iterator().next()} is used instead.
- *
* @param defaultValue the default value to return if the iterable is empty
* @return the first element of {@code iterable} or the default value
* @since 7.0
*/
- @Nullable
- public static <T> T getFirst(Iterable<? extends T> iterable, @Nullable T defaultValue) {
+ public static <T> T getFirst(Iterable<T> iterable, @Nullable T defaultValue) {
return Iterators.getNext(iterable.iterator(), defaultValue);
}
@@ -786,17 +776,16 @@ public final class Iterables {
* @return the last element of {@code iterable} or the default value
* @since 3.0
*/
- @Nullable
- public static <T> T getLast(Iterable<? extends T> iterable, @Nullable T defaultValue) {
+ public static <T> T getLast(Iterable<T> iterable, @Nullable T defaultValue) {
if (iterable instanceof Collection) {
- Collection<? extends T> collection = Collections2.cast(iterable);
+ Collection<T> collection = (Collection<T>) iterable;
if (collection.isEmpty()) {
return defaultValue;
}
}
if (iterable instanceof List) {
- List<? extends T> list = Lists.cast(iterable);
+ List<T> list = (List<T>) iterable;
return getLastInNonemptyList(list);
}
@@ -806,7 +795,7 @@ public final class Iterables {
* call this method.
*/
if (iterable instanceof SortedSet) {
- SortedSet<? extends T> sortedSet = Sets.cast(iterable);
+ SortedSet<T> sortedSet = (SortedSet<T>) iterable;
return sortedSet.last();
}
@@ -844,7 +833,7 @@ public final class Iterables {
if (iterable instanceof List) {
final List<T> list = (List<T>) iterable;
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
// TODO(kevinb): Support a concurrently modified collection?
@@ -855,12 +844,12 @@ public final class Iterables {
};
}
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
final Iterator<T> iterator = iterable.iterator();
- Iterators.advance(iterator, numberToSkip);
+ Iterators.skip(iterator, numberToSkip);
/*
* We can't just return the iterator because an immediate call to its
@@ -916,7 +905,7 @@ public final class Iterables {
final Iterable<T> iterable, final int limitSize) {
checkNotNull(iterable);
checkArgument(limitSize >= 0, "limit is negative");
- return new FluentIterable<T>() {
+ return new IterableWithToString<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.limit(iterable.iterator(), limitSize);
@@ -945,7 +934,7 @@ public final class Iterables {
*/
public static <T> Iterable<T> consumingIterable(final Iterable<T> iterable) {
if (iterable instanceof Queue) {
- return new FluentIterable<T>() {
+ return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return new ConsumingQueueIterator<T>((Queue<T>) iterable);
@@ -955,7 +944,7 @@ public final class Iterables {
checkNotNull(iterable);
- return new FluentIterable<T>() {
+ return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.consumingIterator(iterable.iterator());
@@ -982,6 +971,30 @@ public final class Iterables {
// Methods only in Iterables, not in Iterators
/**
+ * Adapts a list to an iterable with reversed iteration order. It is
+ * especially useful in foreach-style loops: <pre> {@code
+ *
+ * List<String> mylist = ...
+ * for (String str : Iterables.reverse(mylist)) {
+ * ...
+ * }}</pre>
+ *
+ * There is no corresponding method in {@link Iterators}, since {@link
+ * Iterable#iterator} can simply be invoked on the result of calling this
+ * method.
+ *
+ * @return an iterable with the same elements as the list, in reverse
+ *
+ * @deprecated use {@link Lists#reverse(List)} or {@link
+ * ImmutableList#reverse()}. <b>This method is scheduled for deletion in
+ * July 2012.</b>
+ */
+ @Deprecated
+ public static <T> Iterable<T> reverse(final List<T> list) {
+ return Lists.reverse(list);
+ }
+
+ /**
* Determines if the given iterable contains no elements.
*
* <p>There is no precise {@link Iterator} equivalent to this method, since
@@ -997,6 +1010,43 @@ public final class Iterables {
return !iterable.iterator().hasNext();
}
+ // Non-public
+
+ /**
+ * Removes the specified element from the specified iterable.
+ *
+ * <p>This method iterates over the iterable, checking each element returned
+ * by the iterator in turn to see if it equals the object {@code o}. If they
+ * are equal, it is removed from the iterable with the iterator's
+ * {@code remove} method. At most one element is removed, even if the iterable
+ * contains multiple members that equal {@code o}.
+ *
+ * <p><b>Warning:</b> Do not use this method for a collection, such as a
+ * {@link HashSet}, that has a fast {@code remove} method.
+ *
+ * @param iterable the iterable from which to remove
+ * @param o an element to remove from the collection
+ * @return {@code true} if the iterable changed as a result
+ * @throws UnsupportedOperationException if the iterator does not support the
+ * {@code remove} method and the iterable contains the object
+ */
+ static boolean remove(Iterable<?> iterable, @Nullable Object o) {
+ Iterator<?> i = iterable.iterator();
+ while (i.hasNext()) {
+ if (Objects.equal(i.next(), o)) {
+ i.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ abstract static class IterableWithToString<E> implements Iterable<E> {
+ @Override public String toString() {
+ return Iterables.toString(this);
+ }
+ }
+
/**
* Returns an iterable over the merged contents of all given
* {@code iterables}. Equivalent entries will not be de-duplicated.
@@ -1015,7 +1065,7 @@ public final class Iterables {
final Comparator<? super T> comparator) {
checkNotNull(iterables, "iterables");
checkNotNull(comparator, "comparator");
- Iterable<T> iterable = new FluentIterable<T>() {
+ Iterable<T> iterable = new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return Iterators.mergeSorted(
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterators.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterators.java
index ead102f..9da1da6 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterators.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Iterators.java
@@ -23,7 +23,6 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Function;
-import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
@@ -36,7 +35,6 @@ import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
-import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.PriorityQueue;
import java.util.Queue;
@@ -52,10 +50,6 @@ import javax.annotation.Nullable;
* produced in this class are <i>lazy</i>, which means that they only advance
* the backing iteration when absolutely necessary.
*
- * <p>See the Guava User Guide section on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Iterables">
- * {@code Iterators}</a>.
- *
* @author Kevin Bourrillion
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
@@ -64,8 +58,8 @@ import javax.annotation.Nullable;
public final class Iterators {
private Iterators() {}
- static final UnmodifiableListIterator<Object> EMPTY_LIST_ITERATOR
- = new UnmodifiableListIterator<Object>() {
+ static final UnmodifiableIterator<Object> EMPTY_ITERATOR
+ = new UnmodifiableIterator<Object>() {
@Override
public boolean hasNext() {
return false;
@@ -74,22 +68,6 @@ public final class Iterators {
public Object next() {
throw new NoSuchElementException();
}
- @Override
- public boolean hasPrevious() {
- return false;
- }
- @Override
- public Object previous() {
- throw new NoSuchElementException();
- }
- @Override
- public int nextIndex() {
- return 0;
- }
- @Override
- public int previousIndex() {
- return -1;
- }
};
/**
@@ -98,20 +76,10 @@ public final class Iterators {
* <p>The {@link Iterable} equivalent of this method is {@link
* ImmutableSet#of()}.
*/
- public static <T> UnmodifiableIterator<T> emptyIterator() {
- return emptyListIterator();
- }
-
- /**
- * Returns the empty iterator.
- *
- * <p>The {@link Iterable} equivalent of this method is {@link
- * ImmutableSet#of()}.
- */
// Casting to any type is safe since there are no actual elements.
@SuppressWarnings("unchecked")
- static <T> UnmodifiableListIterator<T> emptyListIterator() {
- return (UnmodifiableListIterator<T>) EMPTY_LIST_ITERATOR;
+ public static <T> UnmodifiableIterator<T> emptyIterator() {
+ return (UnmodifiableIterator<T>) EMPTY_ITERATOR;
}
private static final Iterator<Object> EMPTY_MODIFIABLE_ITERATOR =
@@ -305,11 +273,15 @@ public final class Iterators {
* {@code hasNext()} method will return {@code false}.
*/
public static String toString(Iterator<?> iterator) {
- return Joiner.on(", ")
- .useForNull("null")
- .appendTo(new StringBuilder().append('['), iterator)
- .append(']')
- .toString();
+ if (!iterator.hasNext()) {
+ return "[]";
+ }
+ StringBuilder builder = new StringBuilder();
+ builder.append('[').append(iterator.next());
+ while (iterator.hasNext()) {
+ builder.append(", ").append(iterator.next());
+ }
+ return builder.append(']').toString();
}
/**
@@ -345,8 +317,8 @@ public final class Iterators {
* @throws IllegalArgumentException if the iterator contains multiple
* elements. The state of the iterator is unspecified.
*/
- @Nullable
- public static <T> T getOnlyElement(Iterator<? extends T> iterator, @Nullable T defaultValue) {
+ public static <T> T getOnlyElement(
+ Iterator<T> iterator, @Nullable T defaultValue) {
return iterator.hasNext() ? getOnlyElement(iterator) : defaultValue;
}
@@ -441,8 +413,8 @@ public final class Iterators {
/**
* Returns an iterator that cycles indefinitely over the provided elements.
*
- * <p>The returned iterator supports {@code remove()}. After {@code remove()}
- * is called, subsequent cycles omit the removed
+ * <p>The returned iterator supports {@code remove()} if the provided iterator
+ * does. After {@code remove()} is called, subsequent cycles omit the removed
* element, but {@code elements} does not change. The iterator's
* {@code hasNext()} method returns {@code true} until all of the original
* elements have been removed.
@@ -462,11 +434,6 @@ public final class Iterators {
*
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it.
- *
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
*/
@SuppressWarnings("unchecked")
public static <T> Iterator<T> concat(Iterator<? extends T> a,
@@ -484,11 +451,6 @@ public final class Iterators {
*
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it.
- *
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
*/
@SuppressWarnings("unchecked")
public static <T> Iterator<T> concat(Iterator<? extends T> a,
@@ -507,11 +469,6 @@ public final class Iterators {
*
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it.
- *
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
*/
@SuppressWarnings("unchecked")
public static <T> Iterator<T> concat(Iterator<? extends T> a,
@@ -532,11 +489,6 @@ public final class Iterators {
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it.
*
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
- *
* @throws NullPointerException if any of the provided iterators is null
*/
public static <T> Iterator<T> concat(Iterator<? extends T>... inputs) {
@@ -551,11 +503,6 @@ public final class Iterators {
* <p>The returned iterator supports {@code remove()} when the corresponding
* input iterator supports it. The methods of the returned iterator may throw
* {@code NullPointerException} if any of the input iterators is null.
- *
- * <p><b>Note:</b> the current implementation is not suitable for nested
- * concatenated iterators, i.e. the following should be avoided when in a loop:
- * {@code iterator = Iterators.concat(iterator, suffix);}, since iteration over the
- * resulting iterator has a cubic complexity to the depth of the nesting.
*/
public static <T> Iterator<T> concat(
final Iterator<? extends Iterator<? extends T>> inputs) {
@@ -728,8 +675,8 @@ public final class Iterators {
* predicate; use this method only when such an element is known to exist. If
* no such element is found, the iterator will be left exhausted: its {@code
* hasNext()} method will return {@code false}. If it is possible that
- * <i>no</i> element will match, use {@link #tryFind} or {@link
- * #find(Iterator, Predicate, Object)} instead.
+ * <i>no</i> element will match, use {@link #tryFind)} or {@link
+ * #find(Iterator, Predicate, T)} instead.
*
* @throws NoSuchElementException if no element in {@code iterator} matches
* the given predicate
@@ -749,10 +696,9 @@ public final class Iterators {
*
* @since 7.0
*/
- @Nullable
- public static <T> T find(Iterator<? extends T> iterator, Predicate<? super T> predicate,
+ public static <T> T find(Iterator<T> iterator, Predicate<? super T> predicate,
@Nullable T defaultValue) {
- UnmodifiableIterator<? extends T> filteredIterator = filter(iterator, predicate);
+ UnmodifiableIterator<T> filteredIterator = filter(iterator, predicate);
return filteredIterator.hasNext() ? filteredIterator.next() : defaultValue;
}
@@ -817,12 +763,22 @@ public final class Iterators {
*/
public static <F, T> Iterator<T> transform(final Iterator<F> fromIterator,
final Function<? super F, ? extends T> function) {
+ checkNotNull(fromIterator);
checkNotNull(function);
- return new TransformedIterator<F, T>(fromIterator) {
+ return new Iterator<T>() {
+ @Override
+ public boolean hasNext() {
+ return fromIterator.hasNext();
+ }
@Override
- T transform(F from) {
+ public T next() {
+ F from = fromIterator.next();
return function.apply(from);
}
+ @Override
+ public void remove() {
+ fromIterator.remove();
+ }
};
}
@@ -874,8 +830,8 @@ public final class Iterators {
* @throws IndexOutOfBoundsException if {@code position} is negative
* @since 4.0
*/
- @Nullable
- public static <T> T get(Iterator<? extends T> iterator, int position, @Nullable T defaultValue) {
+ public static <T> T get(Iterator<T> iterator, int position,
+ @Nullable T defaultValue) {
checkNonnegative(position);
try {
@@ -894,8 +850,7 @@ public final class Iterators {
* @return the next element of {@code iterator} or the default value
* @since 7.0
*/
- @Nullable
- public static <T> T getNext(Iterator<? extends T> iterator, @Nullable T defaultValue) {
+ public static <T> T getNext(Iterator<T> iterator, @Nullable T defaultValue) {
return iterator.hasNext() ? iterator.next() : defaultValue;
}
@@ -922,24 +877,24 @@ public final class Iterators {
* @return the last element of {@code iterator}
* @since 3.0
*/
- @Nullable
- public static <T> T getLast(Iterator<? extends T> iterator, @Nullable T defaultValue) {
+ public static <T> T getLast(Iterator<T> iterator, @Nullable T defaultValue) {
return iterator.hasNext() ? getLast(iterator) : defaultValue;
}
/**
- * Calls {@code next()} on {@code iterator}, either {@code numberToAdvance} times
+ * Calls {@code next()} on {@code iterator}, either {@code numberToSkip} times
* or until {@code hasNext()} returns {@code false}, whichever comes first.
*
- * @return the number of elements the iterator was advanced
- * @since 13.0 (since 3.0 as {@code Iterators.skip})
+ * @return the number of elements skipped
+ * @since 3.0
*/
- public static int advance(Iterator<?> iterator, int numberToAdvance) {
+ @Beta
+ public static <T> int skip(Iterator<T> iterator, int numberToSkip) {
checkNotNull(iterator);
- checkArgument(numberToAdvance >= 0, "number to advance cannot be negative");
+ checkArgument(numberToSkip >= 0, "number to skip cannot be negative");
int i;
- for (i = 0; i < numberToAdvance && iterator.hasNext(); i++) {
+ for (i = 0; i < numberToSkip && iterator.hasNext(); i++) {
iterator.next();
}
return i;
@@ -1015,21 +970,6 @@ public final class Iterators {
};
}
- /**
- * Deletes and returns the next value from the iterator, or returns
- * {@code defaultValue} if there is no such value.
- */
- @Nullable
- static <T> T pollNext(Iterator<T> iterator) {
- if (iterator.hasNext()) {
- T result = iterator.next();
- iterator.remove();
- return result;
- } else {
- return null;
- }
- }
-
// Methods only in Iterators, not in Iterables
/**
@@ -1067,14 +1007,21 @@ public final class Iterators {
}
/**
- * Returns a list iterator containing the elements in the specified range of
- * {@code array} in order, starting at the specified index.
+ * Returns an iterator containing the elements in the specified range of
+ * {@code array} in order. The returned iterator is a view of the array;
+ * subsequent changes to the array will be reflected in the iterator.
*
* <p>The {@code Iterable} equivalent of this method is {@code
- * Arrays.asList(array).subList(offset, offset + length).listIterator(index)}.
+ * Arrays.asList(array).subList(offset, offset + length)}.
+ *
+ * @param array array to read elements out of
+ * @param offset index of first array element to retrieve
+ * @param length number of elements in iteration
+ * @throws IndexOutOfBoundsException if {@code offset} is negative, {@code
+ * length} is negative, or {@code offset + length > array.length}
*/
- static <T> UnmodifiableListIterator<T> forArray(
- final T[] array, final int offset, int length, int index) {
+ static <T> UnmodifiableIterator<T> forArray(
+ final T[] array, final int offset, int length) {
checkArgument(length >= 0);
int end = offset + length;
@@ -1086,7 +1033,7 @@ public final class Iterators {
* because the returned Iterator is a ListIterator that may be moved back
* past the beginning of the iteration.
*/
- return new AbstractIndexedListIterator<T>(length, index) {
+ return new AbstractIndexedListIterator<T>(length) {
@Override protected T get(int index) {
return array[offset + index];
}
@@ -1343,19 +1290,4 @@ public final class Iterators {
return next;
}
}
-
- /**
- * Precondition tester for {@code Iterator.remove()} that throws an exception with a consistent
- * error message.
- */
- static void checkRemove(boolean canRemove) {
- checkState(canRemove, "no calls to next() since the last call to remove()");
- }
-
- /**
- * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
- */
- static <T> ListIterator<T> cast(Iterator<T> iterator) {
- return (ListIterator<T>) iterator;
- }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultimap.java
index 74e0ff1..d426893 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultimap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultimap.java
@@ -16,20 +16,16 @@
package com.google.common.collect;
-import static com.google.common.base.Preconditions.checkArgument;
-
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Ints;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
-import java.util.NoSuchElementException;
import java.util.Set;
import javax.annotation.Nullable;
@@ -65,23 +61,29 @@ import javax.annotation.Nullable;
* update operations, wrap your multimap with a call to {@link
* Multimaps#synchronizedSetMultimap}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
- *
* @author Jared Levy
- * @author Louis Wasserman
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(serializable = true, emulated = true)
public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
+ private static final int DEFAULT_VALUES_PER_KEY = 8;
+
+ @VisibleForTesting
+ transient int expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
+
+ /**
+ * Map entries with an iteration order corresponding to the order in which the
+ * key-value pairs were added to the multimap.
+ */
+ // package-private for GWT deserialization
+ transient Collection<Map.Entry<K, V>> linkedEntries;
/**
* Creates a new, empty {@code LinkedHashMultimap} with the default initial
* capacities.
*/
public static <K, V> LinkedHashMultimap<K, V> create() {
- return new LinkedHashMultimap<K, V>(DEFAULT_KEY_CAPACITY, DEFAULT_VALUE_SET_CAPACITY);
+ return new LinkedHashMultimap<K, V>();
}
/**
@@ -95,9 +97,7 @@ public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
*/
public static <K, V> LinkedHashMultimap<K, V> create(
int expectedKeys, int expectedValuesPerKey) {
- return new LinkedHashMultimap<K, V>(
- Maps.capacity(expectedKeys),
- Maps.capacity(expectedValuesPerKey));
+ return new LinkedHashMultimap<K, V>(expectedKeys, expectedValuesPerKey);
}
/**
@@ -111,158 +111,201 @@ public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
*/
public static <K, V> LinkedHashMultimap<K, V> create(
Multimap<? extends K, ? extends V> multimap) {
- LinkedHashMultimap<K, V> result = create(multimap.keySet().size(), DEFAULT_VALUE_SET_CAPACITY);
- result.putAll(multimap);
- return result;
- }
-
- private interface ValueSetLink<K, V> {
- ValueSetLink<K, V> getPredecessorInValueSet();
- ValueSetLink<K, V> getSuccessorInValueSet();
-
- void setPredecessorInValueSet(ValueSetLink<K, V> entry);
- void setSuccessorInValueSet(ValueSetLink<K, V> entry);
+ return new LinkedHashMultimap<K, V>(multimap);
}
- private static <K, V> void succeedsInValueSet(ValueSetLink<K, V> pred, ValueSetLink<K, V> succ) {
- pred.setSuccessorInValueSet(succ);
- succ.setPredecessorInValueSet(pred);
+ private LinkedHashMultimap() {
+ super(new LinkedHashMap<K, Collection<V>>());
+ linkedEntries = Sets.newLinkedHashSet();
}
- private static <K, V> void succeedsInMultimap(
- ValueEntry<K, V> pred, ValueEntry<K, V> succ) {
- pred.setSuccessorInMultimap(succ);
- succ.setPredecessorInMultimap(pred);
+ private LinkedHashMultimap(int expectedKeys, int expectedValuesPerKey) {
+ super(new LinkedHashMap<K, Collection<V>>(expectedKeys));
+ Preconditions.checkArgument(expectedValuesPerKey >= 0);
+ this.expectedValuesPerKey = expectedValuesPerKey;
+ linkedEntries = new LinkedHashSet<Map.Entry<K, V>>(
+ (int) Math.min(Ints.MAX_POWER_OF_TWO,
+ ((long) expectedKeys) * expectedValuesPerKey));
}
- private static <K, V> void deleteFromValueSet(ValueSetLink<K, V> entry) {
- succeedsInValueSet(entry.getPredecessorInValueSet(), entry.getSuccessorInValueSet());
+ private LinkedHashMultimap(Multimap<? extends K, ? extends V> multimap) {
+ super(new LinkedHashMap<K, Collection<V>>(
+ Maps.capacity(multimap.keySet().size())));
+ linkedEntries
+ = new LinkedHashSet<Map.Entry<K, V>>(Maps.capacity(multimap.size()));
+ putAll(multimap);
}
- private static <K, V> void deleteFromMultimap(ValueEntry<K, V> entry) {
- succeedsInMultimap(entry.getPredecessorInMultimap(), entry.getSuccessorInMultimap());
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Creates an empty {@code LinkedHashSet} for a collection of values for
+ * one key.
+ *
+ * @return a new {@code LinkedHashSet} containing a collection of values for
+ * one key
+ */
+ @Override Set<V> createCollection() {
+ return new LinkedHashSet<V>(Maps.capacity(expectedValuesPerKey));
}
/**
- * LinkedHashMultimap entries are in no less than three coexisting linked lists:
- * a row in the hash table for a Set<V> associated with a key, the linked list
- * of insertion-ordered entries in that Set<V>, and the linked list of entries
- * in the LinkedHashMultimap as a whole.
+ * {@inheritDoc}
+ *
+ * <p>Creates a decorated {@code LinkedHashSet} that also keeps track of the
+ * order in which key-value pairs are added to the multimap.
+ *
+ * @param key key to associate with values in the collection
+ * @return a new decorated {@code LinkedHashSet} containing a collection of
+ * values for one key
*/
- @VisibleForTesting
- static final class ValueEntry<K, V> extends AbstractMapEntry<K, V>
- implements ValueSetLink<K, V> {
- final K key;
- final V value;
- final int valueHash;
-
- @Nullable ValueEntry<K, V> nextInValueSetHashRow;
-
- ValueSetLink<K, V> predecessorInValueSet;
- ValueSetLink<K, V> successorInValueSet;
+ @Override Collection<V> createCollection(@Nullable K key) {
+ return new SetDecorator(key, createCollection());
+ }
- ValueEntry<K, V> predecessorInMultimap;
- ValueEntry<K, V> successorInMultimap;
+ private class SetDecorator extends ForwardingSet<V> {
+ final Set<V> delegate;
+ final K key;
- ValueEntry(@Nullable K key, @Nullable V value, int valueHash,
- @Nullable ValueEntry<K, V> nextInValueSetHashRow) {
+ SetDecorator(@Nullable K key, Set<V> delegate) {
+ this.delegate = delegate;
this.key = key;
- this.value = value;
- this.valueHash = valueHash;
- this.nextInValueSetHashRow = nextInValueSetHashRow;
}
- @Override
- public K getKey() {
- return key;
+ @Override protected Set<V> delegate() {
+ return delegate;
}
- @Override
- public V getValue() {
- return value;
+ <E> Map.Entry<K, E> createEntry(@Nullable E value) {
+ return Maps.immutableEntry(key, value);
}
- @Override
- public ValueSetLink<K, V> getPredecessorInValueSet() {
- return predecessorInValueSet;
+ <E> Collection<Map.Entry<K, E>> createEntries(Collection<E> values) {
+ // converts a collection of values into a list of key/value map entries
+ Collection<Map.Entry<K, E>> entries
+ = Lists.newArrayListWithExpectedSize(values.size());
+ for (E value : values) {
+ entries.add(createEntry(value));
+ }
+ return entries;
}
- @Override
- public ValueSetLink<K, V> getSuccessorInValueSet() {
- return successorInValueSet;
+ @Override public boolean add(@Nullable V value) {
+ boolean changed = delegate.add(value);
+ if (changed) {
+ linkedEntries.add(createEntry(value));
+ }
+ return changed;
}
- @Override
- public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
- predecessorInValueSet = entry;
+ @Override public boolean addAll(Collection<? extends V> values) {
+ boolean changed = delegate.addAll(values);
+ if (changed) {
+ linkedEntries.addAll(createEntries(delegate()));
+ }
+ return changed;
}
- @Override
- public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
- successorInValueSet = entry;
+ @Override public void clear() {
+ for (V value : delegate) {
+ linkedEntries.remove(createEntry(value));
+ }
+ delegate.clear();
}
- public ValueEntry<K, V> getPredecessorInMultimap() {
- return predecessorInMultimap;
- }
+ @Override public Iterator<V> iterator() {
+ final Iterator<V> delegateIterator = delegate.iterator();
+ return new Iterator<V>() {
+ V value;
- public ValueEntry<K, V> getSuccessorInMultimap() {
- return successorInMultimap;
+ @Override
+ public boolean hasNext() {
+ return delegateIterator.hasNext();
+ }
+ @Override
+ public V next() {
+ value = delegateIterator.next();
+ return value;
+ }
+ @Override
+ public void remove() {
+ delegateIterator.remove();
+ linkedEntries.remove(createEntry(value));
+ }
+ };
}
- public void setSuccessorInMultimap(ValueEntry<K, V> multimapSuccessor) {
- this.successorInMultimap = multimapSuccessor;
+ @Override public boolean remove(@Nullable Object value) {
+ boolean changed = delegate.remove(value);
+ if (changed) {
+ /*
+ * linkedEntries.remove() will return false when this method is called
+ * by entries().iterator().remove()
+ */
+ linkedEntries.remove(createEntry(value));
+ }
+ return changed;
}
- public void setPredecessorInMultimap(ValueEntry<K, V> multimapPredecessor) {
- this.predecessorInMultimap = multimapPredecessor;
+ @Override public boolean removeAll(Collection<?> values) {
+ boolean changed = delegate.removeAll(values);
+ if (changed) {
+ linkedEntries.removeAll(createEntries(values));
+ }
+ return changed;
}
- }
- private static final int DEFAULT_KEY_CAPACITY = 16;
- private static final int DEFAULT_VALUE_SET_CAPACITY = 2;
- @VisibleForTesting static final double VALUE_SET_LOAD_FACTOR = 1.0;
-
- @VisibleForTesting transient int valueSetCapacity = DEFAULT_VALUE_SET_CAPACITY;
- private transient ValueEntry<K, V> multimapHeaderEntry;
-
- private LinkedHashMultimap(int keyCapacity, int valueSetCapacity) {
- super(new LinkedHashMap<K, Collection<V>>(keyCapacity));
-
- checkArgument(valueSetCapacity >= 0,
- "expectedValuesPerKey must be >= 0 but was %s", valueSetCapacity);
-
- this.valueSetCapacity = valueSetCapacity;
- this.multimapHeaderEntry = new ValueEntry<K, V>(null, null, 0, null);
- succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
+ @Override public boolean retainAll(Collection<?> values) {
+ /*
+ * Calling linkedEntries.retainAll() would incorrectly remove values
+ * with other keys.
+ */
+ boolean changed = false;
+ Iterator<V> iterator = delegate.iterator();
+ while (iterator.hasNext()) {
+ V value = iterator.next();
+ if (!values.contains(value)) {
+ iterator.remove();
+ linkedEntries.remove(Maps.immutableEntry(key, value));
+ changed = true;
+ }
+ }
+ return changed;
+ }
}
/**
* {@inheritDoc}
*
- * <p>Creates an empty {@code LinkedHashSet} for a collection of values for
- * one key.
+ * <p>Generates an iterator across map entries that follows the ordering in
+ * which the key-value pairs were added to the multimap.
*
- * @return a new {@code LinkedHashSet} containing a collection of values for
- * one key
+ * @return a key-value iterator with the correct ordering
*/
- @Override
- Set<V> createCollection() {
- return new LinkedHashSet<V>(valueSetCapacity);
- }
+ @Override Iterator<Map.Entry<K, V>> createEntryIterator() {
+ final Iterator<Map.Entry<K, V>> delegateIterator = linkedEntries.iterator();
- /**
- * {@inheritDoc}
- *
- * <p>Creates a decorated insertion-ordered set that also keeps track of the
- * order in which key-value pairs are added to the multimap.
- *
- * @param key key to associate with values in the collection
- * @return a new decorated set containing a collection of values for one key
- */
- @Override
- Collection<V> createCollection(K key) {
- return new ValueSet(key, valueSetCapacity);
+ return new Iterator<Map.Entry<K, V>>() {
+ Map.Entry<K, V> entry;
+
+ @Override
+ public boolean hasNext() {
+ return delegateIterator.hasNext();
+ }
+
+ @Override
+ public Map.Entry<K, V> next() {
+ entry = delegateIterator.next();
+ return entry;
+ }
+
+ @Override
+ public void remove() {
+ // Remove from iterator first to keep iterator valid.
+ delegateIterator.remove();
+ LinkedHashMultimap.this.remove(entry.getKey(), entry.getValue());
+ }
+ };
}
/**
@@ -273,8 +316,8 @@ public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
* However, the provided values always come last in the {@link #entries()} and
* {@link #values()} iteration orderings.
*/
- @Override
- public Set<V> replaceValues(@Nullable K key, Iterable<? extends V> values) {
+ @Override public Set<V> replaceValues(
+ @Nullable K key, Iterable<? extends V> values) {
return super.replaceValues(key, values);
}
@@ -305,249 +348,7 @@ public final class LinkedHashMultimap<K, V> extends AbstractSetMultimap<K, V> {
return super.values();
}
- @VisibleForTesting
- final class ValueSet extends Sets.ImprovedAbstractSet<V> implements ValueSetLink<K, V> {
- /*
- * We currently use a fixed load factor of 1.0, a bit higher than normal to reduce memory
- * consumption.
- */
-
- private final K key;
- @VisibleForTesting ValueEntry<K, V>[] hashTable;
- private int size = 0;
- private int modCount = 0;
-
- // We use the set object itself as the end of the linked list, avoiding an unnecessary
- // entry object per key.
- private ValueSetLink<K, V> firstEntry;
- private ValueSetLink<K, V> lastEntry;
-
- ValueSet(K key, int expectedValues) {
- this.key = key;
- this.firstEntry = this;
- this.lastEntry = this;
- // Round expected values up to a power of 2 to get the table size.
- int tableSize = Hashing.closedTableSize(expectedValues, VALUE_SET_LOAD_FACTOR);
-
- @SuppressWarnings("unchecked")
- ValueEntry<K, V>[] hashTable = new ValueEntry[tableSize];
- this.hashTable = hashTable;
- }
-
- @Override
- public ValueSetLink<K, V> getPredecessorInValueSet() {
- return lastEntry;
- }
-
- @Override
- public ValueSetLink<K, V> getSuccessorInValueSet() {
- return firstEntry;
- }
-
- @Override
- public void setPredecessorInValueSet(ValueSetLink<K, V> entry) {
- lastEntry = entry;
- }
-
- @Override
- public void setSuccessorInValueSet(ValueSetLink<K, V> entry) {
- firstEntry = entry;
- }
-
- @Override
- public Iterator<V> iterator() {
- return new Iterator<V>() {
- ValueSetLink<K, V> nextEntry = firstEntry;
- ValueEntry<K, V> toRemove;
- int expectedModCount = modCount;
-
- private void checkForComodification() {
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- }
-
- @Override
- public boolean hasNext() {
- checkForComodification();
- return nextEntry != ValueSet.this;
- }
-
- @Override
- public V next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- ValueEntry<K, V> entry = (ValueEntry<K, V>) nextEntry;
- V result = entry.getValue();
- toRemove = entry;
- nextEntry = entry.getSuccessorInValueSet();
- return result;
- }
-
- @Override
- public void remove() {
- checkForComodification();
- Iterators.checkRemove(toRemove != null);
- Object o = toRemove.getValue();
- int hash = (o == null) ? 0 : o.hashCode();
- int row = Hashing.smear(hash) & (hashTable.length - 1);
- ValueEntry<K, V> prev = null;
- for (ValueEntry<K, V> entry = hashTable[row]; entry != null;
- prev = entry, entry = entry.nextInValueSetHashRow) {
- if (entry == toRemove) {
- if (prev == null) {
- // first entry in row
- hashTable[row] = entry.nextInValueSetHashRow;
- } else {
- prev.nextInValueSetHashRow = entry.nextInValueSetHashRow;
- }
- deleteFromValueSet(toRemove);
- deleteFromMultimap(toRemove);
- size--;
- expectedModCount = ++modCount;
- break;
- }
- }
- toRemove = null;
- }
- };
- }
-
- @Override
- public int size() {
- return size;
- }
-
- @Override
- public boolean contains(@Nullable Object o) {
- int hash = (o == null) ? 0 : o.hashCode();
- int row = Hashing.smear(hash) & (hashTable.length - 1);
-
- for (ValueEntry<K, V> entry = hashTable[row]; entry != null;
- entry = entry.nextInValueSetHashRow) {
- if (hash == entry.valueHash && Objects.equal(o, entry.getValue())) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean add(@Nullable V value) {
- int hash = (value == null) ? 0 : value.hashCode();
- int row = Hashing.smear(hash) & (hashTable.length - 1);
-
- ValueEntry<K, V> rowHead = hashTable[row];
- for (ValueEntry<K, V> entry = rowHead; entry != null;
- entry = entry.nextInValueSetHashRow) {
- if (hash == entry.valueHash && Objects.equal(value, entry.getValue())) {
- return false;
- }
- }
-
- ValueEntry<K, V> newEntry = new ValueEntry<K, V>(key, value, hash, rowHead);
- succeedsInValueSet(lastEntry, newEntry);
- succeedsInValueSet(newEntry, this);
- succeedsInMultimap(multimapHeaderEntry.getPredecessorInMultimap(), newEntry);
- succeedsInMultimap(newEntry, multimapHeaderEntry);
- hashTable[row] = newEntry;
- size++;
- modCount++;
- rehashIfNecessary();
- return true;
- }
-
- private void rehashIfNecessary() {
- if (Hashing.needsResizing(size, hashTable.length, VALUE_SET_LOAD_FACTOR)) {
- @SuppressWarnings("unchecked")
- ValueEntry<K, V>[] hashTable = new ValueEntry[this.hashTable.length * 2];
- this.hashTable = hashTable;
- int mask = hashTable.length - 1;
- for (ValueSetLink<K, V> entry = firstEntry;
- entry != this; entry = entry.getSuccessorInValueSet()) {
- ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
- int row = Hashing.smear(valueEntry.valueHash) & mask;
- valueEntry.nextInValueSetHashRow = hashTable[row];
- hashTable[row] = valueEntry;
- }
- }
- }
-
- @Override
- public boolean remove(@Nullable Object o) {
- int hash = (o == null) ? 0 : o.hashCode();
- int row = Hashing.smear(hash) & (hashTable.length - 1);
-
- ValueEntry<K, V> prev = null;
- for (ValueEntry<K, V> entry = hashTable[row]; entry != null;
- prev = entry, entry = entry.nextInValueSetHashRow) {
- if (hash == entry.valueHash && Objects.equal(o, entry.getValue())) {
- if (prev == null) {
- // first entry in the row
- hashTable[row] = entry.nextInValueSetHashRow;
- } else {
- prev.nextInValueSetHashRow = entry.nextInValueSetHashRow;
- }
- deleteFromValueSet(entry);
- deleteFromMultimap(entry);
- size--;
- modCount++;
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void clear() {
- Arrays.fill(hashTable, null);
- size = 0;
- for (ValueSetLink<K, V> entry = firstEntry;
- entry != this; entry = entry.getSuccessorInValueSet()) {
- ValueEntry<K, V> valueEntry = (ValueEntry<K, V>) entry;
- deleteFromMultimap(valueEntry);
- }
- succeedsInValueSet(this, this);
- modCount++;
- }
- }
-
- @Override
- Iterator<Map.Entry<K, V>> entryIterator() {
- return new Iterator<Map.Entry<K, V>>() {
- ValueEntry<K, V> nextEntry = multimapHeaderEntry.successorInMultimap;
- ValueEntry<K, V> toRemove;
-
- @Override
- public boolean hasNext() {
- return nextEntry != multimapHeaderEntry;
- }
-
- @Override
- public Map.Entry<K, V> next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- ValueEntry<K, V> result = nextEntry;
- toRemove = result;
- nextEntry = nextEntry.successorInMultimap;
- return result;
- }
-
- @Override
- public void remove() {
- Iterators.checkRemove(toRemove != null);
- LinkedHashMultimap.this.remove(toRemove.getKey(), toRemove.getValue());
- toRemove = null;
- }
- };
- }
-
- @Override
- public void clear() {
- super.clear();
- succeedsInMultimap(multimapHeaderEntry, multimapHeaderEntry);
- }
+ // Unfortunately, the entries() ordering does not determine the key ordering;
+ // see the example in the LinkedListMultimap class Javadoc.
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultiset.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultiset.java
index da93ead..7715784 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultiset.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedHashMultiset.java
@@ -27,10 +27,6 @@ import java.util.LinkedHashMap;
* element, those instances are consecutive in the iteration order. If all
* occurrences of an element are removed, after which that element is added to
* the multiset, the element will appear at the end of the iteration.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
- * {@code Multiset}</a>.
*
* @author Kevin Bourrillion
* @author Jared Levy
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedListMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedListMultimap.java
index f51d292..2273535 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedListMultimap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/LinkedListMultimap.java
@@ -17,7 +17,9 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Multisets.setCountImpl;
import static java.util.Collections.unmodifiableList;
import com.google.common.annotations.GwtCompatible;
@@ -25,10 +27,11 @@ import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
import java.util.AbstractSequentialList;
+import java.util.AbstractSet;
import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
@@ -88,10 +91,6 @@ import javax.annotation.Nullable;
* update operations, wrap your multimap with a call to {@link
* Multimaps#synchronizedListMultimap}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
- *
* @author Mike Bostock
* @since 2.0 (imported from Google Collections Library)
*/
@@ -122,32 +121,12 @@ public class LinkedListMultimap<K, V>
return key + "=" + value;
}
}
-
- private static class KeyList<K, V> {
- Node<K, V> head;
- Node<K, V> tail;
- int count;
-
- KeyList(Node<K, V> firstNode) {
- this.head = firstNode;
- this.tail = firstNode;
- firstNode.previousSibling = null;
- firstNode.nextSibling = null;
- this.count = 1;
- }
- }
private transient Node<K, V> head; // the head for all keys
private transient Node<K, V> tail; // the tail for all keys
- private transient Map<K, KeyList<K, V>> keyToKeyList;
- private transient int size;
-
- /*
- * Tracks modifications to keyToKeyList so that addition or removal of keys invalidates
- * preexisting iterators. This does *not* track simple additions and removals of values
- * that are not the first to be added or last to be removed for their key.
- */
- private transient int modCount;
+ private transient Multiset<K> keyCount; // the number of values for each key
+ private transient Map<K, Node<K, V>> keyToKeyHead; // the head for a given key
+ private transient Map<K, Node<K, V>> keyToKeyTail; // the tail for a given key
/**
* Creates a new, empty {@code LinkedListMultimap} with the default initial
@@ -181,11 +160,15 @@ public class LinkedListMultimap<K, V>
}
LinkedListMultimap() {
- keyToKeyList = Maps.newHashMap();
+ keyCount = LinkedHashMultiset.create();
+ keyToKeyHead = Maps.newHashMap();
+ keyToKeyTail = Maps.newHashMap();
}
private LinkedListMultimap(int expectedKeys) {
- keyToKeyList = new HashMap<K, KeyList<K, V>>(expectedKeys);
+ keyCount = LinkedHashMultiset.create(expectedKeys);
+ keyToKeyHead = Maps.newHashMapWithExpectedSize(expectedKeys);
+ keyToKeyTail = Maps.newHashMapWithExpectedSize(expectedKeys);
}
private LinkedListMultimap(Multimap<? extends K, ? extends V> multimap) {
@@ -204,32 +187,27 @@ public class LinkedListMultimap<K, V>
Node<K, V> node = new Node<K, V>(key, value);
if (head == null) { // empty list
head = tail = node;
- keyToKeyList.put(key, new KeyList<K, V>(node));
- modCount++;
+ keyToKeyHead.put(key, node);
+ keyToKeyTail.put(key, node);
} else if (nextSibling == null) { // non-empty list, add to tail
tail.next = node;
node.previous = tail;
- tail = node;
- KeyList<K, V> keyList = keyToKeyList.get(key);
- if (keyList == null) {
- keyToKeyList.put(key, keyList = new KeyList<K, V>(node));
- modCount++;
+ Node<K, V> keyTail = keyToKeyTail.get(key);
+ if (keyTail == null) { // first for this key
+ keyToKeyHead.put(key, node);
} else {
- keyList.count++;
- Node<K, V> keyTail = keyList.tail;
keyTail.nextSibling = node;
node.previousSibling = keyTail;
- keyList.tail = node;
}
+ keyToKeyTail.put(key, node);
+ tail = node;
} else { // non-empty list, insert before nextSibling
- KeyList<K, V> keyList = keyToKeyList.get(key);
- keyList.count++;
node.previous = nextSibling.previous;
node.previousSibling = nextSibling.previousSibling;
node.next = nextSibling;
node.nextSibling = nextSibling;
if (nextSibling.previousSibling == null) { // nextSibling was key head
- keyToKeyList.get(key).head = node;
+ keyToKeyHead.put(key, node);
} else {
nextSibling.previousSibling.nextSibling = node;
}
@@ -241,7 +219,7 @@ public class LinkedListMultimap<K, V>
nextSibling.previous = node;
nextSibling.previousSibling = node;
}
- size++;
+ keyCount.add(key);
return node;
}
@@ -261,27 +239,21 @@ public class LinkedListMultimap<K, V>
} else { // node was tail
tail = node.previous;
}
- if (node.previousSibling == null && node.nextSibling == null) {
- KeyList<K, V> keyList = keyToKeyList.remove(node.key);
- keyList.count = 0;
- modCount++;
+ if (node.previousSibling != null) {
+ node.previousSibling.nextSibling = node.nextSibling;
+ } else if (node.nextSibling != null) { // node was key head
+ keyToKeyHead.put(node.key, node.nextSibling);
} else {
- KeyList<K, V> keyList = keyToKeyList.get(node.key);
- keyList.count--;
-
- if (node.previousSibling == null) {
- keyList.head = node.nextSibling;
- } else {
- node.previousSibling.nextSibling = node.nextSibling;
- }
-
- if (node.nextSibling == null) {
- keyList.tail = node.previousSibling;
- } else {
- node.nextSibling.previousSibling = node.previousSibling;
- }
+ keyToKeyHead.remove(node.key); // don't leak a key-null entry
}
- size--;
+ if (node.nextSibling != null) {
+ node.nextSibling.previousSibling = node.previousSibling;
+ } else if (node.previousSibling != null) { // node was key tail
+ keyToKeyTail.put(node.key, node.previousSibling);
+ } else {
+ keyToKeyTail.remove(node.key); // don't leak a key-null entry
+ }
+ keyCount.remove(node.key);
}
/** Removes all nodes for the specified key. */
@@ -305,7 +277,6 @@ public class LinkedListMultimap<K, V>
Node<K, V> next;
Node<K, V> current;
Node<K, V> previous;
- int expectedModCount = modCount;
NodeIterator() {
next = head;
@@ -327,19 +298,12 @@ public class LinkedListMultimap<K, V>
}
current = null;
}
- private void checkForConcurrentModification() {
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- }
@Override
public boolean hasNext() {
- checkForConcurrentModification();
return next != null;
}
@Override
public Node<K, V> next() {
- checkForConcurrentModification();
checkElement(next);
previous = current = next;
next = next.next;
@@ -348,7 +312,6 @@ public class LinkedListMultimap<K, V>
}
@Override
public void remove() {
- checkForConcurrentModification();
checkState(current != null);
if (current != next) { // after call to next()
previous = current.previous;
@@ -358,16 +321,13 @@ public class LinkedListMultimap<K, V>
}
removeNode(current);
current = null;
- expectedModCount = modCount;
}
@Override
public boolean hasPrevious() {
- checkForConcurrentModification();
return previous != null;
}
@Override
public Node<K, V> previous() {
- checkForConcurrentModification();
checkElement(previous);
next = current = previous;
previous = previous.previous;
@@ -401,21 +361,13 @@ public class LinkedListMultimap<K, V>
final Set<K> seenKeys = Sets.<K>newHashSetWithExpectedSize(keySet().size());
Node<K, V> next = head;
Node<K, V> current;
- int expectedModCount = modCount;
-
- private void checkForConcurrentModification() {
- if (modCount != expectedModCount) {
- throw new ConcurrentModificationException();
- }
- }
+
@Override
public boolean hasNext() {
- checkForConcurrentModification();
return next != null;
}
@Override
public K next() {
- checkForConcurrentModification();
checkElement(next);
current = next;
seenKeys.add(current.key);
@@ -426,11 +378,9 @@ public class LinkedListMultimap<K, V>
}
@Override
public void remove() {
- checkForConcurrentModification();
checkState(current != null);
removeAllNodes(current.key);
current = null;
- expectedModCount = modCount;
}
}
@@ -445,8 +395,7 @@ public class LinkedListMultimap<K, V>
/** Constructs a new iterator over all values for the specified key. */
ValueForKeyIterator(@Nullable Object key) {
this.key = key;
- KeyList<K, V> keyList = keyToKeyList.get(key);
- next = (keyList == null) ? null : keyList.head;
+ next = keyToKeyHead.get(key);
}
/**
@@ -459,17 +408,16 @@ public class LinkedListMultimap<K, V>
* @throws IndexOutOfBoundsException if index is invalid
*/
public ValueForKeyIterator(@Nullable Object key, int index) {
- KeyList<K, V> keyList = keyToKeyList.get(key);
- int size = (keyList == null) ? 0 : keyList.count;
+ int size = keyCount.count(key);
Preconditions.checkPositionIndex(index, size);
if (index >= (size / 2)) {
- previous = (keyList == null) ? null : keyList.tail;
+ previous = keyToKeyTail.get(key);
nextIndex = size;
while (index++ < size) {
previous();
}
} else {
- next = (keyList == null) ? null : keyList.head;
+ next = keyToKeyHead.get(key);
while (index-- > 0) {
next();
}
@@ -548,7 +496,7 @@ public class LinkedListMultimap<K, V>
@Override
public int size() {
- return size;
+ return keyCount.size();
}
@Override
@@ -558,7 +506,7 @@ public class LinkedListMultimap<K, V>
@Override
public boolean containsKey(@Nullable Object key) {
- return keyToKeyList.containsKey(key);
+ return keyToKeyHead.containsKey(key);
}
@Override
@@ -685,9 +633,9 @@ public class LinkedListMultimap<K, V>
public void clear() {
head = null;
tail = null;
- keyToKeyList.clear();
- size = 0;
- modCount++;
+ keyCount.clear();
+ keyToKeyHead.clear();
+ keyToKeyTail.clear();
}
// Views
@@ -705,8 +653,7 @@ public class LinkedListMultimap<K, V>
public List<V> get(final @Nullable K key) {
return new AbstractSequentialList<V>() {
@Override public int size() {
- KeyList<K, V> keyList = keyToKeyList.get(key);
- return (keyList == null) ? 0 : keyList.count;
+ return keyCount.count(key);
}
@Override public ListIterator<V> listIterator(int index) {
return new ValueForKeyIterator(key, index);
@@ -726,19 +673,19 @@ public class LinkedListMultimap<K, V>
public Set<K> keySet() {
Set<K> result = keySet;
if (result == null) {
- keySet = result = new Sets.ImprovedAbstractSet<K>() {
+ keySet = result = new AbstractSet<K>() {
@Override public int size() {
- return keyToKeyList.size();
+ return keyCount.elementSet().size();
}
@Override public Iterator<K> iterator() {
return new DistinctKeyIterator();
}
@Override public boolean contains(Object key) { // for performance
- return containsKey(key);
+ return keyCount.contains(key);
}
- @Override
- public boolean remove(Object o) { // for performance
- return !LinkedListMultimap.this.removeAll(o).isEmpty();
+ @Override public boolean removeAll(Collection<?> c) {
+ checkNotNull(c); // eager for GWT
+ return super.removeAll(c);
}
};
}
@@ -756,50 +703,39 @@ public class LinkedListMultimap<K, V>
return result;
}
- private class MultisetView extends AbstractMultiset<K> {
- @Override
- public int size() {
- return size;
- }
+ private class MultisetView extends AbstractCollection<K>
+ implements Multiset<K> {
- @Override
- public int count(Object element) {
- KeyList<K, V> keyList = keyToKeyList.get(element);
- return (keyList == null) ? 0 : keyList.count;
+ @Override public int size() {
+ return keyCount.size();
}
- @Override
- Iterator<Entry<K>> entryIterator() {
- return new TransformedIterator<K, Entry<K>>(new DistinctKeyIterator()) {
+ @Override public Iterator<K> iterator() {
+ final Iterator<Node<K, V>> nodes = new NodeIterator();
+ return new Iterator<K>() {
@Override
- Entry<K> transform(final K key) {
- return new Multisets.AbstractEntry<K>() {
- @Override
- public K getElement() {
- return key;
- }
-
- @Override
- public int getCount() {
- return keyToKeyList.get(key).count;
- }
- };
+ public boolean hasNext() {
+ return nodes.hasNext();
+ }
+ @Override
+ public K next() {
+ return nodes.next().key;
+ }
+ @Override
+ public void remove() {
+ nodes.remove();
}
};
}
@Override
- int distinctElements() {
- return elementSet().size();
+ public int count(@Nullable Object key) {
+ return keyCount.count(key);
}
- @Override public Iterator<K> iterator() {
- return new TransformedIterator<Node<K, V>, K>(new NodeIterator()) {
- @Override
- K transform(Node<K, V> node) {
- return node.key;
- }
- };
+ @Override
+ public int add(@Nullable K key, int occurrences) {
+ throw new UnsupportedOperationException();
}
@Override
@@ -815,9 +751,77 @@ public class LinkedListMultimap<K, V>
}
@Override
+ public int setCount(K element, int count) {
+ return setCountImpl(this, element, count);
+ }
+
+ @Override
+ public boolean setCount(K element, int oldCount, int newCount) {
+ return setCountImpl(this, element, oldCount, newCount);
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ return Iterators.removeAll(iterator(), c);
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ return Iterators.retainAll(iterator(), c);
+ }
+
+ @Override
public Set<K> elementSet() {
return keySet();
}
+
+ @Override
+ public Set<Entry<K>> entrySet() {
+ // TODO(jlevy): lazy init?
+ return new AbstractSet<Entry<K>>() {
+ @Override public int size() {
+ return keyCount.elementSet().size();
+ }
+
+ @Override public Iterator<Entry<K>> iterator() {
+ final Iterator<K> keyIterator = new DistinctKeyIterator();
+ return new Iterator<Entry<K>>() {
+ @Override
+ public boolean hasNext() {
+ return keyIterator.hasNext();
+ }
+ @Override
+ public Entry<K> next() {
+ final K key = keyIterator.next();
+ return new Multisets.AbstractEntry<K>() {
+ @Override
+ public K getElement() {
+ return key;
+ }
+ @Override
+ public int getCount() {
+ return keyCount.count(key);
+ }
+ };
+ }
+ @Override
+ public void remove() {
+ keyIterator.remove();
+ }
+ };
+ }
+ };
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ return keyCount.equals(object);
+ }
+
+ @Override public int hashCode() {
+ return keyCount.hashCode();
+ }
+
+ @Override public String toString() {
+ return keyCount.toString(); // XXX observe order?
+ }
}
private transient List<V> valuesList;
@@ -837,20 +841,47 @@ public class LinkedListMultimap<K, V>
if (result == null) {
valuesList = result = new AbstractSequentialList<V>() {
@Override public int size() {
- return size;
+ return keyCount.size();
}
@Override
public ListIterator<V> listIterator(int index) {
final NodeIterator nodes = new NodeIterator(index);
- return new TransformedListIterator<Node<K, V>, V>(nodes) {
+ return new ListIterator<V>() {
@Override
- V transform(Node<K, V> node) {
- return node.value;
+ public boolean hasNext() {
+ return nodes.hasNext();
+ }
+ @Override
+ public V next() {
+ return nodes.next().value;
+ }
+ @Override
+ public boolean hasPrevious() {
+ return nodes.hasPrevious();
+ }
+ @Override
+ public V previous() {
+ return nodes.previous().value;
}
-
@Override
- public void set(V value) {
- nodes.setValue(value);
+ public int nextIndex() {
+ return nodes.nextIndex();
+ }
+ @Override
+ public int previousIndex() {
+ return nodes.previousIndex();
+ }
+ @Override
+ public void remove() {
+ nodes.remove();
+ }
+ @Override
+ public void set(V e) {
+ nodes.setValue(e);
+ }
+ @Override
+ public void add(V e) {
+ throw new UnsupportedOperationException();
}
};
}
@@ -901,14 +932,55 @@ public class LinkedListMultimap<K, V>
if (result == null) {
entries = result = new AbstractSequentialList<Entry<K, V>>() {
@Override public int size() {
- return size;
+ return keyCount.size();
}
@Override public ListIterator<Entry<K, V>> listIterator(int index) {
- return new TransformedListIterator<Node<K, V>, Entry<K, V>>(new NodeIterator(index)) {
+ final ListIterator<Node<K, V>> nodes = new NodeIterator(index);
+ return new ListIterator<Entry<K, V>>() {
+ @Override
+ public boolean hasNext() {
+ return nodes.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ return createEntry(nodes.next());
+ }
+
+ @Override
+ public void remove() {
+ nodes.remove();
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return nodes.hasPrevious();
+ }
+
+ @Override
+ public Map.Entry<K, V> previous() {
+ return createEntry(nodes.previous());
+ }
+
+ @Override
+ public int nextIndex() {
+ return nodes.nextIndex();
+ }
+
+ @Override
+ public int previousIndex() {
+ return nodes.previousIndex();
+ }
+
+ @Override
+ public void set(Map.Entry<K, V> e) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
- Entry<K, V> transform(Node<K, V> node) {
- return createEntry(node);
+ public void add(Map.Entry<K, V> e) {
+ throw new UnsupportedOperationException();
}
};
}
@@ -917,39 +989,75 @@ public class LinkedListMultimap<K, V>
return result;
}
+ private class AsMapEntries extends AbstractSet<Entry<K, Collection<V>>> {
+ @Override public int size() {
+ return keyCount.elementSet().size();
+ }
+
+ @Override public Iterator<Entry<K, Collection<V>>> iterator() {
+ final Iterator<K> keyIterator = new DistinctKeyIterator();
+ return new Iterator<Entry<K, Collection<V>>>() {
+ @Override
+ public boolean hasNext() {
+ return keyIterator.hasNext();
+ }
+
+ @Override
+ public Entry<K, Collection<V>> next() {
+ final K key = keyIterator.next();
+ return new AbstractMapEntry<K, Collection<V>>() {
+ @Override public K getKey() {
+ return key;
+ }
+
+ @Override public Collection<V> getValue() {
+ return LinkedListMultimap.this.get(key);
+ }
+ };
+ }
+
+ @Override
+ public void remove() {
+ keyIterator.remove();
+ }
+ };
+ }
+
+ // TODO(jlevy): Override contains() and remove() for better performance.
+ }
+
private transient Map<K, Collection<V>> map;
@Override
public Map<K, Collection<V>> asMap() {
Map<K, Collection<V>> result = map;
if (result == null) {
- map = result = new Multimaps.AsMap<K, V>() {
- @Override
- public int size() {
- return keyToKeyList.size();
+ map = result = new AbstractMap<K, Collection<V>>() {
+ Set<Entry<K, Collection<V>>> entrySet;
+
+ @Override public Set<Entry<K, Collection<V>>> entrySet() {
+ Set<Entry<K, Collection<V>>> result = entrySet;
+ if (result == null) {
+ entrySet = result = new AsMapEntries();
+ }
+ return result;
}
- @Override
- Multimap<K, V> multimap() {
- return LinkedListMultimap.this;
+ // The following methods are included for performance.
+
+ @Override public boolean containsKey(@Nullable Object key) {
+ return LinkedListMultimap.this.containsKey(key);
}
- @Override
- Iterator<Entry<K, Collection<V>>> entryIterator() {
- return new TransformedIterator<K, Entry<K, Collection<V>>>(new DistinctKeyIterator()) {
- @Override
- Entry<K, Collection<V>> transform(final K key) {
- return new AbstractMapEntry<K, Collection<V>>() {
- @Override public K getKey() {
- return key;
- }
+ @SuppressWarnings("unchecked")
+ @Override public Collection<V> get(@Nullable Object key) {
+ Collection<V> collection = LinkedListMultimap.this.get((K) key);
+ return collection.isEmpty() ? null : collection;
+ }
- @Override public Collection<V> getValue() {
- return LinkedListMultimap.this.get(key);
- }
- };
- }
- };
+ @Override public Collection<V> remove(@Nullable Object key) {
+ Collection<V> collection = removeAll(key);
+ return collection.isEmpty() ? null : collection;
}
};
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Lists.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Lists.java
deleted file mode 100644
index 0bdb38a..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Lists.java
+++ /dev/null
@@ -1,1122 +0,0 @@
-/*
- * Copyright (C) 2007 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkElementIndex;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndex;
-import static com.google.common.base.Preconditions.checkPositionIndexes;
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.primitives.Ints;
-
-import java.io.Serializable;
-import java.util.AbstractList;
-import java.util.AbstractSequentialList;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-import java.util.RandomAccess;
-
-import javax.annotation.Nullable;
-
-/**
- * Static utility methods pertaining to {@link List} instances. Also see this
- * class's counterparts {@link Sets}, {@link Maps} and {@link Queues}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Lists">
- * {@code Lists}</a>.
- *
- * @author Kevin Bourrillion
- * @author Mike Bostock
- * @author Louis Wasserman
- * @since 2.0 (imported from Google Collections Library)
- */
-@GwtCompatible(emulated = true)
-public final class Lists {
- private Lists() {}
-
- // ArrayList
-
- /**
- * Creates a <i>mutable</i>, empty {@code ArrayList} instance.
- *
- * <p><b>Note:</b> if mutability is not required, use {@link
- * ImmutableList#of()} instead.
- *
- * @return a new, empty {@code ArrayList}
- */
- @GwtCompatible(serializable = true)
- public static <E> ArrayList<E> newArrayList() {
- return new ArrayList<E>();
- }
-
- /**
- * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
- * elements.
- *
- * <p><b>Note:</b> if mutability is not required and the elements are
- * non-null, use an overload of {@link ImmutableList#of()} (for varargs) or
- * {@link ImmutableList#copyOf(Object[])} (for an array) instead.
- *
- * @param elements the elements that the list should contain, in order
- * @return a new {@code ArrayList} containing those elements
- */
- @GwtCompatible(serializable = true)
- public static <E> ArrayList<E> newArrayList(E... elements) {
- checkNotNull(elements); // for GWT
- // Avoid integer overflow when a large array is passed in
- int capacity = computeArrayListCapacity(elements.length);
- ArrayList<E> list = new ArrayList<E>(capacity);
- Collections.addAll(list, elements);
- return list;
- }
-
- @VisibleForTesting static int computeArrayListCapacity(int arraySize) {
- checkArgument(arraySize >= 0);
-
- // TODO(kevinb): Figure out the right behavior, and document it
- return Ints.saturatedCast(5L + arraySize + (arraySize / 10));
- }
-
- /**
- * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
- * elements.
- *
- * <p><b>Note:</b> if mutability is not required and the elements are
- * non-null, use {@link ImmutableList#copyOf(Iterator)} instead.
- *
- * @param elements the elements that the list should contain, in order
- * @return a new {@code ArrayList} containing those elements
- */
- @GwtCompatible(serializable = true)
- public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
- checkNotNull(elements); // for GWT
- // Let ArrayList's sizing logic work, if possible
- return (elements instanceof Collection)
- ? new ArrayList<E>(Collections2.cast(elements))
- : newArrayList(elements.iterator());
- }
-
- /**
- * Creates a <i>mutable</i> {@code ArrayList} instance containing the given
- * elements.
- *
- * <p><b>Note:</b> if mutability is not required and the elements are
- * non-null, use {@link ImmutableList#copyOf(Iterator)} instead.
- *
- * @param elements the elements that the list should contain, in order
- * @return a new {@code ArrayList} containing those elements
- */
- @GwtCompatible(serializable = true)
- public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
- checkNotNull(elements); // for GWT
- ArrayList<E> list = newArrayList();
- while (elements.hasNext()) {
- list.add(elements.next());
- }
- return list;
- }
-
- /**
- * Creates an {@code ArrayList} instance backed by an array of the
- * <i>exact</i> size specified; equivalent to
- * {@link ArrayList#ArrayList(int)}.
- *
- * <p><b>Note:</b> if you know the exact size your list will be, consider
- * using a fixed-size list ({@link Arrays#asList(Object[])}) or an {@link
- * ImmutableList} instead of a growable {@link ArrayList}.
- *
- * <p><b>Note:</b> If you have only an <i>estimate</i> of the eventual size of
- * the list, consider padding this estimate by a suitable amount, or simply
- * use {@link #newArrayListWithExpectedSize(int)} instead.
- *
- * @param initialArraySize the exact size of the initial backing array for
- * the returned array list ({@code ArrayList} documentation calls this
- * value the "capacity")
- * @return a new, empty {@code ArrayList} which is guaranteed not to resize
- * itself unless its size reaches {@code initialArraySize + 1}
- * @throws IllegalArgumentException if {@code initialArraySize} is negative
- */
- @GwtCompatible(serializable = true)
- public static <E> ArrayList<E> newArrayListWithCapacity(
- int initialArraySize) {
- checkArgument(initialArraySize >= 0); // for GWT.
- return new ArrayList<E>(initialArraySize);
- }
-
- /**
- * Creates an {@code ArrayList} instance sized appropriately to hold an
- * <i>estimated</i> number of elements without resizing. A small amount of
- * padding is added in case the estimate is low.
- *
- * <p><b>Note:</b> If you know the <i>exact</i> number of elements the list
- * will hold, or prefer to calculate your own amount of padding, refer to
- * {@link #newArrayListWithCapacity(int)}.
- *
- * @param estimatedSize an estimate of the eventual {@link List#size()} of
- * the new list
- * @return a new, empty {@code ArrayList}, sized appropriately to hold the
- * estimated number of elements
- * @throws IllegalArgumentException if {@code estimatedSize} is negative
- */
- @GwtCompatible(serializable = true)
- public static <E> ArrayList<E> newArrayListWithExpectedSize(
- int estimatedSize) {
- return new ArrayList<E>(computeArrayListCapacity(estimatedSize));
- }
-
- // LinkedList
-
- /**
- * Creates an empty {@code LinkedList} instance.
- *
- * <p><b>Note:</b> if you need an immutable empty {@link List}, use
- * {@link ImmutableList#of()} instead.
- *
- * @return a new, empty {@code LinkedList}
- */
- @GwtCompatible(serializable = true)
- public static <E> LinkedList<E> newLinkedList() {
- return new LinkedList<E>();
- }
-
- /**
- * Creates a {@code LinkedList} instance containing the given elements.
- *
- * @param elements the elements that the list should contain, in order
- * @return a new {@code LinkedList} containing those elements
- */
- @GwtCompatible(serializable = true)
- public static <E> LinkedList<E> newLinkedList(
- Iterable<? extends E> elements) {
- LinkedList<E> list = newLinkedList();
- for (E element : elements) {
- list.add(element);
- }
- return list;
- }
-
- /**
- * Returns an unmodifiable list containing the specified first element and
- * backed by the specified array of additional elements. Changes to the {@code
- * rest} array will be reflected in the returned list. Unlike {@link
- * Arrays#asList}, the returned list is unmodifiable.
- *
- * <p>This is useful when a varargs method needs to use a signature such as
- * {@code (Foo firstFoo, Foo... moreFoos)}, in order to avoid overload
- * ambiguity or to enforce a minimum argument count.
- *
- * <p>The returned list is serializable and implements {@link RandomAccess}.
- *
- * @param first the first element
- * @param rest an array of additional elements, possibly empty
- * @return an unmodifiable list containing the specified elements
- */
- public static <E> List<E> asList(@Nullable E first, E[] rest) {
- return new OnePlusArrayList<E>(first, rest);
- }
-
- /** @see Lists#asList(Object, Object[]) */
- private static class OnePlusArrayList<E> extends AbstractList<E>
- implements Serializable, RandomAccess {
- final E first;
- final E[] rest;
-
- OnePlusArrayList(@Nullable E first, E[] rest) {
- this.first = first;
- this.rest = checkNotNull(rest);
- }
- @Override public int size() {
- return rest.length + 1;
- }
- @Override public E get(int index) {
- // check explicitly so the IOOBE will have the right message
- checkElementIndex(index, size());
- return (index == 0) ? first : rest[index - 1];
- }
- private static final long serialVersionUID = 0;
- }
-
- /**
- * Returns an unmodifiable list containing the specified first and second
- * element, and backed by the specified array of additional elements. Changes
- * to the {@code rest} array will be reflected in the returned list. Unlike
- * {@link Arrays#asList}, the returned list is unmodifiable.
- *
- * <p>This is useful when a varargs method needs to use a signature such as
- * {@code (Foo firstFoo, Foo secondFoo, Foo... moreFoos)}, in order to avoid
- * overload ambiguity or to enforce a minimum argument count.
- *
- * <p>The returned list is serializable and implements {@link RandomAccess}.
- *
- * @param first the first element
- * @param second the second element
- * @param rest an array of additional elements, possibly empty
- * @return an unmodifiable list containing the specified elements
- */
- public static <E> List<E> asList(
- @Nullable E first, @Nullable E second, E[] rest) {
- return new TwoPlusArrayList<E>(first, second, rest);
- }
-
- /** @see Lists#asList(Object, Object, Object[]) */
- private static class TwoPlusArrayList<E> extends AbstractList<E>
- implements Serializable, RandomAccess {
- final E first;
- final E second;
- final E[] rest;
-
- TwoPlusArrayList(@Nullable E first, @Nullable E second, E[] rest) {
- this.first = first;
- this.second = second;
- this.rest = checkNotNull(rest);
- }
- @Override public int size() {
- return rest.length + 2;
- }
- @Override public E get(int index) {
- switch (index) {
- case 0:
- return first;
- case 1:
- return second;
- default:
- // check explicitly so the IOOBE will have the right message
- checkElementIndex(index, size());
- return rest[index - 2];
- }
- }
- private static final long serialVersionUID = 0;
- }
-
- /**
- * Returns every possible list that can be formed by choosing one element
- * from each of the given lists in order; the "n-ary
- * <a href="http://en.wikipedia.org/wiki/Cartesian_product">Cartesian
- * product</a>" of the lists. For example: <pre> {@code
- *
- * Lists.cartesianProduct(ImmutableList.of(
- * ImmutableList.of(1, 2),
- * ImmutableList.of("A", "B", "C")))}</pre>
- *
- * returns a list containing six lists in the following order:
- *
- * <ul>
- * <li>{@code ImmutableList.of(1, "A")}
- * <li>{@code ImmutableList.of(1, "B")}
- * <li>{@code ImmutableList.of(1, "C")}
- * <li>{@code ImmutableList.of(2, "A")}
- * <li>{@code ImmutableList.of(2, "B")}
- * <li>{@code ImmutableList.of(2, "C")}
- * </ul>
- *
- * The result is guaranteed to be in the "traditional", lexicographical
- * order for Cartesian products that you would get from nesting for loops:
- * <pre> {@code
- *
- * for (B b0 : lists.get(0)) {
- * for (B b1 : lists.get(1)) {
- * ...
- * ImmutableList<B> tuple = ImmutableList.of(b0, b1, ...);
- * // operate on tuple
- * }
- * }}</pre>
- *
- * Note that if any input list is empty, the Cartesian product will also be
- * empty. If no lists at all are provided (an empty list), the resulting
- * Cartesian product has one element, an empty list (counter-intuitive, but
- * mathematically consistent).
- *
- * <p><i>Performance notes:</i> while the cartesian product of lists of size
- * {@code m, n, p} is a list of size {@code m x n x p}, its actual memory
- * consumption is much smaller. When the cartesian product is constructed, the
- * input lists are merely copied. Only as the resulting list is iterated are
- * the individual lists created, and these are not retained after iteration.
- *
- * @param lists the lists to choose elements from, in the order that
- * the elements chosen from those lists should appear in the resulting
- * lists
- * @param <B> any common base class shared by all axes (often just {@link
- * Object})
- * @return the Cartesian product, as an immutable list containing immutable
- * lists
- * @throws IllegalArgumentException if the size of the cartesian product would
- * be greater than {@link Integer#MAX_VALUE}
- * @throws NullPointerException if {@code lists}, any one of the {@code lists},
- * or any element of a provided list is null
- */
- static <B> List<List<B>> cartesianProduct(
- List<? extends List<? extends B>> lists) {
- return CartesianList.create(lists);
- }
-
- /**
- * Returns every possible list that can be formed by choosing one element
- * from each of the given lists in order; the "n-ary
- * <a href="http://en.wikipedia.org/wiki/Cartesian_product">Cartesian
- * product</a>" of the lists. For example: <pre> {@code
- *
- * Lists.cartesianProduct(ImmutableList.of(
- * ImmutableList.of(1, 2),
- * ImmutableList.of("A", "B", "C")))}</pre>
- *
- * returns a list containing six lists in the following order:
- *
- * <ul>
- * <li>{@code ImmutableList.of(1, "A")}
- * <li>{@code ImmutableList.of(1, "B")}
- * <li>{@code ImmutableList.of(1, "C")}
- * <li>{@code ImmutableList.of(2, "A")}
- * <li>{@code ImmutableList.of(2, "B")}
- * <li>{@code ImmutableList.of(2, "C")}
- * </ul>
- *
- * The result is guaranteed to be in the "traditional", lexicographical
- * order for Cartesian products that you would get from nesting for loops:
- * <pre> {@code
- *
- * for (B b0 : lists.get(0)) {
- * for (B b1 : lists.get(1)) {
- * ...
- * ImmutableList<B> tuple = ImmutableList.of(b0, b1, ...);
- * // operate on tuple
- * }
- * }}</pre>
- *
- * Note that if any input list is empty, the Cartesian product will also be
- * empty. If no lists at all are provided (an empty list), the resulting
- * Cartesian product has one element, an empty list (counter-intuitive, but
- * mathematically consistent).
- *
- * <p><i>Performance notes:</i> while the cartesian product of lists of size
- * {@code m, n, p} is a list of size {@code m x n x p}, its actual memory
- * consumption is much smaller. When the cartesian product is constructed, the
- * input lists are merely copied. Only as the resulting list is iterated are
- * the individual lists created, and these are not retained after iteration.
- *
- * @param lists the lists to choose elements from, in the order that
- * the elements chosen from those lists should appear in the resulting
- * lists
- * @param <B> any common base class shared by all axes (often just {@link
- * Object})
- * @return the Cartesian product, as an immutable list containing immutable
- * lists
- * @throws IllegalArgumentException if the size of the cartesian product would
- * be greater than {@link Integer#MAX_VALUE}
- * @throws NullPointerException if {@code lists}, any one of the
- * {@code lists}, or any element of a provided list is null
- */
- static <B> List<List<B>> cartesianProduct(List<? extends B>... lists) {
- return cartesianProduct(Arrays.asList(lists));
- }
-
- /**
- * Returns a list that applies {@code function} to each element of {@code
- * fromList}. The returned list is a transformed view of {@code fromList};
- * changes to {@code fromList} will be reflected in the returned list and vice
- * versa.
- *
- * <p>Since functions are not reversible, the transform is one-way and new
- * items cannot be stored in the returned list. The {@code add},
- * {@code addAll} and {@code set} methods are unsupported in the returned
- * list.
- *
- * <p>The function is applied lazily, invoked when needed. This is necessary
- * for the returned list to be a view, but it means that the function will be
- * applied many times for bulk operations like {@link List#contains} and
- * {@link List#hashCode}. For this to perform well, {@code function} should be
- * fast. To avoid lazy evaluation when the returned list doesn't need to be a
- * view, copy the returned list into a new list of your choosing.
- *
- * <p>If {@code fromList} implements {@link RandomAccess}, so will the
- * returned list. The returned list is threadsafe if the supplied list and
- * function are.
- *
- * <p>If only a {@code Collection} or {@code Iterable} input is available, use
- * {@link Collections2#transform} or {@link Iterables#transform}.
- *
- * <p><b>Note:</b> serializing the returned list is implemented by serializing
- * {@code fromList}, its contents, and {@code function} -- <i>not</i> by
- * serializing the transformed values. This can lead to surprising behavior,
- * so serializing the returned list is <b>not recommended</b>. Instead,
- * copy the list using {@link ImmutableList#copyOf(Collection)} (for example),
- * then serialize the copy. Other methods similar to this do not implement
- * serialization at all for this reason.
- */
- public static <F, T> List<T> transform(
- List<F> fromList, Function<? super F, ? extends T> function) {
- return (fromList instanceof RandomAccess)
- ? new TransformingRandomAccessList<F, T>(fromList, function)
- : new TransformingSequentialList<F, T>(fromList, function);
- }
-
- /**
- * Implementation of a sequential transforming list.
- *
- * @see Lists#transform
- */
- private static class TransformingSequentialList<F, T>
- extends AbstractSequentialList<T> implements Serializable {
- final List<F> fromList;
- final Function<? super F, ? extends T> function;
-
- TransformingSequentialList(
- List<F> fromList, Function<? super F, ? extends T> function) {
- this.fromList = checkNotNull(fromList);
- this.function = checkNotNull(function);
- }
- /**
- * The default implementation inherited is based on iteration and removal of
- * each element which can be overkill. That's why we forward this call
- * directly to the backing list.
- */
- @Override public void clear() {
- fromList.clear();
- }
- @Override public int size() {
- return fromList.size();
- }
- @Override public ListIterator<T> listIterator(final int index) {
- return new TransformedListIterator<F, T>(fromList.listIterator(index)) {
- @Override
- T transform(F from) {
- return function.apply(from);
- }
- };
- }
-
- private static final long serialVersionUID = 0;
- }
-
- /**
- * Implementation of a transforming random access list. We try to make as many
- * of these methods pass-through to the source list as possible so that the
- * performance characteristics of the source list and transformed list are
- * similar.
- *
- * @see Lists#transform
- */
- private static class TransformingRandomAccessList<F, T>
- extends AbstractList<T> implements RandomAccess, Serializable {
- final List<F> fromList;
- final Function<? super F, ? extends T> function;
-
- TransformingRandomAccessList(
- List<F> fromList, Function<? super F, ? extends T> function) {
- this.fromList = checkNotNull(fromList);
- this.function = checkNotNull(function);
- }
- @Override public void clear() {
- fromList.clear();
- }
- @Override public T get(int index) {
- return function.apply(fromList.get(index));
- }
- @Override public boolean isEmpty() {
- return fromList.isEmpty();
- }
- @Override public T remove(int index) {
- return function.apply(fromList.remove(index));
- }
- @Override public int size() {
- return fromList.size();
- }
- private static final long serialVersionUID = 0;
- }
-
- /**
- * Returns consecutive {@linkplain List#subList(int, int) sublists} of a list,
- * each of the same size (the final list may be smaller). For example,
- * partitioning a list containing {@code [a, b, c, d, e]} with a partition
- * size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer list containing
- * two inner lists of three and two elements, all in the original order.
- *
- * <p>The outer list is unmodifiable, but reflects the latest state of the
- * source list. The inner lists are sublist views of the original list,
- * produced on demand using {@link List#subList(int, int)}, and are subject
- * to all the usual caveats about modification as explained in that API.
- *
- * @param list the list to return consecutive sublists of
- * @param size the desired size of each sublist (the last may be
- * smaller)
- * @return a list of consecutive sublists
- * @throws IllegalArgumentException if {@code partitionSize} is nonpositive
- */
- public static <T> List<List<T>> partition(List<T> list, int size) {
- checkNotNull(list);
- checkArgument(size > 0);
- return (list instanceof RandomAccess)
- ? new RandomAccessPartition<T>(list, size)
- : new Partition<T>(list, size);
- }
-
- private static class Partition<T> extends AbstractList<List<T>> {
- final List<T> list;
- final int size;
-
- Partition(List<T> list, int size) {
- this.list = list;
- this.size = size;
- }
-
- @Override public List<T> get(int index) {
- int listSize = size();
- checkElementIndex(index, listSize);
- int start = index * size;
- int end = Math.min(start + size, list.size());
- return list.subList(start, end);
- }
-
- @Override public int size() {
- // TODO(user): refactor to common.math.IntMath.divide
- int result = list.size() / size;
- if (result * size != list.size()) {
- result++;
- }
- return result;
- }
-
- @Override public boolean isEmpty() {
- return list.isEmpty();
- }
- }
-
- private static class RandomAccessPartition<T> extends Partition<T>
- implements RandomAccess {
- RandomAccessPartition(List<T> list, int size) {
- super(list, size);
- }
- }
-
- /**
- * Returns a view of the specified string as an immutable list of {@code
- * Character} values.
- *
- * @since 7.0
- */
- @Beta public static ImmutableList<Character> charactersOf(String string) {
- return new StringAsImmutableList(checkNotNull(string));
- }
-
- @SuppressWarnings("serial") // serialized using ImmutableList serialization
- private static final class StringAsImmutableList
- extends ImmutableList<Character> {
-
- private final String string;
-
- StringAsImmutableList(String string) {
- this.string = string;
- }
-
- @Override public int indexOf(@Nullable Object object) {
- return (object instanceof Character)
- ? string.indexOf((Character) object) : -1;
- }
-
- @Override public int lastIndexOf(@Nullable Object object) {
- return (object instanceof Character)
- ? string.lastIndexOf((Character) object) : -1;
- }
-
- @Override public ImmutableList<Character> subList(
- int fromIndex, int toIndex) {
- checkPositionIndexes(fromIndex, toIndex, size()); // for GWT
- return charactersOf(string.substring(fromIndex, toIndex));
- }
-
- @Override boolean isPartialView() {
- return false;
- }
-
- @Override public Character get(int index) {
- checkElementIndex(index, size()); // for GWT
- return string.charAt(index);
- }
-
- @Override public int size() {
- return string.length();
- }
-
- @Override public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof List)) {
- return false;
- }
- List<?> list = (List<?>) obj;
- int n = string.length();
- if (n != list.size()) {
- return false;
- }
- Iterator<?> iterator = list.iterator();
- for (int i = 0; i < n; i++) {
- Object elem = iterator.next();
- if (!(elem instanceof Character)
- || ((Character) elem).charValue() != string.charAt(i)) {
- return false;
- }
- }
- return true;
- }
-
- int hash = 0;
-
- @Override public int hashCode() {
- int h = hash;
- if (h == 0) {
- h = 1;
- for (int i = 0; i < string.length(); i++) {
- h = h * 31 + string.charAt(i);
- }
- hash = h;
- }
- return h;
- }
- }
-
- /**
- * Returns a view of the specified {@code CharSequence} as a {@code
- * List<Character>}, viewing {@code sequence} as a sequence of Unicode code
- * units. The view does not support any modification operations, but reflects
- * any changes to the underlying character sequence.
- *
- * @param sequence the character sequence to view as a {@code List} of
- * characters
- * @return an {@code List<Character>} view of the character sequence
- * @since 7.0
- */
- @Beta public static List<Character> charactersOf(CharSequence sequence) {
- return new CharSequenceAsList(checkNotNull(sequence));
- }
-
- private static final class CharSequenceAsList
- extends AbstractList<Character> {
- private final CharSequence sequence;
-
- CharSequenceAsList(CharSequence sequence) {
- this.sequence = sequence;
- }
-
- @Override public Character get(int index) {
- checkElementIndex(index, size()); // for GWT
- return sequence.charAt(index);
- }
-
- @Override public boolean contains(@Nullable Object o) {
- return indexOf(o) >= 0;
- }
-
- @Override public int indexOf(@Nullable Object o) {
- if (o instanceof Character) {
- char c = (Character) o;
- for (int i = 0; i < sequence.length(); i++) {
- if (sequence.charAt(i) == c) {
- return i;
- }
- }
- }
- return -1;
- }
-
- @Override public int lastIndexOf(@Nullable Object o) {
- if (o instanceof Character) {
- char c = ((Character) o).charValue();
- for (int i = sequence.length() - 1; i >= 0; i--) {
- if (sequence.charAt(i) == c) {
- return i;
- }
- }
- }
- return -1;
- }
-
- @Override public int size() {
- return sequence.length();
- }
-
- @Override public List<Character> subList(int fromIndex, int toIndex) {
- checkPositionIndexes(fromIndex, toIndex, size()); // for GWT
- return charactersOf(sequence.subSequence(fromIndex, toIndex));
- }
-
- @Override public int hashCode() {
- int hash = 1;
- for (int i = 0; i < sequence.length(); i++) {
- hash = hash * 31 + sequence.charAt(i);
- }
- return hash;
- }
-
- @Override public boolean equals(@Nullable Object o) {
- if (!(o instanceof List)) {
- return false;
- }
- List<?> list = (List<?>) o;
- int n = sequence.length();
- if (n != list.size()) {
- return false;
- }
- Iterator<?> iterator = list.iterator();
- for (int i = 0; i < n; i++) {
- Object elem = iterator.next();
- if (!(elem instanceof Character)
- || ((Character) elem).charValue() != sequence.charAt(i)) {
- return false;
- }
- }
- return true;
- }
- }
-
- /**
- * Returns a reversed view of the specified list. For example, {@code
- * Lists.reverse(Arrays.asList(1, 2, 3))} returns a list containing {@code 3,
- * 2, 1}. The returned list is backed by this list, so changes in the returned
- * list are reflected in this list, and vice-versa. The returned list supports
- * all of the optional list operations supported by this list.
- *
- * <p>The returned list is random-access if the specified list is random
- * access.
- *
- * @since 7.0
- */
- public static <T> List<T> reverse(List<T> list) {
- if (list instanceof ReverseList) {
- return ((ReverseList<T>) list).getForwardList();
- } else if (list instanceof RandomAccess) {
- return new RandomAccessReverseList<T>(list);
- } else {
- return new ReverseList<T>(list);
- }
- }
-
- private static class ReverseList<T> extends AbstractList<T> {
- private final List<T> forwardList;
-
- ReverseList(List<T> forwardList) {
- this.forwardList = checkNotNull(forwardList);
- }
-
- List<T> getForwardList() {
- return forwardList;
- }
-
- private int reverseIndex(int index) {
- int size = size();
- checkElementIndex(index, size);
- return (size - 1) - index;
- }
-
- private int reversePosition(int index) {
- int size = size();
- checkPositionIndex(index, size);
- return size - index;
- }
-
- @Override public void add(int index, @Nullable T element) {
- forwardList.add(reversePosition(index), element);
- }
-
- @Override public void clear() {
- forwardList.clear();
- }
-
- @Override public T remove(int index) {
- return forwardList.remove(reverseIndex(index));
- }
-
- @Override protected void removeRange(int fromIndex, int toIndex) {
- subList(fromIndex, toIndex).clear();
- }
-
- @Override public T set(int index, @Nullable T element) {
- return forwardList.set(reverseIndex(index), element);
- }
-
- @Override public T get(int index) {
- return forwardList.get(reverseIndex(index));
- }
-
- @Override public boolean isEmpty() {
- return forwardList.isEmpty();
- }
-
- @Override public int size() {
- return forwardList.size();
- }
-
- @Override public boolean contains(@Nullable Object o) {
- return forwardList.contains(o);
- }
-
- @Override public boolean containsAll(Collection<?> c) {
- return forwardList.containsAll(c);
- }
-
- @Override public List<T> subList(int fromIndex, int toIndex) {
- checkPositionIndexes(fromIndex, toIndex, size());
- return reverse(forwardList.subList(
- reversePosition(toIndex), reversePosition(fromIndex)));
- }
-
- @Override public int indexOf(@Nullable Object o) {
- int index = forwardList.lastIndexOf(o);
- return (index >= 0) ? reverseIndex(index) : -1;
- }
-
- @Override public int lastIndexOf(@Nullable Object o) {
- int index = forwardList.indexOf(o);
- return (index >= 0) ? reverseIndex(index) : -1;
- }
-
- @Override public Iterator<T> iterator() {
- return listIterator();
- }
-
- @Override public ListIterator<T> listIterator(int index) {
- int start = reversePosition(index);
- final ListIterator<T> forwardIterator = forwardList.listIterator(start);
- return new ListIterator<T>() {
-
- boolean canRemove;
- boolean canSet;
-
- @Override public void add(T e) {
- forwardIterator.add(e);
- forwardIterator.previous();
- canSet = canRemove = false;
- }
-
- @Override public boolean hasNext() {
- return forwardIterator.hasPrevious();
- }
-
- @Override public boolean hasPrevious() {
- return forwardIterator.hasNext();
- }
-
- @Override public T next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- canSet = canRemove = true;
- return forwardIterator.previous();
- }
-
- @Override public int nextIndex() {
- return reversePosition(forwardIterator.nextIndex());
- }
-
- @Override public T previous() {
- if (!hasPrevious()) {
- throw new NoSuchElementException();
- }
- canSet = canRemove = true;
- return forwardIterator.next();
- }
-
- @Override public int previousIndex() {
- return nextIndex() - 1;
- }
-
- @Override public void remove() {
- checkState(canRemove);
- forwardIterator.remove();
- canRemove = canSet = false;
- }
-
- @Override public void set(T e) {
- checkState(canSet);
- forwardIterator.set(e);
- }
- };
- }
- }
-
- private static class RandomAccessReverseList<T> extends ReverseList<T>
- implements RandomAccess {
- RandomAccessReverseList(List<T> forwardList) {
- super(forwardList);
- }
- }
-
- /**
- * An implementation of {@link List#hashCode()}.
- */
- static int hashCodeImpl(List<?> list) {
- int hashCode = 1;
- for (Object o : list) {
- hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
-
- hashCode = ~~hashCode;
- // needed to deal with GWT integer overflow
- }
- return hashCode;
- }
-
- /**
- * An implementation of {@link List#equals(Object)}.
- */
- static boolean equalsImpl(List<?> list, @Nullable Object object) {
- if (object == checkNotNull(list)) {
- return true;
- }
- if (!(object instanceof List)) {
- return false;
- }
-
- List<?> o = (List<?>) object;
-
- return list.size() == o.size()
- && Iterators.elementsEqual(list.iterator(), o.iterator());
- }
-
- /**
- * An implementation of {@link List#addAll(int, Collection)}.
- */
- static <E> boolean addAllImpl(
- List<E> list, int index, Iterable<? extends E> elements) {
- boolean changed = false;
- ListIterator<E> listIterator = list.listIterator(index);
- for (E e : elements) {
- listIterator.add(e);
- changed = true;
- }
- return changed;
- }
-
- /**
- * An implementation of {@link List#indexOf(Object)}.
- */
- static int indexOfImpl(List<?> list, @Nullable Object element){
- ListIterator<?> listIterator = list.listIterator();
- while (listIterator.hasNext()) {
- if (Objects.equal(element, listIterator.next())) {
- return listIterator.previousIndex();
- }
- }
- return -1;
- }
-
- /**
- * An implementation of {@link List#lastIndexOf(Object)}.
- */
- static int lastIndexOfImpl(List<?> list, @Nullable Object element){
- ListIterator<?> listIterator = list.listIterator(list.size());
- while (listIterator.hasPrevious()) {
- if (Objects.equal(element, listIterator.previous())) {
- return listIterator.nextIndex();
- }
- }
- return -1;
- }
-
- /**
- * Returns an implementation of {@link List#listIterator(int)}.
- */
- static <E> ListIterator<E> listIteratorImpl(List<E> list, int index) {
- return new AbstractListWrapper<E>(list).listIterator(index);
- }
-
- /**
- * An implementation of {@link List#subList(int, int)}.
- */
- static <E> List<E> subListImpl(
- final List<E> list, int fromIndex, int toIndex) {
- List<E> wrapper;
- if (list instanceof RandomAccess) {
- wrapper = new RandomAccessListWrapper<E>(list) {
- @Override public ListIterator<E> listIterator(int index) {
- return backingList.listIterator(index);
- }
-
- private static final long serialVersionUID = 0;
- };
- } else {
- wrapper = new AbstractListWrapper<E>(list) {
- @Override public ListIterator<E> listIterator(int index) {
- return backingList.listIterator(index);
- }
-
- private static final long serialVersionUID = 0;
- };
- }
- return wrapper.subList(fromIndex, toIndex);
- }
-
- private static class AbstractListWrapper<E> extends AbstractList<E> {
- final List<E> backingList;
-
- AbstractListWrapper(List<E> backingList) {
- this.backingList = checkNotNull(backingList);
- }
-
- @Override public void add(int index, E element) {
- backingList.add(index, element);
- }
-
- @Override public boolean addAll(int index, Collection<? extends E> c) {
- return backingList.addAll(index, c);
- }
-
- @Override public E get(int index) {
- return backingList.get(index);
- }
-
- @Override public E remove(int index) {
- return backingList.remove(index);
- }
-
- @Override public E set(int index, E element) {
- return backingList.set(index, element);
- }
-
- @Override public boolean contains(Object o) {
- return backingList.contains(o);
- }
-
- @Override public int size() {
- return backingList.size();
- }
- }
-
- private static class RandomAccessListWrapper<E>
- extends AbstractListWrapper<E> implements RandomAccess {
- RandomAccessListWrapper(List<E> backingList) {
- super(backingList);
- }
- }
-
- /**
- * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
- */
- static <T> List<T> cast(Iterable<T> iterable) {
- return (List<T>) iterable;
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/MapMaker.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/MapMaker.java
index 6f88f89..52c1a98 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/MapMaker.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/MapMaker.java
@@ -42,8 +42,8 @@ public class MapMaker extends GenericMapMaker<Object, Object> {
private final Function<? super K, ? extends V> computer;
private final int maximumSize;
- ExpiringComputingMap(
- long expirationMillis, int maximumSize, int initialCapacity, float loadFactor) {
+ ExpiringComputingMap(long expirationMillis, int maximumSize, int initialCapacity,
+ float loadFactor) {
this(expirationMillis, null, maximumSize, initialCapacity, loadFactor);
}
@@ -184,6 +184,12 @@ public class MapMaker extends GenericMapMaker<Object, Object> {
}
@Override
+ public
+ MapMaker expiration(long duration, TimeUnit unit) {
+ return expireAfterWrite(duration, unit);
+ }
+
+ @Override
MapMaker expireAfterWrite(long duration, TimeUnit unit) {
if (expirationMillis != 0) {
throw new IllegalStateException(
@@ -221,16 +227,26 @@ public class MapMaker extends GenericMapMaker<Object, Object> {
}
@Override
+ MapMaker strongKeys() {
+ return this;
+ }
+
+ @Override
+ MapMaker strongValues() {
+ return this;
+ }
+
+ @Override
public <K, V> ConcurrentMap<K, V> makeMap() {
return useCustomMap
- ? new ExpiringComputingMap<K, V>(
- expirationMillis, null, maximumSize, initialCapacity, loadFactor)
+ ? new ExpiringComputingMap<K, V>(expirationMillis, null, maximumSize, initialCapacity,
+ loadFactor)
: new ConcurrentHashMap<K, V>(initialCapacity, loadFactor);
}
@Override
public <K, V> ConcurrentMap<K, V> makeComputingMap(Function<? super K, ? extends V> computer) {
- return new ExpiringComputingMap<K, V>(
- expirationMillis, computer, maximumSize, initialCapacity, loadFactor);
+ return new ExpiringComputingMap<K, V>(expirationMillis, computer, maximumSize, initialCapacity,
+ loadFactor);
}
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java
index fd6909d..78165de 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Maps.java
@@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalences;
import com.google.common.base.Function;
import com.google.common.base.Joiner.MapJoiner;
import com.google.common.base.Objects;
@@ -34,6 +35,7 @@ import com.google.common.primitives.Ints;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractMap;
+import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -46,20 +48,14 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
-import java.util.SortedSet;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nullable;
/**
- * Static utility methods pertaining to {@link Map} instances (including instances of
- * {@link SortedMap}, {@link BiMap}, etc.). Also see this class's counterparts
- * {@link Lists}, {@link Sets} and {@link Queues}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Maps">
- * {@code Maps}</a>.
+ * Static utility methods pertaining to {@link Map} instances. Also see this
+ * class's counterparts {@link Lists} and {@link Sets}.
*
* @author Kevin Bourrillion
* @author Mike Bostock
@@ -71,60 +67,6 @@ import javax.annotation.Nullable;
public final class Maps {
private Maps() {}
- private enum EntryFunction implements Function<Entry, Object> {
- KEY {
- @Override
- @Nullable
- public Object apply(Entry entry) {
- return entry.getKey();
- }
- },
- VALUE {
- @Override
- @Nullable
- public Object apply(Entry entry) {
- return entry.getValue();
- }
- };
- }
-
- @SuppressWarnings("unchecked")
- static <K> Function<Entry<K, ?>, K> keyFunction() {
- return (Function) EntryFunction.KEY;
- }
-
- static <V> Function<Entry<?, V>, V> valueFunction() {
- return (Function) EntryFunction.VALUE;
- }
-
- /**
- * Returns an immutable map instance containing the given entries.
- * Internally, the returned set will be backed by an {@link EnumMap}.
- *
- * <p>The iteration order of the returned map follows the enum's iteration
- * order, not the order in which the elements appear in the given map.
- *
- * @param map the map to make an immutable copy of
- * @return an immutable map containing those entries
- * @since 14.0
- */
- @GwtCompatible(serializable = true)
- @Beta
- public static <K extends Enum<K>, V> ImmutableMap<K, V> immutableEnumMap(
- Map<K, V> map) {
- if (map instanceof ImmutableEnumMap) {
- return (ImmutableEnumMap<K, V>) map;
- } else if (map.isEmpty()) {
- return ImmutableMap.of();
- } else {
- for (Map.Entry<K, V> entry : map.entrySet()) {
- checkNotNull(entry.getKey());
- checkNotNull(entry.getValue());
- }
- return ImmutableEnumMap.asImmutable(new EnumMap<K, V>(map));
- }
- }
-
/**
* Creates a <i>mutable</i>, empty {@code HashMap} instance.
*
@@ -324,6 +266,38 @@ public final class Maps {
}
/**
+ * Returns a synchronized (thread-safe) bimap backed by the specified bimap.
+ * In order to guarantee serial access, it is critical that <b>all</b> access
+ * to the backing bimap is accomplished through the returned bimap.
+ *
+ * <p>It is imperative that the user manually synchronize on the returned map
+ * when accessing any of its collection views: <pre> {@code
+ *
+ * BiMap<Long, String> map = Maps.synchronizedBiMap(
+ * HashBiMap.<Long, String>create());
+ * ...
+ * Set<Long> set = map.keySet(); // Needn't be in synchronized block
+ * ...
+ * synchronized (map) { // Synchronizing on map, not set!
+ * Iterator<Long> it = set.iterator(); // Must be in synchronized block
+ * while (it.hasNext()) {
+ * foo(it.next());
+ * }
+ * }}</pre>
+ *
+ * Failure to follow this advice may result in non-deterministic behavior.
+ *
+ * <p>The returned bimap will be serializable if the specified bimap is
+ * serializable.
+ *
+ * @param bimap the bimap to be wrapped in a synchronized view
+ * @return a sychronized view of the specified bimap
+ */
+ public static <K, V> BiMap<K, V> synchronizedBiMap(BiMap<K, V> bimap) {
+ return Synchronized.biMap(bimap, null);
+ }
+
+ /**
* Computes the difference between two maps. This difference is an immutable
* snapshot of the state of the maps at the time this method is called. It
* will never change, even if the maps change at a later time.
@@ -347,7 +321,7 @@ public final class Maps {
SortedMapDifference<K, V> result = difference(sortedLeft, right);
return result;
}
- return difference(left, right, Equivalence.equals());
+ return difference(left, right, Equivalences.equals());
}
/**
@@ -519,7 +493,7 @@ public final class Maps {
}
@Override public boolean equals(@Nullable Object object) {
- if (object instanceof MapDifference.ValueDifference) {
+ if (object instanceof MapDifference.ValueDifference<?>) {
MapDifference.ValueDifference<?> that =
(MapDifference.ValueDifference<?>) object;
return Objects.equal(this.left, that.leftValue())
@@ -556,6 +530,7 @@ public final class Maps {
* @return the difference between the two maps
* @since 11.0
*/
+ @Beta
public static <K, V> SortedMapDifference<K, V> difference(
SortedMap<K, ? extends V> left, Map<? extends K, ? extends V> right) {
checkNotNull(left);
@@ -640,313 +615,6 @@ public final class Maps {
}
return (Comparator<E>) Ordering.natural();
}
-
- /**
- * Returns a view of the set as a map, mapping keys from the set according to
- * the specified function.
- *
- * <p>Specifically, for each {@code k} in the backing set, the returned map
- * has an entry mapping {@code k} to {@code function.apply(k)}. The {@code
- * keySet}, {@code values}, and {@code entrySet} views of the returned map
- * iterate in the same order as the backing set.
- *
- * <p>Modifications to the backing set are read through to the returned map.
- * The returned map supports removal operations if the backing set does.
- * Removal operations write through to the backing set. The returned map
- * does not support put operations.
- *
- * <p><b>Warning</b>: If the function rejects {@code null}, caution is
- * required to make sure the set does not contain {@code null}, because the
- * view cannot stop {@code null} from being added to the set.
- *
- * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
- * key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also
- * of type {@code K}. Using a key type for which this may not hold, such as
- * {@code ArrayList}, may risk a {@code ClassCastException} when calling
- * methods on the resulting map view.
- *
- * @since 14.0
- */
- @Beta
- public static <K, V> Map<K, V> asMap(
- Set<K> set, Function<? super K, V> function) {
- if (set instanceof SortedSet) {
- return asMap((SortedSet<K>) set, function);
- } else {
- return new AsMapView<K, V>(set, function);
- }
- }
-
- /**
- * Returns a view of the sorted set as a map, mapping keys from the set
- * according to the specified function.
- *
- * <p>Specifically, for each {@code k} in the backing set, the returned map
- * has an entry mapping {@code k} to {@code function.apply(k)}. The {@code
- * keySet}, {@code values}, and {@code entrySet} views of the returned map
- * iterate in the same order as the backing set.
- *
- * <p>Modifications to the backing set are read through to the returned map.
- * The returned map supports removal operations if the backing set does.
- * Removal operations write through to the backing set. The returned map does
- * not support put operations.
- *
- * <p><b>Warning</b>: If the function rejects {@code null}, caution is
- * required to make sure the set does not contain {@code null}, because the
- * view cannot stop {@code null} from being added to the set.
- *
- * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
- * key type {@code K}, {@code k.equals(k2)} implies that {@code k2} is also of
- * type {@code K}. Using a key type for which this may not hold, such as
- * {@code ArrayList}, may risk a {@code ClassCastException} when calling
- * methods on the resulting map view.
- *
- * @since 14.0
- */
- @Beta
- public static <K, V> SortedMap<K, V> asMap(
- SortedSet<K> set, Function<? super K, V> function) {
- return Platform.mapsAsMapSortedSet(set, function);
- }
-
- static <K, V> SortedMap<K, V> asMapSortedIgnoreNavigable(SortedSet<K> set,
- Function<? super K, V> function) {
- return new SortedAsMapView<K, V>(set, function);
- }
-
- private static class AsMapView<K, V> extends ImprovedAbstractMap<K, V> {
-
- private final Set<K> set;
- final Function<? super K, V> function;
-
- Set<K> backingSet() {
- return set;
- }
-
- AsMapView(Set<K> set, Function<? super K, V> function) {
- this.set = checkNotNull(set);
- this.function = checkNotNull(function);
- }
-
- @Override
- public Set<K> keySet() {
- // probably not worth caching
- return removeOnlySet(backingSet());
- }
-
- @Override
- public Collection<V> values() {
- // probably not worth caching
- return Collections2.transform(set, function);
- }
-
- @Override
- public int size() {
- return backingSet().size();
- }
-
- @Override
- public boolean containsKey(@Nullable Object key) {
- return backingSet().contains(key);
- }
-
- @Override
- public V get(@Nullable Object key) {
- if (backingSet().contains(key)) {
- @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
- K k = (K) key;
- return function.apply(k);
- } else {
- return null;
- }
- }
-
- @Override
- public V remove(@Nullable Object key) {
- if (backingSet().remove(key)) {
- @SuppressWarnings("unchecked") // unsafe, but Javadoc warns about it
- K k = (K) key;
- return function.apply(k);
- } else {
- return null;
- }
- }
-
- @Override
- public void clear() {
- backingSet().clear();
- }
-
- @Override
- protected Set<Entry<K, V>> createEntrySet() {
- return new EntrySet<K, V>() {
- @Override
- Map<K, V> map() {
- return AsMapView.this;
- }
-
- @Override
- public Iterator<Entry<K, V>> iterator() {
- return asSetEntryIterator(backingSet(), function);
- }
- };
- }
- }
-
- private static <K, V> Iterator<Entry<K, V>> asSetEntryIterator(
- Set<K> set, final Function<? super K, V> function) {
- return new TransformedIterator<K, Entry<K,V>>(set.iterator()) {
- @Override
- Entry<K, V> transform(K key) {
- return Maps.immutableEntry(key, function.apply(key));
- }
- };
- }
-
- private static class SortedAsMapView<K, V> extends AsMapView<K, V>
- implements SortedMap<K, V> {
-
- SortedAsMapView(SortedSet<K> set, Function<? super K, V> function) {
- super(set, function);
- }
-
- @Override
- SortedSet<K> backingSet() {
- return (SortedSet<K>) super.backingSet();
- }
-
- @Override
- public Comparator<? super K> comparator() {
- return backingSet().comparator();
- }
-
- @Override
- public Set<K> keySet() {
- return removeOnlySortedSet(backingSet());
- }
-
- @Override
- public SortedMap<K, V> subMap(K fromKey, K toKey) {
- return asMap(backingSet().subSet(fromKey, toKey), function);
- }
-
- @Override
- public SortedMap<K, V> headMap(K toKey) {
- return asMap(backingSet().headSet(toKey), function);
- }
-
- @Override
- public SortedMap<K, V> tailMap(K fromKey) {
- return asMap(backingSet().tailSet(fromKey), function);
- }
-
- @Override
- public K firstKey() {
- return backingSet().first();
- }
-
- @Override
- public K lastKey() {
- return backingSet().last();
- }
- }
-
- private static <E> Set<E> removeOnlySet(final Set<E> set) {
- return new ForwardingSet<E>() {
- @Override
- protected Set<E> delegate() {
- return set;
- }
-
- @Override
- public boolean add(E element) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addAll(Collection<? extends E> es) {
- throw new UnsupportedOperationException();
- }
- };
- }
-
- private static <E> SortedSet<E> removeOnlySortedSet(final SortedSet<E> set) {
- return new ForwardingSortedSet<E>() {
- @Override
- protected SortedSet<E> delegate() {
- return set;
- }
-
- @Override
- public boolean add(E element) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addAll(Collection<? extends E> es) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SortedSet<E> headSet(E toElement) {
- return removeOnlySortedSet(super.headSet(toElement));
- }
-
- @Override
- public SortedSet<E> subSet(E fromElement, E toElement) {
- return removeOnlySortedSet(super.subSet(fromElement, toElement));
- }
-
- @Override
- public SortedSet<E> tailSet(E fromElement) {
- return removeOnlySortedSet(super.tailSet(fromElement));
- }
- };
- }
-
- /**
- * Returns an immutable map for which the given {@code keys} are mapped to
- * values by the given function in the order they appear in the original
- * iterable. If {@code keys} contains duplicate elements, the returned map
- * will contain each distinct key once in the order it first appears in
- * {@code keys}.
- *
- * @throws NullPointerException if any element of {@code keys} is
- * {@code null}, or if {@code valueFunction} produces {@code null}
- * for any key
- * @since 14.0
- */
- @Beta
- public static <K, V> ImmutableMap<K, V> toMap(Iterable<K> keys,
- Function<? super K, V> valueFunction) {
- return toMap(keys.iterator(), valueFunction);
- }
-
- /**
- * Returns an immutable map for which the given {@code keys} are mapped to
- * values by the given function in the order they appear in the original
- * iterator. If {@code keys} contains duplicate elements, the returned map
- * will contain each distinct key once in the order it first appears in
- * {@code keys}.
- *
- * @throws NullPointerException if any element of {@code keys} is
- * {@code null}, or if {@code valueFunction} produces {@code null}
- * for any key
- * @since 14.0
- */
- @Beta
- public static <K, V> ImmutableMap<K, V> toMap(Iterator<K> keys,
- Function<? super K, V> valueFunction) {
- checkNotNull(valueFunction);
- // Using LHM instead of a builder so as not to fail on duplicate keys
- Map<K, V> builder = newLinkedHashMap();
- while (keys.hasNext()) {
- K key = keys.next();
- builder.put(key, valueFunction.apply(key));
- }
- return ImmutableMap.copyOf(builder);
- }
-
/**
* Returns an immutable map for which the {@link Map#values} are the given
* elements in the given order, and each key is the product of invoking a
@@ -967,6 +635,24 @@ public final class Maps {
}
/**
+ * <b>Deprecated.</b>
+ *
+ * @since 10.0
+ * @deprecated use {@link #uniqueIndex(Iterator, Function)} by casting {@code
+ * values} to {@code Iterator<V>}, or better yet, by implementing only
+ * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled
+ * for deletion in March 2012.</b>
+ */
+ @Beta
+ @Deprecated
+ public static <K, V, I extends Object & Iterable<V> & Iterator<V>>
+ ImmutableMap<K, V> uniqueIndex(
+ I values, Function<? super V, K> keyFunction) {
+ Iterable<V> valuesIterable = checkNotNull(values);
+ return uniqueIndex(valuesIterable, keyFunction);
+ }
+
+ /**
* Returns an immutable map for which the {@link Map#values} are the given
* elements in the given order, and each key is the product of invoking a
* supplied function on its corresponding value.
@@ -1128,38 +814,6 @@ public final class Maps {
}
/**
- * Returns a synchronized (thread-safe) bimap backed by the specified bimap.
- * In order to guarantee serial access, it is critical that <b>all</b> access
- * to the backing bimap is accomplished through the returned bimap.
- *
- * <p>It is imperative that the user manually synchronize on the returned map
- * when accessing any of its collection views: <pre> {@code
- *
- * BiMap<Long, String> map = Maps.synchronizedBiMap(
- * HashBiMap.<Long, String>create());
- * ...
- * Set<Long> set = map.keySet(); // Needn't be in synchronized block
- * ...
- * synchronized (map) { // Synchronizing on map, not set!
- * Iterator<Long> it = set.iterator(); // Must be in synchronized block
- * while (it.hasNext()) {
- * foo(it.next());
- * }
- * }}</pre>
- *
- * Failure to follow this advice may result in non-deterministic behavior.
- *
- * <p>The returned bimap will be serializable if the specified bimap is
- * serializable.
- *
- * @param bimap the bimap to be wrapped in a synchronized view
- * @return a sychronized view of the specified bimap
- */
- public static <K, V> BiMap<K, V> synchronizedBiMap(BiMap<K, V> bimap) {
- return Synchronized.biMap(bimap, null);
- }
-
- /**
* Returns an unmodifiable view of the specified bimap. This method allows
* modules to provide users with "read-only" access to internal bimaps. Query
* operations on the returned bimap "read through" to the specified bimap, and
@@ -1182,7 +836,7 @@ public final class Maps {
extends ForwardingMap<K, V> implements BiMap<K, V>, Serializable {
final Map<K, V> unmodifiableMap;
final BiMap<? extends K, ? extends V> delegate;
- BiMap<V, K> inverse;
+ transient BiMap<V, K> inverse;
transient Set<V> values;
UnmodifiableBiMap(BiMap<? extends K, ? extends V> delegate,
@@ -1256,8 +910,16 @@ public final class Maps {
* a view, copy the returned map into a new map of your choosing.
*/
public static <K, V1, V2> Map<K, V2> transformValues(
- Map<K, V1> fromMap, Function<? super V1, V2> function) {
- return transformEntries(fromMap, asEntryTransformer(function));
+ Map<K, V1> fromMap, final Function<? super V1, V2> function) {
+ checkNotNull(function);
+ EntryTransformer<K, V1, V2> transformer =
+ new EntryTransformer<K, V1, V2>() {
+ @Override
+ public V2 transformEntry(K key, V1 value) {
+ return function.apply(value);
+ }
+ };
+ return transformEntries(fromMap, transformer);
}
/**
@@ -1299,20 +961,18 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V1, V2> SortedMap<K, V2> transformValues(
- SortedMap<K, V1> fromMap, Function<? super V1, V2> function) {
- return transformEntries(fromMap, asEntryTransformer(function));
- }
-
- private static <K, V1, V2> EntryTransformer<K, V1, V2>
- asEntryTransformer(final Function<? super V1, V2> function) {
+ SortedMap<K, V1> fromMap, final Function<? super V1, V2> function) {
checkNotNull(function);
- return new EntryTransformer<K, V1, V2>() {
- @Override
- public V2 transformEntry(K key, V1 value) {
- return function.apply(value);
- }
- };
+ EntryTransformer<K, V1, V2> transformer =
+ new EntryTransformer<K, V1, V2>() {
+ @Override
+ public V2 transformEntry(K key, V1 value) {
+ return function.apply(value);
+ }
+ };
+ return transformEntries(fromMap, transformer);
}
/**
@@ -1427,14 +1087,9 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V1, V2> SortedMap<K, V2> transformEntries(
- SortedMap<K, V1> fromMap,
- EntryTransformer<? super K, ? super V1, V2> transformer) {
- return Platform.mapsTransformEntriesSortedMap(fromMap, transformer);
- }
-
- static <K, V1, V2> SortedMap<K, V2> transformEntriesIgnoreNavigable(
- SortedMap<K, V1> fromMap,
+ final SortedMap<K, V1> fromMap,
EntryTransformer<? super K, ? super V1, V2> transformer) {
return new TransformedEntriesSortedMap<K, V1, V2>(fromMap, transformer);
}
@@ -1526,23 +1181,17 @@ public final class Maps {
}
@Override public Iterator<Entry<K, V2>> iterator() {
- return new TransformedIterator<Entry<K, V1>, Entry<K, V2>>(
- fromMap.entrySet().iterator()) {
- @Override
- Entry<K, V2> transform(final Entry<K, V1> entry) {
- return new AbstractMapEntry<K, V2>() {
- @Override
- public K getKey() {
- return entry.getKey();
+ final Iterator<Entry<K, V1>> backingIterator =
+ fromMap.entrySet().iterator();
+ return Iterators.transform(backingIterator,
+ new Function<Entry<K, V1>, Entry<K, V2>>() {
+ @Override public Entry<K, V2> apply(Entry<K, V1> entry) {
+ return immutableEntry(
+ entry.getKey(),
+ transformer.transformEntry(entry.getKey(),
+ entry.getValue()));
}
-
- @Override
- public V2 getValue() {
- return transformer.transformEntry(entry.getKey(), entry.getValue());
- }
- };
- }
- };
+ });
}
};
}
@@ -1600,32 +1249,7 @@ public final class Maps {
@Override public SortedMap<K, V2> tailMap(K fromKey) {
return transformEntries(fromMap().tailMap(fromKey), transformer);
}
- }
-
- private static final class KeyPredicate<K, V> implements Predicate<Entry<K, V>> {
- private final Predicate<? super K> keyPredicate;
-
- KeyPredicate(Predicate<? super K> keyPredicate) {
- this.keyPredicate = checkNotNull(keyPredicate);
- }
- @Override
- public boolean apply(Entry<K, V> input) {
- return keyPredicate.apply(input.getKey());
- }
- }
-
- private static final class ValuePredicate<K, V> implements Predicate<Entry<K, V>> {
- private final Predicate<? super V> valuePredicate;
-
- ValuePredicate(Predicate<? super V> valuePredicate) {
- this.valuePredicate = checkNotNull(valuePredicate);
- }
-
- @Override
- public boolean apply(Entry<K, V> input) {
- return valuePredicate.apply(input.getValue());
- }
}
/**
@@ -1660,11 +1284,15 @@ public final class Maps {
Map<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
if (unfiltered instanceof SortedMap) {
return filterKeys((SortedMap<K, V>) unfiltered, keyPredicate);
- } else if (unfiltered instanceof BiMap) {
- return filterKeys((BiMap<K, V>) unfiltered, keyPredicate);
}
checkNotNull(keyPredicate);
- Predicate<Entry<K, V>> entryPredicate = new KeyPredicate<K, V>(keyPredicate);
+ Predicate<Entry<K, V>> entryPredicate =
+ new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return keyPredicate.apply(input.getKey());
+ }
+ };
return (unfiltered instanceof AbstractFilteredMap)
? filterFiltered((AbstractFilteredMap<K, V>) unfiltered, entryPredicate)
: new FilteredKeyMap<K, V>(
@@ -1701,42 +1329,19 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V> SortedMap<K, V> filterKeys(
SortedMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
- // TODO(user): Return a subclass of Maps.FilteredKeyMap for slightly better
+ // TODO: Return a subclass of Maps.FilteredKeyMap for slightly better
// performance.
- return filterEntries(unfiltered, new KeyPredicate<K, V>(keyPredicate));
- }
-
- /**
- * Returns a bimap containing the mappings in {@code unfiltered} whose keys satisfy a predicate.
- * The returned bimap is a live view of {@code unfiltered}; changes to one affect the other.
- *
- * <p>The resulting bimap's {@code keySet()}, {@code entrySet()}, and {@code values()} views have
- * iterators that don't support {@code remove()}, but all other methods are supported by the
- * bimap and its views. When given a key that doesn't satisfy the predicate, the bimap's {@code
- * put()}, {@code forcePut()} and {@code putAll()} methods throw an {@link
- * IllegalArgumentException}.
- *
- * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered
- * bimap or its views, only mappings that satisfy the filter will be removed from the underlying
- * bimap.
- *
- * <p>The returned bimap isn't threadsafe or serializable, even if {@code unfiltered} is.
- *
- * <p>Many of the filtered bimap's methods, such as {@code size()}, iterate across every key in
- * the underlying bimap and determine which satisfy the filter. When a live view is <i>not</i>
- * needed, it may be faster to copy the filtered bimap and use the copy.
- *
- * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals </i>, as
- * documented at {@link Predicate#apply}.
- *
- * @since 14.0
- */
- public static <K, V> BiMap<K, V> filterKeys(
- BiMap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
checkNotNull(keyPredicate);
- return filterEntries(unfiltered, new KeyPredicate<K, V>(keyPredicate));
+ Predicate<Entry<K, V>> entryPredicate = new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return keyPredicate.apply(input.getKey());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
}
/**
@@ -1772,10 +1377,16 @@ public final class Maps {
Map<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
if (unfiltered instanceof SortedMap) {
return filterValues((SortedMap<K, V>) unfiltered, valuePredicate);
- } else if (unfiltered instanceof BiMap) {
- return filterValues((BiMap<K, V>) unfiltered, valuePredicate);
}
- return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate));
+ checkNotNull(valuePredicate);
+ Predicate<Entry<K, V>> entryPredicate =
+ new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return valuePredicate.apply(input.getValue());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
}
/**
@@ -1809,42 +1420,18 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V> SortedMap<K, V> filterValues(
SortedMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
- return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate));
- }
-
- /**
- * Returns a bimap containing the mappings in {@code unfiltered} whose values satisfy a
- * predicate. The returned bimap is a live view of {@code unfiltered}; changes to one affect the
- * other.
- *
- * <p>The resulting bimap's {@code keySet()}, {@code entrySet()}, and {@code values()} views have
- * iterators that don't support {@code remove()}, but all other methods are supported by the
- * bimap and its views. When given a value that doesn't satisfy the predicate, the bimap's
- * {@code put()}, {@code forcePut()} and {@code putAll()} methods throw an {@link
- * IllegalArgumentException}. Similarly, the map's entries have a {@link Entry#setValue} method
- * that throws an {@link IllegalArgumentException} when the provided value doesn't satisfy the
- * predicate.
- *
- * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered
- * bimap or its views, only mappings that satisfy the filter will be removed from the underlying
- * bimap.
- *
- * <p>The returned bimap isn't threadsafe or serializable, even if {@code unfiltered} is.
- *
- * <p>Many of the filtered bimap's methods, such as {@code size()}, iterate across every value in
- * the underlying bimap and determine which satisfy the filter. When a live view is <i>not</i>
- * needed, it may be faster to copy the filtered bimap and use the copy.
- *
- * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals </i>, as
- * documented at {@link Predicate#apply}.
- *
- * @since 14.0
- */
- public static <K, V> BiMap<K, V> filterValues(
- BiMap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
- return filterEntries(unfiltered, new ValuePredicate<K, V>(valuePredicate));
+ checkNotNull(valuePredicate);
+ Predicate<Entry<K, V>> entryPredicate =
+ new Predicate<Entry<K, V>>() {
+ @Override
+ public boolean apply(Entry<K, V> input) {
+ return valuePredicate.apply(input.getValue());
+ }
+ };
+ return filterEntries(unfiltered, entryPredicate);
}
/**
@@ -1880,8 +1467,6 @@ public final class Maps {
Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
if (unfiltered instanceof SortedMap) {
return filterEntries((SortedMap<K, V>) unfiltered, entryPredicate);
- } else if (unfiltered instanceof BiMap) {
- return filterEntries((BiMap<K, V>) unfiltered, entryPredicate);
}
checkNotNull(entryPredicate);
return (unfiltered instanceof AbstractFilteredMap)
@@ -1920,15 +1505,10 @@ public final class Maps {
*
* @since 11.0
*/
+ @Beta
public static <K, V> SortedMap<K, V> filterEntries(
SortedMap<K, V> unfiltered,
Predicate<? super Entry<K, V>> entryPredicate) {
- return Platform.mapsFilterSortedMap(unfiltered, entryPredicate);
- }
-
- static <K, V> SortedMap<K, V> filterSortedIgnoreNavigable(
- SortedMap<K, V> unfiltered,
- Predicate<? super Entry<K, V>> entryPredicate) {
checkNotNull(entryPredicate);
return (unfiltered instanceof FilteredEntrySortedMap)
? filterFiltered((FilteredEntrySortedMap<K, V>) unfiltered, entryPredicate)
@@ -1936,42 +1516,6 @@ public final class Maps {
}
/**
- * Returns a bimap containing the mappings in {@code unfiltered} that satisfy a predicate. The
- * returned bimap is a live view of {@code unfiltered}; changes to one affect the other.
- *
- * <p>The resulting bimap's {@code keySet()}, {@code entrySet()}, and {@code values()} views have
- * iterators that don't support {@code remove()}, but all other methods are supported by the bimap
- * and its views. When given a key/value pair that doesn't satisfy the predicate, the bimap's
- * {@code put()}, {@code forcePut()} and {@code putAll()} methods throw an
- * {@link IllegalArgumentException}. Similarly, the map's entries have an {@link Entry#setValue}
- * method that throws an {@link IllegalArgumentException} when the existing key and the provided
- * value don't satisfy the predicate.
- *
- * <p>When methods such as {@code removeAll()} and {@code clear()} are called on the filtered
- * bimap or its views, only mappings that satisfy the filter will be removed from the underlying
- * bimap.
- *
- * <p>The returned bimap isn't threadsafe or serializable, even if {@code unfiltered} is.
- *
- * <p>Many of the filtered bimap's methods, such as {@code size()}, iterate across every
- * key/value mapping in the underlying bimap and determine which satisfy the filter. When a live
- * view is <i>not</i> needed, it may be faster to copy the filtered bimap and use the copy.
- *
- * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with equals </i>, as
- * documented at {@link Predicate#apply}.
- *
- * @since 14.0
- */
- public static <K, V> BiMap<K, V> filterEntries(
- BiMap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
- checkNotNull(unfiltered);
- checkNotNull(entryPredicate);
- return (unfiltered instanceof FilteredEntryBiMap)
- ? filterFiltered((FilteredEntryBiMap<K, V>) unfiltered, entryPredicate)
- : new FilteredEntryBiMap<K, V>(unfiltered, entryPredicate);
- }
-
- /**
* Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
* filtering a filtered map.
*/
@@ -2116,7 +1660,6 @@ public final class Maps {
}
}
}
-
/**
* Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
* filtering a filtered sorted map.
@@ -2177,66 +1720,6 @@ public final class Maps {
}
}
- /**
- * Support {@code clear()}, {@code removeAll()}, and {@code retainAll()} when
- * filtering a filtered map.
- */
- private static <K, V> BiMap<K, V> filterFiltered(
- FilteredEntryBiMap<K, V> map, Predicate<? super Entry<K, V>> entryPredicate) {
- Predicate<Entry<K, V>> predicate = Predicates.and(map.predicate, entryPredicate);
- return new FilteredEntryBiMap<K, V>(map.unfiltered(), predicate);
- }
-
- static final class FilteredEntryBiMap<K, V> extends FilteredEntryMap<K, V>
- implements BiMap<K, V> {
- private final BiMap<V, K> inverse;
-
- private static <K, V> Predicate<Entry<V, K>> inversePredicate(
- final Predicate<? super Entry<K, V>> forwardPredicate) {
- return new Predicate<Entry<V, K>>() {
- @Override
- public boolean apply(Entry<V, K> input) {
- return forwardPredicate.apply(
- Maps.immutableEntry(input.getValue(), input.getKey()));
- }
- };
- }
-
- FilteredEntryBiMap(BiMap<K, V> delegate,
- Predicate<? super Entry<K, V>> predicate) {
- super(delegate, predicate);
- this.inverse = new FilteredEntryBiMap<V, K>(
- delegate.inverse(), inversePredicate(predicate), this);
- }
-
- private FilteredEntryBiMap(
- BiMap<K, V> delegate, Predicate<? super Entry<K, V>> predicate,
- BiMap<V, K> inverse) {
- super(delegate, predicate);
- this.inverse = inverse;
- }
-
- BiMap<K, V> unfiltered() {
- return (BiMap<K, V>) unfiltered;
- }
-
- @Override
- public V forcePut(@Nullable K key, @Nullable V value) {
- checkArgument(predicate.apply(Maps.immutableEntry(key, value)));
- return unfiltered().forcePut(key, value);
- }
-
- @Override
- public BiMap<V, K> inverse() {
- return inverse;
- }
-
- @Override
- public Set<V> values() {
- return inverse.keySet();
- }
- }
-
private static class FilteredKeyMap<K, V> extends AbstractFilteredMap<K, V> {
Predicate<? super K> keyPredicate;
@@ -2328,14 +1811,10 @@ public final class Maps {
@Override public Set<K> keySet() {
Set<K> result = keySet;
- return (result == null) ? keySet = createKeySet() : result;
- }
-
- Set<K> createKeySet() {
- return new KeySet();
+ return (result == null) ? keySet = new KeySet() : result;
}
- private class KeySet extends Sets.ImprovedAbstractSet<K> {
+ private class KeySet extends AbstractSet<K> {
@Override public Iterator<K> iterator() {
final Iterator<Entry<K, V>> iterator = filteredEntrySet.iterator();
return new UnmodifiableIterator<K>() {
@@ -2371,13 +1850,22 @@ public final class Maps {
return false;
}
+ @Override public boolean removeAll(Collection<?> collection) {
+ checkNotNull(collection); // for GWT
+ boolean changed = false;
+ for (Object obj : collection) {
+ changed |= remove(obj);
+ }
+ return changed;
+ }
+
@Override public boolean retainAll(Collection<?> collection) {
checkNotNull(collection); // for GWT
boolean changed = false;
Iterator<Entry<K, V>> iterator = unfiltered.entrySet().iterator();
while (iterator.hasNext()) {
Entry<K, V> entry = iterator.next();
- if (predicate.apply(entry) && !collection.contains(entry.getKey())) {
+ if (!collection.contains(entry.getKey()) && predicate.apply(entry)) {
iterator.remove();
changed = true;
}
@@ -2396,10 +1884,6 @@ public final class Maps {
}
}
- @Nullable private static <K, V> Entry<K, V> unmodifiableOrNull(@Nullable Entry<K, V> entry) {
- return (entry == null) ? null : Maps.unmodifiableEntry(entry);
- }
-
/**
* {@code AbstractMap} extension that implements {@link #isEmpty()} as {@code
* entrySet().isEmpty()} instead of {@code size() == 0} to speed up
@@ -2408,7 +1892,7 @@ public final class Maps {
* implementation.
*/
@GwtCompatible
- abstract static class ImprovedAbstractMap<K, V> extends AbstractMap<K, V> {
+ static abstract class ImprovedAbstractMap<K, V> extends AbstractMap<K, V> {
/**
* Creates the entry set to be returned by {@link #entrySet()}. This method
* is invoked at most once on a given map, at the time when {@code entrySet}
@@ -2445,7 +1929,7 @@ public final class Maps {
@Override public Collection<V> values() {
Collection<V> result = values;
if (result == null) {
- return values = new Values<K, V>() {
+ return values = new Values<K, V>(){
@Override Map<K, V> map() {
return ImprovedAbstractMap.this;
}
@@ -2453,6 +1937,17 @@ public final class Maps {
}
return result;
}
+
+ /**
+ * Returns {@code true} if this map contains no key-value mappings.
+ *
+ * <p>The implementation returns {@code entrySet().isEmpty()}.
+ *
+ * @return {@code true} if this map contains no key-value mappings
+ */
+ @Override public boolean isEmpty() {
+ return entrySet().isEmpty();
+ }
}
static final MapJoiner STANDARD_JOINER =
@@ -2460,46 +1955,25 @@ public final class Maps {
/**
* Delegates to {@link Map#get}. Returns {@code null} on {@code
- * ClassCastException} and {@code NullPointerException}.
+ * ClassCastException}.
*/
static <V> V safeGet(Map<?, V> map, Object key) {
- checkNotNull(map);
try {
return map.get(key);
} catch (ClassCastException e) {
return null;
- } catch (NullPointerException e) {
- return null;
}
}
/**
* Delegates to {@link Map#containsKey}. Returns {@code false} on {@code
- * ClassCastException} and {@code NullPointerException}.
+ * ClassCastException}
*/
static boolean safeContainsKey(Map<?, ?> map, Object key) {
- checkNotNull(map);
try {
return map.containsKey(key);
} catch (ClassCastException e) {
return false;
- } catch (NullPointerException e) {
- return false;
- }
- }
-
- /**
- * Delegates to {@link Map#remove}. Returns {@code null} on {@code
- * ClassCastException} and {@code NullPointerException}.
- */
- static <V> V safeRemove(Map<?, V> map, Object key) {
- checkNotNull(map);
- try {
- return map.remove(key);
- } catch (ClassCastException e) {
- return null;
- } catch (NullPointerException e) {
- return null;
}
}
@@ -2558,6 +2032,13 @@ public final class Maps {
}
/**
+ * An implementation of {@link Map#hashCode}.
+ */
+ static int hashCodeImpl(Map<?, ?> map) {
+ return Sets.hashCodeImpl(map.entrySet());
+ }
+
+ /**
* An implementation of {@link Map#toString}.
*/
static String toStringImpl(Map<?, ?> map) {
@@ -2581,30 +2062,36 @@ public final class Maps {
* An admittedly inefficient implementation of {@link Map#containsKey}.
*/
static boolean containsKeyImpl(Map<?, ?> map, @Nullable Object key) {
- return Iterators.contains(keyIterator(map.entrySet().iterator()), key);
+ for (Entry<?, ?> entry : map.entrySet()) {
+ if (Objects.equal(entry.getKey(), key)) {
+ return true;
+ }
+ }
+ return false;
}
/**
* An implementation of {@link Map#containsValue}.
*/
static boolean containsValueImpl(Map<?, ?> map, @Nullable Object value) {
- return Iterators.contains(valueIterator(map.entrySet().iterator()), value);
- }
-
- static <K, V> Iterator<K> keyIterator(Iterator<Entry<K, V>> entryIterator) {
- return new TransformedIterator<Entry<K, V>, K>(entryIterator) {
- @Override
- K transform(Entry<K, V> entry) {
- return entry.getKey();
+ for (Entry<?, ?> entry : map.entrySet()) {
+ if (Objects.equal(entry.getValue(), value)) {
+ return true;
}
- };
+ }
+ return false;
}
- abstract static class KeySet<K, V> extends Sets.ImprovedAbstractSet<K> {
+ abstract static class KeySet<K, V> extends AbstractSet<K> {
abstract Map<K, V> map();
@Override public Iterator<K> iterator() {
- return keyIterator(map().entrySet().iterator());
+ return Iterators.transform(map().entrySet().iterator(),
+ new Function<Map.Entry<K, V>, K>() {
+ @Override public K apply(Entry<K, V> entry) {
+ return entry.getKey();
+ }
+ });
}
@Override public int size() {
@@ -2627,50 +2114,27 @@ public final class Maps {
return false;
}
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ // TODO(user): find out why this is necessary to make GWT tests pass.
+ return super.removeAll(checkNotNull(c));
+ }
+
@Override public void clear() {
map().clear();
}
}
- @Nullable
- static <K> K keyOrNull(@Nullable Entry<K, ?> entry) {
- return (entry == null) ? null : entry.getKey();
- }
-
- @Nullable
- static <V> V valueOrNull(@Nullable Entry<?, V> entry) {
- return (entry == null) ? null : entry.getValue();
- }
-
- static <K, V> Iterator<V> valueIterator(Iterator<Entry<K, V>> entryIterator) {
- return new TransformedIterator<Entry<K, V>, V>(entryIterator) {
- @Override
- V transform(Entry<K, V> entry) {
- return entry.getValue();
- }
- };
- }
-
- static <K, V> UnmodifiableIterator<V> valueIterator(
- final UnmodifiableIterator<Entry<K, V>> entryIterator) {
- return new UnmodifiableIterator<V>() {
- @Override
- public boolean hasNext() {
- return entryIterator.hasNext();
- }
-
- @Override
- public V next() {
- return entryIterator.next().getValue();
- }
- };
- }
-
abstract static class Values<K, V> extends AbstractCollection<V> {
abstract Map<K, V> map();
@Override public Iterator<V> iterator() {
- return valueIterator(map().entrySet().iterator());
+ return Iterators.transform(map().entrySet().iterator(),
+ new Function<Entry<K, V>, V>() {
+ @Override public V apply(Entry<K, V> entry) {
+ return entry.getValue();
+ }
+ });
}
@Override public boolean remove(Object o) {
@@ -2732,8 +2196,7 @@ public final class Maps {
}
}
- abstract static class EntrySet<K, V>
- extends Sets.ImprovedAbstractSet<Entry<K, V>> {
+ abstract static class EntrySet<K, V> extends AbstractSet<Entry<K, V>> {
abstract Map<K, V> map();
@Override public int size() {
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Multimaps.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Multimaps.java
index c2d630f..7e8e2f7 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Multimaps.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Multimaps.java
@@ -20,17 +20,21 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Joiner.MapJoiner;
+import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
+import com.google.common.collect.Collections2.TransformedCollection;
import com.google.common.collect.Maps.EntryTransformer;
import java.io.Serializable;
import java.util.AbstractCollection;
+import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -48,10 +52,6 @@ import javax.annotation.Nullable;
/**
* Provides static methods acting on or generating a {@code Multimap}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Multimaps">
- * {@code Multimaps}</a>.
- *
* @author Jared Levy
* @author Robert Konigsberg
* @author Mike Bostock
@@ -63,14 +63,9 @@ public final class Multimaps {
private Multimaps() {}
/**
- * Creates a new {@code Multimap} backed by {@code map}, whose internal value
- * collections are generated by {@code factory}.
- *
- * <b>Warning: do not use</b> this method when the collections returned by
- * {@code factory} implement either {@link List} or {@code Set}! Use the more
- * specific method {@link #newListMultimap}, {@link #newSetMultimap} or {@link
- * #newSortedSetMultimap} instead, to avoid very surprising behavior from
- * {@link Multimap#equals}.
+ * Creates a new {@code Multimap} that uses the provided map and factory. It
+ * can generate a multimap based on arbitrary {@link Map} and
+ * {@link Collection} classes.
*
* <p>The {@code factory}-generated and {@code map} classes determine the
* multimap iteration order. They also specify the behavior of the
@@ -110,7 +105,7 @@ public final class Multimaps {
return new CustomMultimap<K, V>(map, factory);
}
- private static class CustomMultimap<K, V> extends AbstractMapBasedMultimap<K, V> {
+ private static class CustomMultimap<K, V> extends AbstractMultimap<K, V> {
transient Supplier<? extends Collection<V>> factory;
CustomMultimap(Map<K, Collection<V>> map,
@@ -334,13 +329,13 @@ public final class Multimaps {
* <p>It is imperative that the user manually synchronize on the returned
* multimap when accessing any of its collection views: <pre> {@code
*
- * Multimap<K, V> multimap = Multimaps.synchronizedMultimap(
+ * Multimap<K, V> m = Multimaps.synchronizedMultimap(
* HashMultimap.<K, V>create());
* ...
- * Collection<V> values = multimap.get(key); // Needn't be in synchronized block
+ * Set<K> s = m.keySet(); // Needn't be in synchronized block
* ...
- * synchronized (multimap) { // Synchronizing on multimap, not values!
- * Iterator<V> i = values.iterator(); // Must be in synchronized block
+ * synchronized (m) { // Synchronizing on m, not s!
+ * Iterator<K> i = s.iterator(); // Must be in synchronized block
* while (i.hasNext()) {
* foo(i.next());
* }
@@ -541,7 +536,7 @@ public final class Multimaps {
}
@Override public Iterator<Collection<V>> iterator() {
final Iterator<Collection<V>> iterator = delegate.iterator();
- return new UnmodifiableIterator<Collection<V>>() {
+ return new Iterator<Collection<V>>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
@@ -550,6 +545,10 @@ public final class Multimaps {
public Collection<V> next() {
return unmodifiableValueCollection(iterator.next());
}
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
};
}
@Override public Object[] toArray() {
@@ -972,7 +971,7 @@ public final class Multimaps {
@Override
public Set<V> get(final K key) {
- return new Sets.ImprovedAbstractSet<V>() {
+ return new AbstractSet<V>() {
@Override public Iterator<V> iterator() {
return new Iterator<V>() {
int i;
@@ -1053,7 +1052,7 @@ public final class Multimaps {
@Override
public Multiset<K> keys() {
- return new Multimaps.Keys<K, V>(this);
+ return Multisets.forSet(map.keySet());
}
@Override
@@ -1104,27 +1103,35 @@ public final class Multimaps {
}
/** @see MapMultimap#asMap */
- class AsMapEntries extends Sets.ImprovedAbstractSet<Entry<K, Collection<V>>> {
+ class AsMapEntries extends AbstractSet<Entry<K, Collection<V>>> {
@Override public int size() {
return map.size();
}
@Override public Iterator<Entry<K, Collection<V>>> iterator() {
- return new TransformedIterator<K, Entry<K, Collection<V>>>(map.keySet().iterator()) {
+ return new Iterator<Entry<K, Collection<V>>>() {
+ final Iterator<K> keys = map.keySet().iterator();
+
@Override
- Entry<K, Collection<V>> transform(final K key) {
+ public boolean hasNext() {
+ return keys.hasNext();
+ }
+ @Override
+ public Entry<K, Collection<V>> next() {
+ final K key = keys.next();
return new AbstractMapEntry<K, Collection<V>>() {
- @Override
- public K getKey() {
+ @Override public K getKey() {
return key;
}
-
- @Override
- public Collection<V> getValue() {
+ @Override public Collection<V> getValue() {
return get(key);
}
};
}
+ @Override
+ public void remove() {
+ keys.remove();
+ }
};
}
@@ -1226,6 +1233,7 @@ public final class Multimaps {
*
* @since 7.0
*/
+ @Beta
public static <K, V1, V2> Multimap<K, V2> transformValues(
Multimap<K, V1> fromMultimap, final Function<? super V1, V2> function) {
checkNotNull(function);
@@ -1294,29 +1302,15 @@ public final class Multimaps {
*
* @since 7.0
*/
+ @Beta
public static <K, V1, V2> Multimap<K, V2> transformEntries(
Multimap<K, V1> fromMap,
EntryTransformer<? super K, ? super V1, V2> transformer) {
return new TransformedEntriesMultimap<K, V1, V2>(fromMap, transformer);
}
-
- static final class ValueFunction<K, V1, V2> implements Function<V1, V2> {
- private final K key;
- private final EntryTransformer<? super K, ? super V1, V2> transformer;
-
- ValueFunction(K key, EntryTransformer<? super K, ? super V1, V2> transformer) {
- this.key = key;
- this.transformer = transformer;
- }
-
- @Override
- public V2 apply(@Nullable V1 value) {
- return transformer.transformEntry(key, value);
- }
- }
private static class TransformedEntriesMultimap<K, V1, V2>
- extends AbstractMultimap<K, V2> {
+ implements Multimap<K, V2> {
final Multimap<K, V1> fromMultimap;
final EntryTransformer<? super K, ? super V1, V2> transformer;
@@ -1326,25 +1320,30 @@ public final class Multimaps {
this.transformer = checkNotNull(transformer);
}
- Collection<V2> transform(K key, Collection<V1> values) {
- Function<V1, V2> function = new ValueFunction<K, V1, V2>(key, transformer);
- if (values instanceof List) {
- return Lists.transform((List<V1>) values, function);
- } else {
- return Collections2.transform(values, function);
- }
+ Collection<V2> transform(final K key, Collection<V1> values) {
+ return Collections2.transform(values, new Function<V1, V2>() {
+ @Override public V2 apply(V1 value) {
+ return transformer.transformEntry(key, value);
+ }
+ });
}
- @Override
- Map<K, Collection<V2>> createAsMap() {
- return Maps.transformEntries(fromMultimap.asMap(),
- new EntryTransformer<K, Collection<V1>, Collection<V2>>() {
+ private transient Map<K, Collection<V2>> asMap;
- @Override public Collection<V2> transformEntry(
- K key, Collection<V1> value) {
- return transform(key, value);
- }
- });
+ @Override public Map<K, Collection<V2>> asMap() {
+ if (asMap == null) {
+ Map<K, Collection<V2>> aM = Maps.transformEntries(fromMultimap.asMap(),
+ new EntryTransformer<K, Collection<V1>, Collection<V2>>() {
+
+ @Override public Collection<V2> transformEntry(
+ K key, Collection<V1> value) {
+ return transform(key, value);
+ }
+ });
+ asMap = aM;
+ return aM;
+ }
+ return asMap;
}
@Override public void clear() {
@@ -1365,25 +1364,58 @@ public final class Multimaps {
return values().contains(value);
}
- @Override
- Iterator<Entry<K, V2>> entryIterator() {
- return Iterators.transform(
- fromMultimap.entries().iterator(), new Function<Entry<K, V1>, Entry<K, V2>>() {
- @Override
- public Entry<K, V2> apply(final Entry<K, V1> entry) {
- return new AbstractMapEntry<K, V2>() {
- @Override
- public K getKey() {
- return entry.getKey();
- }
+ private transient Collection<Entry<K, V2>> entries;
+
+ @Override public Collection<Entry<K, V2>> entries() {
+ if (entries == null) {
+ Collection<Entry<K, V2>> es = new TransformedEntries(transformer);
+ entries = es;
+ return es;
+ }
+ return entries;
+ }
+
+ private class TransformedEntries
+ extends TransformedCollection<Entry<K, V1>, Entry<K, V2>> {
+
+ TransformedEntries(
+ final EntryTransformer<? super K, ? super V1, V2> transformer) {
+ super(fromMultimap.entries(),
+ new Function<Entry<K, V1>, Entry<K, V2>>() {
+ @Override public Entry<K, V2> apply(final Entry<K, V1> entry) {
+ return new AbstractMapEntry<K, V2>() {
+
+ @Override public K getKey() {
+ return entry.getKey();
+ }
+
+ @Override public V2 getValue() {
+ return transformer.transformEntry(
+ entry.getKey(), entry.getValue());
+ }
+ };
+ }
+ });
+ }
+
+ @Override public boolean contains(Object o) {
+ if (o instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ return containsEntry(entry.getKey(), entry.getValue());
+ }
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override public boolean remove(Object o) {
+ if (o instanceof Entry) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ Collection<V2> values = get((K) entry.getKey());
+ return values.remove(entry.getValue());
+ }
+ return false;
+ }
- @Override
- public V2 getValue() {
- return transformer.transformEntry(entry.getKey(), entry.getValue());
- }
- };
- }
- });
}
@Override public Collection<V2> get(final K key) {
@@ -1433,16 +1465,39 @@ public final class Multimaps {
@Override public int size() {
return fromMultimap.size();
}
-
- @Override
- Collection<V2> createValues() {
- return Collections2.transform(
- fromMultimap.entries(), new Function<Entry<K, V1>, V2>() {
- @Override public V2 apply(Entry<K, V1> entry) {
- return transformer.transformEntry(
- entry.getKey(), entry.getValue());
- }
- });
+
+ private transient Collection<V2> values;
+
+ @Override public Collection<V2> values() {
+ if (values == null) {
+ Collection<V2> vs = Collections2.transform(
+ fromMultimap.entries(), new Function<Entry<K, V1>, V2>() {
+
+ @Override public V2 apply(Entry<K, V1> entry) {
+ return transformer.transformEntry(
+ entry.getKey(), entry.getValue());
+ }
+ });
+ values = vs;
+ return vs;
+ }
+ return values;
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof Multimap) {
+ Multimap<?, ?> other = (Multimap<?, ?>) obj;
+ return asMap().equals(other.asMap());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return asMap().hashCode();
+ }
+
+ @Override public String toString() {
+ return asMap().toString();
}
}
@@ -1487,6 +1542,7 @@ public final class Multimaps {
*
* @since 7.0
*/
+ @Beta
public static <K, V1, V2> ListMultimap<K, V2> transformValues(
ListMultimap<K, V1> fromMultimap,
final Function<? super V1, V2> function) {
@@ -1553,6 +1609,7 @@ public final class Multimaps {
*
* @since 7.0
*/
+ @Beta
public static <K, V1, V2> ListMultimap<K, V2> transformEntries(
ListMultimap<K, V1> fromMap,
EntryTransformer<? super K, ? super V1, V2> transformer) {
@@ -1639,6 +1696,24 @@ public final class Multimaps {
}
/**
+ * <b>Deprecated.</b>
+ *
+ * @since 10.0
+ * @deprecated use {@link #index(Iterator, Function)} by casting {@code
+ * values} to {@code Iterator<V>}, or better yet, by implementing only
+ * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled
+ * for deletion in March 2012.</b>
+ */
+ @Beta
+ @Deprecated
+ public static <K, V, I extends Object & Iterable<V> & Iterator<V>>
+ ImmutableListMultimap<K, V> index(
+ I values, Function<? super V, K> keyFunction) {
+ Iterable<V> valuesIterable = checkNotNull(values);
+ return index(valuesIterable, keyFunction);
+ }
+
+ /**
* Creates an index {@code ImmutableListMultimap} that contains the results of
* applying a specified function to each item in an {@code Iterator} of
* values. Each value will be stored as a value in the resulting multimap,
@@ -1694,36 +1769,39 @@ public final class Multimaps {
return builder.build();
}
- static class Keys<K, V> extends AbstractMultiset<K> {
- final Multimap<K, V> multimap;
-
- Keys(Multimap<K, V> multimap) {
- this.multimap = multimap;
- }
+ static abstract class Keys<K, V> extends AbstractMultiset<K> {
+ abstract Multimap<K, V> multimap();
@Override Iterator<Multiset.Entry<K>> entryIterator() {
- return new TransformedIterator<Map.Entry<K, Collection<V>>, Multiset.Entry<K>>(
- multimap.asMap().entrySet().iterator()) {
- @Override
- Multiset.Entry<K> transform(
- final Map.Entry<K, Collection<V>> backingEntry) {
+ final Iterator<Map.Entry<K, Collection<V>>> backingIterator =
+ multimap().asMap().entrySet().iterator();
+ return new Iterator<Multiset.Entry<K>>() {
+ @Override public boolean hasNext() {
+ return backingIterator.hasNext();
+ }
+
+ @Override public Multiset.Entry<K> next() {
+ final Map.Entry<K, Collection<V>> backingEntry =
+ backingIterator.next();
return new Multisets.AbstractEntry<K>() {
- @Override
- public K getElement() {
+ @Override public K getElement() {
return backingEntry.getKey();
}
- @Override
- public int getCount() {
+ @Override public int getCount() {
return backingEntry.getValue().size();
}
};
}
+
+ @Override public void remove() {
+ backingIterator.remove();
+ }
};
}
@Override int distinctElements() {
- return multimap.asMap().size();
+ return multimap().asMap().size();
}
@Override Set<Multiset.Entry<K>> createEntrySet() {
@@ -1744,22 +1822,22 @@ public final class Multimaps {
}
@Override public boolean isEmpty() {
- return multimap.isEmpty();
+ return multimap().isEmpty();
}
@Override public boolean contains(@Nullable Object o) {
- if (o instanceof Multiset.Entry) {
+ if (o instanceof Multiset.Entry<?>) {
Multiset.Entry<?> entry = (Multiset.Entry<?>) o;
- Collection<V> collection = multimap.asMap().get(entry.getElement());
+ Collection<V> collection = multimap().asMap().get(entry.getElement());
return collection != null && collection.size() == entry.getCount();
}
return false;
}
@Override public boolean remove(@Nullable Object o) {
- if (o instanceof Multiset.Entry) {
+ if (o instanceof Multiset.Entry<?>) {
Multiset.Entry<?> entry = (Multiset.Entry<?>) o;
- Collection<V> collection = multimap.asMap().get(entry.getElement());
+ Collection<V> collection = multimap().asMap().get(entry.getElement());
if (collection != null && collection.size() == entry.getCount()) {
collection.clear();
return true;
@@ -1770,16 +1848,30 @@ public final class Multimaps {
}
@Override public boolean contains(@Nullable Object element) {
- return multimap.containsKey(element);
+ return multimap().containsKey(element);
}
@Override public Iterator<K> iterator() {
- return Maps.keyIterator(multimap.entries().iterator());
+ return Iterators.transform(multimap().entries().iterator(),
+ new Function<Map.Entry<K, V>, K>() {
+ @Override public K apply(Map.Entry<K, V> entry) {
+ return entry.getKey();
+ }
+ });
}
@Override public int count(@Nullable Object element) {
- Collection<V> values = Maps.safeGet(multimap.asMap(), element);
- return (values == null) ? 0 : values.size();
+ try {
+ if (multimap().containsKey(element)) {
+ Collection<V> values = multimap().asMap().get(element);
+ return (values == null) ? 0 : values.size();
+ }
+ return 0;
+ } catch (ClassCastException e) {
+ return 0;
+ } catch (NullPointerException e) {
+ return 0;
+ }
}
@Override public int remove(@Nullable Object element, int occurrences) {
@@ -1788,7 +1880,14 @@ public final class Multimaps {
return count(element);
}
- Collection<V> values = Maps.safeGet(multimap.asMap(), element);
+ Collection<V> values;
+ try {
+ values = multimap().asMap().get(element);
+ } catch (ClassCastException e) {
+ return 0;
+ } catch (NullPointerException e) {
+ return 0;
+ }
if (values == null) {
return 0;
@@ -1808,35 +1907,45 @@ public final class Multimaps {
}
@Override public void clear() {
- multimap.clear();
+ multimap().clear();
}
@Override public Set<K> elementSet() {
- return multimap.keySet();
+ return multimap().keySet();
}
}
- static class Values<K, V> extends AbstractCollection<V> {
- final Multimap<K, V> multimap;
-
- Values(Multimap<K, V> multimap) {
- this.multimap = multimap;
- }
+ static abstract class Values<K, V> extends AbstractCollection<V> {
+ abstract Multimap<K, V> multimap();
@Override public Iterator<V> iterator() {
- return Maps.valueIterator(multimap.entries().iterator());
+ final Iterator<Map.Entry<K, V>> backingIterator =
+ multimap().entries().iterator();
+ return new Iterator<V>() {
+ @Override public boolean hasNext() {
+ return backingIterator.hasNext();
+ }
+
+ @Override public V next() {
+ return backingIterator.next().getValue();
+ }
+
+ @Override public void remove() {
+ backingIterator.remove();
+ }
+ };
}
@Override public int size() {
- return multimap.size();
+ return multimap().size();
}
@Override public boolean contains(@Nullable Object o) {
- return multimap.containsValue(o);
+ return multimap().containsValue(o);
}
@Override public void clear() {
- multimap.clear();
+ multimap().clear();
}
}
@@ -1852,7 +1961,7 @@ public final class Multimaps {
}
@Override public boolean contains(@Nullable Object o) {
- if (o instanceof Map.Entry) {
+ if (o instanceof Map.Entry<?, ?>) {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
return multimap().containsEntry(entry.getKey(), entry.getValue());
}
@@ -1860,7 +1969,7 @@ public final class Multimaps {
}
@Override public boolean remove(@Nullable Object o) {
- if (o instanceof Map.Entry) {
+ if (o instanceof Map.Entry<?, ?>) {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
return multimap().remove(entry.getKey(), entry.getValue());
}
@@ -1953,15 +2062,476 @@ public final class Multimaps {
/**
* Support removal operations when filtering a filtered multimap. Since a
* filtered multimap has iterators that don't support remove, passing one to
- * the FilteredEntryMultimap constructor would lead to a multimap whose removal
+ * the FilteredMultimap constructor would lead to a multimap whose removal
* operations would fail. This method combines the predicates to avoid that
* problem.
*/
- private static <K, V> Multimap<K, V> filterFiltered(FilteredMultimap<K, V> multimap,
+ private static <K, V> Multimap<K, V> filterFiltered(FilteredMultimap<K, V> map,
Predicate<? super Entry<K, V>> entryPredicate) {
Predicate<Entry<K, V>> predicate
- = Predicates.and(multimap.entryPredicate(), entryPredicate);
- return new FilteredEntryMultimap<K, V>(multimap.unfiltered, predicate);
+ = Predicates.and(map.predicate, entryPredicate);
+ return new FilteredMultimap<K, V>(map.unfiltered, predicate);
+ }
+
+ private static class FilteredMultimap<K, V> implements Multimap<K, V> {
+ final Multimap<K, V> unfiltered;
+ final Predicate<? super Entry<K, V>> predicate;
+
+ FilteredMultimap(Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> predicate) {
+ this.unfiltered = unfiltered;
+ this.predicate = predicate;
+ }
+
+ @Override public int size() {
+ return entries().size();
+ }
+
+ @Override public boolean isEmpty() {
+ return entries().isEmpty();
+ }
+
+ @Override public boolean containsKey(Object key) {
+ return asMap().containsKey(key);
+ }
+
+ @Override public boolean containsValue(Object value) {
+ return values().contains(value);
+ }
+
+ // This method should be called only when key is a K and value is a V.
+ @SuppressWarnings("unchecked")
+ boolean satisfiesPredicate(Object key, Object value) {
+ return predicate.apply(Maps.immutableEntry((K) key, (V) value));
+ }
+
+ @Override public boolean containsEntry(Object key, Object value) {
+ return unfiltered.containsEntry(key, value) && satisfiesPredicate(key, value);
+ }
+
+ @Override public boolean put(K key, V value) {
+ checkArgument(satisfiesPredicate(key, value));
+ return unfiltered.put(key, value);
+ }
+
+ @Override public boolean remove(Object key, Object value) {
+ return containsEntry(key, value) ? unfiltered.remove(key, value) : false;
+ }
+
+ @Override public boolean putAll(K key, Iterable<? extends V> values) {
+ for (V value : values) {
+ checkArgument(satisfiesPredicate(key, value));
+ }
+ return unfiltered.putAll(key, values);
+ }
+
+ @Override public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
+ for (Entry<? extends K, ? extends V> entry : multimap.entries()) {
+ checkArgument(satisfiesPredicate(entry.getKey(), entry.getValue()));
+ }
+ return unfiltered.putAll(multimap);
+ }
+
+ @Override public Collection<V> replaceValues(K key, Iterable<? extends V> values) {
+ for (V value : values) {
+ checkArgument(satisfiesPredicate(key, value));
+ }
+ // Not calling unfiltered.replaceValues() since values that don't satisify
+ // the filter should remain in the multimap.
+ Collection<V> oldValues = removeAll(key);
+ unfiltered.putAll(key, values);
+ return oldValues;
+ }
+
+ @Override public Collection<V> removeAll(Object key) {
+ List<V> removed = Lists.newArrayList();
+ Collection<V> values = unfiltered.asMap().get(key);
+ if (values != null) {
+ Iterator<V> iterator = values.iterator();
+ while (iterator.hasNext()) {
+ V value = iterator.next();
+ if (satisfiesPredicate(key, value)) {
+ removed.add(value);
+ iterator.remove();
+ }
+ }
+ }
+ if (unfiltered instanceof SetMultimap) {
+ return Collections.unmodifiableSet(Sets.newLinkedHashSet(removed));
+ } else {
+ return Collections.unmodifiableList(removed);
+ }
+ }
+
+ @Override public void clear() {
+ entries().clear();
+ }
+
+ @Override public boolean equals(@Nullable Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof Multimap) {
+ Multimap<?, ?> that = (Multimap<?, ?>) object;
+ return asMap().equals(that.asMap());
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ return asMap().hashCode();
+ }
+
+ @Override public String toString() {
+ return asMap().toString();
+ }
+
+ class ValuePredicate implements Predicate<V> {
+ final K key;
+ ValuePredicate(K key) {
+ this.key = key;
+ }
+ @Override public boolean apply(V value) {
+ return satisfiesPredicate(key, value);
+ }
+ }
+
+ Collection<V> filterCollection(Collection<V> collection, Predicate<V> predicate) {
+ if (collection instanceof Set) {
+ return Sets.filter((Set<V>) collection, predicate);
+ } else {
+ return Collections2.filter(collection, predicate);
+ }
+ }
+
+ @Override public Collection<V> get(K key) {
+ return filterCollection(unfiltered.get(key), new ValuePredicate(key));
+ }
+
+ @Override public Set<K> keySet() {
+ return asMap().keySet();
+ }
+
+ Collection<V> values;
+
+ @Override public Collection<V> values() {
+ return (values == null) ? values = new Values() : values;
+ }
+
+ class Values extends Multimaps.Values<K, V> {
+ @Override Multimap<K, V> multimap() {
+ return FilteredMultimap.this;
+ }
+
+ @Override public boolean contains(@Nullable Object o) {
+ return Iterators.contains(iterator(), o);
+ }
+
+ // Override remove methods since iterator doesn't support remove.
+
+ @Override public boolean remove(Object o) {
+ Iterator<Entry<K, V>> iterator = unfiltered.entries().iterator();
+ while (iterator.hasNext()) {
+ Entry<K, V> entry = iterator.next();
+ if (Objects.equal(o, entry.getValue()) && predicate.apply(entry)) {
+ iterator.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ boolean changed = false;
+ Iterator<Entry<K, V>> iterator = unfiltered.entries().iterator();
+ while (iterator.hasNext()) {
+ Entry<K, V> entry = iterator.next();
+ if (c.contains(entry.getValue()) && predicate.apply(entry)) {
+ iterator.remove();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ @Override public boolean retainAll(Collection<?> c) {
+ boolean changed = false;
+ Iterator<Entry<K, V>> iterator = unfiltered.entries().iterator();
+ while (iterator.hasNext()) {
+ Entry<K, V> entry = iterator.next();
+ if (!c.contains(entry.getValue()) && predicate.apply(entry)) {
+ iterator.remove();
+ changed = true;
+ }
+ }
+ return changed;
+ }
+ }
+
+ Collection<Entry<K, V>> entries;
+
+ @Override public Collection<Entry<K, V>> entries() {
+ return (entries == null)
+ ? entries = Collections2.filter(unfiltered.entries(), predicate)
+ : entries;
+ }
+
+ /**
+ * Remove all filtered asMap() entries that satisfy the predicate.
+ */
+ boolean removeEntriesIf(Predicate<Map.Entry<K, Collection<V>>> removalPredicate) {
+ Iterator<Map.Entry<K, Collection<V>>> iterator = unfiltered.asMap().entrySet().iterator();
+ boolean changed = false;
+ while (iterator.hasNext()) {
+ // Determine whether to remove the filtered values with this key.
+ Map.Entry<K, Collection<V>> entry = iterator.next();
+ K key = entry.getKey();
+ Collection<V> collection = entry.getValue();
+ Predicate<V> valuePredicate = new ValuePredicate(key);
+ Collection<V> filteredCollection = filterCollection(collection, valuePredicate);
+ Map.Entry<K, Collection<V>> filteredEntry = Maps.immutableEntry(key, filteredCollection);
+ if (removalPredicate.apply(filteredEntry) && !filteredCollection.isEmpty()) {
+ changed = true;
+ if (Iterables.all(collection, valuePredicate)) {
+ iterator.remove(); // Remove all values for the key.
+ } else {
+ filteredCollection.clear(); // Remove the filtered values only.
+ }
+ }
+ }
+ return changed;
+ }
+
+ Map<K, Collection<V>> asMap;
+
+ @Override public Map<K, Collection<V>> asMap() {
+ return (asMap == null) ? asMap = createAsMap() : asMap;
+ }
+
+ static final Predicate<Collection<?>> NOT_EMPTY = new Predicate<Collection<?>>() {
+ @Override public boolean apply(Collection<?> input) {
+ return !input.isEmpty();
+ }
+ };
+
+ Map<K, Collection<V>> createAsMap() {
+ // Select the values that satisify the predicate.
+ EntryTransformer<K, Collection<V>, Collection<V>> transformer
+ = new EntryTransformer<K, Collection<V>, Collection<V>>() {
+ @Override public Collection<V> transformEntry(K key, Collection<V> collection) {
+ return filterCollection(collection, new ValuePredicate(key));
+ }
+ };
+ Map<K, Collection<V>> transformed
+ = Maps.transformEntries(unfiltered.asMap(), transformer);
+
+ // Select the keys that have at least one value remaining.
+ Map<K, Collection<V>> filtered = Maps.filterValues(transformed, NOT_EMPTY);
+
+ // Override the removal methods, since removing a map entry should not
+ // affect values that don't satisfy the filter.
+ return new AsMap(filtered);
+ }
+
+ class AsMap extends ForwardingMap<K, Collection<V>> {
+ final Map<K, Collection<V>> delegate;
+
+ AsMap(Map<K, Collection<V>> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override protected Map<K, Collection<V>> delegate() {
+ return delegate;
+ }
+
+ @Override public Collection<V> remove(Object o) {
+ Collection<V> output = FilteredMultimap.this.removeAll(o);
+ return output.isEmpty() ? null : output;
+ }
+
+ @Override public void clear() {
+ FilteredMultimap.this.clear();
+ }
+
+ Set<K> keySet;
+
+ @Override public Set<K> keySet() {
+ return (keySet == null) ? keySet = new KeySet() : keySet;
+ }
+
+ class KeySet extends Maps.KeySet<K, Collection<V>> {
+ @Override Map<K, Collection<V>> map() {
+ return AsMap.this;
+ }
+
+ @Override public boolean remove(Object o) {
+ Collection<V> collection = delegate.get(o);
+ if (collection == null) {
+ return false;
+ }
+ collection.clear();
+ return true;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ return Sets.removeAllImpl(this, c);
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ return !c.contains(entry.getKey());
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+ }
+
+ Values asMapValues;
+
+ @Override public Collection<Collection<V>> values() {
+ return (asMapValues == null) ? asMapValues = new Values() : asMapValues;
+ }
+
+ class Values extends Maps.Values<K, Collection<V>> {
+ @Override Map<K, Collection<V>> map() {
+ return AsMap.this;
+ }
+
+ @Override public boolean remove(Object o) {
+ for (Collection<V> collection : this) {
+ if (collection.equals(o)) {
+ collection.clear();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean removeAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ return c.contains(entry.getValue());
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ return !c.contains(entry.getValue());
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+ }
+
+ EntrySet entrySet;
+
+ @Override public Set<Map.Entry<K, Collection<V>>> entrySet() {
+ return (entrySet == null) ? entrySet = new EntrySet(super.entrySet()) : entrySet;
+ }
+
+ class EntrySet extends Maps.EntrySet<K, Collection<V>> {
+ Set<Map.Entry<K, Collection<V>>> delegateEntries;
+
+ public EntrySet(Set<Map.Entry<K, Collection<V>>> delegateEntries) {
+ this.delegateEntries = delegateEntries;
+ }
+
+ @Override Map<K, Collection<V>> map() {
+ return AsMap.this;
+ }
+
+ @Override public Iterator<Map.Entry<K, Collection<V>>> iterator() {
+ return delegateEntries.iterator();
+ }
+
+ @Override public boolean remove(Object o) {
+ if (o instanceof Entry<?, ?>) {
+ Entry<?, ?> entry = (Entry<?, ?>) o;
+ Collection<V> collection = delegate.get(entry.getKey());
+ if (collection != null && collection.equals(entry.getValue())) {
+ collection.clear();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override public boolean removeAll(Collection<?> c) {
+ return Sets.removeAllImpl(this, c);
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ return !c.contains(entry);
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+ }
+ }
+
+ AbstractMultiset<K> keys;
+
+ @Override public Multiset<K> keys() {
+ return (keys == null) ? keys = new Keys() : keys;
+ }
+
+ class Keys extends Multimaps.Keys<K, V> {
+ @Override Multimap<K, V> multimap() {
+ return FilteredMultimap.this;
+ }
+
+ @Override public int remove(Object o, int occurrences) {
+ checkArgument(occurrences >= 0);
+ Collection<V> values = unfiltered.asMap().get(o);
+ if (values == null) {
+ return 0;
+ }
+ int priorCount = 0;
+ int removed = 0;
+ Iterator<V> iterator = values.iterator();
+ while (iterator.hasNext()) {
+ if (satisfiesPredicate(o, iterator.next())) {
+ priorCount++;
+ if (removed < occurrences) {
+ iterator.remove();
+ removed++;
+ }
+ }
+ }
+ return priorCount;
+ }
+
+ @Override Set<Multiset.Entry<K>> createEntrySet() {
+ return new EntrySet();
+ }
+
+ class EntrySet extends Multimaps.Keys<K, V>.KeysEntrySet {
+ @Override public boolean removeAll(Collection<?> c) {
+ return Sets.removeAllImpl(this, c);
+ }
+
+ @Override public boolean retainAll(final Collection<?> c) {
+ Predicate<Map.Entry<K, Collection<V>>> removalPredicate
+ = new Predicate<Map.Entry<K, Collection<V>>>() {
+ @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
+ Multiset.Entry<K> multisetEntry
+ = Multisets.immutableEntry(entry.getKey(), entry.getValue().size());
+ return !c.contains(multisetEntry);
+ }
+ };
+ return removeEntriesIf(removalPredicate);
+ }
+ }
+ }
}
// TODO(jlevy): Create methods that filter a SetMultimap or SortedSetMultimap.
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ObjectArrays.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ObjectArrays.java
index 6465ee7..087fd17 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ObjectArrays.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/ObjectArrays.java
@@ -30,8 +30,6 @@ import javax.annotation.Nullable;
*/
@GwtCompatible(emulated = true)
public final class ObjectArrays {
- static final Object[] EMPTY_ARRAY = new Object[0];
-
private ObjectArrays() {}
/**
@@ -57,7 +55,7 @@ public final class ObjectArrays {
public static <T> T[] concat(@Nullable T element, T[] array) {
T[] result = newArray(array, array.length + 1);
result[0] = element;
- System.arraycopy(array, 0, result, 1, array.length);
+ Platform.unsafeArrayCopy(array, 0, result, 1, array.length);
return result;
}
@@ -79,7 +77,7 @@ public final class ObjectArrays {
/** GWT safe version of Arrays.copyOf. */
static <T> T[] arraysCopyOf(T[] original, int newLength) {
T[] copy = newArray(original, newLength);
- System.arraycopy(
+ Platform.unsafeArrayCopy(
original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
}
@@ -154,14 +152,5 @@ public final class ObjectArrays {
array[i] = array[j];
array[j] = temp;
}
-
- // We do this instead of Preconditions.checkNotNull to save boxing and array
- // creation cost.
- static Object checkElementNotNull(Object element, int index) {
- if (element == null) {
- throw new NullPointerException("at index " + index);
- }
- return element;
- }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Platform.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Platform.java
index 3fe8150..4fbdde0 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Platform.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Platform.java
@@ -16,14 +16,6 @@
package com.google.common.collect;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Maps.EntryTransformer;
-
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.SortedSet;
-
/**
* Minimal GWT emulation of {@code com.google.common.collect.Platform}.
*
@@ -37,32 +29,24 @@ class Platform {
return GwtPlatform.clone(array);
}
- static <T> T[] newArray(T[] reference, int length) {
- return GwtPlatform.newArray(reference, length);
+ // TODO: Fix System.arraycopy in GWT so that it isn't necessary.
+ static void unsafeArrayCopy(
+ Object[] src, int srcPos, Object[] dest, int destPos, int length) {
+ for (int i = 0; i < length; i++) {
+ dest[destPos + i] = src[srcPos + i];
+ }
}
- static MapMaker tryWeakKeys(MapMaker mapMaker) {
- return mapMaker;
+ static <T> T[] newArray(Class<T> type, int length) {
+ throw new UnsupportedOperationException(
+ "Platform.newArray is not supported in GWT yet.");
}
- static <K, V1, V2> SortedMap<K, V2> mapsTransformEntriesSortedMap(
- SortedMap<K, V1> fromMap,
- EntryTransformer<? super K, ? super V1, V2> transformer) {
- return Maps.transformEntriesIgnoreNavigable(fromMap, transformer);
- }
-
- static <K, V> SortedMap<K, V> mapsAsMapSortedSet(
- SortedSet<K> set, Function<? super K, V> function) {
- return Maps.asMapSortedIgnoreNavigable(set, function);
+ static <T> T[] newArray(T[] reference, int length) {
+ return GwtPlatform.newArray(reference, length);
}
- static <E> SortedSet<E> setsFilterSortedSet(
- SortedSet<E> unfiltered, Predicate<? super E> predicate) {
- return Sets.filterSortedIgnoreNavigable(unfiltered, predicate);
- }
-
- static <K, V> SortedMap<K, V> mapsFilterSortedMap(
- SortedMap<K, V> unfiltered, Predicate<? super Map.Entry<K, V>> predicate) {
- return Maps.filterSortedIgnoreNavigable(unfiltered, predicate);
+ static MapMaker tryWeakKeys(MapMaker mapMaker) {
+ return mapMaker;
}
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularContiguousSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularContiguousSet.java
index 999f6ee..a63b391 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularContiguousSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularContiguousSet.java
@@ -39,33 +39,32 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
this.range = range;
}
- private ContiguousSet<C> intersectionInCurrentDomain(Range<C> other) {
- return (range.isConnected(other))
- ? ContiguousSet.create(range.intersection(other), domain)
- : new EmptyContiguousSet<C>(domain);
+ // Abstract method doesn't exist in GWT emulation
+ /* @Override */ ContiguousSet<C> headSetImpl(C toElement, boolean inclusive) {
+ return range.intersection(Ranges.upTo(toElement, BoundType.forBoolean(inclusive)))
+ .asSet(domain);
}
- @Override ContiguousSet<C> headSetImpl(C toElement, boolean inclusive) {
- return intersectionInCurrentDomain(Range.upTo(toElement, BoundType.forBoolean(inclusive)));
+ // Abstract method doesn't exist in GWT emulation
+ /* @Override */ int indexOf(Object target) {
+ return contains(target) ? (int) domain.distance(first(), (C) target) : -1;
}
- @Override ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive, C toElement,
+ // Abstract method doesn't exist in GWT emulation
+ /* @Override */ ContiguousSet<C> subSetImpl(C fromElement, boolean fromInclusive, C toElement,
boolean toInclusive) {
- if (fromElement.compareTo(toElement) == 0 && !fromInclusive && !toInclusive) {
- // Range would reject our attempt to create (x, x).
- return new EmptyContiguousSet<C>(domain);
- }
- return intersectionInCurrentDomain(Range.range(
- fromElement, BoundType.forBoolean(fromInclusive),
- toElement, BoundType.forBoolean(toInclusive)));
+ return range.intersection(Ranges.range(fromElement, BoundType.forBoolean(fromInclusive),
+ toElement, BoundType.forBoolean(toInclusive))).asSet(domain);
}
- @Override ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive) {
- return intersectionInCurrentDomain(Range.downTo(fromElement, BoundType.forBoolean(inclusive)));
+ // Abstract method doesn't exist in GWT emulation
+ /* @Override */ ContiguousSet<C> tailSetImpl(C fromElement, boolean inclusive) {
+ return range.intersection(Ranges.downTo(fromElement, BoundType.forBoolean(inclusive)))
+ .asSet(domain);
}
@Override public UnmodifiableIterator<C> iterator() {
- return new AbstractSequentialIterator<C>(first()) {
+ return new AbstractLinkedIterator<C>(first()) {
final C last = last();
@Override
@@ -96,10 +95,7 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
return (distance >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) distance + 1;
}
- @Override public boolean contains(@Nullable Object object) {
- if (object == null) {
- return false;
- }
+ @Override public boolean contains(Object object) {
try {
return range.contains((C) object);
} catch (ClassCastException e) {
@@ -108,7 +104,11 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
}
@Override public boolean containsAll(Collection<?> targets) {
- return Collections2.containsAllImpl(this, targets);
+ try {
+ return range.containsAll((Iterable<? extends C>) targets);
+ } catch (ClassCastException e) {
+ return false;
+ }
}
@Override public boolean isEmpty() {
@@ -134,7 +134,7 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
C lowerEndpoint = Ordering.natural().max(this.first(), other.first());
C upperEndpoint = Ordering.natural().min(this.last(), other.last());
return (lowerEndpoint.compareTo(upperEndpoint) < 0)
- ? ContiguousSet.create(Range.closed(lowerEndpoint, upperEndpoint), domain)
+ ? Ranges.closed(lowerEndpoint, upperEndpoint).asSet(domain)
: new EmptyContiguousSet<C>(domain);
}
}
@@ -144,14 +144,14 @@ final class RegularContiguousSet<C extends Comparable> extends ContiguousSet<C>
}
@Override public Range<C> range(BoundType lowerBoundType, BoundType upperBoundType) {
- return Range.create(range.lowerBound.withLowerBoundType(lowerBoundType, domain),
+ return Ranges.create(range.lowerBound.withLowerBoundType(lowerBoundType, domain),
range.upperBound.withUpperBoundType(upperBoundType, domain));
}
- @Override public boolean equals(@Nullable Object object) {
+ @Override public boolean equals(Object object) {
if (object == this) {
return true;
- } else if (object instanceof RegularContiguousSet) {
+ } else if (object instanceof RegularContiguousSet<?>) {
RegularContiguousSet<?> that = (RegularContiguousSet<?>) object;
if (this.domain.equals(that.domain)) {
return this.first().equals(that.first())
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableList.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableList.java
index f82a6b6..5cdddff 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableList.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableList.java
@@ -16,8 +16,6 @@
package com.google.common.collect;
-import static java.util.Collections.unmodifiableList;
-
import java.util.List;
/**
@@ -25,15 +23,8 @@ import java.util.List;
*
* @author Hayward Chan
*/
-class RegularImmutableList<E> extends ForwardingImmutableList<E> {
- private final List<E> delegate;
-
+class RegularImmutableList<E> extends ImmutableList<E> {
RegularImmutableList(List<E> delegate) {
- // TODO(cpovirk): avoid redundant unmodifiableList wrapping
- this.delegate = unmodifiableList(delegate);
- }
-
- @Override List<E> delegateList() {
- return delegate;
+ super(delegate);
}
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableMap.java
index b79ce80..bdf536b 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableMap.java
@@ -23,7 +23,7 @@ import java.util.Map;
*
* @author Hayward Chan
*/
-final class RegularImmutableMap<K, V> extends ForwardingImmutableMap<K, V> {
+final class RegularImmutableMap<K, V> extends ImmutableMap<K, V> {
RegularImmutableMap(Map<? extends K, ? extends V> delegate) {
super(delegate);
@@ -31,5 +31,5 @@ final class RegularImmutableMap<K, V> extends ForwardingImmutableMap<K, V> {
RegularImmutableMap(Entry<? extends K, ? extends V>... entries) {
super(entries);
- }
+ }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSet.java
index 72da3e4..f462ade 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSet.java
@@ -25,7 +25,7 @@ import java.util.Set;
*
* @author Hayward Chan
*/
-final class RegularImmutableSet<E> extends ForwardingImmutableSet<E> {
+final class RegularImmutableSet<E> extends ImmutableSet<E> {
RegularImmutableSet(Set<E> delegate) {
super(delegate);
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSortedSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSortedSet.java
index 3279449..8256e98 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSortedSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSortedSet.java
@@ -32,8 +32,4 @@ final class RegularImmutableSortedSet<E> extends ImmutableSortedSet<E> {
super(delegate);
this.isSubset = isSubset;
}
-
- @Override ImmutableList<E> createAsList() {
- return new ImmutableSortedAsList<E>(this, ImmutableList.<E>asImmutableList(toArray()));
- }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Sets.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Sets.java
index bb06a9c..be31363 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Sets.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Sets.java
@@ -19,10 +19,15 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2.FilteredCollection;
+import com.google.common.math.IntMath;
import java.io.Serializable;
import java.util.AbstractSet;
@@ -45,11 +50,7 @@ import javax.annotation.Nullable;
/**
* Static utility methods pertaining to {@link Set} instances. Also see this
- * class's counterparts {@link Lists}, {@link Maps} and {@link Queues}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Sets">
- * {@code Sets}</a>.
+ * class's counterparts {@link Lists} and {@link Maps}.
*
* @author Kevin Bourrillion
* @author Jared Levy
@@ -61,22 +62,6 @@ public final class Sets {
private Sets() {}
/**
- * {@link AbstractSet} substitute without the potentially-quadratic
- * {@code removeAll} implementation.
- */
- abstract static class ImprovedAbstractSet<E> extends AbstractSet<E> {
- @Override
- public boolean removeAll(Collection<?> c) {
- return removeAllImpl(this, c);
- }
-
- @Override
- public boolean retainAll(Collection<?> c) {
- return super.retainAll(checkNotNull(c)); // GWT compatibility
- }
- }
-
- /**
* Returns an immutable set instance containing the given enum elements.
* Internally, the returned set will be backed by an {@link EnumSet}.
*
@@ -91,7 +76,7 @@ public final class Sets {
@GwtCompatible(serializable = true)
public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(
E anElement, E... otherElements) {
- return ImmutableEnumSet.asImmutable(EnumSet.of(anElement, otherElements));
+ return new ImmutableEnumSet<E>(EnumSet.of(anElement, otherElements));
}
/**
@@ -109,25 +94,20 @@ public final class Sets {
@GwtCompatible(serializable = true)
public static <E extends Enum<E>> ImmutableSet<E> immutableEnumSet(
Iterable<E> elements) {
- if (elements instanceof ImmutableEnumSet) {
- return (ImmutableEnumSet<E>) elements;
- } else if (elements instanceof Collection) {
- Collection<E> collection = (Collection<E>) elements;
- if (collection.isEmpty()) {
- return ImmutableSet.of();
- } else {
- return ImmutableEnumSet.asImmutable(EnumSet.copyOf(collection));
- }
- } else {
- Iterator<E> itr = elements.iterator();
- if (itr.hasNext()) {
- EnumSet<E> enumSet = EnumSet.of(itr.next());
- Iterators.addAll(enumSet, itr);
- return ImmutableEnumSet.asImmutable(enumSet);
- } else {
- return ImmutableSet.of();
- }
+ Iterator<E> iterator = elements.iterator();
+ if (!iterator.hasNext()) {
+ return ImmutableSet.of();
+ }
+ if (elements instanceof EnumSet) {
+ EnumSet<E> enumSetClone = EnumSet.copyOf((EnumSet<E>) elements);
+ return new ImmutableEnumSet<E>(enumSetClone);
}
+ E first = iterator.next();
+ EnumSet<E> set = EnumSet.of(first);
+ while (iterator.hasNext()) {
+ set.add(iterator.next());
+ }
+ return new ImmutableEnumSet<E>(set);
}
/**
@@ -138,6 +118,20 @@ public final class Sets {
*/
public static <E extends Enum<E>> EnumSet<E> newEnumSet(Iterable<E> iterable,
Class<E> elementType) {
+ /*
+ * TODO(cpovirk): noneOf() and addAll() will both throw
+ * NullPointerExceptions when appropriate. However, NullPointerTester will
+ * fail on this method because it passes in Class.class instead of an enum
+ * type. This means that, when iterable is null but elementType is not,
+ * noneOf() will throw a ClassCastException before addAll() has a chance to
+ * throw a NullPointerException. NullPointerTester considers this a failure.
+ * Ideally the test would be fixed, but it would require a special case for
+ * Class<E> where E extends Enum. Until that happens (if ever), leave
+ * checkNotNull() here. For now, contemplate the irony that checking
+ * elementType, the problem argument, is harmful, while checking iterable,
+ * the innocent bystander, is effective.
+ */
+ checkNotNull(iterable);
EnumSet<E> set = EnumSet.noneOf(elementType);
Iterables.addAll(set, iterable);
return set;
@@ -572,11 +566,6 @@ public final class Sets {
* <p><b>Note:</b> The returned view performs better when {@code set1} is the
* smaller of the two sets. If you have reason to believe one of your sets
* will generally be smaller than the other, pass it first.
- *
- * <p>Further, note that the current implementation is not suitable for nested
- * {@code union} views, i.e. the following should be avoided when in a loop:
- * {@code union = Sets.union(union, anotherSet);}, since iterating over the resulting
- * set has a cubic complexity to the depth of the nesting.
*/
public static <E> SetView<E> union(
final Set<? extends E> set1, final Set<? extends E> set2) {
@@ -807,13 +796,10 @@ public final class Sets {
*
* @since 11.0
*/
+ @Beta
+ @SuppressWarnings("unchecked")
public static <E> SortedSet<E> filter(
SortedSet<E> unfiltered, Predicate<? super E> predicate) {
- return Platform.setsFilterSortedSet(unfiltered, predicate);
- }
-
- static <E> SortedSet<E> filterSortedIgnoreNavigable(
- SortedSet<E> unfiltered, Predicate<? super E> predicate) {
if (unfiltered instanceof FilteredSet) {
// Support clear(), removeAll(), and retainAll() when filtering a filtered
// collection.
@@ -828,13 +814,21 @@ public final class Sets {
checkNotNull(unfiltered), checkNotNull(predicate));
}
- private static class FilteredSortedSet<E> extends FilteredSet<E>
+ private static class FilteredSortedSet<E> extends FilteredCollection<E>
implements SortedSet<E> {
FilteredSortedSet(SortedSet<E> unfiltered, Predicate<? super E> predicate) {
super(unfiltered, predicate);
}
+ @Override public boolean equals(@Nullable Object object) {
+ return equalsImpl(this, object);
+ }
+
+ @Override public int hashCode() {
+ return hashCodeImpl(this);
+ }
+
@Override
public Comparator<? super E> comparator() {
return ((SortedSet<E>) unfiltered).comparator();
@@ -895,22 +889,12 @@ public final class Sets {
* <li>{@code ImmutableList.of(2, "C")}
* </ul>
*
- * The result is guaranteed to be in the "traditional", lexicographical
- * order for Cartesian products that you would get from nesting for loops:
- * <pre> {@code
- *
- * for (B b0 : sets.get(0)) {
- * for (B b1 : sets.get(1)) {
- * ...
- * ImmutableList<B> tuple = ImmutableList.of(b0, b1, ...);
- * // operate on tuple
- * }
- * }}</pre>
- *
- * Note that if any input set is empty, the Cartesian product will also be
- * empty. If no sets at all are provided (an empty list), the resulting
- * Cartesian product has one element, an empty list (counter-intuitive, but
- * mathematically consistent).
+ * The order in which these lists are returned is not guaranteed, however the
+ * position of an element inside a tuple always corresponds to the position of
+ * the set from which it came in the input list. Note that if any input set is
+ * empty, the Cartesian product will also be empty. If no sets at all are
+ * provided (an empty list), the resulting Cartesian product has one element,
+ * an empty list (counter-intuitive, but mathematically consistent).
*
* <p><i>Performance notes:</i> while the cartesian product of sets of size
* {@code m, n, p} is a set of size {@code m x n x p}, its actual memory
@@ -936,7 +920,8 @@ public final class Sets {
return ImmutableSet.of();
}
}
- return CartesianSet.create(sets);
+ CartesianSet<B> cartesianSet = new CartesianSet<B>(sets);
+ return cartesianSet;
}
/**
@@ -960,22 +945,12 @@ public final class Sets {
* <li>{@code ImmutableList.of(2, "C")}
* </ul>
*
- * The result is guaranteed to be in the "traditional", lexicographical
- * order for Cartesian products that you would get from nesting for loops:
- * <pre> {@code
- *
- * for (B b0 : sets.get(0)) {
- * for (B b1 : sets.get(1)) {
- * ...
- * ImmutableList<B> tuple = ImmutableList.of(b0, b1, ...);
- * // operate on tuple
- * }
- * }}</pre>
- *
- * Note that if any input set is empty, the Cartesian product will also be
- * empty. If no sets at all are provided (an empty list), the resulting
- * Cartesian product has one element, an empty list (counter-intuitive, but
- * mathematically consistent).
+ * The order in which these lists are returned is not guaranteed, however the
+ * position of an element inside a tuple always corresponds to the position of
+ * the set from which it came in the input list. Note that if any input set is
+ * empty, the Cartesian product will also be empty. If no sets at all are
+ * provided, the resulting Cartesian product has one element, an empty list
+ * (counter-intuitive, but mathematically consistent).
*
* <p><i>Performance notes:</i> while the cartesian product of sets of size
* {@code m, n, p} is a set of size {@code m x n x p}, its actual memory
@@ -999,51 +974,73 @@ public final class Sets {
return cartesianProduct(Arrays.asList(sets));
}
- private static final class CartesianSet<E>
- extends ForwardingCollection<List<E>> implements Set<List<E>> {
- private transient final ImmutableList<ImmutableSet<E>> axes;
- private transient final CartesianList<E> delegate;
-
- static <E> Set<List<E>> create(List<? extends Set<? extends E>> sets) {
- ImmutableList.Builder<ImmutableSet<E>> axesBuilder =
- new ImmutableList.Builder<ImmutableSet<E>>(sets.size());
- for (Set<? extends E> set : sets) {
- ImmutableSet<E> copy = ImmutableSet.copyOf(set);
- if (copy.isEmpty()) {
- return ImmutableSet.of();
+ private static class CartesianSet<B> extends AbstractSet<List<B>> {
+ final ImmutableList<Axis> axes;
+ final int size;
+
+ CartesianSet(List<? extends Set<? extends B>> sets) {
+ int dividend = 1;
+ ImmutableList.Builder<Axis> builder = ImmutableList.builder();
+ try {
+ for (Set<? extends B> set : sets) {
+ Axis axis = new Axis(set, dividend);
+ builder.add(axis);
+ dividend = IntMath.checkedMultiply(dividend, axis.size());
}
- axesBuilder.add(copy);
+ } catch (ArithmeticException overflow) {
+ throw new IllegalArgumentException("cartesian product too big");
}
- final ImmutableList<ImmutableSet<E>> axes = axesBuilder.build();
- ImmutableList<List<E>> listAxes = new ImmutableList<List<E>>() {
+ this.axes = builder.build();
+ size = dividend;
+ }
- @Override
- public int size() {
- return axes.size();
- }
+ @Override public int size() {
+ return size;
+ }
+
+ @Override public UnmodifiableIterator<List<B>> iterator() {
+ return new UnmodifiableIterator<List<B>>() {
+ int index;
@Override
- public List<E> get(int index) {
- return axes.get(index).asList();
+ public boolean hasNext() {
+ return index < size;
}
@Override
- boolean isPartialView() {
- return true;
+ public List<B> next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ Object[] tuple = new Object[axes.size()];
+ for (int i = 0 ; i < tuple.length; i++) {
+ tuple[i] = axes.get(i).getForIndex(index);
+ }
+ index++;
+
+ @SuppressWarnings("unchecked") // only B's are put in here
+ List<B> result = (ImmutableList<B>) ImmutableList.copyOf(tuple);
+ return result;
}
};
- return new CartesianSet<E>(axes, new CartesianList<E>(listAxes));
}
- private CartesianSet(
- ImmutableList<ImmutableSet<E>> axes, CartesianList<E> delegate) {
- this.axes = axes;
- this.delegate = delegate;
- }
-
- @Override
- protected Collection<List<E>> delegate() {
- return delegate;
+ @Override public boolean contains(Object element) {
+ if (!(element instanceof List<?>)) {
+ return false;
+ }
+ List<?> tuple = (List<?>) element;
+ int dimensions = axes.size();
+ if (tuple.size() != dimensions) {
+ return false;
+ }
+ for (int i = 0; i < dimensions; i++) {
+ if (!axes.get(i).contains(tuple.get(i))) {
+ return false;
+ }
+ }
+ return true;
}
@Override public boolean equals(@Nullable Object object) {
@@ -1056,26 +1053,56 @@ public final class Sets {
return super.equals(object);
}
- @Override
- public int hashCode() {
+ @Override public int hashCode() {
// Warning: this is broken if size() == 0, so it is critical that we
// substitute an empty ImmutableSet to the user in place of this
// It's a weird formula, but tests prove it works.
- int adjust = size() - 1;
+ int adjust = size - 1;
for (int i = 0; i < axes.size(); i++) {
adjust *= 31;
- adjust = ~~adjust;
- // in GWT, we have to deal with integer overflow carefully
}
- int hash = 1;
- for (Set<E> axis : axes) {
- hash = 31 * hash + (size() / axis.size() * axis.hashCode());
+ return axes.hashCode() + adjust;
+ }
- hash = ~~hash;
+ private class Axis {
+ final ImmutableSet<? extends B> choices;
+ final ImmutableList<? extends B> choicesList;
+ final int dividend;
+
+ Axis(Set<? extends B> set, int dividend) {
+ choices = ImmutableSet.copyOf(set);
+ choicesList = choices.asList();
+ this.dividend = dividend;
+ }
+
+ int size() {
+ return choices.size();
+ }
+
+ B getForIndex(int index) {
+ return choicesList.get(index / dividend % size());
+ }
+
+ boolean contains(Object target) {
+ return choices.contains(target);
+ }
+
+ @Override public boolean equals(Object obj) {
+ if (obj instanceof CartesianSet.Axis) {
+ CartesianSet.Axis that = (CartesianSet.Axis) obj;
+ return this.choices.equals(that.choices);
+ // dividends must be equal or we wouldn't have gotten this far
+ }
+ return false;
+ }
+
+ @Override public int hashCode() {
+ // Because Axis instances are not exposed, we can
+ // opportunistically choose whatever bizarre formula happens
+ // to make CartesianSet.hashCode() as simple as possible.
+ return size / choices.size() * choices.hashCode();
}
- hash += adjust;
- return ~~hash;
}
}
@@ -1213,9 +1240,6 @@ public final class Sets {
int hashCode = 0;
for (Object o : s) {
hashCode += o != null ? o.hashCode() : 0;
-
- hashCode = ~~hashCode;
- // Needed to deal with unusual integer overflow in GWT.
}
return hashCode;
}
@@ -1242,47 +1266,117 @@ public final class Sets {
}
/**
- * Remove each element in an iterable from a set.
+ * Creates a view of Set<B> for a Set<A>, given a bijection between A and B.
+ * (Modelled for now as InvertibleFunction<A, B>, can't be Converter<A, B>
+ * because that's not in Guava, though both designs are less than optimal).
+ * Note that the bijection is treated as undefined for values not in the
+ * given Set<A> - it doesn't have to define a true bijection for those.
+ *
+ * <p>Note that the returned Set's contains method is unsafe -
+ * you *must* pass an instance of B to it, since the bijection
+ * can only invert B's (not any Object) back to A, so we can
+ * then delegate the call to the original Set<A>.
*/
- static boolean removeAllImpl(Set<?> set, Iterator<?> iterator) {
- boolean changed = false;
- while (iterator.hasNext()) {
- changed |= set.remove(iterator.next());
+ static <A, B> Set<B> transform(
+ Set<A> set, InvertibleFunction<A, B> bijection) {
+ return new TransformedSet<A, B>(
+ Preconditions.checkNotNull(set, "set"),
+ Preconditions.checkNotNull(bijection, "bijection")
+ );
+ }
+
+ /**
+ * Stop-gap measure since there is no bijection related type in Guava.
+ */
+ abstract static class InvertibleFunction<A, B> implements Function<A, B> {
+ abstract A invert(B b);
+
+ public InvertibleFunction<B, A> inverse() {
+ return new InvertibleFunction<B, A>() {
+ @Override public A apply(B b) {
+ return InvertibleFunction.this.invert(b);
+ }
+
+ @Override B invert(A a) {
+ return InvertibleFunction.this.apply(a);
+ }
+
+ // Not required per se, but just for good karma.
+ @Override public InvertibleFunction<A, B> inverse() {
+ return InvertibleFunction.this;
+ }
+ };
}
- return changed;
}
- static boolean removeAllImpl(Set<?> set, Collection<?> collection) {
- checkNotNull(collection); // for GWT
- if (collection instanceof Multiset) {
- collection = ((Multiset<?>) collection).elementSet();
+ private static class TransformedSet<A, B> extends AbstractSet<B> {
+ final Set<A> delegate;
+ final InvertibleFunction<A, B> bijection;
+
+ TransformedSet(Set<A> delegate, InvertibleFunction<A, B> bijection) {
+ this.delegate = delegate;
+ this.bijection = bijection;
}
- /*
- * AbstractSet.removeAll(List) has quadratic behavior if the list size
- * is just less than the set's size. We augment the test by
- * assuming that sets have fast contains() performance, and other
- * collections don't. See
- * http://code.google.com/p/guava-libraries/issues/detail?id=1013
- */
- if (collection instanceof Set && collection.size() > set.size()) {
- Iterator<?> setIterator = set.iterator();
- boolean changed = false;
- while (setIterator.hasNext()) {
- if (collection.contains(setIterator.next())) {
- changed = true;
- setIterator.remove();
- }
- }
- return changed;
- } else {
- return removeAllImpl(set, collection.iterator());
+
+ @Override public Iterator<B> iterator() {
+ return Iterators.transform(delegate.iterator(), bijection);
+ }
+
+ @Override public int size() {
+ return delegate.size();
+ }
+
+ @SuppressWarnings("unchecked") // unsafe, passed object *must* be B
+ @Override public boolean contains(Object o) {
+ B b = (B) o;
+ A a = bijection.invert(b);
+ /*
+ * Mathematically, Converter<A, B> defines a bijection between ALL A's
+ * on ALL B's. Here we concern ourselves with a subset
+ * of this relation: we only want the part that is defined by a *subset*
+ * of all A's (defined by that Set<A> delegate), and the image
+ * of *that* on B (which is this set). We don't care whether
+ * the converter is *not* a bijection for A's that are not in Set<A>
+ * or B's not in this Set<B>.
+ *
+ * We only want to return true if and only f the user passes a B instance
+ * that is contained in precisely in the image of Set<A>.
+ *
+ * The first test is whether the inverse image of this B is indeed
+ * in Set<A>. But we don't know whether that B belongs in this Set<B>
+ * or not; if not, the converter is free to return
+ * anything it wants, even an element of Set<A> (and this relationship
+ * is not part of the Set<A> <--> Set<B> bijection), and we must not
+ * be confused by that. So we have to do a final check to see if the
+ * image of that A is really equivalent to the passed B, which proves
+ * that the given B belongs indeed in the image of Set<A>.
+ */
+ return delegate.contains(a) && Objects.equal(bijection.apply(a), o);
+ }
+
+ @Override public boolean add(B b) {
+ return delegate.add(bijection.invert(b));
+ }
+
+ @SuppressWarnings("unchecked") // unsafe, passed object *must* be B
+ @Override public boolean remove(Object o) {
+ return contains(o) && delegate.remove(bijection.invert((B) o));
+ }
+
+ @Override public void clear() {
+ delegate.clear();
}
}
/**
- * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
+ * Remove each element in an iterable from a set.
*/
- static <T> SortedSet<T> cast(Iterable<T> iterable) {
- return (SortedSet<T>) iterable;
+ static boolean removeAllImpl(Set<?> set, Iterable<?> iterable) {
+ // TODO(jlevy): Have ForwardingSet.standardRemoveAll() call this method.
+ boolean changed = false;
+ for (Object o : iterable) {
+ changed |= set.remove(o);
+ }
+ return changed;
}
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableList.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableList.java
index e570f00..6172191 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableList.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableList.java
@@ -17,29 +17,23 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.Collections.singletonList;
-import java.util.List;
+import java.util.Collections;
/**
* GWT emulated version of {@link SingletonImmutableList}.
*
* @author Hayward Chan
*/
-final class SingletonImmutableList<E> extends ForwardingImmutableList<E> {
+final class SingletonImmutableList<E> extends ImmutableList<E> {
- final transient List<E> delegate;
// This reference is used both by the custom field serializer, and by the
// GWT compiler to infer the elements of the lists that needs to be
// serialized.
E element;
SingletonImmutableList(E element) {
- this.delegate = singletonList(checkNotNull(element));
+ super(Collections.singletonList(checkNotNull(element)));
this.element = element;
}
-
- @Override List<E> delegateList() {
- return delegate;
- }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableBiMap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableMap.java
index f086bf3..236d76e 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableBiMap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableMap.java
@@ -21,11 +21,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collections;
/**
- * GWT emulation of {@link SingletonImmutableBiMap}.
+ * GWT emulation of {@link SingletonImmutableMap}.
*
* @author Hayward Chan
*/
-final class SingletonImmutableBiMap<K, V> extends ImmutableBiMap<K, V> {
+final class SingletonImmutableMap<K, V> extends ImmutableMap<K, V> {
// These references are used both by the custom field serializer, and by the
// GWT compiler to infer the keys and values of the map that needs to be
@@ -36,34 +36,9 @@ final class SingletonImmutableBiMap<K, V> extends ImmutableBiMap<K, V> {
K singleKey;
V singleValue;
- transient SingletonImmutableBiMap<V, K> inverse;
-
- SingletonImmutableBiMap(K key, V value) {
+ SingletonImmutableMap(K key, V value) {
super(Collections.singletonMap(checkNotNull(key), checkNotNull(value)));
this.singleKey = key;
this.singleValue = value;
}
-
- private SingletonImmutableBiMap(
- K key, V value, SingletonImmutableBiMap<V, K> inverse) {
- super(Collections.singletonMap(checkNotNull(key), checkNotNull(value)));
- this.singleKey = singleKey;
- this.singleValue = singleValue;
- this.inverse = inverse;
- }
-
- @Override
- public ImmutableBiMap<V, K> inverse() {
- ImmutableBiMap<V, K> result = inverse;
- if (result == null) {
- return inverse = new SingletonImmutableBiMap<V, K>(singleValue, singleKey, this);
- } else {
- return result;
- }
- }
-
- @Override
- public ImmutableSet<V> values() {
- return ImmutableSet.of(singleValue);
- }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableSet.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableSet.java
index d1aa6b2..b51d4aa 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableSet.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SingletonImmutableSet.java
@@ -18,8 +18,7 @@ package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.UnmodifiableIterator;
+import java.util.Collections;
/**
* GWT emulation of {@link SingletonImmutableSet}.
@@ -27,7 +26,7 @@ import com.google.common.collect.UnmodifiableIterator;
* @author Hayward Chan
*/
final class SingletonImmutableSet<E> extends ImmutableSet<E> {
-
+
// This reference is used both by the custom field serializer, and by the
// GWT compiler to infer the elements of the lists that needs to be
// serialized.
@@ -36,21 +35,7 @@ final class SingletonImmutableSet<E> extends ImmutableSet<E> {
E element;
SingletonImmutableSet(E element) {
- this.element = checkNotNull(element);
- }
-
- @Override
- public int size() {
- return 1;
- }
-
- @Override
- public UnmodifiableIterator<E> iterator() {
- return Iterators.singletonIterator(element);
- }
-
- @Override
- public boolean contains(Object object) {
- return element.equals(object);
+ super(Collections.singleton(checkNotNull(element)));
+ this.element = element;
}
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SortedMultiset.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SortedMultiset.java
deleted file mode 100644
index d9248dd..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SortedMultiset.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.annotations.Beta;
-
-import java.util.Comparator;
-import java.util.SortedSet;
-
-/**
- * GWT emulation of {@code SortedMultiset}, with {@code elementSet} reduced
- * to returning a {@code SortedSet} for GWT compatibility.
- *
- * @author Louis Wasserman
- * @since 11.0
- */
-@Beta
-public interface SortedMultiset<E> extends Multiset<E>, SortedIterable<E> {
- Comparator<? super E> comparator();
-
- Entry<E> firstEntry();
-
- Entry<E> lastEntry();
-
- Entry<E> pollFirstEntry();
-
- Entry<E> pollLastEntry();
-
- /**
- * Returns a {@link SortedSet} view of the distinct elements in this multiset.
- * (Outside GWT, this returns a {@code NavigableSet}.)
- */
- @Override SortedSet<E> elementSet();
-
- SortedMultiset<E> descendingMultiset();
-
- SortedMultiset<E> headMultiset(E upperBound, BoundType boundType);
-
- SortedMultiset<E> subMultiset(E lowerBound, BoundType lowerBoundType,
- E upperBound, BoundType upperBoundType);
-
- SortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType);
-}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SortedMultisets.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SortedMultisets.java
deleted file mode 100644
index e3955b5..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/SortedMultisets.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.collect;
-
-import static com.google.common.collect.BoundType.CLOSED;
-import static com.google.common.collect.BoundType.OPEN;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.collect.Multiset.Entry;
-
-import java.util.Comparator;
-import java.util.NoSuchElementException;
-import java.util.SortedSet;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides static utility methods for creating and working with
- * {@link SortedMultiset} instances.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-final class SortedMultisets {
- private SortedMultisets() {
- }
-
- /**
- * A skeleton implementation for {@link SortedMultiset#elementSet}.
- */
- static class ElementSet<E> extends Multisets.ElementSet<E> implements
- SortedSet<E> {
- private final SortedMultiset<E> multiset;
-
- ElementSet(SortedMultiset<E> multiset) {
- this.multiset = multiset;
- }
-
- @Override final SortedMultiset<E> multiset() {
- return multiset;
- }
-
- @Override public Comparator<? super E> comparator() {
- return multiset().comparator();
- }
-
- @Override public SortedSet<E> subSet(E fromElement, E toElement) {
- return multiset().subMultiset(fromElement, CLOSED, toElement, OPEN).elementSet();
- }
-
- @Override public SortedSet<E> headSet(E toElement) {
- return multiset().headMultiset(toElement, OPEN).elementSet();
- }
-
- @Override public SortedSet<E> tailSet(E fromElement) {
- return multiset().tailMultiset(fromElement, CLOSED).elementSet();
- }
-
- @Override public E first() {
- return getElementOrThrow(multiset().firstEntry());
- }
-
- @Override public E last() {
- return getElementOrThrow(multiset().lastEntry());
- }
- }
-
- private static <E> E getElementOrThrow(Entry<E> entry) {
- if (entry == null) {
- throw new NoSuchElementException();
- }
- return entry.getElement();
- }
-
- private static <E> E getElementOrNull(@Nullable Entry<E> entry) {
- return (entry == null) ? null : entry.getElement();
- }
-}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Synchronized.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Synchronized.java
index c809da8..fd09c97 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Synchronized.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Synchronized.java
@@ -28,8 +28,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Queue;
import java.util.RandomAccess;
import java.util.Set;
import java.util.SortedMap;
@@ -196,7 +194,7 @@ final class Synchronized {
static class SynchronizedSet<E>
extends SynchronizedCollection<E> implements Set<E> {
-
+
SynchronizedSet(Set<E> delegate, @Nullable Object mutex) {
super(delegate, mutex);
}
@@ -836,7 +834,7 @@ final class Synchronized {
}
@Override public Map.Entry<K, Collection<V>> next() {
- final Map.Entry<K, Collection<V>> entry = super.next();
+ final Map.Entry<K, Collection<V>> entry = iterator.next();
return new ForwardingMapEntry<K, Collection<V>>() {
@Override protected Map.Entry<K, Collection<V>> delegate() {
return entry;
@@ -1028,12 +1026,12 @@ final class Synchronized {
private static final long serialVersionUID = 0;
}
-
+
static <K, V> SortedMap<K, V> sortedMap(
SortedMap<K, V> sortedMap, @Nullable Object mutex) {
return new SynchronizedSortedMap<K, V>(sortedMap, mutex);
}
-
+
static class SynchronizedSortedMap<K, V> extends SynchronizedMap<K, V>
implements SortedMap<K, V> {
@@ -1197,67 +1195,12 @@ final class Synchronized {
return iterator;
}
@Override public Collection<V> next() {
- return typePreservingCollection(super.next(), mutex);
+ return typePreservingCollection(iterator.next(), mutex);
}
};
}
private static final long serialVersionUID = 0;
}
-
- static <E> Queue<E> queue(Queue<E> queue, @Nullable Object mutex) {
- return (queue instanceof SynchronizedQueue)
- ? queue
- : new SynchronizedQueue<E>(queue, mutex);
- }
-
- private static class SynchronizedQueue<E> extends SynchronizedCollection<E>
- implements Queue<E> {
-
- SynchronizedQueue(Queue<E> delegate, @Nullable Object mutex) {
- super(delegate, mutex);
- }
-
- @Override Queue<E> delegate() {
- return (Queue<E>) super.delegate();
- }
-
- @Override
- public E element() {
- synchronized (mutex) {
- return delegate().element();
- }
- }
-
- @Override
- public boolean offer(E e) {
- synchronized (mutex) {
- return delegate().offer(e);
- }
- }
-
- @Override
- public E peek() {
- synchronized (mutex) {
- return delegate().peek();
- }
- }
-
- @Override
- public E poll() {
- synchronized (mutex) {
- return delegate().poll();
- }
- }
-
- @Override
- public E remove() {
- synchronized (mutex) {
- return delegate().remove();
- }
- }
-
- private static final long serialVersionUID = 0;
- }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultimap.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultimap.java
index 5023a0c..228dc2d 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultimap.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultimap.java
@@ -22,12 +22,11 @@ import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
import java.util.Comparator;
+import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
-import javax.annotation.Nullable;
-
/**
* Implementation of {@code Multimap} whose keys and values are ordered by
* their natural ordering or by supplied comparators. In all cases, this
@@ -61,16 +60,11 @@ import javax.annotation.Nullable;
* update operations, wrap your multimap with a call to {@link
* Multimaps#synchronizedSortedSetMultimap}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multimap">
- * {@code Multimap}</a>.
- *
* @author Jared Levy
- * @author Louis Wasserman
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(serializable = true, emulated = true)
-public class TreeMultimap<K, V> extends AbstractSortedKeySortedSetMultimap<K, V> {
+public class TreeMultimap<K, V> extends AbstractSortedSetMultimap<K, V> {
private transient Comparator<? super K> keyComparator;
private transient Comparator<? super V> valueComparator;
@@ -136,14 +130,6 @@ public class TreeMultimap<K, V> extends AbstractSortedKeySortedSetMultimap<K, V>
return new TreeSet<V>(valueComparator);
}
- @Override
- Collection<V> createCollection(@Nullable K key) {
- if (key == null) {
- keyComparator().compare(key, key);
- }
- return super.createCollection(key);
- }
-
/**
* Returns the comparator that orders the multimap keys.
*/
@@ -156,10 +142,26 @@ public class TreeMultimap<K, V> extends AbstractSortedKeySortedSetMultimap<K, V>
return valueComparator;
}
- /*
- * The following @GwtIncompatible methods override the methods in
- * AbstractSortedKeySortedSetMultimap, so GWT will fall back to the ASKSSM implementations,
- * which return SortedSets and SortedMaps.
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code TreeMultimap} has unique sorted keys, this method
+ * returns a {@link SortedSet}, instead of the {@link java.util.Set} specified
+ * in the {@link Multimap} interface.
*/
+ @Override public SortedSet<K> keySet() {
+ return (SortedSet<K>) super.keySet();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>Because a {@code TreeMultimap} has unique sorted keys, this method
+ * returns a {@link SortedMap}, instead of the {@link java.util.Map} specified
+ * in the {@link Multimap} interface.
+ */
+ @Override public SortedMap<K, Collection<V>> asMap() {
+ return (SortedMap<K, Collection<V>>) super.asMap();
+ }
}
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultiset.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultiset.java
index b45d127..622454d 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultiset.java
+++ b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/TreeMultiset.java
@@ -17,217 +17,168 @@
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Objects;
-import com.google.common.primitives.Ints;
+import static com.google.common.collect.BstSide.LEFT;
+import static com.google.common.collect.BstSide.RIGHT;
import java.io.Serializable;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
-import java.util.NoSuchElementException;
import javax.annotation.Nullable;
+import com.google.common.annotations.GwtCompatible;
+import com.google.common.primitives.Ints;
+
/**
- * A multiset which maintains the ordering of its elements, according to either their natural order
- * or an explicit {@link Comparator}. In all cases, this implementation uses
- * {@link Comparable#compareTo} or {@link Comparator#compare} instead of {@link Object#equals} to
- * determine equivalence of instances.
+ * A multiset which maintains the ordering of its elements, according to either
+ * their natural order or an explicit {@link Comparator}. In all cases, this
+ * implementation uses {@link Comparable#compareTo} or {@link
+ * Comparator#compare} instead of {@link Object#equals} to determine
+ * equivalence of instances.
*
- * <p><b>Warning:</b> The comparison must be <i>consistent with equals</i> as explained by the
- * {@link Comparable} class specification. Otherwise, the resulting multiset will violate the
- * {@link java.util.Collection} contract, which is specified in terms of {@link Object#equals}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
- * {@code Multiset}</a>.
+ * <p><b>Warning:</b> The comparison must be <i>consistent with equals</i> as
+ * explained by the {@link Comparable} class specification. Otherwise, the
+ * resulting multiset will violate the {@link java.util.Collection} contract,
+ * which is specified in terms of {@link Object#equals}.
*
* @author Louis Wasserman
* @author Jared Levy
* @since 2.0 (imported from Google Collections Library)
*/
@GwtCompatible(emulated = true)
-public final class TreeMultiset<E> extends AbstractSortedMultiset<E> implements Serializable {
+public final class TreeMultiset<E> extends AbstractSortedMultiset<E>
+ implements Serializable {
/**
- * Creates a new, empty multiset, sorted according to the elements' natural order. All elements
- * inserted into the multiset must implement the {@code Comparable} interface. Furthermore, all
- * such elements must be <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
- * {@code ClassCastException} for any elements {@code e1} and {@code e2} in the multiset. If the
- * user attempts to add an element to the multiset that violates this constraint (for example,
- * the user attempts to add a string element to a set whose elements are integers), the
- * {@code add(Object)} call will throw a {@code ClassCastException}.
+ * Creates a new, empty multiset, sorted according to the elements' natural
+ * order. All elements inserted into the multiset must implement the
+ * {@code Comparable} interface. Furthermore, all such elements must be
+ * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
+ * {@code ClassCastException} for any elements {@code e1} and {@code e2} in
+ * the multiset. If the user attempts to add an element to the multiset that
+ * violates this constraint (for example, the user attempts to add a string
+ * element to a set whose elements are integers), the {@code add(Object)}
+ * call will throw a {@code ClassCastException}.
*
- * <p>The type specification is {@code <E extends Comparable>}, instead of the more specific
- * {@code <E extends Comparable<? super E>>}, to support classes defined without generics.
+ * <p>The type specification is {@code <E extends Comparable>}, instead of the
+ * more specific {@code <E extends Comparable<? super E>>}, to support
+ * classes defined without generics.
*/
public static <E extends Comparable> TreeMultiset<E> create() {
return new TreeMultiset<E>(Ordering.natural());
}
/**
- * Creates a new, empty multiset, sorted according to the specified comparator. All elements
- * inserted into the multiset must be <i>mutually comparable</i> by the specified comparator:
- * {@code comparator.compare(e1,
- * e2)} must not throw a {@code ClassCastException} for any elements {@code e1} and {@code e2} in
- * the multiset. If the user attempts to add an element to the multiset that violates this
- * constraint, the {@code add(Object)} call will throw a {@code ClassCastException}.
+ * Creates a new, empty multiset, sorted according to the specified
+ * comparator. All elements inserted into the multiset must be <i>mutually
+ * comparable</i> by the specified comparator: {@code comparator.compare(e1,
+ * e2)} must not throw a {@code ClassCastException} for any elements {@code
+ * e1} and {@code e2} in the multiset. If the user attempts to add an element
+ * to the multiset that violates this constraint, the {@code add(Object)} call
+ * will throw a {@code ClassCastException}.
*
- * @param comparator
- * the comparator that will be used to sort this multiset. A null value indicates that
- * the elements' <i>natural ordering</i> should be used.
+ * @param comparator the comparator that will be used to sort this multiset. A
+ * null value indicates that the elements' <i>natural ordering</i> should
+ * be used.
*/
@SuppressWarnings("unchecked")
- public static <E> TreeMultiset<E> create(@Nullable Comparator<? super E> comparator) {
+ public static <E> TreeMultiset<E> create(
+ @Nullable Comparator<? super E> comparator) {
return (comparator == null)
- ? new TreeMultiset<E>((Comparator) Ordering.natural())
- : new TreeMultiset<E>(comparator);
+ ? new TreeMultiset<E>((Comparator) Ordering.natural())
+ : new TreeMultiset<E>(comparator);
}
/**
- * Creates an empty multiset containing the given initial elements, sorted according to the
- * elements' natural order.
+ * Creates an empty multiset containing the given initial elements, sorted
+ * according to the elements' natural order.
*
- * <p>This implementation is highly efficient when {@code elements} is itself a {@link Multiset}.
+ * <p>This implementation is highly efficient when {@code elements} is itself
+ * a {@link Multiset}.
*
- * <p>The type specification is {@code <E extends Comparable>}, instead of the more specific
- * {@code <E extends Comparable<? super E>>}, to support classes defined without generics.
+ * <p>The type specification is {@code <E extends Comparable>}, instead of the
+ * more specific {@code <E extends Comparable<? super E>>}, to support
+ * classes defined without generics.
*/
- public static <E extends Comparable> TreeMultiset<E> create(Iterable<? extends E> elements) {
+ public static <E extends Comparable> TreeMultiset<E> create(
+ Iterable<? extends E> elements) {
TreeMultiset<E> multiset = create();
Iterables.addAll(multiset, elements);
return multiset;
}
- private final transient Reference<AvlNode<E>> rootReference;
- private final transient GeneralRange<E> range;
- private final transient AvlNode<E> header;
-
- TreeMultiset(Reference<AvlNode<E>> rootReference, GeneralRange<E> range, AvlNode<E> endLink) {
- super(range.comparator());
- this.rootReference = rootReference;
- this.range = range;
- this.header = endLink;
+ /**
+ * Returns an iterator over the elements contained in this collection.
+ */
+ @Override
+ public Iterator<E> iterator() {
+ // Needed to avoid Javadoc bug.
+ return super.iterator();
}
- TreeMultiset(Comparator<? super E> comparator) {
+ private TreeMultiset(Comparator<? super E> comparator) {
super(comparator);
this.range = GeneralRange.all(comparator);
- this.header = new AvlNode<E>(null, 1);
- successor(header, header);
- this.rootReference = new Reference<AvlNode<E>>();
+ this.rootReference = new Reference<Node<E>>();
}
- /**
- * A function which can be summed across a subtree.
- */
- private enum Aggregate {
- SIZE {
- @Override
- int nodeAggregate(AvlNode<?> node) {
- return node.elemCount;
- }
+ private TreeMultiset(GeneralRange<E> range, Reference<Node<E>> root) {
+ super(range.comparator());
+ this.range = range;
+ this.rootReference = root;
+ }
- @Override
- long treeAggregate(@Nullable AvlNode<?> root) {
- return (root == null) ? 0 : root.totalCount;
- }
- },
- DISTINCT {
- @Override
- int nodeAggregate(AvlNode<?> node) {
- return 1;
- }
+ @SuppressWarnings("unchecked")
+ E checkElement(Object o) {
+ return (E) o;
+ }
- @Override
- long treeAggregate(@Nullable AvlNode<?> root) {
- return (root == null) ? 0 : root.distinctElements;
- }
- };
- abstract int nodeAggregate(AvlNode<?> node);
+ private transient final GeneralRange<E> range;
- abstract long treeAggregate(@Nullable AvlNode<?> root);
- }
+ private transient final Reference<Node<E>> rootReference;
- private long aggregateForEntries(Aggregate aggr) {
- AvlNode<E> root = rootReference.get();
- long total = aggr.treeAggregate(root);
- if (range.hasLowerBound()) {
- total -= aggregateBelowRange(aggr, root);
- }
- if (range.hasUpperBound()) {
- total -= aggregateAboveRange(aggr, root);
- }
- return total;
- }
+ static final class Reference<T> {
+ T value;
- private long aggregateBelowRange(Aggregate aggr, @Nullable AvlNode<E> node) {
- if (node == null) {
- return 0;
- }
- int cmp = comparator().compare(range.getLowerEndpoint(), node.elem);
- if (cmp < 0) {
- return aggregateBelowRange(aggr, node.left);
- } else if (cmp == 0) {
- switch (range.getLowerBoundType()) {
- case OPEN:
- return aggr.nodeAggregate(node) + aggr.treeAggregate(node.left);
- case CLOSED:
- return aggr.treeAggregate(node.left);
- default:
- throw new AssertionError();
- }
- } else {
- return aggr.treeAggregate(node.left) + aggr.nodeAggregate(node)
- + aggregateBelowRange(aggr, node.right);
- }
- }
+ public Reference() {}
- private long aggregateAboveRange(Aggregate aggr, @Nullable AvlNode<E> node) {
- if (node == null) {
- return 0;
+ public T get() {
+ return value;
}
- int cmp = comparator().compare(range.getUpperEndpoint(), node.elem);
- if (cmp > 0) {
- return aggregateAboveRange(aggr, node.right);
- } else if (cmp == 0) {
- switch (range.getUpperBoundType()) {
- case OPEN:
- return aggr.nodeAggregate(node) + aggr.treeAggregate(node.right);
- case CLOSED:
- return aggr.treeAggregate(node.right);
- default:
- throw new AssertionError();
+
+ public boolean compareAndSet(T expected, T newValue) {
+ if (value == expected) {
+ value = newValue;
+ return true;
}
- } else {
- return aggr.treeAggregate(node.right) + aggr.nodeAggregate(node)
- + aggregateAboveRange(aggr, node.left);
+ return false;
}
}
@Override
- public int size() {
- return Ints.saturatedCast(aggregateForEntries(Aggregate.SIZE));
+ int distinctElements() {
+ Node<E> root = rootReference.get();
+ return Ints.checkedCast(BstRangeOps.totalInRange(distinctAggregate(), range, root));
}
@Override
- int distinctElements() {
- return Ints.saturatedCast(aggregateForEntries(Aggregate.DISTINCT));
+ public int size() {
+ Node<E> root = rootReference.get();
+ return Ints.saturatedCast(BstRangeOps.totalInRange(sizeAggregate(), range, root));
}
@Override
public int count(@Nullable Object element) {
try {
- @SuppressWarnings("unchecked")
- E e = (E) element;
- AvlNode<E> root = rootReference.get();
- if (!range.contains(e) || root == null) {
- return 0;
+ E e = checkElement(element);
+ if (range.contains(e)) {
+ Node<E> node = BstOperations.seek(comparator(), rootReference.get(), e);
+ return countOrZero(node);
}
- return root.count(comparator(), e);
+ return 0;
} catch (ClassCastException e) {
return 0;
} catch (NullPointerException e) {
@@ -235,713 +186,354 @@ public final class TreeMultiset<E> extends AbstractSortedMultiset<E> implements
}
}
+ private int mutate(@Nullable E e, MultisetModifier modifier) {
+ BstMutationRule<E, Node<E>> mutationRule = BstMutationRule.createRule(
+ modifier,
+ BstCountBasedBalancePolicies.
+ <E, Node<E>>singleRebalancePolicy(distinctAggregate()),
+ nodeFactory());
+ BstMutationResult<E, Node<E>> mutationResult =
+ BstOperations.mutate(comparator(), mutationRule, rootReference.get(), e);
+ if (!rootReference.compareAndSet(
+ mutationResult.getOriginalRoot(), mutationResult.getChangedRoot())) {
+ throw new ConcurrentModificationException();
+ }
+ Node<E> original = mutationResult.getOriginalTarget();
+ return countOrZero(original);
+ }
+
@Override
- public int add(@Nullable E element, int occurrences) {
- checkArgument(occurrences >= 0, "occurrences must be >= 0 but was %s", occurrences);
+ public int add(E element, int occurrences) {
+ checkElement(element);
if (occurrences == 0) {
return count(element);
}
checkArgument(range.contains(element));
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- comparator().compare(element, element);
- AvlNode<E> newRoot = new AvlNode<E>(element, occurrences);
- successor(header, newRoot, header);
- rootReference.checkAndSet(root, newRoot);
- return 0;
- }
- int[] result = new int[1]; // used as a mutable int reference to hold result
- AvlNode<E> newRoot = root.add(comparator(), element, occurrences, result);
- rootReference.checkAndSet(root, newRoot);
- return result[0];
+ return mutate(element, new AddModifier(occurrences));
}
@Override
public int remove(@Nullable Object element, int occurrences) {
- checkArgument(occurrences >= 0, "occurrences must be >= 0 but was %s", occurrences);
- if (occurrences == 0) {
+ if (element == null) {
+ return 0;
+ } else if (occurrences == 0) {
return count(element);
}
- AvlNode<E> root = rootReference.get();
- int[] result = new int[1]; // used as a mutable int reference to hold result
- AvlNode<E> newRoot;
try {
- @SuppressWarnings("unchecked")
- E e = (E) element;
- if (!range.contains(e) || root == null) {
- return 0;
- }
- newRoot = root.remove(comparator(), e, occurrences, result);
+ E e = checkElement(element);
+ return range.contains(e) ? mutate(e, new RemoveModifier(occurrences)) : 0;
} catch (ClassCastException e) {
return 0;
- } catch (NullPointerException e) {
- return 0;
}
- rootReference.checkAndSet(root, newRoot);
- return result[0];
}
@Override
- public int setCount(@Nullable E element, int count) {
- checkArgument(count >= 0);
- if (!range.contains(element)) {
- checkArgument(count == 0);
- return 0;
- }
-
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- if (count > 0) {
- add(element, count);
- }
- return 0;
- }
- int[] result = new int[1]; // used as a mutable int reference to hold result
- AvlNode<E> newRoot = root.setCount(comparator(), element, count, result);
- rootReference.checkAndSet(root, newRoot);
- return result[0];
+ public boolean setCount(E element, int oldCount, int newCount) {
+ checkElement(element);
+ checkArgument(range.contains(element));
+ return mutate(element, new ConditionalSetCountModifier(oldCount, newCount))
+ == oldCount;
}
@Override
- public boolean setCount(@Nullable E element, int oldCount, int newCount) {
- checkArgument(newCount >= 0);
- checkArgument(oldCount >= 0);
+ public int setCount(E element, int count) {
+ checkElement(element);
checkArgument(range.contains(element));
-
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- if (oldCount == 0) {
- if (newCount > 0) {
- add(element, newCount);
- }
- return true;
- } else {
- return false;
- }
- }
- int[] result = new int[1]; // used as a mutable int reference to hold result
- AvlNode<E> newRoot = root.setCount(comparator(), element, oldCount, newCount, result);
- rootReference.checkAndSet(root, newRoot);
- return result[0] == oldCount;
+ return mutate(element, new SetCountModifier(count));
}
- private Entry<E> wrapEntry(final AvlNode<E> baseEntry) {
- return new Multisets.AbstractEntry<E>() {
- @Override
- public E getElement() {
- return baseEntry.getElement();
- }
-
- @Override
- public int getCount() {
- int result = baseEntry.getCount();
- if (result == 0) {
- return count(getElement());
- } else {
- return result;
- }
- }
- };
+ private BstPathFactory<Node<E>, BstInOrderPath<Node<E>>> pathFactory() {
+ return BstInOrderPath.inOrderFactory();
}
- /**
- * Returns the first node in the tree that is in range.
- */
- @Nullable private AvlNode<E> firstNode() {
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- return null;
- }
- AvlNode<E> node;
- if (range.hasLowerBound()) {
- E endpoint = range.getLowerEndpoint();
- node = rootReference.get().ceiling(comparator(), endpoint);
- if (node == null) {
- return null;
- }
- if (range.getLowerBoundType() == BoundType.OPEN
- && comparator().compare(endpoint, node.getElement()) == 0) {
- node = node.succ;
- }
- } else {
- node = header.succ;
- }
- return (node == header || !range.contains(node.getElement())) ? null : node;
+ @Override
+ Iterator<Entry<E>> entryIterator() {
+ Node<E> root = rootReference.get();
+ final BstInOrderPath<Node<E>> startingPath =
+ BstRangeOps.furthestPath(range, LEFT, pathFactory(), root);
+ return iteratorInDirection(startingPath, RIGHT);
}
- @Nullable private AvlNode<E> lastNode() {
- AvlNode<E> root = rootReference.get();
- if (root == null) {
- return null;
- }
- AvlNode<E> node;
- if (range.hasUpperBound()) {
- E endpoint = range.getUpperEndpoint();
- node = rootReference.get().floor(comparator(), endpoint);
- if (node == null) {
- return null;
- }
- if (range.getUpperBoundType() == BoundType.OPEN
- && comparator().compare(endpoint, node.getElement()) == 0) {
- node = node.pred;
- }
- } else {
- node = header.pred;
- }
- return (node == header || !range.contains(node.getElement())) ? null : node;
+ @Override
+ Iterator<Entry<E>> descendingEntryIterator() {
+ Node<E> root = rootReference.get();
+ final BstInOrderPath<Node<E>> startingPath =
+ BstRangeOps.furthestPath(range, RIGHT, pathFactory(), root);
+ return iteratorInDirection(startingPath, LEFT);
}
- @Override
- Iterator<Entry<E>> entryIterator() {
+ private Iterator<Entry<E>> iteratorInDirection(
+ @Nullable BstInOrderPath<Node<E>> start, final BstSide direction) {
+ final Iterator<BstInOrderPath<Node<E>>> pathIterator =
+ new AbstractLinkedIterator<BstInOrderPath<Node<E>>>(start) {
+ @Override
+ protected BstInOrderPath<Node<E>> computeNext(BstInOrderPath<Node<E>> previous) {
+ if (!previous.hasNext(direction)) {
+ return null;
+ }
+ BstInOrderPath<Node<E>> next = previous.next(direction);
+ // TODO(user): only check against one side
+ return range.contains(next.getTip().getKey()) ? next : null;
+ }
+ };
return new Iterator<Entry<E>>() {
- AvlNode<E> current = firstNode();
- Entry<E> prevEntry;
+ E toRemove = null;
@Override
public boolean hasNext() {
- if (current == null) {
- return false;
- } else if (range.tooHigh(current.getElement())) {
- current = null;
- return false;
- } else {
- return true;
- }
+ return pathIterator.hasNext();
}
@Override
public Entry<E> next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- Entry<E> result = wrapEntry(current);
- prevEntry = result;
- if (current.succ == header) {
- current = null;
- } else {
- current = current.succ;
- }
- return result;
+ BstInOrderPath<Node<E>> path = pathIterator.next();
+ return new LiveEntry(
+ toRemove = path.getTip().getKey(), path.getTip().elemCount());
}
@Override
public void remove() {
- checkState(prevEntry != null);
- setCount(prevEntry.getElement(), 0);
- prevEntry = null;
+ checkState(toRemove != null);
+ setCount(toRemove, 0);
+ toRemove = null;
}
};
}
- @Override
- Iterator<Entry<E>> descendingEntryIterator() {
- return new Iterator<Entry<E>>() {
- AvlNode<E> current = lastNode();
- Entry<E> prevEntry = null;
+ class LiveEntry extends Multisets.AbstractEntry<E> {
+ private Node<E> expectedRoot;
+ private final E element;
+ private int count;
- @Override
- public boolean hasNext() {
- if (current == null) {
- return false;
- } else if (range.tooLow(current.getElement())) {
- current = null;
- return false;
- } else {
- return true;
- }
- }
+ private LiveEntry(E element, int count) {
+ this.expectedRoot = rootReference.get();
+ this.element = element;
+ this.count = count;
+ }
- @Override
- public Entry<E> next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- Entry<E> result = wrapEntry(current);
- prevEntry = result;
- if (current.pred == header) {
- current = null;
- } else {
- current = current.pred;
- }
- return result;
- }
+ @Override
+ public E getElement() {
+ return element;
+ }
- @Override
- public void remove() {
- checkState(prevEntry != null);
- setCount(prevEntry.getElement(), 0);
- prevEntry = null;
+ @Override
+ public int getCount() {
+ if (rootReference.get() == expectedRoot) {
+ return count;
+ } else {
+ // check for updates
+ expectedRoot = rootReference.get();
+ return count = TreeMultiset.this.count(element);
}
- };
+ }
}
@Override
- public SortedMultiset<E> headMultiset(@Nullable E upperBound, BoundType boundType) {
- return new TreeMultiset<E>(rootReference, range.intersect(GeneralRange.upTo(
- comparator(),
- upperBound,
- boundType)), header);
+ public void clear() {
+ Node<E> root = rootReference.get();
+ Node<E> cleared = BstRangeOps.minusRange(range,
+ BstCountBasedBalancePolicies.<E, Node<E>>fullRebalancePolicy(distinctAggregate()),
+ nodeFactory(), root);
+ if (!rootReference.compareAndSet(root, cleared)) {
+ throw new ConcurrentModificationException();
+ }
}
@Override
- public SortedMultiset<E> tailMultiset(@Nullable E lowerBound, BoundType boundType) {
- return new TreeMultiset<E>(rootReference, range.intersect(GeneralRange.downTo(
- comparator(),
- lowerBound,
- boundType)), header);
+ public SortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
+ checkNotNull(upperBound);
+ return new TreeMultiset<E>(
+ range.intersect(GeneralRange.upTo(comparator, upperBound, boundType)), rootReference);
}
- static int distinctElements(@Nullable AvlNode<?> node) {
- return (node == null) ? 0 : node.distinctElements;
+ @Override
+ public SortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
+ checkNotNull(lowerBound);
+ return new TreeMultiset<E>(
+ range.intersect(GeneralRange.downTo(comparator, lowerBound, boundType)), rootReference);
}
- private static final class Reference<T> {
- @Nullable private T value;
-
- @Nullable public T get() {
- return value;
- }
-
- public void checkAndSet(@Nullable T expected, T newValue) {
- if (value != expected) {
- throw new ConcurrentModificationException();
- }
- value = newValue;
- }
+ /**
+ * {@inheritDoc}
+ *
+ * @since 11.0
+ */
+ @Override
+ public Comparator<? super E> comparator() {
+ return super.comparator();
}
- private static final class AvlNode<E> extends Multisets.AbstractEntry<E> {
- @Nullable private final E elem;
+ private static final class Node<E> extends BstNode<E, Node<E>> implements Serializable {
+ private final long size;
+ private final int distinct;
- // elemCount is 0 iff this node has been deleted.
- private int elemCount;
-
- private int distinctElements;
- private long totalCount;
- private int height;
- private AvlNode<E> left;
- private AvlNode<E> right;
- private AvlNode<E> pred;
- private AvlNode<E> succ;
-
- AvlNode(@Nullable E elem, int elemCount) {
+ private Node(E key, int elemCount, @Nullable Node<E> left,
+ @Nullable Node<E> right) {
+ super(key, left, right);
checkArgument(elemCount > 0);
- this.elem = elem;
- this.elemCount = elemCount;
- this.totalCount = elemCount;
- this.distinctElements = 1;
- this.height = 1;
- this.left = null;
- this.right = null;
- }
-
- public int count(Comparator<? super E> comparator, E e) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- return (left == null) ? 0 : left.count(comparator, e);
- } else if (cmp > 0) {
- return (right == null) ? 0 : right.count(comparator, e);
- } else {
- return elemCount;
- }
- }
-
- private AvlNode<E> addRightChild(E e, int count) {
- right = new AvlNode<E>(e, count);
- successor(this, right, succ);
- height = Math.max(2, height);
- distinctElements++;
- totalCount += count;
- return this;
+ this.size = (long) elemCount + sizeOrZero(left) + sizeOrZero(right);
+ this.distinct = 1 + distinctOrZero(left) + distinctOrZero(right);
}
- private AvlNode<E> addLeftChild(E e, int count) {
- left = new AvlNode<E>(e, count);
- successor(pred, left, this);
- height = Math.max(2, height);
- distinctElements++;
- totalCount += count;
- return this;
+ int elemCount() {
+ long result = size - sizeOrZero(childOrNull(LEFT))
+ - sizeOrZero(childOrNull(RIGHT));
+ return Ints.checkedCast(result);
}
- AvlNode<E> add(Comparator<? super E> comparator, @Nullable E e, int count, int[] result) {
- /*
- * It speeds things up considerably to unconditionally add count to totalCount here,
- * but that destroys failure atomicity in the case of count overflow. =(
- */
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- AvlNode<E> initLeft = left;
- if (initLeft == null) {
- result[0] = 0;
- return addLeftChild(e, count);
- }
- int initHeight = initLeft.height;
-
- left = initLeft.add(comparator, e, count, result);
- if (result[0] == 0) {
- distinctElements++;
- }
- this.totalCount += count;
- return (left.height == initHeight) ? this : rebalance();
- } else if (cmp > 0) {
- AvlNode<E> initRight = right;
- if (initRight == null) {
- result[0] = 0;
- return addRightChild(e, count);
- }
- int initHeight = initRight.height;
-
- right = initRight.add(comparator, e, count, result);
- if (result[0] == 0) {
- distinctElements++;
- }
- this.totalCount += count;
- return (right.height == initHeight) ? this : rebalance();
- }
-
- // adding count to me! No rebalance possible.
- result[0] = elemCount;
- long resultCount = (long) elemCount + count;
- checkArgument(resultCount <= Integer.MAX_VALUE);
- this.elemCount += count;
- this.totalCount += count;
- return this;
+ private Node(E key, int elemCount) {
+ this(key, elemCount, null, null);
}
- AvlNode<E> remove(Comparator<? super E> comparator, @Nullable E e, int count, int[] result) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- AvlNode<E> initLeft = left;
- if (initLeft == null) {
- result[0] = 0;
- return this;
- }
+ private static final long serialVersionUID = 0;
+ }
- left = initLeft.remove(comparator, e, count, result);
+ private static long sizeOrZero(@Nullable Node<?> node) {
+ return (node == null) ? 0 : node.size;
+ }
- if (result[0] > 0) {
- if (count >= result[0]) {
- this.distinctElements--;
- this.totalCount -= result[0];
- } else {
- this.totalCount -= count;
- }
- }
- return (result[0] == 0) ? this : rebalance();
- } else if (cmp > 0) {
- AvlNode<E> initRight = right;
- if (initRight == null) {
- result[0] = 0;
- return this;
- }
+ private static int distinctOrZero(@Nullable Node<?> node) {
+ return (node == null) ? 0 : node.distinct;
+ }
- right = initRight.remove(comparator, e, count, result);
+ private static int countOrZero(@Nullable Node<?> entry) {
+ return (entry == null) ? 0 : entry.elemCount();
+ }
- if (result[0] > 0) {
- if (count >= result[0]) {
- this.distinctElements--;
- this.totalCount -= result[0];
- } else {
- this.totalCount -= count;
- }
- }
- return rebalance();
- }
+ @SuppressWarnings("unchecked")
+ private BstAggregate<Node<E>> distinctAggregate() {
+ return (BstAggregate) DISTINCT_AGGREGATE;
+ }
- // removing count from me!
- result[0] = elemCount;
- if (count >= elemCount) {
- return deleteMe();
- } else {
- this.elemCount -= count;
- this.totalCount -= count;
- return this;
- }
+ private static final BstAggregate<Node<Object>> DISTINCT_AGGREGATE =
+ new BstAggregate<Node<Object>>() {
+ @Override
+ public int entryValue(Node<Object> entry) {
+ return 1;
}
- AvlNode<E> setCount(Comparator<? super E> comparator, @Nullable E e, int count, int[] result) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- AvlNode<E> initLeft = left;
- if (initLeft == null) {
- result[0] = 0;
- return (count > 0) ? addLeftChild(e, count) : this;
- }
-
- left = initLeft.setCount(comparator, e, count, result);
-
- if (count == 0 && result[0] != 0) {
- this.distinctElements--;
- } else if (count > 0 && result[0] == 0) {
- this.distinctElements++;
- }
-
- this.totalCount += count - result[0];
- return rebalance();
- } else if (cmp > 0) {
- AvlNode<E> initRight = right;
- if (initRight == null) {
- result[0] = 0;
- return (count > 0) ? addRightChild(e, count) : this;
- }
-
- right = initRight.setCount(comparator, e, count, result);
-
- if (count == 0 && result[0] != 0) {
- this.distinctElements--;
- } else if (count > 0 && result[0] == 0) {
- this.distinctElements++;
- }
-
- this.totalCount += count - result[0];
- return rebalance();
- }
-
- // setting my count
- result[0] = elemCount;
- if (count == 0) {
- return deleteMe();
- }
- this.totalCount += count - elemCount;
- this.elemCount = count;
- return this;
+ @Override
+ public long treeValue(@Nullable Node<Object> tree) {
+ return distinctOrZero(tree);
}
+ };
- AvlNode<E> setCount(
- Comparator<? super E> comparator,
- @Nullable E e,
- int expectedCount,
- int newCount,
- int[] result) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- AvlNode<E> initLeft = left;
- if (initLeft == null) {
- result[0] = 0;
- if (expectedCount == 0 && newCount > 0) {
- return addLeftChild(e, newCount);
- }
- return this;
- }
-
- left = initLeft.setCount(comparator, e, expectedCount, newCount, result);
+ @SuppressWarnings("unchecked")
+ private BstAggregate<Node<E>> sizeAggregate() {
+ return (BstAggregate) SIZE_AGGREGATE;
+ }
- if (result[0] == expectedCount) {
- if (newCount == 0 && result[0] != 0) {
- this.distinctElements--;
- } else if (newCount > 0 && result[0] == 0) {
- this.distinctElements++;
- }
- this.totalCount += newCount - result[0];
- }
- return rebalance();
- } else if (cmp > 0) {
- AvlNode<E> initRight = right;
- if (initRight == null) {
- result[0] = 0;
- if (expectedCount == 0 && newCount > 0) {
- return addRightChild(e, newCount);
- }
- return this;
+ private static final BstAggregate<Node<Object>> SIZE_AGGREGATE =
+ new BstAggregate<Node<Object>>() {
+ @Override
+ public int entryValue(Node<Object> entry) {
+ return entry.elemCount();
}
- right = initRight.setCount(comparator, e, expectedCount, newCount, result);
-
- if (result[0] == expectedCount) {
- if (newCount == 0 && result[0] != 0) {
- this.distinctElements--;
- } else if (newCount > 0 && result[0] == 0) {
- this.distinctElements++;
- }
- this.totalCount += newCount - result[0];
+ @Override
+ public long treeValue(@Nullable Node<Object> tree) {
+ return sizeOrZero(tree);
}
- return rebalance();
- }
+ };
- // setting my count
- result[0] = elemCount;
- if (expectedCount == elemCount) {
- if (newCount == 0) {
- return deleteMe();
- }
- this.totalCount += newCount - elemCount;
- this.elemCount = newCount;
- }
- return this;
- }
+ @SuppressWarnings("unchecked")
+ private BstNodeFactory<Node<E>> nodeFactory() {
+ return (BstNodeFactory) NODE_FACTORY;
+ }
- private AvlNode<E> deleteMe() {
- int oldElemCount = this.elemCount;
- this.elemCount = 0;
- successor(pred, succ);
- if (left == null) {
- return right;
- } else if (right == null) {
- return left;
- } else if (left.height >= right.height) {
- AvlNode<E> newTop = pred;
- // newTop is the maximum node in my left subtree
- newTop.left = left.removeMax(newTop);
- newTop.right = right;
- newTop.distinctElements = distinctElements - 1;
- newTop.totalCount = totalCount - oldElemCount;
- return newTop.rebalance();
- } else {
- AvlNode<E> newTop = succ;
- newTop.right = right.removeMin(newTop);
- newTop.left = left;
- newTop.distinctElements = distinctElements - 1;
- newTop.totalCount = totalCount - oldElemCount;
- return newTop.rebalance();
- }
- }
+ private static final BstNodeFactory<Node<Object>> NODE_FACTORY =
+ new BstNodeFactory<Node<Object>>() {
+ @Override
+ public Node<Object> createNode(Node<Object> source, @Nullable Node<Object> left,
+ @Nullable Node<Object> right) {
+ return new Node<Object>(source.getKey(), source.elemCount(), left, right);
+ }
+ };
- // Removes the minimum node from this subtree to be reused elsewhere
- private AvlNode<E> removeMin(AvlNode<E> node) {
- if (left == null) {
- return right;
- } else {
- left = left.removeMin(node);
- distinctElements--;
- totalCount -= node.elemCount;
- return rebalance();
- }
- }
+ private abstract class MultisetModifier implements BstModifier<E, Node<E>> {
+ abstract int newCount(int oldCount);
- // Removes the maximum node from this subtree to be reused elsewhere
- private AvlNode<E> removeMax(AvlNode<E> node) {
- if (right == null) {
- return left;
+ @Nullable
+ @Override
+ public BstModificationResult<Node<E>> modify(E key, @Nullable Node<E> originalEntry) {
+ int oldCount = countOrZero(originalEntry);
+ int newCount = newCount(oldCount);
+ if (oldCount == newCount) {
+ return BstModificationResult.identity(originalEntry);
+ } else if (newCount == 0) {
+ return BstModificationResult.rebalancingChange(originalEntry, null);
+ } else if (oldCount == 0) {
+ return BstModificationResult.rebalancingChange(null, new Node<E>(key, newCount));
} else {
- right = right.removeMax(node);
- distinctElements--;
- totalCount -= node.elemCount;
- return rebalance();
+ return BstModificationResult.rebuildingChange(originalEntry,
+ new Node<E>(originalEntry.getKey(), newCount));
}
}
+ }
- private void recomputeMultiset() {
- this.distinctElements = 1 + TreeMultiset.distinctElements(left)
- + TreeMultiset.distinctElements(right);
- this.totalCount = elemCount + totalCount(left) + totalCount(right);
- }
-
- private void recomputeHeight() {
- this.height = 1 + Math.max(height(left), height(right));
- }
-
- private void recompute() {
- recomputeMultiset();
- recomputeHeight();
- }
+ private final class AddModifier extends MultisetModifier {
+ private final int countToAdd;
- private AvlNode<E> rebalance() {
- switch (balanceFactor()) {
- case -2:
- if (right.balanceFactor() > 0) {
- right = right.rotateRight();
- }
- return rotateLeft();
- case 2:
- if (left.balanceFactor() < 0) {
- left = left.rotateLeft();
- }
- return rotateRight();
- default:
- recomputeHeight();
- return this;
- }
+ private AddModifier(int countToAdd) {
+ checkArgument(countToAdd > 0);
+ this.countToAdd = countToAdd;
}
- private int balanceFactor() {
- return height(left) - height(right);
+ @Override
+ int newCount(int oldCount) {
+ checkArgument(countToAdd <= Integer.MAX_VALUE - oldCount, "Cannot add this many elements");
+ return oldCount + countToAdd;
}
+ }
- private AvlNode<E> rotateLeft() {
- checkState(right != null);
- AvlNode<E> newTop = right;
- this.right = newTop.left;
- newTop.left = this;
- newTop.totalCount = this.totalCount;
- newTop.distinctElements = this.distinctElements;
- this.recompute();
- newTop.recomputeHeight();
- return newTop;
- }
+ private final class RemoveModifier extends MultisetModifier {
+ private final int countToRemove;
- private AvlNode<E> rotateRight() {
- checkState(left != null);
- AvlNode<E> newTop = left;
- this.left = newTop.right;
- newTop.right = this;
- newTop.totalCount = this.totalCount;
- newTop.distinctElements = this.distinctElements;
- this.recompute();
- newTop.recomputeHeight();
- return newTop;
+ private RemoveModifier(int countToRemove) {
+ checkArgument(countToRemove > 0);
+ this.countToRemove = countToRemove;
}
- private static long totalCount(@Nullable AvlNode<?> node) {
- return (node == null) ? 0 : node.totalCount;
+ @Override
+ int newCount(int oldCount) {
+ return Math.max(0, oldCount - countToRemove);
}
+ }
- private static int height(@Nullable AvlNode<?> node) {
- return (node == null) ? 0 : node.height;
- }
+ private final class SetCountModifier extends MultisetModifier {
+ private final int countToSet;
- @Nullable private AvlNode<E> ceiling(Comparator<? super E> comparator, E e) {
- int cmp = comparator.compare(e, elem);
- if (cmp < 0) {
- return (left == null) ? this : Objects.firstNonNull(left.ceiling(comparator, e), this);
- } else if (cmp == 0) {
- return this;
- } else {
- return (right == null) ? null : right.ceiling(comparator, e);
- }
- }
-
- @Nullable private AvlNode<E> floor(Comparator<? super E> comparator, E e) {
- int cmp = comparator.compare(e, elem);
- if (cmp > 0) {
- return (right == null) ? this : Objects.firstNonNull(right.floor(comparator, e), this);
- } else if (cmp == 0) {
- return this;
- } else {
- return (left == null) ? null : left.floor(comparator, e);
- }
+ private SetCountModifier(int countToSet) {
+ checkArgument(countToSet >= 0);
+ this.countToSet = countToSet;
}
@Override
- public E getElement() {
- return elem;
+ int newCount(int oldCount) {
+ return countToSet;
}
+ }
- @Override
- public int getCount() {
- return elemCount;
+ private final class ConditionalSetCountModifier extends MultisetModifier {
+ private final int expectedCount;
+ private final int setCount;
+
+ private ConditionalSetCountModifier(int expectedCount, int setCount) {
+ checkArgument(setCount >= 0 & expectedCount >= 0);
+ this.expectedCount = expectedCount;
+ this.setCount = setCount;
}
@Override
- public String toString() {
- return Multisets.immutableEntry(getElement(), getCount()).toString();
+ int newCount(int oldCount) {
+ return (oldCount == expectedCount) ? setCount : oldCount;
}
}
- private static <T> void successor(AvlNode<T> a, AvlNode<T> b) {
- a.succ = b;
- b.pred = a;
- }
-
- private static <T> void successor(AvlNode<T> a, AvlNode<T> b, AvlNode<T> c) {
- successor(a, b);
- successor(b, c);
- }
-
/*
- * TODO(jlevy): Decide whether entrySet() should return entries with an equals() method that
- * calls the comparator to compare the two keys. If that change is made,
- * AbstractMultiset.equals() can simply check whether two multisets have equal entry sets.
+ * TODO(jlevy): Decide whether entrySet() should return entries with an
+ * equals() method that calls the comparator to compare the two keys. If that
+ * change is made, AbstractMultiset.equals() can simply check whether two
+ * multisets have equal entry sets.
*/
}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/UnmodifiableSortedMultiset.java b/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/UnmodifiableSortedMultiset.java
deleted file mode 100644
index 87937fe..0000000
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/UnmodifiableSortedMultiset.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.collect;
-
-import com.google.common.collect.Multisets.UnmodifiableMultiset;
-
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.SortedSet;
-
-/**
- * Implementation of {@link Multisets#unmodifiableSortedMultiset(SortedMultiset)}
- * for GWT.
- *
- * @author Louis Wasserman
- */
-final class UnmodifiableSortedMultiset<E>
- extends UnmodifiableMultiset<E> implements SortedMultiset<E> {
- UnmodifiableSortedMultiset(SortedMultiset<E> delegate) {
- super(delegate);
- }
-
- @Override
- protected SortedMultiset<E> delegate() {
- return (SortedMultiset<E>) super.delegate();
- }
-
- @Override
- public Comparator<? super E> comparator() {
- return delegate().comparator();
- }
-
- @Override
- SortedSet<E> createElementSet() {
- return Collections.unmodifiableSortedSet(delegate().elementSet());
- }
-
- @Override
- public SortedSet<E> elementSet() {
- return (SortedSet<E>) super.elementSet();
- }
-
- private transient UnmodifiableSortedMultiset<E> descendingMultiset;
-
- @Override
- public SortedMultiset<E> descendingMultiset() {
- UnmodifiableSortedMultiset<E> result = descendingMultiset;
- if (result == null) {
- result = new UnmodifiableSortedMultiset<E>(
- delegate().descendingMultiset());
- result.descendingMultiset = this;
- return descendingMultiset = result;
- }
- return result;
- }
-
- @Override
- public Entry<E> firstEntry() {
- return delegate().firstEntry();
- }
-
- @Override
- public Entry<E> lastEntry() {
- return delegate().lastEntry();
- }
-
- @Override
- public Entry<E> pollFirstEntry() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Entry<E> pollLastEntry() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SortedMultiset<E> headMultiset(E upperBound, BoundType boundType) {
- return Multisets.unmodifiableSortedMultiset(
- delegate().headMultiset(upperBound, boundType));
- }
-
- @Override
- public SortedMultiset<E> subMultiset(
- E lowerBound, BoundType lowerBoundType,
- E upperBound, BoundType upperBoundType) {
- return Multisets.unmodifiableSortedMultiset(delegate().subMultiset(
- lowerBound, lowerBoundType, upperBound, upperBoundType));
- }
-
- @Override
- public SortedMultiset<E> tailMultiset(E lowerBound, BoundType boundType) {
- return Multisets.unmodifiableSortedMultiset(
- delegate().tailMultiset(lowerBound, boundType));
- }
-
- private static final long serialVersionUID = 0;
-} \ No newline at end of file
diff --git a/guava-gwt/src-super/java/nio/charset/IllegalCharsetNameException.java b/guava-gwt/src-super/com/google/common/escape/super/com/google/common/escape/Platform.java
index 19755e2..36f1b2e 100644
--- a/guava-gwt/src-super/java/nio/charset/IllegalCharsetNameException.java
+++ b/guava-gwt/src-super/com/google/common/escape/super/com/google/common/escape/Platform.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Guava Authors
+ * Copyright (C) 2009 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,22 +14,20 @@
* limitations under the License.
*/
-package java.nio.charset;
+package com.google.common.escape;
/**
- * GWT emulation of {@link IllegalCharsetNameException}.
- *
- * @author Gregory Kick
+ * @author Jesse Wilson
*/
-public class IllegalCharsetNameException extends IllegalArgumentException {
- private final String charsetName;
+class Platform {
- public IllegalCharsetNameException(String charsetName) {
- super(String.valueOf(charsetName));
- this.charsetName = charsetName;
- }
+ private static final char[] CHAR_BUFFER = new char[1024];
- public String getCharsetName() {
- return charsetName;
+ static char[] charBufferFromThreadLocal() {
+ // ThreadLocal is not available to GWT, so we always reuse the same
+ // instance. It is always safe to return the same instance because
+ // javascript is single-threaded, and only used by blocks that doesn't
+ // involve async callbacks.
+ return CHAR_BUFFER;
}
}
diff --git a/guava-gwt/src-super/com/google/common/io/super/com/google/common/io/BaseEncoding.java b/guava-gwt/src-super/com/google/common/io/super/com/google/common/io/BaseEncoding.java
deleted file mode 100644
index dee5b89..0000000
--- a/guava-gwt/src-super/com/google/common/io/super/com/google/common/io/BaseEncoding.java
+++ /dev/null
@@ -1,794 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.io;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndexes;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.io.GwtWorkarounds.asCharInput;
-import static com.google.common.io.GwtWorkarounds.stringBuilderOutput;
-import static com.google.common.math.IntMath.divide;
-import static com.google.common.math.IntMath.log2;
-import static java.math.RoundingMode.CEILING;
-import static java.math.RoundingMode.FLOOR;
-import static java.math.RoundingMode.UNNECESSARY;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.base.Ascii;
-import com.google.common.base.CharMatcher;
-import com.google.common.io.GwtWorkarounds.ByteInput;
-import com.google.common.io.GwtWorkarounds.ByteOutput;
-import com.google.common.io.GwtWorkarounds.CharInput;
-import com.google.common.io.GwtWorkarounds.CharOutput;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-import javax.annotation.CheckReturnValue;
-import javax.annotation.Nullable;
-
-/**
- * A binary encoding scheme for reversibly translating between byte sequences and printable ASCII
- * strings. This class includes several constants for encoding schemes specified by <a
- * href="http://tools.ietf.org/html/rfc4648">RFC 4648</a>. For example, the expression:
- * <pre> {@code
- *
- * BaseEncoding.base32().encode("foo".getBytes(Charsets.US_ASCII))
- * }</pre>
- * returns the string {@code "MZXW6==="}, and <pre> {@code
- *
- * byte[] decoded = BaseEncoding.base32().decode("MZXW6===");
- * }</pre>
- *
- * ...returns the ASCII bytes of the string {@code "foo"}.
- *
- * <p>By default, {@code BaseEncoding}'s behavior is relatively strict and in accordance with
- * RFC 4648. Decoding rejects characters in the wrong case, though padding is optional.
- * To modify encoding and decoding behavior, use configuration methods to obtain a new encoding
- * with modified behavior: <pre> {@code
- *
- * BaseEncoding.base16().lowerCase().decode("deadbeef");
- * }</pre>
- *
- * <p>Warning: BaseEncoding instances are immutable. Invoking a configuration method has no effect
- * on the receiving instance; you must store and use the new encoding instance it returns, instead.
- * <pre> {@code
- *
- * // Do NOT do this
- * BaseEncoding hex = BaseEncoding.base16();
- * hex.lowerCase(); // does nothing!
- * return hex.decode("deadbeef"); // throws an IllegalArgumentException
- * }</pre>
- *
- * <p>It is guaranteed that {@code encoding.decode(encoding.encode(x))} is always equal to
- * {@code x}, but the reverse does not necessarily hold.
- *
- * <p>
- * <table>
- * <tr>
- * <th>Encoding
- * <th>Alphabet
- * <th>{@code char:byte} ratio
- * <th>Default padding
- * <th>Comments
- * <tr>
- * <td>{@link #base16()}
- * <td>0-9 A-F
- * <td>2.00
- * <td>N/A
- * <td>Traditional hexadecimal. Defaults to upper case.
- * <tr>
- * <td>{@link #base32()}
- * <td>A-Z 2-7
- * <td>1.60
- * <td>=
- * <td>Human-readable; no possibility of mixing up 0/O or 1/I. Defaults to upper case.
- * <tr>
- * <td>{@link #base32Hex()}
- * <td>0-9 A-V
- * <td>1.60
- * <td>=
- * <td>"Numerical" base 32; extended from the traditional hex alphabet. Defaults to upper case.
- * <tr>
- * <td>{@link #base64()}
- * <td>A-Z a-z 0-9 + /
- * <td>1.33
- * <td>=
- * <td>
- * <tr>
- * <td>{@link #base64Url()}
- * <td>A-Z a-z 0-9 - _
- * <td>1.33
- * <td>=
- * <td>Safe to use as filenames, or to pass in URLs without escaping
- * </table>
- *
- * <p>
- * All instances of this class are immutable, so they may be stored safely as static constants.
- *
- * @author Louis Wasserman
- * @since 14.0
- */
-@Beta
-@GwtCompatible(emulated = true)
-public abstract class BaseEncoding {
- // TODO(user): consider adding encodeTo(Appendable, byte[], [int, int])
-
- BaseEncoding() {}
-
- /**
- * Encodes the specified byte array, and returns the encoded {@code String}.
- */
- public String encode(byte[] bytes) {
- return encode(checkNotNull(bytes), 0, bytes.length);
- }
-
- /**
- * Encodes the specified range of the specified byte array, and returns the encoded
- * {@code String}.
- */
- public final String encode(byte[] bytes, int off, int len) {
- checkNotNull(bytes);
- checkPositionIndexes(off, off + len, bytes.length);
- CharOutput result = stringBuilderOutput(maxEncodedSize(len));
- ByteOutput byteOutput = encodingStream(result);
- try {
- for (int i = 0; i < len; i++) {
- byteOutput.write(bytes[off + i]);
- }
- byteOutput.close();
- } catch (IOException impossible) {
- throw new AssertionError("impossible");
- }
- return result.toString();
- }
-
- // TODO(user): document the extent of leniency, probably after adding ignore(CharMatcher)
-
- private static byte[] extract(byte[] result, int length) {
- if (length == result.length) {
- return result;
- } else {
- byte[] trunc = new byte[length];
- System.arraycopy(result, 0, trunc, 0, length);
- return trunc;
- }
- }
-
- /**
- * Decodes the specified character sequence, and returns the resulting {@code byte[]}.
- * This is the inverse operation to {@link #encode(byte[])}.
- *
- * @throws IllegalArgumentException if the input is not a valid encoded string according to this
- * encoding.
- */
- public final byte[] decode(CharSequence chars) {
- chars = padding().trimTrailingFrom(chars);
- ByteInput decodedInput = decodingStream(asCharInput(chars));
- byte[] tmp = new byte[maxDecodedSize(chars.length())];
- int index = 0;
- try {
- for (int i = decodedInput.read(); i != -1; i = decodedInput.read()) {
- tmp[index++] = (byte) i;
- }
- } catch (IOException badInput) {
- throw new IllegalArgumentException(badInput);
- }
- return extract(tmp, index);
- }
-
- // Implementations for encoding/decoding
-
- abstract int maxEncodedSize(int bytes);
-
- abstract ByteOutput encodingStream(CharOutput charOutput);
-
- abstract int maxDecodedSize(int chars);
-
- abstract ByteInput decodingStream(CharInput charInput);
-
- abstract CharMatcher padding();
-
- // Modified encoding generators
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but omits any padding
- * characters as specified by <a href="http://tools.ietf.org/html/rfc4648#section-3.2">RFC 4648
- * section 3.2</a>, Padding of Encoded Data.
- */
- @CheckReturnValue
- public abstract BaseEncoding omitPadding();
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but uses an alternate character
- * for padding.
- *
- * @throws IllegalArgumentException if this padding character is already used in the alphabet or a
- * separator
- */
- @CheckReturnValue
- public abstract BaseEncoding withPadChar(char padChar);
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but adds a separator string
- * after every {@code n} characters. Any occurrences of any characters that occur in the separator
- * are skipped over in decoding.
- *
- * @throws IllegalArgumentException if any alphabet or padding characters appear in the separator
- * string, or if {@code n <= 0}
- * @throws UnsupportedOperationException if this encoding already uses a separator
- */
- @CheckReturnValue
- public abstract BaseEncoding withSeparator(String separator, int n);
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but encodes and decodes with
- * uppercase letters. Padding and separator characters remain in their original case.
- *
- * @throws IllegalStateException if the alphabet used by this encoding contains mixed upper- and
- * lower-case characters
- */
- @CheckReturnValue
- public abstract BaseEncoding upperCase();
-
- /**
- * Returns an encoding that behaves equivalently to this encoding, but encodes and decodes with
- * lowercase letters. Padding and separator characters remain in their original case.
- *
- * @throws IllegalStateException if the alphabet used by this encoding contains mixed upper- and
- * lower-case characters
- */
- @CheckReturnValue
- public abstract BaseEncoding lowerCase();
-
- private static final BaseEncoding BASE64 = new StandardBaseEncoding(
- "base64()", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", '=');
-
- /**
- * The "base64" base encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-4">RFC 4648 section 4</a>, Base 64 Encoding.
- * (This is the same as the base 64 encoding from <a
- * href="http://tools.ietf.org/html/rfc3548#section-3">RFC 3548</a>.)
- *
- * <p>The character {@code '='} is used for padding, but can be {@linkplain #omitPadding()
- * omitted} or {@linkplain #withPadChar(char) replaced}.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base64() {
- return BASE64;
- }
-
- private static final BaseEncoding BASE64_URL = new StandardBaseEncoding(
- "base64Url()", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", '=');
-
- /**
- * The "base64url" encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-5">RFC 4648 section 5</a>, Base 64 Encoding
- * with URL and Filename Safe Alphabet, also sometimes referred to as the "web safe Base64."
- * (This is the same as the base 64 encoding with URL and filename safe alphabet from <a
- * href="http://tools.ietf.org/html/rfc3548#section-4">RFC 3548</a>.)
- *
- * <p>The character {@code '='} is used for padding, but can be {@linkplain #omitPadding()
- * omitted} or {@linkplain #withPadChar(char) replaced}.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base64Url() {
- return BASE64_URL;
- }
-
- private static final BaseEncoding BASE32 =
- new StandardBaseEncoding("base32()", "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", '=');
-
- /**
- * The "base32" encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-6">RFC 4648 section 6</a>, Base 32 Encoding.
- * (This is the same as the base 32 encoding from <a
- * href="http://tools.ietf.org/html/rfc3548#section-5">RFC 3548</a>.)
- *
- * <p>The character {@code '='} is used for padding, but can be {@linkplain #omitPadding()
- * omitted} or {@linkplain #withPadChar(char) replaced}.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base32() {
- return BASE32;
- }
-
- private static final BaseEncoding BASE32_HEX =
- new StandardBaseEncoding("base32Hex()", "0123456789ABCDEFGHIJKLMNOPQRSTUV", '=');
-
- /**
- * The "base32hex" encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-7">RFC 4648 section 7</a>, Base 32 Encoding
- * with Extended Hex Alphabet. There is no corresponding encoding in RFC 3548.
- *
- * <p>The character {@code '='} is used for padding, but can be {@linkplain #omitPadding()
- * omitted} or {@linkplain #withPadChar(char) replaced}.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base32Hex() {
- return BASE32_HEX;
- }
-
- private static final BaseEncoding BASE16 =
- new StandardBaseEncoding("base16()", "0123456789ABCDEF", null);
-
- /**
- * The "base16" encoding specified by <a
- * href="http://tools.ietf.org/html/rfc4648#section-8">RFC 4648 section 8</a>, Base 16 Encoding.
- * (This is the same as the base 16 encoding from <a
- * href="http://tools.ietf.org/html/rfc3548#section-6">RFC 3548</a>.) This is commonly known as
- * "hexadecimal" format.
- *
- * <p>No padding is necessary in base 16, so {@link #withPadChar(char)} and
- * {@link #omitPadding()} have no effect.
- *
- * <p>No line feeds are added by default, as per <a
- * href="http://tools.ietf.org/html/rfc4648#section-3.1"> RFC 4648 section 3.1</a>, Line Feeds in
- * Encoded Data. Line feeds may be added using {@link #withSeparator(String, int)}.
- */
- public static BaseEncoding base16() {
- return BASE16;
- }
-
- private static final class Alphabet extends CharMatcher {
- private final String name;
- // this is meant to be immutable -- don't modify it!
- private final char[] chars;
- final int mask;
- final int bitsPerChar;
- final int charsPerChunk;
- final int bytesPerChunk;
- private final byte[] decodabet;
- private final boolean[] validPadding;
-
- Alphabet(String name, char[] chars) {
- this.name = checkNotNull(name);
- this.chars = checkNotNull(chars);
- try {
- this.bitsPerChar = log2(chars.length, UNNECESSARY);
- } catch (ArithmeticException e) {
- throw new IllegalArgumentException("Illegal alphabet length " + chars.length, e);
- }
-
- /*
- * e.g. for base64, bitsPerChar == 6, charsPerChunk == 4, and bytesPerChunk == 3. This makes
- * for the smallest chunk size that still has charsPerChunk * bitsPerChar be a multiple of 8.
- */
- int gcd = Math.min(8, Integer.lowestOneBit(bitsPerChar));
- this.charsPerChunk = 8 / gcd;
- this.bytesPerChunk = bitsPerChar / gcd;
-
- this.mask = chars.length - 1;
-
- byte[] decodabet = new byte[Ascii.MAX + 1];
- Arrays.fill(decodabet, (byte) -1);
- for (int i = 0; i < chars.length; i++) {
- char c = chars[i];
- checkArgument(CharMatcher.ASCII.matches(c), "Non-ASCII character: %s", c);
- checkArgument(decodabet[c] == -1, "Duplicate character: %s", c);
- decodabet[c] = (byte) i;
- }
- this.decodabet = decodabet;
-
- boolean[] validPadding = new boolean[charsPerChunk];
- for (int i = 0; i < bytesPerChunk; i++) {
- validPadding[divide(i * 8, bitsPerChar, CEILING)] = true;
- }
- this.validPadding = validPadding;
- }
-
- char encode(int bits) {
- return chars[bits];
- }
-
- boolean isValidPaddingStartPosition(int index) {
- return validPadding[index % charsPerChunk];
- }
-
- int decode(char ch) throws IOException {
- if (ch > Ascii.MAX || decodabet[ch] == -1) {
- throw new IOException("Unrecognized character: " + ch);
- }
- return decodabet[ch];
- }
-
- private boolean hasLowerCase() {
- for (char c : chars) {
- if (Ascii.isLowerCase(c)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean hasUpperCase() {
- for (char c : chars) {
- if (Ascii.isUpperCase(c)) {
- return true;
- }
- }
- return false;
- }
-
- Alphabet upperCase() {
- if (!hasLowerCase()) {
- return this;
- } else {
- checkState(!hasUpperCase(), "Cannot call upperCase() on a mixed-case alphabet");
- char[] upperCased = new char[chars.length];
- for (int i = 0; i < chars.length; i++) {
- upperCased[i] = Ascii.toUpperCase(chars[i]);
- }
- return new Alphabet(name + ".upperCase()", upperCased);
- }
- }
-
- Alphabet lowerCase() {
- if (!hasUpperCase()) {
- return this;
- } else {
- checkState(!hasLowerCase(), "Cannot call lowerCase() on a mixed-case alphabet");
- char[] lowerCased = new char[chars.length];
- for (int i = 0; i < chars.length; i++) {
- lowerCased[i] = Ascii.toLowerCase(chars[i]);
- }
- return new Alphabet(name + ".lowerCase()", lowerCased);
- }
- }
-
- @Override
- public boolean matches(char c) {
- return CharMatcher.ASCII.matches(c) && decodabet[c] != -1;
- }
-
- @Override
- public String toString() {
- return name;
- }
- }
-
- static final class StandardBaseEncoding extends BaseEncoding {
- // TODO(user): provide a useful toString
- private final Alphabet alphabet;
-
- @Nullable
- private final Character paddingChar;
-
- StandardBaseEncoding(String name, String alphabetChars, @Nullable Character paddingChar) {
- this(new Alphabet(name, alphabetChars.toCharArray()), paddingChar);
- }
-
- StandardBaseEncoding(Alphabet alphabet, Character paddingChar) {
- this.alphabet = checkNotNull(alphabet);
- checkArgument(paddingChar == null || !alphabet.matches(paddingChar),
- "Padding character %s was already in alphabet", paddingChar);
- this.paddingChar = paddingChar;
- }
-
- @Override
- CharMatcher padding() {
- return (paddingChar == null) ? CharMatcher.NONE : CharMatcher.is(paddingChar.charValue());
- }
-
- @Override
- int maxEncodedSize(int bytes) {
- return alphabet.charsPerChunk * divide(bytes, alphabet.bytesPerChunk, CEILING);
- }
-
- @Override
- ByteOutput encodingStream(final CharOutput out) {
- checkNotNull(out);
- return new ByteOutput() {
- int bitBuffer = 0;
- int bitBufferLength = 0;
- int writtenChars = 0;
-
- @Override
- public void write(byte b) throws IOException {
- bitBuffer <<= 8;
- bitBuffer |= b & 0xFF;
- bitBufferLength += 8;
- while (bitBufferLength >= alphabet.bitsPerChar) {
- int charIndex = (bitBuffer >> (bitBufferLength - alphabet.bitsPerChar))
- & alphabet.mask;
- out.write(alphabet.encode(charIndex));
- writtenChars++;
- bitBufferLength -= alphabet.bitsPerChar;
- }
- }
-
- @Override
- public void flush() throws IOException {
- out.flush();
- }
-
- @Override
- public void close() throws IOException {
- if (bitBufferLength > 0) {
- int charIndex = (bitBuffer << (alphabet.bitsPerChar - bitBufferLength))
- & alphabet.mask;
- out.write(alphabet.encode(charIndex));
- writtenChars++;
- if (paddingChar != null) {
- while (writtenChars % alphabet.charsPerChunk != 0) {
- out.write(paddingChar.charValue());
- writtenChars++;
- }
- }
- }
- out.close();
- }
- };
- }
-
- @Override
- int maxDecodedSize(int chars) {
- return (int) ((alphabet.bitsPerChar * (long) chars + 7L) / 8L);
- }
-
- @Override
- ByteInput decodingStream(final CharInput reader) {
- checkNotNull(reader);
- return new ByteInput() {
- int bitBuffer = 0;
- int bitBufferLength = 0;
- int readChars = 0;
- boolean hitPadding = false;
- final CharMatcher paddingMatcher = padding();
-
- @Override
- public int read() throws IOException {
- while (true) {
- int readChar = reader.read();
- if (readChar == -1) {
- if (!hitPadding && !alphabet.isValidPaddingStartPosition(readChars)) {
- throw new IOException("Invalid input length " + readChars);
- }
- return -1;
- }
- readChars++;
- char ch = (char) readChar;
- if (paddingMatcher.matches(ch)) {
- if (!hitPadding
- && (readChars == 1 || !alphabet.isValidPaddingStartPosition(readChars - 1))) {
- throw new IOException("Padding cannot start at index " + readChars);
- }
- hitPadding = true;
- } else if (hitPadding) {
- throw new IOException(
- "Expected padding character but found '" + ch + "' at index " + readChars);
- } else {
- bitBuffer <<= alphabet.bitsPerChar;
- bitBuffer |= alphabet.decode(ch);
- bitBufferLength += alphabet.bitsPerChar;
-
- if (bitBufferLength >= 8) {
- bitBufferLength -= 8;
- return (bitBuffer >> bitBufferLength) & 0xFF;
- }
- }
- }
- }
-
- @Override
- public void close() throws IOException {
- reader.close();
- }
- };
- }
-
- @Override
- public BaseEncoding omitPadding() {
- return (paddingChar == null) ? this : new StandardBaseEncoding(alphabet, null);
- }
-
- @Override
- public BaseEncoding withPadChar(char padChar) {
- if (8 % alphabet.bitsPerChar == 0 ||
- (paddingChar != null && paddingChar.charValue() == padChar)) {
- return this;
- } else {
- return new StandardBaseEncoding(alphabet, padChar);
- }
- }
-
- @Override
- public BaseEncoding withSeparator(String separator, int afterEveryChars) {
- checkNotNull(separator);
- checkArgument(padding().or(alphabet).matchesNoneOf(separator),
- "Separator cannot contain alphabet or padding characters");
- return new SeparatedBaseEncoding(this, separator, afterEveryChars);
- }
-
- private transient BaseEncoding upperCase;
- private transient BaseEncoding lowerCase;
-
- @Override
- public BaseEncoding upperCase() {
- BaseEncoding result = upperCase;
- if (result == null) {
- Alphabet upper = alphabet.upperCase();
- result = upperCase =
- (upper == alphabet) ? this : new StandardBaseEncoding(upper, paddingChar);
- }
- return result;
- }
-
- @Override
- public BaseEncoding lowerCase() {
- BaseEncoding result = lowerCase;
- if (result == null) {
- Alphabet lower = alphabet.lowerCase();
- result = lowerCase =
- (lower == alphabet) ? this : new StandardBaseEncoding(lower, paddingChar);
- }
- return result;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder("BaseEncoding.");
- builder.append(alphabet.toString());
- if (8 % alphabet.bitsPerChar != 0) {
- if (paddingChar == null) {
- builder.append(".omitPadding()");
- } else {
- builder.append(".withPadChar(").append(paddingChar).append(')');
- }
- }
- return builder.toString();
- }
- }
-
- static CharInput ignoringInput(final CharInput delegate, final CharMatcher toIgnore) {
- checkNotNull(delegate);
- checkNotNull(toIgnore);
- return new CharInput() {
- @Override
- public int read() throws IOException {
- int readChar;
- do {
- readChar = delegate.read();
- } while (readChar != -1 && toIgnore.matches((char) readChar));
- return readChar;
- }
-
- @Override
- public void close() throws IOException {
- delegate.close();
- }
- };
- }
-
- static CharOutput separatingOutput(
- final CharOutput delegate, final String separator, final int afterEveryChars) {
- checkNotNull(delegate);
- checkNotNull(separator);
- checkArgument(afterEveryChars > 0);
- return new CharOutput() {
- int charsUntilSeparator = afterEveryChars;
-
- @Override
- public void write(char c) throws IOException {
- if (charsUntilSeparator == 0) {
- for (int i = 0; i < separator.length(); i++) {
- delegate.write(separator.charAt(i));
- }
- charsUntilSeparator = afterEveryChars;
- }
- delegate.write(c);
- charsUntilSeparator--;
- }
-
- @Override
- public void flush() throws IOException {
- delegate.flush();
- }
-
- @Override
- public void close() throws IOException {
- delegate.close();
- }
- };
- }
-
- static final class SeparatedBaseEncoding extends BaseEncoding {
- private final BaseEncoding delegate;
- private final String separator;
- private final int afterEveryChars;
- private final CharMatcher separatorChars;
-
- SeparatedBaseEncoding(BaseEncoding delegate, String separator, int afterEveryChars) {
- this.delegate = checkNotNull(delegate);
- this.separator = checkNotNull(separator);
- this.afterEveryChars = afterEveryChars;
- checkArgument(
- afterEveryChars > 0, "Cannot add a separator after every %s chars", afterEveryChars);
- this.separatorChars = CharMatcher.anyOf(separator).precomputed();
- }
-
- @Override
- CharMatcher padding() {
- return delegate.padding();
- }
-
- @Override
- int maxEncodedSize(int bytes) {
- int unseparatedSize = delegate.maxEncodedSize(bytes);
- return unseparatedSize + separator.length()
- * divide(Math.max(0, unseparatedSize - 1), afterEveryChars, FLOOR);
- }
-
- @Override
- ByteOutput encodingStream(final CharOutput output) {
- return delegate.encodingStream(separatingOutput(output, separator, afterEveryChars));
- }
-
- @Override
- int maxDecodedSize(int chars) {
- return delegate.maxDecodedSize(chars);
- }
-
- @Override
- ByteInput decodingStream(final CharInput input) {
- return delegate.decodingStream(ignoringInput(input, separatorChars));
- }
-
- @Override
- public BaseEncoding omitPadding() {
- return delegate.omitPadding().withSeparator(separator, afterEveryChars);
- }
-
- @Override
- public BaseEncoding withPadChar(char padChar) {
- return delegate.withPadChar(padChar).withSeparator(separator, afterEveryChars);
- }
-
- @Override
- public BaseEncoding withSeparator(String separator, int afterEveryChars) {
- throw new UnsupportedOperationException("Already have a separator");
- }
-
- @Override
- public BaseEncoding upperCase() {
- return delegate.upperCase().withSeparator(separator, afterEveryChars);
- }
-
- @Override
- public BaseEncoding lowerCase() {
- return delegate.lowerCase().withSeparator(separator, afterEveryChars);
- }
-
- @Override
- public String toString() {
- return delegate.toString() +
- ".withSeparator(\"" + separator + "\", " + afterEveryChars + ")";
- }
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/io/super/com/google/common/io/GwtWorkarounds.java b/guava-gwt/src-super/com/google/common/io/super/com/google/common/io/GwtWorkarounds.java
deleted file mode 100644
index f3f955e..0000000
--- a/guava-gwt/src-super/com/google/common/io/super/com/google/common/io/GwtWorkarounds.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.google.common.io;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.io.IOException;
-
-/**
- * Provides simple GWT-compatible substitutes for {@code InputStream}, {@code OutputStream},
- * {@code Reader}, and {@code Writer} so that {@code BaseEncoding} can use streaming implementations
- * while remaining GWT-compatible.
- *
- * @author Louis Wasserman
- */
-@GwtCompatible(emulated = true)
-final class GwtWorkarounds {
- private GwtWorkarounds() {}
-
- /**
- * A GWT-compatible substitute for a {@code Reader}.
- */
- interface CharInput {
- int read() throws IOException;
- void close() throws IOException;
- }
-
- /**
- * Views a {@code CharSequence} as a {@code CharInput}.
- */
- static CharInput asCharInput(final CharSequence chars) {
- checkNotNull(chars);
- return new CharInput() {
- int index = 0;
-
- @Override
- public int read() {
- if (index < chars.length()) {
- return chars.charAt(index++);
- } else {
- return -1;
- }
- }
-
- @Override
- public void close() {
- index = chars.length();
- }
- };
- }
-
- /**
- * A GWT-compatible substitute for an {@code InputStream}.
- */
- interface ByteInput {
- int read() throws IOException;
- void close() throws IOException;
- }
-
- /**
- * A GWT-compatible substitute for an {@code OutputStream}.
- */
- interface ByteOutput {
- void write(byte b) throws IOException;
- void flush() throws IOException;
- void close() throws IOException;
- }
-
- /**
- * A GWT-compatible substitute for a {@code Writer}.
- */
- interface CharOutput {
- void write(char c) throws IOException;
- void flush() throws IOException;
- void close() throws IOException;
- }
-
- /**
- * Returns a {@code CharOutput} whose {@code toString()} method can be used
- * to get the combined output.
- */
- static CharOutput stringBuilderOutput(int initialSize) {
- final StringBuilder builder = new StringBuilder(initialSize);
- return new CharOutput() {
-
- @Override
- public void write(char c) {
- builder.append(c);
- }
-
- @Override
- public void flush() {}
-
- @Override
- public void close() {}
-
- @Override
- public String toString() {
- return builder.toString();
- }
- };
- }
-}
-
diff --git a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/BigIntegerMath.java b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/BigIntegerMath.java
deleted file mode 100644
index 75f19be..0000000
--- a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/BigIntegerMath.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.math;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.math.MathPreconditions.checkNonNegative;
-import static com.google.common.math.MathPreconditions.checkPositive;
-import static com.google.common.math.MathPreconditions.checkRoundingUnnecessary;
-import static java.math.RoundingMode.CEILING;
-import static java.math.RoundingMode.FLOOR;
-import static java.math.RoundingMode.HALF_EVEN;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.VisibleForTesting;
-
-import java.math.BigInteger;
-import java.math.RoundingMode;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A class for arithmetic on values of type {@code BigInteger}.
- *
- * <p>The implementations of many methods in this class are based on material from Henry S. Warren,
- * Jr.'s <i>Hacker's Delight</i>, (Addison Wesley, 2002).
- *
- * <p>Similar functionality for {@code int} and for {@code long} can be found in
- * {@link IntMath} and {@link LongMath} respectively.
- *
- * @author Louis Wasserman
- * @since 11.0
- */
-@GwtCompatible(emulated = true)
-public final class BigIntegerMath {
- /**
- * Returns {@code true} if {@code x} represents a power of two.
- */
- public static boolean isPowerOfTwo(BigInteger x) {
- checkNotNull(x);
- return x.signum() > 0 && x.getLowestSetBit() == x.bitLength() - 1;
- }
-
- /**
- * Returns the base-2 logarithm of {@code x}, rounded according to the specified rounding mode.
- *
- * @throws IllegalArgumentException if {@code x <= 0}
- * @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
- * is not a power of two
- */
- @SuppressWarnings("fallthrough")
- // TODO(kevinb): remove after this warning is disabled globally
- public static int log2(BigInteger x, RoundingMode mode) {
- checkPositive("x", checkNotNull(x));
- int logFloor = x.bitLength() - 1;
- switch (mode) {
- case UNNECESSARY:
- checkRoundingUnnecessary(isPowerOfTwo(x)); // fall through
- case DOWN:
- case FLOOR:
- return logFloor;
-
- case UP:
- case CEILING:
- return isPowerOfTwo(x) ? logFloor : logFloor + 1;
-
- case HALF_DOWN:
- case HALF_UP:
- case HALF_EVEN:
- if (logFloor < SQRT2_PRECOMPUTE_THRESHOLD) {
- BigInteger halfPower = SQRT2_PRECOMPUTED_BITS.shiftRight(
- SQRT2_PRECOMPUTE_THRESHOLD - logFloor);
- if (x.compareTo(halfPower) <= 0) {
- return logFloor;
- } else {
- return logFloor + 1;
- }
- }
- /*
- * Since sqrt(2) is irrational, log2(x) - logFloor cannot be exactly 0.5
- *
- * To determine which side of logFloor.5 the logarithm is, we compare x^2 to 2^(2 *
- * logFloor + 1).
- */
- BigInteger x2 = x.pow(2);
- int logX2Floor = x2.bitLength() - 1;
- return (logX2Floor < 2 * logFloor + 1) ? logFloor : logFloor + 1;
-
- default:
- throw new AssertionError();
- }
- }
-
- /*
- * The maximum number of bits in a square root for which we'll precompute an explicit half power
- * of two. This can be any value, but higher values incur more class load time and linearly
- * increasing memory consumption.
- */
- @VisibleForTesting static final int SQRT2_PRECOMPUTE_THRESHOLD = 256;
-
- @VisibleForTesting static final BigInteger SQRT2_PRECOMPUTED_BITS =
- new BigInteger("16a09e667f3bcc908b2fb1366ea957d3e3adec17512775099da2f590b0667322a", 16);
-
- private static final double LN_10 = Math.log(10);
- private static final double LN_2 = Math.log(2);
-
- /**
- * Returns {@code n!}, that is, the product of the first {@code n} positive
- * integers, or {@code 1} if {@code n == 0}.
- *
- * <p><b>Warning</b>: the result takes <i>O(n log n)</i> space, so use cautiously.
- *
- * <p>This uses an efficient binary recursive algorithm to compute the factorial
- * with balanced multiplies. It also removes all the 2s from the intermediate
- * products (shifting them back in at the end).
- *
- * @throws IllegalArgumentException if {@code n < 0}
- */
- public static BigInteger factorial(int n) {
- checkNonNegative("n", n);
-
- // If the factorial is small enough, just use LongMath to do it.
- if (n < LongMath.factorials.length) {
- return BigInteger.valueOf(LongMath.factorials[n]);
- }
-
- // Pre-allocate space for our list of intermediate BigIntegers.
- int approxSize = IntMath.divide(n * IntMath.log2(n, CEILING), Long.SIZE, CEILING);
- ArrayList<BigInteger> bignums = new ArrayList<BigInteger>(approxSize);
-
- // Start from the pre-computed maximum long factorial.
- int startingNumber = LongMath.factorials.length;
- long product = LongMath.factorials[startingNumber - 1];
- // Strip off 2s from this value.
- int shift = Long.numberOfTrailingZeros(product);
- product >>= shift;
-
- // Use floor(log2(num)) + 1 to prevent overflow of multiplication.
- int productBits = LongMath.log2(product, FLOOR) + 1;
- int bits = LongMath.log2(startingNumber, FLOOR) + 1;
- // Check for the next power of two boundary, to save us a CLZ operation.
- int nextPowerOfTwo = 1 << (bits - 1);
-
- // Iteratively multiply the longs as big as they can go.
- for (long num = startingNumber; num <= n; num++) {
- // Check to see if the floor(log2(num)) + 1 has changed.
- if ((num & nextPowerOfTwo) != 0) {
- nextPowerOfTwo <<= 1;
- bits++;
- }
- // Get rid of the 2s in num.
- int tz = Long.numberOfTrailingZeros(num);
- long normalizedNum = num >> tz;
- shift += tz;
- // Adjust floor(log2(num)) + 1.
- int normalizedBits = bits - tz;
- // If it won't fit in a long, then we store off the intermediate product.
- if (normalizedBits + productBits >= Long.SIZE) {
- bignums.add(BigInteger.valueOf(product));
- product = 1;
- productBits = 0;
- }
- product *= normalizedNum;
- productBits = LongMath.log2(product, FLOOR) + 1;
- }
- // Check for leftovers.
- if (product > 1) {
- bignums.add(BigInteger.valueOf(product));
- }
- // Efficiently multiply all the intermediate products together.
- return listProduct(bignums).shiftLeft(shift);
- }
-
- static BigInteger listProduct(List<BigInteger> nums) {
- return listProduct(nums, 0, nums.size());
- }
-
- static BigInteger listProduct(List<BigInteger> nums, int start, int end) {
- switch (end - start) {
- case 0:
- return BigInteger.ONE;
- case 1:
- return nums.get(start);
- case 2:
- return nums.get(start).multiply(nums.get(start + 1));
- case 3:
- return nums.get(start).multiply(nums.get(start + 1)).multiply(nums.get(start + 2));
- default:
- // Otherwise, split the list in half and recursively do this.
- int m = (end + start) >>> 1;
- return listProduct(nums, start, m).multiply(listProduct(nums, m, end));
- }
- }
-
- /**
- * Returns {@code n} choose {@code k}, also known as the binomial coefficient of {@code n} and
- * {@code k}, that is, {@code n! / (k! (n - k)!)}.
- *
- * <p><b>Warning</b>: the result can take as much as <i>O(k log n)</i> space.
- *
- * @throws IllegalArgumentException if {@code n < 0}, {@code k < 0}, or {@code k > n}
- */
- public static BigInteger binomial(int n, int k) {
- checkNonNegative("n", n);
- checkNonNegative("k", k);
- checkArgument(k <= n, "k (%s) > n (%s)", k, n);
- if (k > (n >> 1)) {
- k = n - k;
- }
- if (k < LongMath.biggestBinomials.length && n <= LongMath.biggestBinomials[k]) {
- return BigInteger.valueOf(LongMath.binomial(n, k));
- }
-
- BigInteger accum = BigInteger.ONE;
-
- long numeratorAccum = n;
- long denominatorAccum = 1;
-
- int bits = LongMath.log2(n, RoundingMode.CEILING);
-
- int numeratorBits = bits;
-
- for (int i = 1; i < k; i++) {
- int p = n - i;
- int q = i + 1;
-
- // log2(p) >= bits - 1, because p >= n/2
-
- if (numeratorBits + bits >= Long.SIZE - 1) {
- // The numerator is as big as it can get without risking overflow.
- // Multiply numeratorAccum / denominatorAccum into accum.
- accum = accum
- .multiply(BigInteger.valueOf(numeratorAccum))
- .divide(BigInteger.valueOf(denominatorAccum));
- numeratorAccum = p;
- denominatorAccum = q;
- numeratorBits = bits;
- } else {
- // We can definitely multiply into the long accumulators without overflowing them.
- numeratorAccum *= p;
- denominatorAccum *= q;
- numeratorBits += bits;
- }
- }
- return accum
- .multiply(BigInteger.valueOf(numeratorAccum))
- .divide(BigInteger.valueOf(denominatorAccum));
- }
-
- // Returns true if BigInteger.valueOf(x.longValue()).equals(x).
-
- private BigIntegerMath() {}
-}
-
diff --git a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/IntMath.java b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/IntMath.java
index 31703ed..352351c 100644
--- a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/IntMath.java
+++ b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/IntMath.java
@@ -16,42 +16,35 @@
package com.google.common.math;
-import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.math.MathPreconditions.checkNoOverflow;
import static com.google.common.math.MathPreconditions.checkNonNegative;
-import static com.google.common.math.MathPreconditions.checkPositive;
-import static com.google.common.math.MathPreconditions.checkRoundingUnnecessary;
-import static java.lang.Math.abs;
-import static java.lang.Math.min;
-import static java.math.RoundingMode.HALF_EVEN;
-import static java.math.RoundingMode.HALF_UP;
+import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.VisibleForTesting;
-import java.math.RoundingMode;
-
/**
* A class for arithmetic on values of type {@code int}. Where possible, methods are defined and
* named analogously to their {@code BigInteger} counterparts.
- *
+ *
* <p>The implementations of many methods in this class are based on material from Henry S. Warren,
* Jr.'s <i>Hacker's Delight</i>, (Addison Wesley, 2002).
- *
+ *
* <p>Similar functionality for {@code long} and for {@link BigInteger} can be found in
* {@link LongMath} and {@link BigIntegerMath} respectively. For other common operations on
* {@code int} values, see {@link com.google.common.primitives.Ints}.
- *
+ *
* @author Louis Wasserman
* @since 11.0
*/
+@Beta
@GwtCompatible(emulated = true)
public final class IntMath {
// NOTE: Whenever both tests are cheap and functional, it's faster to use &, | instead of &&, ||
/**
* Returns {@code true} if {@code x} represents a power of two.
- *
+ *
* <p>This differs from {@code Integer.bitCount(x) == 1}, because
* {@code Integer.bitCount(Integer.MIN_VALUE) == 1}, but {@link Integer#MIN_VALUE} is not a power
* of two.
@@ -60,75 +53,23 @@ public final class IntMath {
return x > 0 & (x & (x - 1)) == 0;
}
- /**
- * Returns the base-2 logarithm of {@code x}, rounded according to the specified rounding mode.
- *
- * @throws IllegalArgumentException if {@code x <= 0}
- * @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
- * is not a power of two
- */
- @SuppressWarnings("fallthrough")
- // TODO(kevinb): remove after this warning is disabled globally
- public static int log2(int x, RoundingMode mode) {
- checkPositive("x", x);
- switch (mode) {
- case UNNECESSARY:
- checkRoundingUnnecessary(isPowerOfTwo(x));
- // fall through
- case DOWN:
- case FLOOR:
- return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(x);
-
- case UP:
- case CEILING:
- return Integer.SIZE - Integer.numberOfLeadingZeros(x - 1);
-
- case HALF_DOWN:
- case HALF_UP:
- case HALF_EVEN:
- // Since sqrt(2) is irrational, log2(x) - logFloor cannot be exactly 0.5
- int leadingZeros = Integer.numberOfLeadingZeros(x);
- int cmp = MAX_POWER_OF_SQRT2_UNSIGNED >>> leadingZeros;
- // floor(2^(logFloor + 0.5))
- int logFloor = (Integer.SIZE - 1) - leadingZeros;
- return (x <= cmp) ? logFloor : logFloor + 1;
-
- default:
- throw new AssertionError();
- }
- }
-
/** The biggest half power of two that can fit in an unsigned int. */
@VisibleForTesting static final int MAX_POWER_OF_SQRT2_UNSIGNED = 0xB504F333;
-
+
private static int log10Floor(int x) {
- /*
- * Based on Hacker's Delight Fig. 11-5, the two-table-lookup, branch-free implementation.
- *
- * The key idea is that based on the number of leading zeros (equivalently, floor(log2(x))),
- * we can narrow the possible floor(log10(x)) values to two. For example, if floor(log2(x))
- * is 6, then 64 <= x < 128, so floor(log10(x)) is either 1 or 2.
- */
- int y = maxLog10ForLeadingZeros[Integer.numberOfLeadingZeros(x)];
- // y is the higher of the two possible values of floor(log10(x))
-
- int sgn = (x - powersOf10[y]) >>> (Integer.SIZE - 1);
- /*
- * sgn is the sign bit of x - 10^y; it is 1 if x < 10^y, and 0 otherwise. If x < 10^y, then we
- * want the lower of the two possible values, or y - 1, otherwise, we want y.
- */
- return y - sgn;
+ for (int i = 1; i < POWERS_OF_10.length; i++) {
+ if (x < POWERS_OF_10[i]) {
+ return i - 1;
+ }
+ }
+ return POWERS_OF_10.length - 1;
}
- // maxLog10ForLeadingZeros[i] == floor(log10(2^(Long.SIZE - i)))
- @VisibleForTesting static final byte[] maxLog10ForLeadingZeros = {9, 9, 9, 8, 8, 8,
- 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0};
-
- @VisibleForTesting static final int[] powersOf10 = {1, 10, 100, 1000, 10000,
- 100000, 1000000, 10000000, 100000000, 1000000000};
+ @VisibleForTesting static final int[] POWERS_OF_10 =
+ {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
- // halfPowersOf10[i] = largest int less than 10^(i + 0.5)
- @VisibleForTesting static final int[] halfPowersOf10 =
+ // HALF_POWERS_OF_10[i] = largest int less than 10^(i + 0.5)
+ @VisibleForTesting static final int[] HALF_POWERS_OF_10 =
{3, 31, 316, 3162, 31622, 316227, 3162277, 31622776, 316227766, Integer.MAX_VALUE};
private static int sqrtFloor(int x) {
@@ -138,81 +79,17 @@ public final class IntMath {
}
/**
- * Returns the result of dividing {@code p} by {@code q}, rounding using the specified
- * {@code RoundingMode}.
- *
- * @throws ArithmeticException if {@code q == 0}, or if {@code mode == UNNECESSARY} and {@code a}
- * is not an integer multiple of {@code b}
- */
- @SuppressWarnings("fallthrough")
- public static int divide(int p, int q, RoundingMode mode) {
- checkNotNull(mode);
- if (q == 0) {
- throw new ArithmeticException("/ by zero"); // for GWT
- }
- int div = p / q;
- int rem = p - q * div; // equal to p % q
-
- if (rem == 0) {
- return div;
- }
-
- /*
- * Normal Java division rounds towards 0, consistently with RoundingMode.DOWN. We just have to
- * deal with the cases where rounding towards 0 is wrong, which typically depends on the sign of
- * p / q.
- *
- * signum is 1 if p and q are both nonnegative or both negative, and -1 otherwise.
- */
- int signum = 1 | ((p ^ q) >> (Integer.SIZE - 1));
- boolean increment;
- switch (mode) {
- case UNNECESSARY:
- checkRoundingUnnecessary(rem == 0);
- // fall through
- case DOWN:
- increment = false;
- break;
- case UP:
- increment = true;
- break;
- case CEILING:
- increment = signum > 0;
- break;
- case FLOOR:
- increment = signum < 0;
- break;
- case HALF_EVEN:
- case HALF_DOWN:
- case HALF_UP:
- int absRem = abs(rem);
- int cmpRemToHalfDivisor = absRem - (abs(q) - absRem);
- // subtracting two nonnegative ints can't overflow
- // cmpRemToHalfDivisor has the same sign as compare(abs(rem), abs(q) / 2).
- if (cmpRemToHalfDivisor == 0) { // exactly on the half mark
- increment = (mode == HALF_UP || (mode == HALF_EVEN & (div & 1) != 0));
- } else {
- increment = cmpRemToHalfDivisor > 0; // closer to the UP value
- }
- break;
- default:
- throw new AssertionError();
- }
- return increment ? div + signum : div;
- }
-
- /**
* Returns {@code x mod m}. This differs from {@code x % m} in that it always returns a
* non-negative result.
- *
+ *
* <p>For example:<pre> {@code
- *
+ *
* mod(7, 4) == 3
* mod(-7, 4) == 1
* mod(-1, 4) == 3
* mod(-8, 4) == 0
* mod(8, 4) == 0}</pre>
- *
+ *
* @throws ArithmeticException if {@code m <= 0}
*/
public static int mod(int x, int m) {
@@ -226,7 +103,7 @@ public final class IntMath {
/**
* Returns the greatest common divisor of {@code a, b}. Returns {@code 0} if
* {@code a == 0 && b == 0}.
- *
+ *
* @throws IllegalArgumentException if {@code a < 0} or {@code b < 0}
*/
public static int gcd(int a, int b) {
@@ -237,46 +114,18 @@ public final class IntMath {
*/
checkNonNegative("a", a);
checkNonNegative("b", b);
- if (a == 0) {
- // 0 % b == 0, so b divides a, but the converse doesn't hold.
- // BigInteger.gcd is consistent with this decision.
- return b;
- } else if (b == 0) {
- return a; // similar logic
- }
- /*
- * Uses the binary GCD algorithm; see http://en.wikipedia.org/wiki/Binary_GCD_algorithm.
- * This is >40% faster than the Euclidean algorithm in benchmarks.
- */
- int aTwos = Integer.numberOfTrailingZeros(a);
- a >>= aTwos; // divide out all 2s
- int bTwos = Integer.numberOfTrailingZeros(b);
- b >>= bTwos; // divide out all 2s
- while (a != b) { // both a, b are odd
- // The key to the binary GCD algorithm is as follows:
- // Both a and b are odd. Assume a > b; then gcd(a - b, b) = gcd(a, b).
- // But in gcd(a - b, b), a - b is even and b is odd, so we can divide out powers of two.
-
- // We bend over backwards to avoid branching, adapting a technique from
- // http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
-
- int delta = a - b; // can't overflow, since a and b are nonnegative
-
- int minDeltaOrZero = delta & (delta >> (Integer.SIZE - 1));
- // equivalent to Math.min(delta, 0)
-
- a = delta - minDeltaOrZero - minDeltaOrZero; // sets a to Math.abs(a - b)
- // a is now nonnegative and even
-
- b += minDeltaOrZero; // sets b to min(old a, b)
- a >>= Integer.numberOfTrailingZeros(a); // divide out all 2s, since 2 doesn't divide b
+ // The simple Euclidean algorithm is the fastest for ints, and is easily the most readable.
+ while (b != 0) {
+ int t = b;
+ b = a % b;
+ a = t;
}
- return a << min(aTwos, bTwos);
+ return a;
}
/**
* Returns the sum of {@code a} and {@code b}, provided it does not overflow.
- *
+ *
* @throws ArithmeticException if {@code a + b} overflows in signed {@code int} arithmetic
*/
public static int checkedAdd(int a, int b) {
@@ -287,7 +136,7 @@ public final class IntMath {
/**
* Returns the difference of {@code a} and {@code b}, provided it does not overflow.
- *
+ *
* @throws ArithmeticException if {@code a - b} overflows in signed {@code int} arithmetic
*/
public static int checkedSubtract(int a, int b) {
@@ -298,7 +147,7 @@ public final class IntMath {
/**
* Returns the product of {@code a} and {@code b}, provided it does not overflow.
- *
+ *
* @throws ArithmeticException if {@code a * b} overflows in signed {@code int} arithmetic
*/
public static int checkedMultiply(int a, int b) {
@@ -307,67 +156,9 @@ public final class IntMath {
return (int) result;
}
- /**
- * Returns the {@code b} to the {@code k}th power, provided it does not overflow.
- *
- * <p>{@link #pow} may be faster, but does not check for overflow.
- *
- * @throws ArithmeticException if {@code b} to the {@code k}th power overflows in signed
- * {@code int} arithmetic
- */
- public static int checkedPow(int b, int k) {
- checkNonNegative("exponent", k);
- switch (b) {
- case 0:
- return (k == 0) ? 1 : 0;
- case 1:
- return 1;
- case (-1):
- return ((k & 1) == 0) ? 1 : -1;
- case 2:
- checkNoOverflow(k < Integer.SIZE - 1);
- return 1 << k;
- case (-2):
- checkNoOverflow(k < Integer.SIZE);
- return ((k & 1) == 0) ? 1 << k : -1 << k;
- default:
- // continue below to handle the general case
- }
- int accum = 1;
- while (true) {
- switch (k) {
- case 0:
- return accum;
- case 1:
- return checkedMultiply(accum, b);
- default:
- if ((k & 1) != 0) {
- accum = checkedMultiply(accum, b);
- }
- k >>= 1;
- if (k > 0) {
- checkNoOverflow(-FLOOR_SQRT_MAX_INT <= b & b <= FLOOR_SQRT_MAX_INT);
- b *= b;
- }
- }
- }
- }
-
@VisibleForTesting static final int FLOOR_SQRT_MAX_INT = 46340;
-
- /**
- * Returns {@code n!}, that is, the product of the first {@code n} positive
- * integers, {@code 1} if {@code n == 0}, or {@link Integer#MAX_VALUE} if the
- * result does not fit in a {@code int}.
- *
- * @throws IllegalArgumentException if {@code n < 0}
- */
- public static int factorial(int n) {
- checkNonNegative("n", n);
- return (n < factorials.length) ? factorials[n] : Integer.MAX_VALUE;
- }
-
- private static final int[] factorials = {
+
+ static final int[] FACTORIALS = {
1,
1,
1 * 2,
@@ -382,8 +173,8 @@ public final class IntMath {
1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11,
1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12};
- // binomial(biggestBinomials[k], k) fits in an int, but not binomial(biggestBinomials[k]+1,k).
- @VisibleForTesting static int[] biggestBinomials = {
+ // binomial(BIGGEST_BINOMIALS[k], k) fits in an int, but not binomial(BIGGEST_BINOMIALS[k]+1,k).
+ @VisibleForTesting static int[] BIGGEST_BINOMIALS = {
Integer.MAX_VALUE,
Integer.MAX_VALUE,
65536,
@@ -402,20 +193,7 @@ public final class IntMath {
34,
33
};
-
- /**
- * Returns the arithmetic mean of {@code x} and {@code y}, rounded towards
- * negative infinity. This method is overflow resilient.
- *
- * @since 14.0
- */
- public static int mean(int x, int y) {
- // Efficient method for computing the arithmetic mean.
- // The alternative (x + y) / 2 fails for large values.
- // The alternative (x + y) >>> 1 fails for negative values.
- return (x & y) + ((x ^ y) >> 1);
- }
-
+
private IntMath() {}
}
diff --git a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/LongMath.java b/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/LongMath.java
deleted file mode 100644
index 2f15360..0000000
--- a/guava-gwt/src-super/com/google/common/math/super/com/google/common/math/LongMath.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.math;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.math.MathPreconditions.checkNonNegative;
-import static com.google.common.math.MathPreconditions.checkPositive;
-import static com.google.common.math.MathPreconditions.checkRoundingUnnecessary;
-import static java.lang.Math.min;
-import static java.math.RoundingMode.HALF_EVEN;
-import static java.math.RoundingMode.HALF_UP;
-
-import com.google.common.annotations.GwtCompatible;
-import com.google.common.annotations.VisibleForTesting;
-
-import java.math.RoundingMode;
-
-/**
- * A class for arithmetic on values of type {@code long}. Where possible, methods are defined and
- * named analogously to their {@code BigInteger} counterparts.
- *
- * <p>The implementations of many methods in this class are based on material from Henry S. Warren,
- * Jr.'s <i>Hacker's Delight</i>, (Addison Wesley, 2002).
- *
- * <p>Similar functionality for {@code int} and for {@link BigInteger} can be found in
- * {@link IntMath} and {@link BigIntegerMath} respectively. For other common operations on
- * {@code long} values, see {@link com.google.common.primitives.Longs}.
- *
- * @author Louis Wasserman
- * @since 11.0
- */
-@GwtCompatible(emulated = true)
-public final class LongMath {
- // NOTE: Whenever both tests are cheap and functional, it's faster to use &, | instead of &&, ||
-
- /**
- * Returns {@code true} if {@code x} represents a power of two.
- *
- * <p>This differs from {@code Long.bitCount(x) == 1}, because
- * {@code Long.bitCount(Long.MIN_VALUE) == 1}, but {@link Long#MIN_VALUE} is not a power of two.
- */
- public static boolean isPowerOfTwo(long x) {
- return x > 0 & (x & (x - 1)) == 0;
- }
-
- /**
- * Returns the base-2 logarithm of {@code x}, rounded according to the specified rounding mode.
- *
- * @throws IllegalArgumentException if {@code x <= 0}
- * @throws ArithmeticException if {@code mode} is {@link RoundingMode#UNNECESSARY} and {@code x}
- * is not a power of two
- */
- @SuppressWarnings("fallthrough")
- // TODO(kevinb): remove after this warning is disabled globally
- public static int log2(long x, RoundingMode mode) {
- checkPositive("x", x);
- switch (mode) {
- case UNNECESSARY:
- checkRoundingUnnecessary(isPowerOfTwo(x));
- // fall through
- case DOWN:
- case FLOOR:
- return (Long.SIZE - 1) - Long.numberOfLeadingZeros(x);
-
- case UP:
- case CEILING:
- return Long.SIZE - Long.numberOfLeadingZeros(x - 1);
-
- case HALF_DOWN:
- case HALF_UP:
- case HALF_EVEN:
- // Since sqrt(2) is irrational, log2(x) - logFloor cannot be exactly 0.5
- int leadingZeros = Long.numberOfLeadingZeros(x);
- long cmp = MAX_POWER_OF_SQRT2_UNSIGNED >>> leadingZeros;
- // floor(2^(logFloor + 0.5))
- int logFloor = (Long.SIZE - 1) - leadingZeros;
- return (x <= cmp) ? logFloor : logFloor + 1;
-
- default:
- throw new AssertionError("impossible");
- }
- }
-
- /** The biggest half power of two that fits into an unsigned long */
- @VisibleForTesting static final long MAX_POWER_OF_SQRT2_UNSIGNED = 0xB504F333F9DE6484L;
-
- // maxLog10ForLeadingZeros[i] == floor(log10(2^(Long.SIZE - i)))
- @VisibleForTesting static final byte[] maxLog10ForLeadingZeros = {
- 19, 18, 18, 18, 18, 17, 17, 17, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 13, 13, 13, 12, 12,
- 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 4, 4,
- 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0 };
-
- // halfPowersOf10[i] = largest long less than 10^(i + 0.5)
-
- /**
- * Returns the greatest common divisor of {@code a, b}. Returns {@code 0} if
- * {@code a == 0 && b == 0}.
- *
- * @throws IllegalArgumentException if {@code a < 0} or {@code b < 0}
- */
- public static long gcd(long a, long b) {
- /*
- * The reason we require both arguments to be >= 0 is because otherwise, what do you return on
- * gcd(0, Long.MIN_VALUE)? BigInteger.gcd would return positive 2^63, but positive 2^63 isn't
- * an int.
- */
- checkNonNegative("a", a);
- checkNonNegative("b", b);
- if (a == 0) {
- // 0 % b == 0, so b divides a, but the converse doesn't hold.
- // BigInteger.gcd is consistent with this decision.
- return b;
- } else if (b == 0) {
- return a; // similar logic
- }
- /*
- * Uses the binary GCD algorithm; see http://en.wikipedia.org/wiki/Binary_GCD_algorithm.
- * This is >60% faster than the Euclidean algorithm in benchmarks.
- */
- int aTwos = Long.numberOfTrailingZeros(a);
- a >>= aTwos; // divide out all 2s
- int bTwos = Long.numberOfTrailingZeros(b);
- b >>= bTwos; // divide out all 2s
- while (a != b) { // both a, b are odd
- // The key to the binary GCD algorithm is as follows:
- // Both a and b are odd. Assume a > b; then gcd(a - b, b) = gcd(a, b).
- // But in gcd(a - b, b), a - b is even and b is odd, so we can divide out powers of two.
-
- // We bend over backwards to avoid branching, adapting a technique from
- // http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
-
- long delta = a - b; // can't overflow, since a and b are nonnegative
-
- long minDeltaOrZero = delta & (delta >> (Long.SIZE - 1));
- // equivalent to Math.min(delta, 0)
-
- a = delta - minDeltaOrZero - minDeltaOrZero; // sets a to Math.abs(a - b)
- // a is now nonnegative and even
-
- b += minDeltaOrZero; // sets b to min(old a, b)
- a >>= Long.numberOfTrailingZeros(a); // divide out all 2s, since 2 doesn't divide b
- }
- return a << min(aTwos, bTwos);
- }
-
- static final long[] factorials = {
- 1L,
- 1L,
- 1L * 2,
- 1L * 2 * 3,
- 1L * 2 * 3 * 4,
- 1L * 2 * 3 * 4 * 5,
- 1L * 2 * 3 * 4 * 5 * 6,
- 1L * 2 * 3 * 4 * 5 * 6 * 7,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19,
- 1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19 * 20
- };
-
- /**
- * Returns {@code n} choose {@code k}, also known as the binomial coefficient of {@code n} and
- * {@code k}, or {@link Long#MAX_VALUE} if the result does not fit in a {@code long}.
- *
- * @throws IllegalArgumentException if {@code n < 0}, {@code k < 0}, or {@code k > n}
- */
- public static long binomial(int n, int k) {
- checkNonNegative("n", n);
- checkNonNegative("k", k);
- checkArgument(k <= n, "k (%s) > n (%s)", k, n);
- if (k > (n >> 1)) {
- k = n - k;
- }
- switch (k) {
- case 0:
- return 1;
- case 1:
- return n;
- default:
- if (n < factorials.length) {
- return factorials[n] / (factorials[k] * factorials[n - k]);
- } else if (k >= biggestBinomials.length || n > biggestBinomials[k]) {
- return Long.MAX_VALUE;
- } else if (k < biggestSimpleBinomials.length && n <= biggestSimpleBinomials[k]) {
- // guaranteed not to overflow
- long result = n--;
- for (int i = 2; i <= k; n--, i++) {
- result *= n;
- result /= i;
- }
- return result;
- } else {
- int nBits = LongMath.log2(n, RoundingMode.CEILING);
-
- long result = 1;
- long numerator = n--;
- long denominator = 1;
-
- int numeratorBits = nBits;
- // This is an upper bound on log2(numerator, ceiling).
-
- /*
- * We want to do this in long math for speed, but want to avoid overflow. We adapt the
- * technique previously used by BigIntegerMath: maintain separate numerator and
- * denominator accumulators, multiplying the fraction into result when near overflow.
- */
- for (int i = 2; i <= k; i++, n--) {
- if (numeratorBits + nBits < Long.SIZE - 1) {
- // It's definitely safe to multiply into numerator and denominator.
- numerator *= n;
- denominator *= i;
- numeratorBits += nBits;
- } else {
- // It might not be safe to multiply into numerator and denominator,
- // so multiply (numerator / denominator) into result.
- result = multiplyFraction(result, numerator, denominator);
- numerator = n;
- denominator = i;
- numeratorBits = nBits;
- }
- }
- return multiplyFraction(result, numerator, denominator);
- }
- }
- }
-
- /**
- * Returns (x * numerator / denominator), which is assumed to come out to an integral value.
- */
- static long multiplyFraction(long x, long numerator, long denominator) {
- if (x == 1) {
- return numerator / denominator;
- }
- long commonDivisor = gcd(x, denominator);
- x /= commonDivisor;
- denominator /= commonDivisor;
- // We know gcd(x, denominator) = 1, and x * numerator / denominator is exact,
- // so denominator must be a divisor of numerator.
- return x * (numerator / denominator);
- }
-
- /*
- * binomial(biggestBinomials[k], k) fits in a long, but not
- * binomial(biggestBinomials[k] + 1, k).
- */
- static final int[] biggestBinomials =
- {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 3810779, 121977, 16175, 4337, 1733,
- 887, 534, 361, 265, 206, 169, 143, 125, 111, 101, 94, 88, 83, 79, 76, 74, 72, 70, 69, 68,
- 67, 67, 66, 66, 66, 66};
-
- /*
- * binomial(biggestSimpleBinomials[k], k) doesn't need to use the slower GCD-based impl,
- * but binomial(biggestSimpleBinomials[k] + 1, k) does.
- */
- @VisibleForTesting static final int[] biggestSimpleBinomials =
- {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 2642246, 86251, 11724, 3218, 1313,
- 684, 419, 287, 214, 169, 139, 119, 105, 95, 87, 81, 76, 73, 70, 68, 66, 64, 63, 62, 62,
- 61, 61, 61};
- // These values were generated by using checkedMultiply to see when the simple multiply/divide
- // algorithm would lead to an overflow.
-
- /**
- * Returns the arithmetic mean of {@code x} and {@code y}, rounded toward
- * negative infinity. This method is resilient to overflow.
- *
- * @since 14.0
- */
- public static long mean(long x, long y) {
- // Efficient method for computing the arithmetic mean.
- // The alternative (x + y) / 2 fails for large values.
- // The alternative (x + y) >>> 1 fails for negative values.
- return (x & y) + ((x ^ y) >> 1);
- }
-
- private LongMath() {}
-}
-
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Chars.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Chars.java
index 62c716a..5f78865 100644
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Chars.java
+++ b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Chars.java
@@ -38,10 +38,6 @@ import java.util.RandomAccess;
* <p>All the operations in this class treat {@code char} values strictly
* numerically; they are neither Unicode-aware nor locale-dependent.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
@@ -472,8 +468,7 @@ public final class Chars {
@Override public Character set(int index, Character element) {
checkElementIndex(index, size());
char oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -524,7 +519,7 @@ public final class Chars {
}
char[] toCharArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
char[] result = new char[size];
System.arraycopy(array, start, result, 0, size);
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Floats.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Floats.java
deleted file mode 100644
index 8e4eaf7..0000000
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Floats.java
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.primitives;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkElementIndex;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkPositionIndexes;
-import static java.lang.Float.NEGATIVE_INFINITY;
-import static java.lang.Float.POSITIVE_INFINITY;
-
-import com.google.common.annotations.GwtCompatible;
-
-import java.io.Serializable;
-import java.util.AbstractList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.RandomAccess;
-
-/**
- * Static utility methods pertaining to {@code float} primitives, that are not
- * already found in either {@link Float} or {@link Arrays}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
- * @author Kevin Bourrillion
- * @since 1.0
- */
-@GwtCompatible(emulated = true)
-public final class Floats {
- private Floats() {}
-
- /**
- * The number of bytes required to represent a primitive {@code float}
- * value.
- *
- * @since 10.0
- */
- public static final int BYTES = Float.SIZE / Byte.SIZE;
-
- /**
- * Returns a hash code for {@code value}; equal to the result of invoking
- * {@code ((Float) value).hashCode()}.
- *
- * @param value a primitive {@code float} value
- * @return a hash code for the value
- */
- public static int hashCode(float value) {
- // TODO(kevinb): is there a better way, that's still gwt-safe?
- return ((Float) value).hashCode();
- }
-
- /**
- * Compares the two specified {@code float} values using {@link
- * Float#compare(float, float)}. You may prefer to invoke that method
- * directly; this method exists only for consistency with the other utilities
- * in this package.
- *
- * @param a the first {@code float} to compare
- * @param b the second {@code float} to compare
- * @return the result of invoking {@link Float#compare(float, float)}
- */
- public static int compare(float a, float b) {
- return Float.compare(a, b);
- }
-
- /**
- * Returns {@code true} if {@code value} represents a real number. This is
- * equivalent to, but not necessarily implemented as,
- * {@code !(Float.isInfinite(value) || Float.isNaN(value))}.
- *
- * @since 10.0
- */
- public static boolean isFinite(float value) {
- return NEGATIVE_INFINITY < value & value < POSITIVE_INFINITY;
- }
-
- /**
- * Returns {@code true} if {@code target} is present as an element anywhere in
- * {@code array}. Note that this always returns {@code false} when {@code
- * target} is {@code NaN}.
- *
- * @param array an array of {@code float} values, possibly empty
- * @param target a primitive {@code float} value
- * @return {@code true} if {@code array[i] == target} for some value of {@code
- * i}
- */
- public static boolean contains(float[] array, float target) {
- for (float value : array) {
- if (value == target) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns the index of the first appearance of the value {@code target} in
- * {@code array}. Note that this always returns {@code -1} when {@code target}
- * is {@code NaN}.
- *
- * @param array an array of {@code float} values, possibly empty
- * @param target a primitive {@code float} value
- * @return the least index {@code i} for which {@code array[i] == target}, or
- * {@code -1} if no such index exists.
- */
- public static int indexOf(float[] array, float target) {
- return indexOf(array, target, 0, array.length);
- }
-
- // TODO(kevinb): consider making this public
- private static int indexOf(
- float[] array, float target, int start, int end) {
- for (int i = start; i < end; i++) {
- if (array[i] == target) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Returns the start position of the first occurrence of the specified {@code
- * target} within {@code array}, or {@code -1} if there is no such occurrence.
- *
- * <p>More formally, returns the lowest index {@code i} such that {@code
- * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
- * the same elements as {@code target}.
- *
- * <p>Note that this always returns {@code -1} when {@code target} contains
- * {@code NaN}.
- *
- * @param array the array to search for the sequence {@code target}
- * @param target the array to search for as a sub-sequence of {@code array}
- */
- public static int indexOf(float[] array, float[] target) {
- checkNotNull(array, "array");
- checkNotNull(target, "target");
- if (target.length == 0) {
- return 0;
- }
-
- outer:
- for (int i = 0; i < array.length - target.length + 1; i++) {
- for (int j = 0; j < target.length; j++) {
- if (array[i + j] != target[j]) {
- continue outer;
- }
- }
- return i;
- }
- return -1;
- }
-
- /**
- * Returns the index of the last appearance of the value {@code target} in
- * {@code array}. Note that this always returns {@code -1} when {@code target}
- * is {@code NaN}.
- *
- * @param array an array of {@code float} values, possibly empty
- * @param target a primitive {@code float} value
- * @return the greatest index {@code i} for which {@code array[i] == target},
- * or {@code -1} if no such index exists.
- */
- public static int lastIndexOf(float[] array, float target) {
- return lastIndexOf(array, target, 0, array.length);
- }
-
- // TODO(kevinb): consider making this public
- private static int lastIndexOf(
- float[] array, float target, int start, int end) {
- for (int i = end - 1; i >= start; i--) {
- if (array[i] == target) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Returns the least value present in {@code array}, using the same rules of
- * comparison as {@link Math#min(float, float)}.
- *
- * @param array a <i>nonempty</i> array of {@code float} values
- * @return the value present in {@code array} that is less than or equal to
- * every other value in the array
- * @throws IllegalArgumentException if {@code array} is empty
- */
- public static float min(float... array) {
- checkArgument(array.length > 0);
- float min = array[0];
- for (int i = 1; i < array.length; i++) {
- min = Math.min(min, array[i]);
- }
- return min;
- }
-
- /**
- * Returns the greatest value present in {@code array}, using the same rules
- * of comparison as {@link Math#min(float, float)}.
- *
- * @param array a <i>nonempty</i> array of {@code float} values
- * @return the value present in {@code array} that is greater than or equal to
- * every other value in the array
- * @throws IllegalArgumentException if {@code array} is empty
- */
- public static float max(float... array) {
- checkArgument(array.length > 0);
- float max = array[0];
- for (int i = 1; i < array.length; i++) {
- max = Math.max(max, array[i]);
- }
- return max;
- }
-
- /**
- * Returns the values from each provided array combined into a single array.
- * For example, {@code concat(new float[] {a, b}, new float[] {}, new
- * float[] {c}} returns the array {@code {a, b, c}}.
- *
- * @param arrays zero or more {@code float} arrays
- * @return a single array containing all the values from the source arrays, in
- * order
- */
- public static float[] concat(float[]... arrays) {
- int length = 0;
- for (float[] array : arrays) {
- length += array.length;
- }
- float[] result = new float[length];
- int pos = 0;
- for (float[] array : arrays) {
- System.arraycopy(array, 0, result, pos, array.length);
- pos += array.length;
- }
- return result;
- }
-
- /**
- * Returns an array containing the same values as {@code array}, but
- * guaranteed to be of a specified minimum length. If {@code array} already
- * has a length of at least {@code minLength}, it is returned directly.
- * Otherwise, a new array of size {@code minLength + padding} is returned,
- * containing the values of {@code array}, and zeroes in the remaining places.
- *
- * @param array the source array
- * @param minLength the minimum length the returned array must guarantee
- * @param padding an extra amount to "grow" the array by if growth is
- * necessary
- * @throws IllegalArgumentException if {@code minLength} or {@code padding} is
- * negative
- * @return an array containing the values of {@code array}, with guaranteed
- * minimum length {@code minLength}
- */
- public static float[] ensureCapacity(
- float[] array, int minLength, int padding) {
- checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
- checkArgument(padding >= 0, "Invalid padding: %s", padding);
- return (array.length < minLength)
- ? copyOf(array, minLength + padding)
- : array;
- }
-
- // Arrays.copyOf() requires Java 6
- private static float[] copyOf(float[] original, int length) {
- float[] copy = new float[length];
- System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
- return copy;
- }
-
- /**
- * Returns a string containing the supplied {@code float} values, converted
- * to strings as specified by {@link Float#toString(float)}, and separated by
- * {@code separator}. For example, {@code join("-", 1.0f, 2.0f, 3.0f)}
- * returns the string {@code "1.0-2.0-3.0"}.
- *
- * <p>Note that {@link Float#toString(float)} formats {@code float}
- * differently in GWT. In the previous example, it returns the string {@code
- * "1-2-3"}.
- *
- * @param separator the text that should appear between consecutive values in
- * the resulting string (but not at the start or end)
- * @param array an array of {@code float} values, possibly empty
- */
- public static String join(String separator, float... array) {
- checkNotNull(separator);
- if (array.length == 0) {
- return "";
- }
-
- // For pre-sizing a builder, just get the right order of magnitude
- StringBuilder builder = new StringBuilder(array.length * 12);
- builder.append(array[0]);
- for (int i = 1; i < array.length; i++) {
- builder.append(separator).append(array[i]);
- }
- return builder.toString();
- }
-
- /**
- * Returns a comparator that compares two {@code float} arrays
- * lexicographically. That is, it compares, using {@link
- * #compare(float, float)}), the first pair of values that follow any
- * common prefix, or when one array is a prefix of the other, treats the
- * shorter array as the lesser. For example, {@code [] < [1.0f] < [1.0f, 2.0f]
- * < [2.0f]}.
- *
- * <p>The returned comparator is inconsistent with {@link
- * Object#equals(Object)} (since arrays support only identity equality), but
- * it is consistent with {@link Arrays#equals(float[], float[])}.
- *
- * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
- * Lexicographical order article at Wikipedia</a>
- * @since 2.0
- */
- public static Comparator<float[]> lexicographicalComparator() {
- return LexicographicalComparator.INSTANCE;
- }
-
- private enum LexicographicalComparator implements Comparator<float[]> {
- INSTANCE;
-
- @Override
- public int compare(float[] left, float[] right) {
- int minLength = Math.min(left.length, right.length);
- for (int i = 0; i < minLength; i++) {
- int result = Floats.compare(left[i], right[i]);
- if (result != 0) {
- return result;
- }
- }
- return left.length - right.length;
- }
- }
-
- /**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code float} value in the manner of {@link Number#floatValue}.
- *
- * <p>Elements are copied from the argument collection as if by {@code
- * collection.toArray()}. Calling this method is as thread-safe as calling
- * that method.
- *
- * @param collection a collection of {@code Number} instances
- * @return an array containing the same values as {@code collection}, in the
- * same order, converted to primitives
- * @throws NullPointerException if {@code collection} or any of its elements
- * is null
- * @since 1.0 (parameter was {@code Collection<Float>} before 12.0)
- */
- public static float[] toArray(Collection<? extends Number> collection) {
- if (collection instanceof FloatArrayAsList) {
- return ((FloatArrayAsList) collection).toFloatArray();
- }
-
- Object[] boxedArray = collection.toArray();
- int len = boxedArray.length;
- float[] array = new float[len];
- for (int i = 0; i < len; i++) {
- // checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).floatValue();
- }
- return array;
- }
-
- /**
- * Returns a fixed-size list backed by the specified array, similar to {@link
- * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)},
- * but any attempt to set a value to {@code null} will result in a {@link
- * NullPointerException}.
- *
- * <p>The returned list maintains the values, but not the identities, of
- * {@code Float} objects written to or read from it. For example, whether
- * {@code list.get(0) == list.get(0)} is true for the returned list is
- * unspecified.
- *
- * <p>The returned list may have unexpected behavior if it contains {@code
- * NaN}, or if {@code NaN} is used as a parameter to any of its methods.
- *
- * @param backingArray the array to back the list
- * @return a list view of the array
- */
- public static List<Float> asList(float... backingArray) {
- if (backingArray.length == 0) {
- return Collections.emptyList();
- }
- return new FloatArrayAsList(backingArray);
- }
-
- @GwtCompatible
- private static class FloatArrayAsList extends AbstractList<Float>
- implements RandomAccess, Serializable {
- final float[] array;
- final int start;
- final int end;
-
- FloatArrayAsList(float[] array) {
- this(array, 0, array.length);
- }
-
- FloatArrayAsList(float[] array, int start, int end) {
- this.array = array;
- this.start = start;
- this.end = end;
- }
-
- @Override public int size() {
- return end - start;
- }
-
- @Override public boolean isEmpty() {
- return false;
- }
-
- @Override public Float get(int index) {
- checkElementIndex(index, size());
- return array[start + index];
- }
-
- @Override public boolean contains(Object target) {
- // Overridden to prevent a ton of boxing
- return (target instanceof Float)
- && Floats.indexOf(array, (Float) target, start, end) != -1;
- }
-
- @Override public int indexOf(Object target) {
- // Overridden to prevent a ton of boxing
- if (target instanceof Float) {
- int i = Floats.indexOf(array, (Float) target, start, end);
- if (i >= 0) {
- return i - start;
- }
- }
- return -1;
- }
-
- @Override public int lastIndexOf(Object target) {
- // Overridden to prevent a ton of boxing
- if (target instanceof Float) {
- int i = Floats.lastIndexOf(array, (Float) target, start, end);
- if (i >= 0) {
- return i - start;
- }
- }
- return -1;
- }
-
- @Override public Float set(int index, Float element) {
- checkElementIndex(index, size());
- float oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
- return oldValue;
- }
-
- @Override public List<Float> subList(int fromIndex, int toIndex) {
- int size = size();
- checkPositionIndexes(fromIndex, toIndex, size);
- if (fromIndex == toIndex) {
- return Collections.emptyList();
- }
- return new FloatArrayAsList(array, start + fromIndex, start + toIndex);
- }
-
- @Override public boolean equals(Object object) {
- if (object == this) {
- return true;
- }
- if (object instanceof FloatArrayAsList) {
- FloatArrayAsList that = (FloatArrayAsList) object;
- int size = size();
- if (that.size() != size) {
- return false;
- }
- for (int i = 0; i < size; i++) {
- if (array[start + i] != that.array[that.start + i]) {
- return false;
- }
- }
- return true;
- }
- return super.equals(object);
- }
-
- @Override public int hashCode() {
- int result = 1;
- for (int i = start; i < end; i++) {
- result = 31 * result + Floats.hashCode(array[i]);
- }
- return result;
- }
-
- @Override public String toString() {
- StringBuilder builder = new StringBuilder(size() * 12);
- builder.append('[').append(array[start]);
- for (int i = start + 1; i < end; i++) {
- builder.append(", ").append(array[i]);
- }
- return builder.append(']').toString();
- }
-
- float[] toFloatArray() {
- // Arrays.copyOfRange() is not available under GWT
- int size = size();
- float[] result = new float[size];
- System.arraycopy(array, start, result, 0, size);
- return result;
- }
-
- private static final long serialVersionUID = 0;
- }
-}
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Ints.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Ints.java
index 8f9315d..0cee6c4 100644
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Ints.java
+++ b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Ints.java
@@ -35,10 +35,6 @@ import java.util.RandomAccess;
* Static utility methods pertaining to {@code int} primitives, that are not
* already found in either {@link Integer} or {@link Arrays}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
@@ -364,21 +360,20 @@ public final class Ints {
}
/**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code int} value in the manner of {@link Number#intValue}.
+ * Copies a collection of {@code Integer} instances into a new array of
+ * primitive {@code int} values.
*
* <p>Elements are copied from the argument collection as if by {@code
* collection.toArray()}. Calling this method is as thread-safe as calling
* that method.
*
- * @param collection a collection of {@code Number} instances
+ * @param collection a collection of {@code Integer} objects
* @return an array containing the same values as {@code collection}, in the
* same order, converted to primitives
* @throws NullPointerException if {@code collection} or any of its elements
* is null
- * @since 1.0 (parameter was {@code Collection<Integer>} before 12.0)
*/
- public static int[] toArray(Collection<? extends Number> collection) {
+ public static int[] toArray(Collection<Integer> collection) {
if (collection instanceof IntArrayAsList) {
return ((IntArrayAsList) collection).toIntArray();
}
@@ -388,7 +383,7 @@ public final class Ints {
int[] array = new int[len];
for (int i = 0; i < len; i++) {
// checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).intValue();
+ array[i] = (Integer) checkNotNull(boxedArray[i]);
}
return array;
}
@@ -475,8 +470,7 @@ public final class Ints {
@Override public Integer set(int index, Integer element) {
checkElementIndex(index, size());
int oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -527,7 +521,7 @@ public final class Ints {
}
int[] toIntArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
int[] result = new int[size];
System.arraycopy(array, start, result, 0, size);
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Doubles.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Longs.java
index 3634fe7..000e055 100644
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Doubles.java
+++ b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Longs.java
@@ -20,8 +20,6 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkPositionIndexes;
-import static java.lang.Double.NEGATIVE_INFINITY;
-import static java.lang.Double.POSITIVE_INFINITY;
import com.google.common.annotations.GwtCompatible;
@@ -34,80 +32,69 @@ import java.util.List;
import java.util.RandomAccess;
/**
- * Static utility methods pertaining to {@code double} primitives, that are not
- * already found in either {@link Double} or {@link Arrays}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
+ * Static utility methods pertaining to {@code long} primitives, that are not
+ * already found in either {@link Long} or {@link Arrays}.
*
* @author Kevin Bourrillion
* @since 1.0
*/
@GwtCompatible(emulated = true)
-public final class Doubles {
- private Doubles() {}
+public final class Longs {
+ private Longs() {}
/**
- * The number of bytes required to represent a primitive {@code double}
+ * The number of bytes required to represent a primitive {@code long}
* value.
+ */
+ public static final int BYTES = Long.SIZE / Byte.SIZE;
+
+ /**
+ * The largest power of two that can be represented as a {@code long}.
*
* @since 10.0
*/
- public static final int BYTES = Double.SIZE / Byte.SIZE;
+ public static final long MAX_POWER_OF_TWO = 1L << (Long.SIZE - 2);
/**
* Returns a hash code for {@code value}; equal to the result of invoking
- * {@code ((Double) value).hashCode()}.
+ * {@code ((Long) value).hashCode()}.
+ *
+ * <p>This method always return the value specified by {@link
+ * Long#hashCode()} in java, which might be different from
+ * {@code ((Long) value).hashCode()} in GWT because {@link Long#hashCode()}
+ * in GWT does not obey the JRE contract.
*
- * @param value a primitive {@code double} value
+ * @param value a primitive {@code long} value
* @return a hash code for the value
*/
- public static int hashCode(double value) {
- return ((Double) value).hashCode();
- // TODO(kevinb): do it this way when we can (GWT problem):
- // long bits = Double.doubleToLongBits(value);
- // return (int)(bits ^ (bits >>> 32));
+ public static int hashCode(long value) {
+ return (int) (value ^ (value >>> 32));
}
/**
- * Compares the two specified {@code double} values. The sign of the value
- * returned is the same as that of <code>((Double) a).{@linkplain
- * Double#compareTo compareTo}(b)</code>. As with that method, {@code NaN} is
- * treated as greater than all other values, and {@code 0.0 > -0.0}.
+ * Compares the two specified {@code long} values. The sign of the value
+ * returned is the same as that of {@code ((Long) a).compareTo(b)}.
*
- * @param a the first {@code double} to compare
- * @param b the second {@code double} to compare
+ * @param a the first {@code long} to compare
+ * @param b the second {@code long} to compare
* @return a negative value if {@code a} is less than {@code b}; a positive
* value if {@code a} is greater than {@code b}; or zero if they are equal
*/
- public static int compare(double a, double b) {
- return Double.compare(a, b);
- }
-
- /**
- * Returns {@code true} if {@code value} represents a real number. This is
- * equivalent to, but not necessarily implemented as,
- * {@code !(Double.isInfinite(value) || Double.isNaN(value))}.
- *
- * @since 10.0
- */
- public static boolean isFinite(double value) {
- return NEGATIVE_INFINITY < value & value < POSITIVE_INFINITY;
+ public static int compare(long a, long b) {
+ return (a < b) ? -1 : ((a > b) ? 1 : 0);
}
/**
* Returns {@code true} if {@code target} is present as an element anywhere in
- * {@code array}. Note that this always returns {@code false} when {@code
- * target} is {@code NaN}.
+ * {@code array}.
*
- * @param array an array of {@code double} values, possibly empty
- * @param target a primitive {@code double} value
+ * @param array an array of {@code long} values, possibly empty
+ * @param target a primitive {@code long} value
* @return {@code true} if {@code array[i] == target} for some value of {@code
* i}
*/
- public static boolean contains(double[] array, double target) {
- for (double value : array) {
+ public static boolean contains(long[] array, long target) {
+ for (long value : array) {
if (value == target) {
return true;
}
@@ -117,21 +104,20 @@ public final class Doubles {
/**
* Returns the index of the first appearance of the value {@code target} in
- * {@code array}. Note that this always returns {@code -1} when {@code target}
- * is {@code NaN}.
+ * {@code array}.
*
- * @param array an array of {@code double} values, possibly empty
- * @param target a primitive {@code double} value
+ * @param array an array of {@code long} values, possibly empty
+ * @param target a primitive {@code long} value
* @return the least index {@code i} for which {@code array[i] == target}, or
* {@code -1} if no such index exists.
*/
- public static int indexOf(double[] array, double target) {
+ public static int indexOf(long[] array, long target) {
return indexOf(array, target, 0, array.length);
}
// TODO(kevinb): consider making this public
private static int indexOf(
- double[] array, double target, int start, int end) {
+ long[] array, long target, int start, int end) {
for (int i = start; i < end; i++) {
if (array[i] == target) {
return i;
@@ -148,13 +134,10 @@ public final class Doubles {
* java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
* the same elements as {@code target}.
*
- * <p>Note that this always returns {@code -1} when {@code target} contains
- * {@code NaN}.
- *
* @param array the array to search for the sequence {@code target}
* @param target the array to search for as a sub-sequence of {@code array}
*/
- public static int indexOf(double[] array, double[] target) {
+ public static int indexOf(long[] array, long[] target) {
checkNotNull(array, "array");
checkNotNull(target, "target");
if (target.length == 0) {
@@ -175,21 +158,20 @@ public final class Doubles {
/**
* Returns the index of the last appearance of the value {@code target} in
- * {@code array}. Note that this always returns {@code -1} when {@code target}
- * is {@code NaN}.
+ * {@code array}.
*
- * @param array an array of {@code double} values, possibly empty
- * @param target a primitive {@code double} value
+ * @param array an array of {@code long} values, possibly empty
+ * @param target a primitive {@code long} value
* @return the greatest index {@code i} for which {@code array[i] == target},
* or {@code -1} if no such index exists.
*/
- public static int lastIndexOf(double[] array, double target) {
+ public static int lastIndexOf(long[] array, long target) {
return lastIndexOf(array, target, 0, array.length);
}
// TODO(kevinb): consider making this public
private static int lastIndexOf(
- double[] array, double target, int start, int end) {
+ long[] array, long target, int start, int end) {
for (int i = end - 1; i >= start; i--) {
if (array[i] == target) {
return i;
@@ -199,58 +181,60 @@ public final class Doubles {
}
/**
- * Returns the least value present in {@code array}, using the same rules of
- * comparison as {@link Math#min(double, double)}.
+ * Returns the least value present in {@code array}.
*
- * @param array a <i>nonempty</i> array of {@code double} values
+ * @param array a <i>nonempty</i> array of {@code long} values
* @return the value present in {@code array} that is less than or equal to
* every other value in the array
* @throws IllegalArgumentException if {@code array} is empty
*/
- public static double min(double... array) {
+ public static long min(long... array) {
checkArgument(array.length > 0);
- double min = array[0];
+ long min = array[0];
for (int i = 1; i < array.length; i++) {
- min = Math.min(min, array[i]);
+ if (array[i] < min) {
+ min = array[i];
+ }
}
return min;
}
/**
- * Returns the greatest value present in {@code array}, using the same rules
- * of comparison as {@link Math#max(double, double)}.
+ * Returns the greatest value present in {@code array}.
*
- * @param array a <i>nonempty</i> array of {@code double} values
+ * @param array a <i>nonempty</i> array of {@code long} values
* @return the value present in {@code array} that is greater than or equal to
* every other value in the array
* @throws IllegalArgumentException if {@code array} is empty
*/
- public static double max(double... array) {
+ public static long max(long... array) {
checkArgument(array.length > 0);
- double max = array[0];
+ long max = array[0];
for (int i = 1; i < array.length; i++) {
- max = Math.max(max, array[i]);
+ if (array[i] > max) {
+ max = array[i];
+ }
}
return max;
}
/**
* Returns the values from each provided array combined into a single array.
- * For example, {@code concat(new double[] {a, b}, new double[] {}, new
- * double[] {c}} returns the array {@code {a, b, c}}.
+ * For example, {@code concat(new long[] {a, b}, new long[] {}, new
+ * long[] {c}} returns the array {@code {a, b, c}}.
*
- * @param arrays zero or more {@code double} arrays
+ * @param arrays zero or more {@code long} arrays
* @return a single array containing all the values from the source arrays, in
* order
*/
- public static double[] concat(double[]... arrays) {
+ public static long[] concat(long[]... arrays) {
int length = 0;
- for (double[] array : arrays) {
+ for (long[] array : arrays) {
length += array.length;
}
- double[] result = new double[length];
+ long[] result = new long[length];
int pos = 0;
- for (double[] array : arrays) {
+ for (long[] array : arrays) {
System.arraycopy(array, 0, result, pos, array.length);
pos += array.length;
}
@@ -273,8 +257,8 @@ public final class Doubles {
* @return an array containing the values of {@code array}, with guaranteed
* minimum length {@code minLength}
*/
- public static double[] ensureCapacity(
- double[] array, int minLength, int padding) {
+ public static long[] ensureCapacity(
+ long[] array, int minLength, int padding) {
checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
checkArgument(padding >= 0, "Invalid padding: %s", padding);
return (array.length < minLength)
@@ -283,34 +267,29 @@ public final class Doubles {
}
// Arrays.copyOf() requires Java 6
- private static double[] copyOf(double[] original, int length) {
- double[] copy = new double[length];
+ private static long[] copyOf(long[] original, int length) {
+ long[] copy = new long[length];
System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
return copy;
}
/**
- * Returns a string containing the supplied {@code double} values, converted
- * to strings as specified by {@link Double#toString(double)}, and separated
- * by {@code separator}. For example, {@code join("-", 1.0, 2.0, 3.0)} returns
- * the string {@code "1.0-2.0-3.0"}.
- *
- * <p>Note that {@link Double#toString(double)} formats {@code double}
- * differently in GWT sometimes. In the previous example, it returns the
- * string {@code "1-2-3"}.
+ * Returns a string containing the supplied {@code long} values separated
+ * by {@code separator}. For example, {@code join("-", 1L, 2L, 3L)} returns
+ * the string {@code "1-2-3"}.
*
* @param separator the text that should appear between consecutive values in
* the resulting string (but not at the start or end)
- * @param array an array of {@code double} values, possibly empty
+ * @param array an array of {@code long} values, possibly empty
*/
- public static String join(String separator, double... array) {
+ public static String join(String separator, long... array) {
checkNotNull(separator);
if (array.length == 0) {
return "";
}
// For pre-sizing a builder, just get the right order of magnitude
- StringBuilder builder = new StringBuilder(array.length * 12);
+ StringBuilder builder = new StringBuilder(array.length * 10);
builder.append(array[0]);
for (int i = 1; i < array.length; i++) {
builder.append(separator).append(array[i]);
@@ -319,33 +298,33 @@ public final class Doubles {
}
/**
- * Returns a comparator that compares two {@code double} arrays
+ * Returns a comparator that compares two {@code long} arrays
* lexicographically. That is, it compares, using {@link
- * #compare(double, double)}), the first pair of values that follow any
+ * #compare(long, long)}), the first pair of values that follow any
* common prefix, or when one array is a prefix of the other, treats the
* shorter array as the lesser. For example,
- * {@code [] < [1.0] < [1.0, 2.0] < [2.0]}.
+ * {@code [] < [1L] < [1L, 2L] < [2L]}.
*
* <p>The returned comparator is inconsistent with {@link
* Object#equals(Object)} (since arrays support only identity equality), but
- * it is consistent with {@link Arrays#equals(double[], double[])}.
+ * it is consistent with {@link Arrays#equals(long[], long[])}.
*
* @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
* Lexicographical order article at Wikipedia</a>
* @since 2.0
*/
- public static Comparator<double[]> lexicographicalComparator() {
+ public static Comparator<long[]> lexicographicalComparator() {
return LexicographicalComparator.INSTANCE;
}
- private enum LexicographicalComparator implements Comparator<double[]> {
+ private enum LexicographicalComparator implements Comparator<long[]> {
INSTANCE;
@Override
- public int compare(double[] left, double[] right) {
+ public int compare(long[] left, long[] right) {
int minLength = Math.min(left.length, right.length);
for (int i = 0; i < minLength; i++) {
- int result = Doubles.compare(left[i], right[i]);
+ int result = Longs.compare(left[i], right[i]);
if (result != 0) {
return result;
}
@@ -355,31 +334,30 @@ public final class Doubles {
}
/**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code double} value in the manner of {@link Number#doubleValue}.
+ * Copies a collection of {@code Long} instances into a new array of
+ * primitive {@code long} values.
*
* <p>Elements are copied from the argument collection as if by {@code
* collection.toArray()}. Calling this method is as thread-safe as calling
* that method.
*
- * @param collection a collection of {@code Number} instances
+ * @param collection a collection of {@code Long} objects
* @return an array containing the same values as {@code collection}, in the
* same order, converted to primitives
* @throws NullPointerException if {@code collection} or any of its elements
* is null
- * @since 1.0 (parameter was {@code Collection<Double>} before 12.0)
*/
- public static double[] toArray(Collection<? extends Number> collection) {
- if (collection instanceof DoubleArrayAsList) {
- return ((DoubleArrayAsList) collection).toDoubleArray();
+ public static long[] toArray(Collection<Long> collection) {
+ if (collection instanceof LongArrayAsList) {
+ return ((LongArrayAsList) collection).toLongArray();
}
Object[] boxedArray = collection.toArray();
int len = boxedArray.length;
- double[] array = new double[len];
+ long[] array = new long[len];
for (int i = 0; i < len; i++) {
// checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).doubleValue();
+ array[i] = (Long) checkNotNull(boxedArray[i]);
}
return array;
}
@@ -391,35 +369,32 @@ public final class Doubles {
* NullPointerException}.
*
* <p>The returned list maintains the values, but not the identities, of
- * {@code Double} objects written to or read from it. For example, whether
+ * {@code Long} objects written to or read from it. For example, whether
* {@code list.get(0) == list.get(0)} is true for the returned list is
* unspecified.
*
- * <p>The returned list may have unexpected behavior if it contains {@code
- * NaN}, or if {@code NaN} is used as a parameter to any of its methods.
- *
* @param backingArray the array to back the list
* @return a list view of the array
*/
- public static List<Double> asList(double... backingArray) {
+ public static List<Long> asList(long... backingArray) {
if (backingArray.length == 0) {
return Collections.emptyList();
}
- return new DoubleArrayAsList(backingArray);
+ return new LongArrayAsList(backingArray);
}
@GwtCompatible
- private static class DoubleArrayAsList extends AbstractList<Double>
+ private static class LongArrayAsList extends AbstractList<Long>
implements RandomAccess, Serializable {
- final double[] array;
+ final long[] array;
final int start;
final int end;
- DoubleArrayAsList(double[] array) {
+ LongArrayAsList(long[] array) {
this(array, 0, array.length);
}
- DoubleArrayAsList(double[] array, int start, int end) {
+ LongArrayAsList(long[] array, int start, int end) {
this.array = array;
this.start = start;
this.end = end;
@@ -433,21 +408,21 @@ public final class Doubles {
return false;
}
- @Override public Double get(int index) {
+ @Override public Long get(int index) {
checkElementIndex(index, size());
return array[start + index];
}
@Override public boolean contains(Object target) {
// Overridden to prevent a ton of boxing
- return (target instanceof Double)
- && Doubles.indexOf(array, (Double) target, start, end) != -1;
+ return (target instanceof Long)
+ && Longs.indexOf(array, (Long) target, start, end) != -1;
}
@Override public int indexOf(Object target) {
// Overridden to prevent a ton of boxing
- if (target instanceof Double) {
- int i = Doubles.indexOf(array, (Double) target, start, end);
+ if (target instanceof Long) {
+ int i = Longs.indexOf(array, (Long) target, start, end);
if (i >= 0) {
return i - start;
}
@@ -457,8 +432,8 @@ public final class Doubles {
@Override public int lastIndexOf(Object target) {
// Overridden to prevent a ton of boxing
- if (target instanceof Double) {
- int i = Doubles.lastIndexOf(array, (Double) target, start, end);
+ if (target instanceof Long) {
+ int i = Longs.lastIndexOf(array, (Long) target, start, end);
if (i >= 0) {
return i - start;
}
@@ -466,29 +441,28 @@ public final class Doubles {
return -1;
}
- @Override public Double set(int index, Double element) {
+ @Override public Long set(int index, Long element) {
checkElementIndex(index, size());
- double oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ long oldValue = array[start + index];
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
- @Override public List<Double> subList(int fromIndex, int toIndex) {
+ @Override public List<Long> subList(int fromIndex, int toIndex) {
int size = size();
checkPositionIndexes(fromIndex, toIndex, size);
if (fromIndex == toIndex) {
return Collections.emptyList();
}
- return new DoubleArrayAsList(array, start + fromIndex, start + toIndex);
+ return new LongArrayAsList(array, start + fromIndex, start + toIndex);
}
@Override public boolean equals(Object object) {
if (object == this) {
return true;
}
- if (object instanceof DoubleArrayAsList) {
- DoubleArrayAsList that = (DoubleArrayAsList) object;
+ if (object instanceof LongArrayAsList) {
+ LongArrayAsList that = (LongArrayAsList) object;
int size = size();
if (that.size() != size) {
return false;
@@ -506,13 +480,13 @@ public final class Doubles {
@Override public int hashCode() {
int result = 1;
for (int i = start; i < end; i++) {
- result = 31 * result + Doubles.hashCode(array[i]);
+ result = 31 * result + Longs.hashCode(array[i]);
}
return result;
}
@Override public String toString() {
- StringBuilder builder = new StringBuilder(size() * 12);
+ StringBuilder builder = new StringBuilder(size() * 10);
builder.append('[').append(array[start]);
for (int i = start + 1; i < end; i++) {
builder.append(", ").append(array[i]);
@@ -520,10 +494,10 @@ public final class Doubles {
return builder.append(']').toString();
}
- double[] toDoubleArray() {
- // Arrays.copyOfRange() is not available under GWT
+ long[] toLongArray() {
+ // Arrays.copyOfRange() requires Java 6
int size = size();
- double[] result = new double[size];
+ long[] result = new long[size];
System.arraycopy(array, start, result, 0, size);
return result;
}
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Shorts.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Shorts.java
index 92899c7..d1cee13 100644
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Shorts.java
+++ b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/Shorts.java
@@ -35,10 +35,6 @@ import java.util.RandomAccess;
* Static utility methods pertaining to {@code short} primitives, that are not
* already found in either {@link Short} or {@link Arrays}.
*
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
- * primitive utilities</a>.
- *
* @author Kevin Bourrillion
* @since 1.0
*/
@@ -366,21 +362,20 @@ public final class Shorts {
}
/**
- * Returns an array containing each value of {@code collection}, converted to
- * a {@code short} value in the manner of {@link Number#shortValue}.
+ * Copies a collection of {@code Short} instances into a new array of
+ * primitive {@code short} values.
*
* <p>Elements are copied from the argument collection as if by {@code
* collection.toArray()}. Calling this method is as thread-safe as calling
* that method.
*
- * @param collection a collection of {@code Number} instances
+ * @param collection a collection of {@code Short} objects
* @return an array containing the same values as {@code collection}, in the
* same order, converted to primitives
* @throws NullPointerException if {@code collection} or any of its elements
* is null
- * @since 1.0 (parameter was {@code Collection<Short>} before 12.0)
*/
- public static short[] toArray(Collection<? extends Number> collection) {
+ public static short[] toArray(Collection<Short> collection) {
if (collection instanceof ShortArrayAsList) {
return ((ShortArrayAsList) collection).toShortArray();
}
@@ -390,7 +385,7 @@ public final class Shorts {
short[] array = new short[len];
for (int i = 0; i < len; i++) {
// checkNotNull for GWT (do not optimize)
- array[i] = ((Number) checkNotNull(boxedArray[i])).shortValue();
+ array[i] = (Short) checkNotNull(boxedArray[i]);
}
return array;
}
@@ -477,8 +472,7 @@ public final class Shorts {
@Override public Short set(int index, Short element) {
checkElementIndex(index, size());
short oldValue = array[start + index];
- // checkNotNull for GWT (do not optimize)
- array[start + index] = checkNotNull(element);
+ array[start + index] = checkNotNull(element); // checkNotNull for GWT (do not optimize)
return oldValue;
}
@@ -529,7 +523,7 @@ public final class Shorts {
}
short[] toShortArray() {
- // Arrays.copyOfRange() is not available under GWT
+ // Arrays.copyOfRange() requires Java 6
int size = size();
short[] result = new short[size];
System.arraycopy(array, start, result, 0, size);
diff --git a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/UnsignedInteger.java b/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/UnsignedInteger.java
deleted file mode 100644
index 20e6dce..0000000
--- a/guava-gwt/src-super/com/google/common/primitives/super/com/google/common/primitives/UnsignedInteger.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (C) 2011 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.common.primitives;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.primitives.UnsignedInts.INT_MASK;
-import static com.google.common.primitives.UnsignedInts.compare;
-import static com.google.common.primitives.UnsignedInts.toLong;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.GwtCompatible;
-
-import java.math.BigInteger;
-
-import javax.annotation.CheckReturnValue;
-import javax.annotation.Nullable;
-
-/**
- * A wrapper class for unsigned {@code int} values, supporting arithmetic operations.
- *
- * <p>In some cases, when speed is more important than code readability, it may be faster simply to
- * treat primitive {@code int} values as unsigned, using the methods from {@link UnsignedInts}.
- *
- * <p>See the Guava User Guide article on <a href=
- * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained#Unsigned_support">
- * unsigned primitive utilities</a>.
- *
- * @author Louis Wasserman
- * @since 11.0
- */
-@GwtCompatible(emulated = true)
-public final class UnsignedInteger extends Number implements Comparable<UnsignedInteger> {
- public static final UnsignedInteger ZERO = asUnsigned(0);
- public static final UnsignedInteger ONE = asUnsigned(1);
- public static final UnsignedInteger MAX_VALUE = asUnsigned(-1);
-
- private final int value;
-
- private UnsignedInteger(int value) {
- // GWT doesn't consistently overflow values to make them 32-bit, so we need to force it.
- this.value = value & 0xffffffff;
- }
-
- /**
- * Returns an {@code UnsignedInteger} that, when treated as signed, is
- * equal to {@code value}.
- *
- * @deprecated Use {@link #fromIntBits(int)}. This method is scheduled to be removed in Guava
- * release 15.0.
- */
- @Deprecated
- @Beta
- public static UnsignedInteger asUnsigned(int value) {
- return fromIntBits(value);
- }
-
- /**
- * Returns an {@code UnsignedInteger} corresponding to a given bit representation.
- * The argument is interpreted as an unsigned 32-bit value. Specifically, the sign bit
- * of {@code bits} is interpreted as a normal bit, and all other bits are treated as usual.
- *
- * <p>If the argument is nonnegative, the returned result will be equal to {@code bits},
- * otherwise, the result will be equal to {@code 2^32 + bits}.
- *
- * <p>To represent unsigned decimal constants, consider {@link #valueOf(long)} instead.
- *
- * @since 14.0
- */
- public static UnsignedInteger fromIntBits(int bits) {
- return new UnsignedInteger(bits);
- }
-
- /**
- * Returns an {@code UnsignedInteger} that is equal to {@code value},
- * if possible. The inverse operation of {@link #longValue()}.
- */
- public static UnsignedInteger valueOf(long value) {
- checkArgument((value & INT_MASK) == value,
- "value (%s) is outside the range for an unsigned integer value", value);
- return fromIntBits((int) value);
- }
-
- /**
- * Returns a {@code UnsignedInteger} representing the same value as the specified
- * {@link BigInteger}. This is the inverse operation of {@link #bigIntegerValue()}.
- *
- * @throws IllegalArgumentException if {@code value} is negative or {@code value >= 2^32}
- */
- public static UnsignedInteger valueOf(BigInteger value) {
- checkNotNull(value);
- checkArgument(value.signum() >= 0 && value.bitLength() <= Integer.SIZE,
- "value (%s) is outside the range for an unsigned integer value", value);
- return fromIntBits(value.intValue());
- }
-
- /**
- * Returns an {@code UnsignedInteger} holding the value of the specified {@code String}, parsed
- * as an unsigned {@code int} value.
- *
- * @throws NumberFormatException if the string does not contain a parsable unsigned {@code int}
- * value
- */
- public static UnsignedInteger valueOf(String string) {
- return valueOf(string, 10);
- }
-
- /**
- * Returns an {@code UnsignedInteger} holding the value of the specified {@code String}, parsed
- * as an unsigned {@code int} value in the specified radix.
- *
- * @throws NumberFormatException if the string does not contain a parsable unsigned {@code int}
- * value
- */
- public static UnsignedInteger valueOf(String string, int radix) {
- return fromIntBits(UnsignedInts.parseUnsignedInt(string, radix));
- }
-
- /**
- * Returns the result of adding this and {@code val}. If the result would have more than 32 bits,
- * returns the low 32 bits of the result.
- *
- * @deprecated Use {@link #plus(UnsignedInteger)}. This method is scheduled to be removed in Guava
- * release 15.0.
- */
- @Deprecated
- @Beta
- public UnsignedInteger add(UnsignedInteger val) {
- return plus(val);
- }
-
- /**
- * Returns the result of adding this and {@code val}. If the result would have more than 32 bits,
- * returns the low 32 bits of the result.
- *
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedInteger plus(UnsignedInteger val) {
- return fromIntBits(this.value + checkNotNull(val).value);
- }
-
- /**
- * Returns the result of subtracting this and {@code val}. If the result would be negative,
- * returns the low 32 bits of the result.
- *
- * @deprecated Use {@link #minus(UnsignedInteger)}. This method is scheduled to be removed in
- * Guava release 15.0.
- */
- @Deprecated
- @Beta
- public UnsignedInteger subtract(UnsignedInteger val) {
- return minus(val);
- }
-
- /**
- * Returns the result of subtracting this and {@code val}. If the result would be negative,
- * returns the low 32 bits of the result.
- *
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedInteger minus(UnsignedInteger val) {
- return fromIntBits(value - checkNotNull(val).value);
- }
-
- /**
- * Returns the result of dividing this by {@code val}.
- *
- * @deprecated Use {@link #dividedBy(UnsignedInteger)}. This method is scheduled to be removed in
- * Guava release 15.0.
- */
- @Deprecated
- @Beta
- public UnsignedInteger divide(UnsignedInteger val) {
- return dividedBy(val);
- }
-
- /**
- * Returns the result of dividing this by {@code val}.
- *
- * @throws ArithmeticException if {@code val} is zero
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedInteger dividedBy(UnsignedInteger val) {
- return fromIntBits(UnsignedInts.divide(value, checkNotNull(val).value));
- }
-
- /**
- * Returns the remainder of dividing this by {@code val}.
- *
- * @deprecated Use {@link #mod(UnsignedInteger)}. This method is scheduled to be removed in Guava
- * release 15.0.
- */
- @Deprecated
- @Beta
- public UnsignedInteger remainder(UnsignedInteger val) {
- return mod(val);
- }
-
- /**
- * Returns this mod {@code val}.
- *
- * @throws ArithmeticException if {@code val} is zero
- * @since 14.0
- */
- @CheckReturnValue
- public UnsignedInteger mod(UnsignedInteger val) {
- return fromIntBits(UnsignedInts.remainder(value, checkNotNull(val).value));
- }
-
- /**
- * Returns the value of this {@code UnsignedInteger} as an {@code int}. This is an inverse
- * operation to {@link #fromIntBits}.
- *
- * <p>Note that if this {@code UnsignedInteger} holds a value {@code >= 2^31}, the returned value
- * will be equal to {@code this - 2^32}.
- */
- @Override
- public int intValue() {
- return value;
- }
-
- /**
- * Returns the value of this {@code UnsignedInteger} as a {@code long}.
- */
- @Override
- public long longValue() {
- return toLong(value);
- }
-
- /**
- * Returns the value of this {@code UnsignedInteger} as a {@code float}, analogous to a widening
- * primitive conversion from {@code int} to {@code float}, and correctly rounded.
- */
- @Override
- public float floatValue() {
- return longValue();
- }
-
- /**
- * Returns the value of this {@code UnsignedInteger} as a {@code float}, analogous to a widening
- * primitive conversion from {@code int} to {@code double}, and correctly rounded.
- */
- @Override
- public double doubleValue() {
- return longValue();
- }
-
- /**
- * Returns the value of this {@code UnsignedInteger} as a {@link BigInteger}.
- */
- public BigInteger bigIntegerValue() {
- return BigInteger.valueOf(longValue());
- }
-
- /**
- * Compares this unsigned integer to another unsigned integer.
- * Returns {@code 0} if they are equal, a negative number if {@code this < other},
- * and a positive number if {@code this > other}.
- */
- @Override
- public int compareTo(UnsignedInteger other) {
- checkNotNull(other);
- return compare(value, other.value);
- }
-
- @Override
- public int hashCode() {
- return value;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (obj instanceof UnsignedInteger) {
- UnsignedInteger other = (UnsignedInteger) obj;
- return value == other.value;
- }
- return false;
- }
-
- /**
- * Returns a string representation of the {@code UnsignedInteger} value, in base 10.
- */
- @Override
- public String toString() {
- return toString(10);
- }
-
- /**
- * Returns a string representation of the {@code UnsignedInteger} value, in base {@code radix}.
- * If {@code radix < Character.MIN_RADIX} or {@code radix > Character.MAX_RADIX}, the radix
- * {@code 10} is used.
- */
- public String toString(int radix) {
- return UnsignedInts.toString(value, radix);
- }
-}
-
diff --git a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSortedMap.java b/guava-gwt/src-super/com/google/common/testing/super/com/google/common/testing/Platform.java
index 2e36f39..9fa092e 100644
--- a/guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/RegularImmutableSortedMap.java
+++ b/guava-gwt/src-super/com/google/common/testing/super/com/google/common/testing/Platform.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Guava Authors
+ * Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,18 +14,23 @@
* limitations under the License.
*/
-package com.google.common.collect;
+package com.google.common.testing;
-import java.util.Comparator;
-import java.util.SortedMap;
+import static com.google.common.base.Preconditions.checkNotNull;
/**
- * GWT emulated version of {@link RegularImmutableSortedMap}.
+ * Methods factored out so that they can be emulated differently in GWT.
*
* @author Chris Povirk
*/
-final class RegularImmutableSortedMap<K, V> extends ImmutableSortedMap<K, V> {
- RegularImmutableSortedMap(SortedMap<K, V> delegate, Comparator<? super K> comparator) {
- super(delegate, comparator);
+final class Platform {
+ /**
+ * Serializes and deserializes the specified object (a no-op under GWT).
+ */
+ @SuppressWarnings("unchecked")
+ static <T> T reserialize(T object) {
+ return checkNotNull(object);
}
+
+ private Platform() {}
}
diff --git a/guava-gwt/src-super/java/nio/charset/Charset.gwt.xml b/guava-gwt/src-super/java/nio/charset/Charset.gwt.xml
deleted file mode 100644
index d23fb8c..0000000
--- a/guava-gwt/src-super/java/nio/charset/Charset.gwt.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<module>
- <source path=""/>
- <inherits name="java.nio.charset.Charset"/>
-</module> \ No newline at end of file
diff --git a/guava-gwt/src-super/java/nio/charset/Charset.java b/guava-gwt/src-super/java/nio/charset/Charset.java
deleted file mode 100644
index 1463333..0000000
--- a/guava-gwt/src-super/java/nio/charset/Charset.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.nio.charset;
-
-import java.util.Collections;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-/**
- * A minimal GWT emulation of {@link Charset}.
- *
- * @author Gregory Kick
- */
-public abstract class Charset implements Comparable<Charset> {
- private static final Charset UTF_8 = new Charset("UTF-8") {};
-
- private static final SortedMap<String, Charset> AVAILABLE_CHARSETS =
- new TreeMap<String, Charset>();
- static {
- AVAILABLE_CHARSETS.put(UTF_8.name(), UTF_8);
- }
-
- public static SortedMap<String, Charset> availableCharsets() {
- return Collections.unmodifiableSortedMap(AVAILABLE_CHARSETS);
- }
-
- public static Charset forName(String charsetName) {
- if (charsetName == null) {
- throw new IllegalArgumentException("Null charset name");
- }
- int length = charsetName.length();
- if (length == 0) {
- throw new IllegalCharsetNameException(charsetName);
- }
- for (int i = 0; i < length; i++) {
- char c = charsetName.charAt(i);
- if ((c >= 'A' && c <= 'Z')
- || (c >= 'a' && c <= 'z')
- || (c >= '0' && c <= '9')
- || (c == '-' && i != 0)
- || (c == ':' && i != 0)
- || (c == '_' && i != 0)
- || (c == '.' && i != 0)) {
- continue;
- }
- throw new IllegalCharsetNameException(charsetName);
- }
- Charset charset = AVAILABLE_CHARSETS.get(charsetName.toUpperCase());
- if (charset != null) {
- return charset;
- }
- throw new UnsupportedCharsetException(charsetName);
- }
-
- private final String name;
-
- private Charset(String name) {
- this.name = name;
- }
-
- public final String name() {
- return name;
- }
-
- public final int compareTo(Charset that) {
- return this.name.compareToIgnoreCase(that.name);
- }
-
- public final int hashCode() {
- return name.hashCode();
- }
-
- public final boolean equals(Object o) {
- if (o == this) {
- return true;
- } else if (o instanceof Charset) {
- Charset that = (Charset) o;
- return this.name.equals(that.name);
- } else {
- return false;
- }
- }
-
- public final String toString() {
- return name;
- }
-}
diff --git a/guava-gwt/src-super/java/nio/charset/UnsupportedCharsetException.java b/guava-gwt/src-super/java/nio/charset/UnsupportedCharsetException.java
deleted file mode 100644
index f489a1d..0000000
--- a/guava-gwt/src-super/java/nio/charset/UnsupportedCharsetException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2012 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.nio.charset;
-
-/**
- * GWT emulation of {@link UnsupportedCharsetException}.
- *
- * @author Gregory Kick
- */
-public class UnsupportedCharsetException extends IllegalArgumentException {
- private final String charsetName;
-
- public UnsupportedCharsetException(String charsetName) {
- super(String.valueOf(charsetName));
- this.charsetName = charsetName;
- }
-
- public String getCharsetName() {
- return charsetName;
- }
-}
diff --git a/guava-gwt/src-super/java/util/super/java/util/concurrent/Callable.java b/guava-gwt/src-super/java/util/super/java/util/concurrent/Callable.java
index 607d3f7..548f3a6 100644
--- a/guava-gwt/src-super/java/util/super/java/util/concurrent/Callable.java
+++ b/guava-gwt/src-super/java/util/super/java/util/concurrent/Callable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Guava Authors
+ * Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentHashMap.java b/guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentHashMap.java
index 886d8f7..77544b5 100644
--- a/guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentHashMap.java
+++ b/guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentHashMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Guava Authors
+ * Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentMap.java b/guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentMap.java
index 49c05ce..61a8a04 100644
--- a/guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentMap.java
+++ b/guava-gwt/src-super/java/util/super/java/util/concurrent/ConcurrentMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Guava Authors
+ * Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/guava-gwt/src-super/java/util/super/java/util/concurrent/ExecutionException.java b/guava-gwt/src-super/java/util/super/java/util/concurrent/ExecutionException.java
index c1fc0f4..b25f476 100644
--- a/guava-gwt/src-super/java/util/super/java/util/concurrent/ExecutionException.java
+++ b/guava-gwt/src-super/java/util/super/java/util/concurrent/ExecutionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Guava Authors
+ * Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ package java.util.concurrent;
/**
* Emulation of ExecutionException.
*
- * @author Charles Fry
+ * @author fry@google.com (Charles Fry)
*/
public class ExecutionException extends Exception {
protected ExecutionException() { }
diff --git a/guava-gwt/src-super/java/util/super/java/util/concurrent/TimeUnit.java b/guava-gwt/src-super/java/util/super/java/util/concurrent/TimeUnit.java
index 52f3fb4..2ce1de3 100644
--- a/guava-gwt/src-super/java/util/super/java/util/concurrent/TimeUnit.java
+++ b/guava-gwt/src-super/java/util/super/java/util/concurrent/TimeUnit.java
@@ -1,8 +1,4 @@
/*
- * This file is a modified version of
- * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/TimeUnit.java
- * which contained the following notice:
- *
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
diff --git a/guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicInteger.java b/guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicInteger.java
index d9c16a6..ac98dcf 100644
--- a/guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicInteger.java
+++ b/guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicInteger.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Guava Authors
+ * Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicLong.java b/guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicLong.java
index fdd1b34..8696422 100644
--- a/guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicLong.java
+++ b/guava-gwt/src-super/java/util/super/java/util/concurrent/atomic/AtomicLong.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Guava Authors
+ * Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.