diff options
Diffstat (limited to 'guava/src/com/google/common/base')
38 files changed, 8536 insertions, 0 deletions
diff --git a/guava/src/com/google/common/base/Absent.java b/guava/src/com/google/common/base/Absent.java new file mode 100644 index 0000000..852fa20 --- /dev/null +++ b/guava/src/com/google/common/base/Absent.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.GwtCompatible; + +import java.util.Collections; +import java.util.Set; + +import javax.annotation.Nullable; + +/** + * Implementation of an {@link Optional} not containing a reference. + */ +@GwtCompatible +final class Absent extends Optional<Object> { + static final Absent INSTANCE = new Absent(); + + @Override public boolean isPresent() { + return false; + } + + @Override public Object get() { + throw new IllegalStateException("value is absent"); + } + + @Override public Object or(Object defaultValue) { + return checkNotNull(defaultValue, "use orNull() instead of or(null)"); + } + + @SuppressWarnings("unchecked") // safe covariant cast + @Override public Optional<Object> or(Optional<?> secondChoice) { + return (Optional) checkNotNull(secondChoice); + } + + @Override public Object or(Supplier<?> supplier) { + return checkNotNull(supplier.get(), + "use orNull() instead of a Supplier that returns null"); + } + + @Override @Nullable public Object orNull() { + return null; + } + + @Override public Set<Object> asSet() { + return Collections.emptySet(); + } + + @Override public <V> Optional<V> transform(Function<Object, V> function) { + checkNotNull(function); + return Optional.absent(); + } + + @Override public boolean equals(@Nullable Object object) { + return object == this; + } + + @Override public int hashCode() { + return 0x598df91c; + } + + @Override public String toString() { + return "Optional.absent()"; + } + + private Object readResolve() { + return INSTANCE; + } + + private static final long serialVersionUID = 0; +} diff --git a/guava/src/com/google/common/base/AbstractIterator.java b/guava/src/com/google/common/base/AbstractIterator.java new file mode 100644 index 0000000..d171af2 --- /dev/null +++ b/guava/src/com/google/common/base/AbstractIterator.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.annotations.GwtCompatible; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Note this class is a copy of + * {@link com.google.common.collect.AbstractIterator} (for dependency reasons). + */ +@GwtCompatible +abstract class AbstractIterator<T> implements Iterator<T> { + private State state = State.NOT_READY; + + protected AbstractIterator() {} + + private enum State { + READY, NOT_READY, DONE, FAILED, + } + + private T next; + + protected abstract T computeNext(); + + protected final T endOfData() { + state = State.DONE; + return null; + } + + @Override + public final boolean hasNext() { + checkState(state != State.FAILED); + switch (state) { + case DONE: + return false; + case READY: + return true; + default: + } + return tryToComputeNext(); + } + + private boolean tryToComputeNext() { + state = State.FAILED; // temporary pessimism + next = computeNext(); + if (state != State.DONE) { + state = State.READY; + return true; + } + return false; + } + + @Override + public final T next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + state = State.NOT_READY; + return next; + } + + @Override public final void remove() { + throw new UnsupportedOperationException(); + } +} diff --git a/guava/src/com/google/common/base/Ascii.java b/guava/src/com/google/common/base/Ascii.java new file mode 100644 index 0000000..792856d --- /dev/null +++ b/guava/src/com/google/common/base/Ascii.java @@ -0,0 +1,487 @@ +/* + * Copyright (C) 2010 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; + +/** + * Static methods pertaining to ASCII characters (those in the range of values + * {@code 0x00} through {@code 0x7F}), and to strings containing such + * characters. + * + * <p>ASCII utilities also exist in other classes of this package: + * <ul> + * <!-- TODO(kevinb): how can we make this not produce a warning when building gwt javadoc? --> + * <li>{@link Charsets#US_ASCII} specifies the {@code Charset} of ASCII characters. + * <li>{@link CharMatcher#ASCII} matches ASCII characters and provides text processing methods + * which operate only on the ASCII characters of a string. + * </ul> + * + * @author Craig Berry + * @author Gregory Kick + * @since 7.0 + */ +@GwtCompatible +public final class Ascii { + + private Ascii() {} + + /* The ASCII control characters, per RFC 20. */ + /** + * Null ('\0'): The all-zeros character which may serve to accomplish + * time fill and media fill. Normally used as a C string terminator. + * <p>Although RFC 20 names this as "Null", note that it is distinct + * from the C/C++ "NULL" pointer. + * + * @since 8.0 + */ + public static final byte NUL = 0; + + /** + * Start of Heading: A communication control character used at + * the beginning of a sequence of characters which constitute a + * machine-sensible address or routing information. Such a sequence is + * referred to as the "heading." An STX character has the effect of + * terminating a heading. + * + * @since 8.0 + */ + public static final byte SOH = 1; + + /** + * Start of Text: A communication control character which + * precedes a sequence of characters that is to be treated as an entity + * and entirely transmitted through to the ultimate destination. Such a + * sequence is referred to as "text." STX may be used to terminate a + * sequence of characters started by SOH. + * + * @since 8.0 + */ + public static final byte STX = 2; + + /** + * End of Text: A communication control character used to + * terminate a sequence of characters started with STX and transmitted + * as an entity. + * + * @since 8.0 + */ + public static final byte ETX = 3; + + /** + * End of Transmission: A communication control character used + * to indicate the conclusion of a transmission, which may have + * contained one or more texts and any associated headings. + * + * @since 8.0 + */ + public static final byte EOT = 4; + + /** + * Enquiry: A communication control character used in data + * communication systems as a request for a response from a remote + * station. It may be used as a "Who Are You" (WRU) to obtain + * identification, or may be used to obtain station status, or both. + * + * @since 8.0 + */ + public static final byte ENQ = 5; + + /** + * Acknowledge: A communication control character transmitted + * by a receiver as an affirmative response to a sender. + * + * @since 8.0 + */ + public static final byte ACK = 6; + + /** + * Bell ('\a'): A character for use when there is a need to call for + * human attention. It may control alarm or attention devices. + * + * @since 8.0 + */ + public static final byte BEL = 7; + + /** + * Backspace ('\b'): A format effector which controls the movement of + * the printing position one printing space backward on the same + * printing line. (Applicable also to display devices.) + * + * @since 8.0 + */ + public static final byte BS = 8; + + /** + * Horizontal Tabulation ('\t'): A format effector which controls the + * movement of the printing position to the next in a series of + * predetermined positions along the printing line. (Applicable also to + * display devices and the skip function on punched cards.) + * + * @since 8.0 + */ + public static final byte HT = 9; + + /** + * Line Feed ('\n'): A format effector which controls the movement of + * the printing position to the next printing line. (Applicable also to + * display devices.) Where appropriate, this character may have the + * meaning "New Line" (NL), a format effector which controls the + * movement of the printing point to the first printing position on the + * next printing line. Use of this convention requires agreement + * between sender and recipient of data. + * + * @since 8.0 + */ + public static final byte LF = 10; + + /** + * Alternate name for {@link #LF}. ({@code LF} is preferred.) + * + * @since 8.0 + */ + public static final byte NL = 10; + + /** + * Vertical Tabulation ('\v'): A format effector which controls the + * movement of the printing position to the next in a series of + * predetermined printing lines. (Applicable also to display devices.) + * + * @since 8.0 + */ + public static final byte VT = 11; + + /** + * Form Feed ('\f'): A format effector which controls the movement of + * the printing position to the first pre-determined printing line on + * the next form or page. (Applicable also to display devices.) + * + * @since 8.0 + */ + public static final byte FF = 12; + + /** + * Carriage Return ('\r'): A format effector which controls the + * movement of the printing position to the first printing position on + * the same printing line. (Applicable also to display devices.) + * + * @since 8.0 + */ + public static final byte CR = 13; + + /** + * Shift Out: A control character indicating that the code + * combinations which follow shall be interpreted as outside of the + * character set of the standard code table until a Shift In character + * is reached. + * + * @since 8.0 + */ + public static final byte SO = 14; + + /** + * Shift In: A control character indicating that the code + * combinations which follow shall be interpreted according to the + * standard code table. + * + * @since 8.0 + */ + public static final byte SI = 15; + + /** + * Data Link Escape: A communication control character which + * will change the meaning of a limited number of contiguously following + * characters. It is used exclusively to provide supplementary controls + * in data communication networks. + * + * @since 8.0 + */ + public static final byte DLE = 16; + + /** + * Device Control 1. Characters for the control + * of ancillary devices associated with data processing or + * telecommunication systems, more especially switching devices "on" or + * "off." (If a single "stop" control is required to interrupt or turn + * off ancillary devices, DC4 is the preferred assignment.) + * + * @since 8.0 + */ + public static final byte DC1 = 17; // aka XON + + /** + * Transmission On: Although originally defined as DC1, this ASCII + * control character is now better known as the XON code used for software + * flow control in serial communications. The main use is restarting + * the transmission after the communication has been stopped by the XOFF + * control code. + * + * @since 8.0 + */ + public static final byte XON = 17; // aka DC1 + + /** + * Device Control 2. Characters for the control + * of ancillary devices associated with data processing or + * telecommunication systems, more especially switching devices "on" or + * "off." (If a single "stop" control is required to interrupt or turn + * off ancillary devices, DC4 is the preferred assignment.) + * + * @since 8.0 + */ + public static final byte DC2 = 18; + + /** + * Device Control 3. Characters for the control + * of ancillary devices associated with data processing or + * telecommunication systems, more especially switching devices "on" or + * "off." (If a single "stop" control is required to interrupt or turn + * off ancillary devices, DC4 is the preferred assignment.) + * + * @since 8.0 + */ + public static final byte DC3 = 19; // aka XOFF + + /** + * Transmission off. See {@link #XON} for explanation. + * + * @since 8.0 + */ + public static final byte XOFF = 19; // aka DC3 + + /** + * Device Control 4. Characters for the control + * of ancillary devices associated with data processing or + * telecommunication systems, more especially switching devices "on" or + * "off." (If a single "stop" control is required to interrupt or turn + * off ancillary devices, DC4 is the preferred assignment.) + * + * @since 8.0 + */ + public static final byte DC4 = 20; + + /** + * Negative Acknowledge: A communication control character + * transmitted by a receiver as a negative response to the sender. + * + * @since 8.0 + */ + public static final byte NAK = 21; + + /** + * Synchronous Idle: A communication control character used by + * a synchronous transmission system in the absence of any other + * character to provide a signal from which synchronism may be achieved + * or retained. + * + * @since 8.0 + */ + public static final byte SYN = 22; + + /** + * End of Transmission Block: A communication control character + * used to indicate the end of a block of data for communication + * purposes. ETB is used for blocking data where the block structure is + * not necessarily related to the processing format. + * + * @since 8.0 + */ + public static final byte ETB = 23; + + /** + * Cancel: A control character used to indicate that the data + * with which it is sent is in error or is to be disregarded. + * + * @since 8.0 + */ + public static final byte CAN = 24; + + /** + * End of Medium: A control character associated with the sent + * data which may be used to identify the physical end of the medium, or + * the end of the used, or wanted, portion of information recorded on a + * medium. (The position of this character does not necessarily + * correspond to the physical end of the medium.) + * + * @since 8.0 + */ + public static final byte EM = 25; + + /** + * Substitute: A character that may be substituted for a + * character which is determined to be invalid or in error. + * + * @since 8.0 + */ + public static final byte SUB = 26; + + /** + * Escape: A control character intended to provide code + * extension (supplementary characters) in general information + * interchange. The Escape character itself is a prefix affecting the + * interpretation of a limited number of contiguously following + * characters. + * + * @since 8.0 + */ + public static final byte ESC = 27; + + /** + * File Separator: These four information separators may be + * used within data in optional fashion, except that their hierarchical + * relationship shall be: FS is the most inclusive, then GS, then RS, + * and US is least inclusive. (The content and length of a File, Group, + * Record, or Unit are not specified.) + * + * @since 8.0 + */ + public static final byte FS = 28; + + /** + * Group Separator: These four information separators may be + * used within data in optional fashion, except that their hierarchical + * relationship shall be: FS is the most inclusive, then GS, then RS, + * and US is least inclusive. (The content and length of a File, Group, + * Record, or Unit are not specified.) + * + * @since 8.0 + */ + public static final byte GS = 29; + + /** + * Record Separator: These four information separators may be + * used within data in optional fashion, except that their hierarchical + * relationship shall be: FS is the most inclusive, then GS, then RS, + * and US is least inclusive. (The content and length of a File, Group, + * Record, or Unit are not specified.) + * + * @since 8.0 + */ + public static final byte RS = 30; + + /** + * Unit Separator: These four information separators may be + * used within data in optional fashion, except that their hierarchical + * relationship shall be: FS is the most inclusive, then GS, then RS, + * and US is least inclusive. (The content and length of a File, Group, + * Record, or Unit are not specified.) + * + * @since 8.0 + */ + public static final byte US = 31; + + /** + * Space: A normally non-printing graphic character used to + * separate words. It is also a format effector which controls the + * movement of the printing position, one printing position forward. + * (Applicable also to display devices.) + * + * @since 8.0 + */ + public static final byte SP = 32; + + /** + * Alternate name for {@link #SP}. + * + * @since 8.0 + */ + public static final byte SPACE = 32; + + /** + * Delete: This character is used primarily to "erase" or + * "obliterate" erroneous or unwanted characters in perforated tape. + * + * @since 8.0 + */ + public static final byte DEL = 127; + + /** + * The minimum value of an ASCII character. + * + * @since 9.0 (was type {@code int} before 12.0) + */ + public static final char MIN = 0; + + /** + * The maximum value of an ASCII character. + * + * @since 9.0 (was type {@code int} before 12.0) + */ + public static final char MAX = 127; + + /** + * Returns a copy of the input string in which all {@linkplain #isUpperCase(char) uppercase ASCII + * characters} have been converted to lowercase. All other characters are copied without + * modification. + */ + public static String toLowerCase(String string) { + int length = string.length(); + StringBuilder builder = new StringBuilder(length); + for (int i = 0; i < length; i++) { + builder.append(toLowerCase(string.charAt(i))); + } + return builder.toString(); + } + + /** + * If the argument is an {@linkplain #isUpperCase(char) uppercase ASCII character} returns the + * lowercase equivalent. Otherwise returns the argument. + */ + public static char toLowerCase(char c) { + return isUpperCase(c) ? (char) (c ^ 0x20) : c; + } + + /** + * Returns a copy of the input string in which all {@linkplain #isLowerCase(char) lowercase ASCII + * characters} have been converted to uppercase. All other characters are copied without + * modification. + */ + public static String toUpperCase(String string) { + int length = string.length(); + StringBuilder builder = new StringBuilder(length); + for (int i = 0; i < length; i++) { + builder.append(toUpperCase(string.charAt(i))); + } + return builder.toString(); + } + + /** + * If the argument is a {@linkplain #isLowerCase(char) lowercase ASCII character} returns the + * uppercase equivalent. Otherwise returns the argument. + */ + public static char toUpperCase(char c) { + return isLowerCase(c) ? (char) (c & 0x5f) : c; + } + + /** + * Indicates whether {@code c} is one of the twenty-six lowercase ASCII alphabetic characters + * between {@code 'a'} and {@code 'z'} inclusive. All others (including non-ASCII characters) + * return {@code false}. + */ + public static boolean isLowerCase(char c) { + return (c >= 'a') && (c <= 'z'); + } + + /** + * Indicates whether {@code c} is one of the twenty-six uppercase ASCII alphabetic characters + * between {@code 'A'} and {@code 'Z'} inclusive. All others (including non-ASCII characters) + * return {@code false}. + */ + public static boolean isUpperCase(char c) { + return (c >= 'A') && (c <= 'Z'); + } +} diff --git a/guava/src/com/google/common/base/CaseFormat.java b/guava/src/com/google/common/base/CaseFormat.java new file mode 100644 index 0000000..8ef7c5c --- /dev/null +++ b/guava/src/com/google/common/base/CaseFormat.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2006 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; + +/** + * Utility class for converting between various ASCII case formats. + * + * @author Mike Bostock + * @since 1.0 + */ +@GwtCompatible +public enum CaseFormat { + /** + * Hyphenated variable naming convention, e.g., "lower-hyphen". + */ + LOWER_HYPHEN(CharMatcher.is('-'), "-"), + + /** + * C++ variable naming convention, e.g., "lower_underscore". + */ + LOWER_UNDERSCORE(CharMatcher.is('_'), "_"), + + /** + * Java variable naming convention, e.g., "lowerCamel". + */ + LOWER_CAMEL(CharMatcher.inRange('A', 'Z'), ""), + + /** + * Java and C++ class naming convention, e.g., "UpperCamel". + */ + UPPER_CAMEL(CharMatcher.inRange('A', 'Z'), ""), + + /** + * Java and C++ constant naming convention, e.g., "UPPER_UNDERSCORE". + */ + UPPER_UNDERSCORE(CharMatcher.is('_'), "_"); + + private final CharMatcher wordBoundary; + private final String wordSeparator; + + CaseFormat(CharMatcher wordBoundary, String wordSeparator) { + this.wordBoundary = wordBoundary; + this.wordSeparator = wordSeparator; + } + + /** + * Converts the specified {@code String s} from this format to the specified {@code format}. A + * "best effort" approach is taken; if {@code s} does not conform to the assumed format, then the + * behavior of this method is undefined but we make a reasonable effort at converting anyway. + */ + public String to(CaseFormat format, String s) { + if (format == null) { + throw new NullPointerException(); + } + if (s == null) { + throw new NullPointerException(); + } + + if (format == this) { + return s; + } + + /* optimize cases where no camel conversion is required */ + switch (this) { + case LOWER_HYPHEN: + switch (format) { + case LOWER_UNDERSCORE: + return s.replace('-', '_'); + case UPPER_UNDERSCORE: + return Ascii.toUpperCase(s.replace('-', '_')); + } + break; + case LOWER_UNDERSCORE: + switch (format) { + case LOWER_HYPHEN: + return s.replace('_', '-'); + case UPPER_UNDERSCORE: + return Ascii.toUpperCase(s); + } + break; + case UPPER_UNDERSCORE: + switch (format) { + case LOWER_HYPHEN: + return Ascii.toLowerCase(s.replace('_', '-')); + case LOWER_UNDERSCORE: + return Ascii.toLowerCase(s); + } + break; + } + + // otherwise, deal with camel conversion + StringBuilder out = null; + int i = 0; + int j = -1; + while ((j = wordBoundary.indexIn(s, ++j)) != -1) { + if (i == 0) { + // include some extra space for separators + out = new StringBuilder(s.length() + 4 * wordSeparator.length()); + out.append(format.normalizeFirstWord(s.substring(i, j))); + } else { + out.append(format.normalizeWord(s.substring(i, j))); + } + out.append(format.wordSeparator); + i = j + wordSeparator.length(); + } + if (i == 0) { + return format.normalizeFirstWord(s); + } + out.append(format.normalizeWord(s.substring(i))); + return out.toString(); + } + + private String normalizeFirstWord(String word) { + switch (this) { + case LOWER_CAMEL: + return Ascii.toLowerCase(word); + default: + return normalizeWord(word); + } + } + + private String normalizeWord(String word) { + switch (this) { + case LOWER_HYPHEN: + return Ascii.toLowerCase(word); + case LOWER_UNDERSCORE: + return Ascii.toLowerCase(word); + case LOWER_CAMEL: + return firstCharOnlyToUpper(word); + case UPPER_CAMEL: + return firstCharOnlyToUpper(word); + case UPPER_UNDERSCORE: + return Ascii.toUpperCase(word); + } + throw new RuntimeException("unknown case: " + this); + } + + private static String firstCharOnlyToUpper(String word) { + int length = word.length(); + if (length == 0) { + return word; + } + return new StringBuilder(length) + .append(Ascii.toUpperCase(word.charAt(0))) + .append(Ascii.toLowerCase(word.substring(1))) + .toString(); + } +} diff --git a/guava/src/com/google/common/base/CharMatcher.java b/guava/src/com/google/common/base/CharMatcher.java new file mode 100644 index 0000000..64a70b7 --- /dev/null +++ b/guava/src/com/google/common/base/CharMatcher.java @@ -0,0 +1,1271 @@ +/* + * Copyright (C) 2008 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; + +import java.util.Arrays; +import javax.annotation.CheckReturnValue; + +/** + * Determines a true or false value for any Java {@code char} value, just as {@link Predicate} does + * for any {@link Object}. Also offers basic text processing methods based on this function. + * Implementations are strongly encouraged to be side-effect-free and immutable. + * + * <p>Throughout the documentation of this class, the phrase "matching character" is used to mean + * "any character {@code c} for which {@code this.matches(c)} returns {@code true}". + * + * <p><b>Note:</b> This class deals only with {@code char} values; it does not understand + * supplementary Unicode code points in the range {@code 0x10000} to {@code 0x10FFFF}. Such logical + * characters are encoded into a {@code String} using surrogate pairs, and a {@code CharMatcher} + * treats these just as two separate characters. + * + * <p>Example usages: <pre> + * String trimmed = {@link #WHITESPACE WHITESPACE}.{@link #trimFrom trimFrom}(userInput); + * if ({@link #ASCII ASCII}.{@link #matchesAllOf matchesAllOf}(s)) { ... }</pre> + * + * <p>See the Guava User Guide article on <a href= + * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#CharMatcher"> + * {@code CharMatcher}</a>. + * + * @author Kevin Bourrillion + * @since 1.0 + */ +@Beta // Possibly change from chars to code points; decide constants vs. methods +@GwtCompatible +public abstract class CharMatcher implements Predicate<Character> { + // Constants + /** + * Determines whether a character is a breaking whitespace (that is, a whitespace which can be + * interpreted as a break between words for formatting purposes). See {@link #WHITESPACE} for a + * discussion of that term. + * + * @since 2.0 + */ + public static final CharMatcher BREAKING_WHITESPACE = + anyOf("\t\n\013\f\r \u0085\u1680\u2028\u2029\u205f\u3000") + .or(inRange('\u2000', '\u2006')) + .or(inRange('\u2008', '\u200a')) + .withToString("CharMatcher.BREAKING_WHITESPACE") + .precomputed(); + + /** + * Determines whether a character is ASCII, meaning that its code point is less than 128. + */ + public static final CharMatcher ASCII = inRange('\0', '\u007f', "CharMatcher.ASCII"); + + /** + * Determines whether a character is a digit according to + * <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bdigit%7D">Unicode</a>. + */ + public static final CharMatcher DIGIT; + + static { + CharMatcher digit = inRange('0', '9'); + String zeroes = + "\u0660\u06f0\u07c0\u0966\u09e6\u0a66\u0ae6\u0b66\u0be6\u0c66" + + "\u0ce6\u0d66\u0e50\u0ed0\u0f20\u1040\u1090\u17e0\u1810\u1946" + + "\u19d0\u1b50\u1bb0\u1c40\u1c50\ua620\ua8d0\ua900\uaa50\uff10"; + for (char base : zeroes.toCharArray()) { + digit = digit.or(inRange(base, (char) (base + 9))); + } + DIGIT = digit.withToString("CharMatcher.DIGIT").precomputed(); + } + + /** + * Determines whether a character is a digit according to {@link Character#isDigit(char) Java's + * definition}. If you only care to match ASCII digits, you can use {@code inRange('0', '9')}. + */ + public static final CharMatcher JAVA_DIGIT = new CharMatcher("CharMatcher.JAVA_DIGIT") { + @Override public boolean matches(char c) { + return Character.isDigit(c); + } + }; + + /** + * Determines whether a character is a letter according to {@link Character#isLetter(char) Java's + * definition}. If you only care to match letters of the Latin alphabet, you can use {@code + * inRange('a', 'z').or(inRange('A', 'Z'))}. + */ + public static final CharMatcher JAVA_LETTER = new CharMatcher("CharMatcher.JAVA_LETTER") { + @Override public boolean matches(char c) { + return Character.isLetter(c); + } + + @Override public CharMatcher precomputed() { + return this; + } + }; + + /** + * Determines whether a character is a letter or digit according to {@link + * Character#isLetterOrDigit(char) Java's definition}. + */ + public static final CharMatcher JAVA_LETTER_OR_DIGIT = + new CharMatcher("CharMatcher.JAVA_LETTER_OR_DIGIT") { + @Override public boolean matches(char c) { + return Character.isLetterOrDigit(c); + } + }; + + /** + * Determines whether a character is upper case according to {@link Character#isUpperCase(char) + * Java's definition}. + */ + public static final CharMatcher JAVA_UPPER_CASE = + new CharMatcher("CharMatcher.JAVA_UPPER_CASE") { + @Override public boolean matches(char c) { + return Character.isUpperCase(c); + } + }; + + /** + * Determines whether a character is lower case according to {@link Character#isLowerCase(char) + * Java's definition}. + */ + public static final CharMatcher JAVA_LOWER_CASE = + new CharMatcher("CharMatcher.JAVA_LOWER_CASE") { + @Override public boolean matches(char c) { + return Character.isLowerCase(c); + } + }; + + /** + * Determines whether a character is an ISO control character as specified by {@link + * Character#isISOControl(char)}. + */ + public static final CharMatcher JAVA_ISO_CONTROL = + inRange('\u0000', '\u001f') + .or(inRange('\u007f', '\u009f')) + .withToString("CharMatcher.JAVA_ISO_CONTROL"); + + /** + * Determines whether a character is invisible; that is, if its Unicode category is any of + * SPACE_SEPARATOR, LINE_SEPARATOR, PARAGRAPH_SEPARATOR, CONTROL, FORMAT, SURROGATE, and + * PRIVATE_USE according to ICU4J. + */ + public static final CharMatcher INVISIBLE = inRange('\u0000', '\u0020') + .or(inRange('\u007f', '\u00a0')) + .or(is('\u00ad')) + .or(inRange('\u0600', '\u0604')) + .or(anyOf("\u06dd\u070f\u1680\u180e")) + .or(inRange('\u2000', '\u200f')) + .or(inRange('\u2028', '\u202f')) + .or(inRange('\u205f', '\u2064')) + .or(inRange('\u206a', '\u206f')) + .or(is('\u3000')) + .or(inRange('\ud800', '\uf8ff')) + .or(anyOf("\ufeff\ufff9\ufffa\ufffb")) + .withToString("CharMatcher.INVISIBLE") + .precomputed(); + + /** + * Determines whether a character is single-width (not double-width). When in doubt, this matcher + * errs on the side of returning {@code false} (that is, it tends to assume a character is + * double-width). + * + * <p><b>Note:</b> as the reference file evolves, we will modify this constant to keep it up to + * date. + */ + public static final CharMatcher SINGLE_WIDTH = inRange('\u0000', '\u04f9') + .or(is('\u05be')) + .or(inRange('\u05d0', '\u05ea')) + .or(is('\u05f3')) + .or(is('\u05f4')) + .or(inRange('\u0600', '\u06ff')) + .or(inRange('\u0750', '\u077f')) + .or(inRange('\u0e00', '\u0e7f')) + .or(inRange('\u1e00', '\u20af')) + .or(inRange('\u2100', '\u213a')) + .or(inRange('\ufb50', '\ufdff')) + .or(inRange('\ufe70', '\ufeff')) + .or(inRange('\uff61', '\uffdc')) + .withToString("CharMatcher.SINGLE_WIDTH") + .precomputed(); + + /** Matches any character. */ + public static final CharMatcher ANY = + new CharMatcher("CharMatcher.ANY") { + @Override public boolean matches(char c) { + return true; + } + + @Override public int indexIn(CharSequence sequence) { + return (sequence.length() == 0) ? -1 : 0; + } + + @Override public int indexIn(CharSequence sequence, int start) { + int length = sequence.length(); + Preconditions.checkPositionIndex(start, length); + return (start == length) ? -1 : start; + } + + @Override public int lastIndexIn(CharSequence sequence) { + return sequence.length() - 1; + } + + @Override public boolean matchesAllOf(CharSequence sequence) { + checkNotNull(sequence); + return true; + } + + @Override public boolean matchesNoneOf(CharSequence sequence) { + return sequence.length() == 0; + } + + @Override public String removeFrom(CharSequence sequence) { + checkNotNull(sequence); + return ""; + } + + @Override public String replaceFrom(CharSequence sequence, char replacement) { + char[] array = new char[sequence.length()]; + Arrays.fill(array, replacement); + return new String(array); + } + + @Override public String replaceFrom(CharSequence sequence, CharSequence replacement) { + StringBuilder retval = new StringBuilder(sequence.length() * replacement.length()); + for (int i = 0; i < sequence.length(); i++) { + retval.append(replacement); + } + return retval.toString(); + } + + @Override public String collapseFrom(CharSequence sequence, char replacement) { + return (sequence.length() == 0) ? "" : String.valueOf(replacement); + } + + @Override public String trimFrom(CharSequence sequence) { + checkNotNull(sequence); + return ""; + } + + @Override public int countIn(CharSequence sequence) { + return sequence.length(); + } + + @Override public CharMatcher and(CharMatcher other) { + return checkNotNull(other); + } + + @Override public CharMatcher or(CharMatcher other) { + checkNotNull(other); + return this; + } + + @Override public CharMatcher negate() { + return NONE; + } + + @Override public CharMatcher precomputed() { + return this; + } + }; + + /** Matches no characters. */ + public static final CharMatcher NONE = + new CharMatcher("CharMatcher.NONE") { + @Override public boolean matches(char c) { + return false; + } + + @Override public int indexIn(CharSequence sequence) { + checkNotNull(sequence); + return -1; + } + + @Override public int indexIn(CharSequence sequence, int start) { + int length = sequence.length(); + Preconditions.checkPositionIndex(start, length); + return -1; + } + + @Override public int lastIndexIn(CharSequence sequence) { + checkNotNull(sequence); + return -1; + } + + @Override public boolean matchesAllOf(CharSequence sequence) { + return sequence.length() == 0; + } + + @Override public boolean matchesNoneOf(CharSequence sequence) { + checkNotNull(sequence); + return true; + } + + @Override public String removeFrom(CharSequence sequence) { + return sequence.toString(); + } + + @Override public String replaceFrom(CharSequence sequence, char replacement) { + return sequence.toString(); + } + + @Override public String replaceFrom(CharSequence sequence, CharSequence replacement) { + checkNotNull(replacement); + return sequence.toString(); + } + + @Override public String collapseFrom(CharSequence sequence, char replacement) { + return sequence.toString(); + } + + @Override public String trimFrom(CharSequence sequence) { + return sequence.toString(); + } + + @Override public int countIn(CharSequence sequence) { + checkNotNull(sequence); + return 0; + } + + @Override public CharMatcher and(CharMatcher other) { + checkNotNull(other); + return this; + } + + @Override public CharMatcher or(CharMatcher other) { + return checkNotNull(other); + } + + @Override public CharMatcher negate() { + return ANY; + } + + @Override void setBits(LookupTable table) {} + + @Override public CharMatcher precomputed() { + return this; + } + }; + + // Static factories + + /** + * Returns a {@code char} matcher that matches only one specified character. + */ + public static CharMatcher is(final char match) { + String description = new StringBuilder("CharMatcher.is(") + .append(Integer.toHexString(match)) + .append(")") + .toString(); + return new CharMatcher(description) { + @Override public boolean matches(char c) { + return c == match; + } + + @Override public String replaceFrom(CharSequence sequence, char replacement) { + return sequence.toString().replace(match, replacement); + } + + @Override public CharMatcher and(CharMatcher other) { + return other.matches(match) ? this : NONE; + } + + @Override public CharMatcher or(CharMatcher other) { + return other.matches(match) ? other : super.or(other); + } + + @Override public CharMatcher negate() { + return isNot(match); + } + + @Override void setBits(LookupTable table) { + table.set(match); + } + + @Override public CharMatcher precomputed() { + return this; + } + }; + } + + /** + * Returns a {@code char} matcher that matches any character except the one specified. + * + * <p>To negate another {@code CharMatcher}, use {@link #negate()}. + */ + public static CharMatcher isNot(final char match) { + String description = new StringBuilder("CharMatcher.isNot(") + .append(Integer.toHexString(match)) + .append(")") + .toString(); + return new CharMatcher(description) { + @Override public boolean matches(char c) { + return c != match; + } + + @Override public CharMatcher and(CharMatcher other) { + return other.matches(match) ? super.and(other) : other; + } + + @Override public CharMatcher or(CharMatcher other) { + return other.matches(match) ? ANY : this; + } + + @Override public CharMatcher negate() { + return is(match); + } + }; + } + + /** + * Returns a {@code char} matcher that matches any character present in the given character + * sequence. + */ + public static CharMatcher anyOf(final CharSequence sequence) { + switch (sequence.length()) { + case 0: + return NONE; + case 1: + return is(sequence.charAt(0)); + case 2: + final char match1 = sequence.charAt(0); + final char match2 = sequence.charAt(1); + return new CharMatcher( + new StringBuilder("CharMatcher.anyOf(\"").append(sequence).append("\")").toString()) { + @Override public boolean matches(char c) { + return c == match1 || c == match2; + } + + @Override void setBits(LookupTable table) { + table.set(match1); + table.set(match2); + } + + @Override public CharMatcher precomputed() { + return this; + } + }; + } + final char[] chars = sequence.toString().toCharArray(); + Arrays.sort(chars); + + return new CharMatcher(new StringBuilder("CharMatcher.anyOf(\"").append(chars) + .append("\")").toString()) { + @Override public boolean matches(char c) { + return Arrays.binarySearch(chars, c) >= 0; + } + }; + } + + /** + * Returns a {@code char} matcher that matches any character not present in the given character + * sequence. + */ + public static CharMatcher noneOf(CharSequence sequence) { + return anyOf(sequence).negate(); + } + + /** + * Returns a {@code char} matcher that matches any character in a given range (both endpoints are + * inclusive). For example, to match any lowercase letter of the English alphabet, use {@code + * CharMatcher.inRange('a', 'z')}. + * + * @throws IllegalArgumentException if {@code endInclusive < startInclusive} + */ + public static CharMatcher inRange(final char startInclusive, final char endInclusive) { + checkArgument(endInclusive >= startInclusive); + String description = new StringBuilder("CharMatcher.inRange(") + .append(Integer.toHexString(startInclusive)) + .append(", ") + .append(Integer.toHexString(endInclusive)) + .append(")") + .toString(); + return inRange(startInclusive, endInclusive, description); + } + + static CharMatcher inRange(final char startInclusive, final char endInclusive, + String description) { + return new CharMatcher(description) { + @Override public boolean matches(char c) { + return startInclusive <= c && c <= endInclusive; + } + + @Override void setBits(LookupTable table) { + char c = startInclusive; + while (true) { + table.set(c); + if (c++ == endInclusive) { + break; + } + } + } + + @Override public CharMatcher precomputed() { + return this; + } + }; + } + + /** + * Returns a matcher with identical behavior to the given {@link Character}-based predicate, but + * which operates on primitive {@code char} instances instead. + */ + public static CharMatcher forPredicate(final Predicate<? super Character> predicate) { + checkNotNull(predicate); + if (predicate instanceof CharMatcher) { + return (CharMatcher) predicate; + } + String description = new StringBuilder("CharMatcher.forPredicate(") + .append(predicate) + .append(')') + .toString(); + return new CharMatcher(description) { + @Override public boolean matches(char c) { + return predicate.apply(c); + } + + @Override public boolean apply(Character character) { + return predicate.apply(checkNotNull(character)); + } + }; + } + + // State + final String description; + + // Constructors + + /** + * Sets the {@code toString()} from the given description. + */ + CharMatcher(String description) { + this.description = description; + } + + /** + * Constructor for use by subclasses. When subclassing, you may want to override + * {@code toString()} to provide a useful description. + */ + protected CharMatcher() { + description = "UnknownCharMatcher"; + } + + // Abstract methods + + /** Determines a true or false value for the given character. */ + public abstract boolean matches(char c); + + // Non-static factories + + /** + * Returns a matcher that matches any character not matched by this matcher. + */ + public CharMatcher negate() { + final CharMatcher original = this; + return new CharMatcher(original + ".negate()") { + @Override public boolean matches(char c) { + return !original.matches(c); + } + + @Override public boolean matchesAllOf(CharSequence sequence) { + return original.matchesNoneOf(sequence); + } + + @Override public boolean matchesNoneOf(CharSequence sequence) { + return original.matchesAllOf(sequence); + } + + @Override public int countIn(CharSequence sequence) { + return sequence.length() - original.countIn(sequence); + } + + @Override public CharMatcher negate() { + return original; + } + }; + } + + /** + * Returns a matcher that matches any character matched by both this matcher and {@code other}. + */ + public CharMatcher and(CharMatcher other) { + return new And(this, checkNotNull(other)); + } + + private static class And extends CharMatcher { + final CharMatcher first; + final CharMatcher second; + + And(CharMatcher a, CharMatcher b) { + this(a, b, "CharMatcher.and(" + a + ", " + b + ")"); + } + + And(CharMatcher a, CharMatcher b, String description) { + super(description); + first = checkNotNull(a); + second = checkNotNull(b); + } + + @Override + public CharMatcher and(CharMatcher other) { + return new And(this, other); + } + + @Override + public boolean matches(char c) { + return first.matches(c) && second.matches(c); + } + + @Override + CharMatcher withToString(String description) { + return new And(first, second, description); + } + } + + /** + * Returns a matcher that matches any character matched by either this matcher or {@code other}. + */ + public CharMatcher or(CharMatcher other) { + return new Or(this, checkNotNull(other)); + } + + private static class Or extends CharMatcher { + final CharMatcher first; + final CharMatcher second; + + Or(CharMatcher a, CharMatcher b, String description) { + super(description); + first = checkNotNull(a); + second = checkNotNull(b); + } + + Or(CharMatcher a, CharMatcher b) { + this(a, b, "CharMatcher.or(" + a + ", " + b + ")"); + } + + @Override + public CharMatcher or(CharMatcher other) { + return new Or(this, checkNotNull(other)); + } + + @Override + public boolean matches(char c) { + return first.matches(c) || second.matches(c); + } + + @Override + CharMatcher withToString(String description) { + return new Or(first, second, description); + } + } + + /** + * Returns a {@code char} matcher functionally equivalent to this one, but which may be faster to + * query than the original; your mileage may vary. Precomputation takes time and is likely to be + * worthwhile only if the precomputed matcher is queried many thousands of times. + * + * <p>This method has no effect (returns {@code this}) when called in GWT: it's unclear whether a + * precomputed matcher is faster, but it certainly consumes more memory, which doesn't seem like a + * worthwhile tradeoff in a browser. + */ + public CharMatcher precomputed() { + return Platform.precomputeCharMatcher(this); + } + + /** + * Construct an array of all possible chars in the slowest way possible. + */ + char[] slowGetChars() { + char[] allChars = new char[65536]; + int size = 0; + for (int c = Character.MIN_VALUE; c <= Character.MAX_VALUE; c++) { + if (matches((char) c)) { + allChars[size++] = (char) c; + } + } + char[] retValue = new char[size]; + System.arraycopy(allChars, 0, retValue, 0, size); + return retValue; + } + + /** + * This is the actual implementation of {@link #precomputed}, but we bounce calls through a method + * on {@link Platform} so that we can have different behavior in GWT. + * + * <p>If the number of matched characters is small enough, we try to build a small hash + * table to contain all of the characters. Otherwise, we record the characters in eight-kilobyte + * bit array. In many situations this produces a matcher which is faster to query + * than the original. + */ + CharMatcher precomputedInternal() { + final char[] chars = slowGetChars(); + int totalCharacters = chars.length; + if (totalCharacters == 0) { + return NONE; + } else if (totalCharacters == 1) { + return is(chars[0]); + } else if (totalCharacters < SmallCharMatcher.MAX_SIZE) { + return SmallCharMatcher.from(chars, toString()); + } else if (totalCharacters < MediumCharMatcher.MAX_SIZE) { + return MediumCharMatcher.from(chars, toString()); + } + // Otherwise, make the full lookup table. + final LookupTable table = new LookupTable(); + setBits(table); + final CharMatcher outer = this; + + return new CharMatcher(outer.toString()) { + @Override public boolean matches(char c) { + return table.get(c); + } + + // TODO(kevinb): make methods like negate() smart? + + @Override public CharMatcher precomputed() { + return this; + } + }; + } + + /** + * Subclasses should provide a new CharMatcher with the same characteristics as {@code this}, + * but with their {@code toString} method overridden with the new description. + * + * <p>This is unsupported by default. + */ + CharMatcher withToString(String description) { + throw new UnsupportedOperationException(); + + } + + /** + * For use by implementors; sets the bit corresponding to each character ('\0' to '{@literal + * \}uFFFF') that matches this matcher in the given bit array, leaving all other bits untouched. + * + * <p>The default implementation loops over every possible character value, invoking {@link + * #matches} for each one. + */ + void setBits(LookupTable table) { + char c = Character.MIN_VALUE; + while (true) { + if (matches(c)) { + table.set(c); + } + if (c++ == Character.MAX_VALUE) { + break; + } + } + } + + /** + * A bit array with one bit per {@code char} value, used by {@link CharMatcher#precomputed}. + * + * <p>TODO(kevinb): possibly share a common BitArray class with BloomFilter and others... a + * simpler java.util.BitSet. + */ + private static final class LookupTable { + int[] data = new int[2048]; + + void set(char index) { + data[index >> 5] |= (1 << index); + } + + boolean get(char index) { + return (data[index >> 5] & (1 << index)) != 0; + } + } + + // Text processing routines + + /** + * Returns {@code true} if a character sequence contains at least one matching character. + * Equivalent to {@code !matchesNoneOf(sequence)}. + * + * <p>The default implementation iterates over the sequence, invoking {@link #matches} for each + * character, until this returns {@code true} or the end is reached. + * + * @param sequence the character sequence to examine, possibly empty + * @return {@code true} if this matcher matches at least one character in the sequence + * @since 8.0 + */ + public boolean matchesAnyOf(CharSequence sequence) { + return !matchesNoneOf(sequence); + } + + /** + * Returns {@code true} if a character sequence contains only matching characters. + * + * <p>The default implementation iterates over the sequence, invoking {@link #matches} for each + * character, until this returns {@code false} or the end is reached. + * + * @param sequence the character sequence to examine, possibly empty + * @return {@code true} if this matcher matches every character in the sequence, including when + * the sequence is empty + */ + public boolean matchesAllOf(CharSequence sequence) { + for (int i = sequence.length() - 1; i >= 0; i--) { + if (!matches(sequence.charAt(i))) { + return false; + } + } + return true; + } + + /** + * Returns {@code true} if a character sequence contains no matching characters. Equivalent to + * {@code !matchesAnyOf(sequence)}. + * + * <p>The default implementation iterates over the sequence, invoking {@link #matches} for each + * character, until this returns {@code false} or the end is reached. + * + * @param sequence the character sequence to examine, possibly empty + * @return {@code true} if this matcher matches every character in the sequence, including when + * the sequence is empty + */ + public boolean matchesNoneOf(CharSequence sequence) { + return indexIn(sequence) == -1; + } + + /** + * Returns the index of the first matching character in a character sequence, or {@code -1} if no + * matching character is present. + * + * <p>The default implementation iterates over the sequence in forward order calling {@link + * #matches} for each character. + * + * @param sequence the character sequence to examine from the beginning + * @return an index, or {@code -1} if no character matches + */ + public int indexIn(CharSequence sequence) { + int length = sequence.length(); + for (int i = 0; i < length; i++) { + if (matches(sequence.charAt(i))) { + return i; + } + } + return -1; + } + + /** + * Returns the index of the first matching character in a character sequence, starting from a + * given position, or {@code -1} if no character matches after that position. + * + * <p>The default implementation iterates over the sequence in forward order, beginning at {@code + * start}, calling {@link #matches} for each character. + * + * @param sequence the character sequence to examine + * @param start the first index to examine; must be nonnegative and no greater than {@code + * sequence.length()} + * @return the index of the first matching character, guaranteed to be no less than {@code start}, + * or {@code -1} if no character matches + * @throws IndexOutOfBoundsException if start is negative or greater than {@code + * sequence.length()} + */ + public int indexIn(CharSequence sequence, int start) { + int length = sequence.length(); + Preconditions.checkPositionIndex(start, length); + for (int i = start; i < length; i++) { + if (matches(sequence.charAt(i))) { + return i; + } + } + return -1; + } + + /** + * Returns the index of the last matching character in a character sequence, or {@code -1} if no + * matching character is present. + * + * <p>The default implementation iterates over the sequence in reverse order calling {@link + * #matches} for each character. + * + * @param sequence the character sequence to examine from the end + * @return an index, or {@code -1} if no character matches + */ + public int lastIndexIn(CharSequence sequence) { + for (int i = sequence.length() - 1; i >= 0; i--) { + if (matches(sequence.charAt(i))) { + return i; + } + } + return -1; + } + + /** + * Returns the number of matching characters found in a character sequence. + */ + public int countIn(CharSequence sequence) { + int count = 0; + for (int i = 0; i < sequence.length(); i++) { + if (matches(sequence.charAt(i))) { + count++; + } + } + return count; + } + + /** + * Returns a string containing all non-matching characters of a character sequence, in order. For + * example: <pre> {@code + * + * CharMatcher.is('a').removeFrom("bazaar")}</pre> + * + * ... returns {@code "bzr"}. + */ + @CheckReturnValue + public String removeFrom(CharSequence sequence) { + String string = sequence.toString(); + int pos = indexIn(string); + if (pos == -1) { + return string; + } + + char[] chars = string.toCharArray(); + int spread = 1; + + // This unusual loop comes from extensive benchmarking + OUT: while (true) { + pos++; + while (true) { + if (pos == chars.length) { + break OUT; + } + if (matches(chars[pos])) { + break; + } + chars[pos - spread] = chars[pos]; + pos++; + } + spread++; + } + return new String(chars, 0, pos - spread); + } + + /** + * Returns a string containing all matching characters of a character sequence, in order. For + * example: <pre> {@code + * + * CharMatcher.is('a').retainFrom("bazaar")}</pre> + * + * ... returns {@code "aaa"}. + */ + @CheckReturnValue + public String retainFrom(CharSequence sequence) { + return negate().removeFrom(sequence); + } + + /** + * Returns a string copy of the input character sequence, with each character that matches this + * matcher replaced by a given replacement character. For example: <pre> {@code + * + * CharMatcher.is('a').replaceFrom("radar", 'o')}</pre> + * + * ... returns {@code "rodor"}. + * + * <p>The default implementation uses {@link #indexIn(CharSequence)} to find the first matching + * character, then iterates the remainder of the sequence calling {@link #matches(char)} for each + * character. + * + * @param sequence the character sequence to replace matching characters in + * @param replacement the character to append to the result string in place of each matching + * character in {@code sequence} + * @return the new string + */ + @CheckReturnValue + public String replaceFrom(CharSequence sequence, char replacement) { + String string = sequence.toString(); + int pos = indexIn(string); + if (pos == -1) { + return string; + } + char[] chars = string.toCharArray(); + chars[pos] = replacement; + for (int i = pos + 1; i < chars.length; i++) { + if (matches(chars[i])) { + chars[i] = replacement; + } + } + return new String(chars); + } + + /** + * Returns a string copy of the input character sequence, with each character that matches this + * matcher replaced by a given replacement sequence. For example: <pre> {@code + * + * CharMatcher.is('a').replaceFrom("yaha", "oo")}</pre> + * + * ... returns {@code "yoohoo"}. + * + * <p><b>Note:</b> If the replacement is a fixed string with only one character, you are better + * off calling {@link #replaceFrom(CharSequence, char)} directly. + * + * @param sequence the character sequence to replace matching characters in + * @param replacement the characters to append to the result string in place of each matching + * character in {@code sequence} + * @return the new string + */ + @CheckReturnValue + public String replaceFrom(CharSequence sequence, CharSequence replacement) { + int replacementLen = replacement.length(); + if (replacementLen == 0) { + return removeFrom(sequence); + } + if (replacementLen == 1) { + return replaceFrom(sequence, replacement.charAt(0)); + } + + String string = sequence.toString(); + int pos = indexIn(string); + if (pos == -1) { + return string; + } + + int len = string.length(); + StringBuilder buf = new StringBuilder((len * 3 / 2) + 16); + + int oldpos = 0; + do { + buf.append(string, oldpos, pos); + buf.append(replacement); + oldpos = pos + 1; + pos = indexIn(string, oldpos); + } while (pos != -1); + + buf.append(string, oldpos, len); + return buf.toString(); + } + + /** + * Returns a substring of the input character sequence that omits all characters this matcher + * matches from the beginning and from the end of the string. For example: <pre> {@code + * + * CharMatcher.anyOf("ab").trimFrom("abacatbab")}</pre> + * + * ... returns {@code "cat"}. + * + * <p>Note that: <pre> {@code + * + * CharMatcher.inRange('\0', ' ').trimFrom(str)}</pre> + * + * ... is equivalent to {@link String#trim()}. + */ + @CheckReturnValue + public String trimFrom(CharSequence sequence) { + int len = sequence.length(); + int first; + int last; + + for (first = 0; first < len; first++) { + if (!matches(sequence.charAt(first))) { + break; + } + } + for (last = len - 1; last > first; last--) { + if (!matches(sequence.charAt(last))) { + break; + } + } + + return sequence.subSequence(first, last + 1).toString(); + } + + /** + * Returns a substring of the input character sequence that omits all characters this matcher + * matches from the beginning of the string. For example: <pre> {@code + * + * CharMatcher.anyOf("ab").trimLeadingFrom("abacatbab")}</pre> + * + * ... returns {@code "catbab"}. + */ + @CheckReturnValue + public String trimLeadingFrom(CharSequence sequence) { + int len = sequence.length(); + int first; + + for (first = 0; first < len; first++) { + if (!matches(sequence.charAt(first))) { + break; + } + } + + return sequence.subSequence(first, len).toString(); + } + + /** + * Returns a substring of the input character sequence that omits all characters this matcher + * matches from the end of the string. For example: <pre> {@code + * + * CharMatcher.anyOf("ab").trimTrailingFrom("abacatbab")}</pre> + * + * ... returns {@code "abacat"}. + */ + @CheckReturnValue + public String trimTrailingFrom(CharSequence sequence) { + int len = sequence.length(); + int last; + + for (last = len - 1; last >= 0; last--) { + if (!matches(sequence.charAt(last))) { + break; + } + } + + return sequence.subSequence(0, last + 1).toString(); + } + + /** + * Returns a string copy of the input character sequence, with each group of consecutive + * characters that match this matcher replaced by a single replacement character. For example: + * <pre> {@code + * + * CharMatcher.anyOf("eko").collapseFrom("bookkeeper", '-')}</pre> + * + * ... returns {@code "b-p-r"}. + * + * <p>The default implementation uses {@link #indexIn(CharSequence)} to find the first matching + * character, then iterates the remainder of the sequence calling {@link #matches(char)} for each + * character. + * + * @param sequence the character sequence to replace matching groups of characters in + * @param replacement the character to append to the result string in place of each group of + * matching characters in {@code sequence} + * @return the new string + */ + @CheckReturnValue + public String collapseFrom(CharSequence sequence, char replacement) { + int first = indexIn(sequence); + if (first == -1) { + return sequence.toString(); + } + + // TODO(kevinb): see if this implementation can be made faster + StringBuilder builder = new StringBuilder(sequence.length()) + .append(sequence.subSequence(0, first)) + .append(replacement); + boolean in = true; + for (int i = first + 1; i < sequence.length(); i++) { + char c = sequence.charAt(i); + if (matches(c)) { + if (!in) { + builder.append(replacement); + in = true; + } + } else { + builder.append(c); + in = false; + } + } + return builder.toString(); + } + + /** + * Collapses groups of matching characters exactly as {@link #collapseFrom} does, except that + * groups of matching characters at the start or end of the sequence are removed without + * replacement. + */ + @CheckReturnValue + public String trimAndCollapseFrom(CharSequence sequence, char replacement) { + int first = negate().indexIn(sequence); + if (first == -1) { + return ""; // everything matches. nothing's left. + } + StringBuilder builder = new StringBuilder(sequence.length()); + boolean inMatchingGroup = false; + for (int i = first; i < sequence.length(); i++) { + char c = sequence.charAt(i); + if (matches(c)) { + inMatchingGroup = true; + } else { + if (inMatchingGroup) { + builder.append(replacement); + inMatchingGroup = false; + } + builder.append(c); + } + } + return builder.toString(); + } + + // Predicate interface + + /** + * Returns {@code true} if this matcher matches the given character. + * + * @throws NullPointerException if {@code character} is null + */ + @Override public boolean apply(Character character) { + return matches(character); + } + + /** + * Returns a string representation of this {@code CharMatcher}, such as + * {@code CharMatcher.or(WHITESPACE, JAVA_DIGIT)}. + */ + @Override + public String toString() { + return description; + } + + /** + * Determines whether a character is whitespace according to the latest Unicode standard, as + * illustrated + * <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7Bwhitespace%7D">here</a>. + * This is not the same definition used by other Java APIs. (See a + * <a href="http://spreadsheets.google.com/pub?key=pd8dAQyHbdewRsnE5x5GzKQ">comparison of several + * definitions of "whitespace"</a>.) + * + * <p><b>Note:</b> as the Unicode definition evolves, we will modify this constant to keep it up + * to date. + */ + public static final CharMatcher WHITESPACE = new CharMatcher("CharMatcher.WHITESPACE") { + /** + * A special-case CharMatcher for Unicode whitespace characters that is extremely + * efficient both in space required and in time to check for matches. + * + * Implementation details. + * It turns out that all current (early 2012) Unicode characters are unique modulo 79: + * so we can construct a lookup table of exactly 79 entries, and just check the character code + * mod 79, and see if that character is in the table. + * + * There is a 1 at the beginning of the table so that the null character is not listed + * as whitespace. + * + * Other things we tried that did not prove to be beneficial, mostly due to speed concerns: + * + * * Binary search into the sorted list of characters, i.e., what + * CharMatcher.anyOf() does</li> + * * Perfect hash function into a table of size 26 (using an offset table and a special + * Jenkins hash function)</li> + * * Perfect-ish hash function that required two lookups into a single table of size 26.</li> + * * Using a power-of-2 sized hash table (size 64) with linear probing.</li> + * + * --Christopher Swenson, February 2012. + */ + + // Mod-79 lookup table. + private final char[] table = {1, 0, 160, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 0, 0, + 8232, 8233, 0, 0, 0, 0, 0, 8239, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, + 8200, 8201, 8202, 0, 0, 0, 0, 0, 8287, 5760, 0, 0, 6158, 0, 0, 0}; + + @Override public boolean matches(char c) { + return table[c % 79] == c; + } + + @Override public CharMatcher precomputed() { + return this; + } + }; +} diff --git a/guava/src/com/google/common/base/Charsets.java b/guava/src/com/google/common/base/Charsets.java new file mode 100644 index 0000000..79c9128 --- /dev/null +++ b/guava/src/com/google/common/base/Charsets.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.GwtIncompatible; + +import java.nio.charset.Charset; + +/** + * Contains constant definitions for the six standard {@link Charset} instances, which are + * guaranteed to be supported by all Java platform implementations. + * + * <p>Assuming you're free to choose, note that <b>{@link #UTF_8} is widely preferred</b>. + * + * <p>See the Guava User Guide article on <a + * href="http://code.google.com/p/guava-libraries/wiki/StringsExplained#Charsets"> + * {@code Charsets}</a>. + * + * @author Mike Bostock + * @since 1.0 + */ +@GwtCompatible(emulated = true) +public final class Charsets { + private Charsets() {} + + /** + * US-ASCII: seven-bit ASCII, the Basic Latin block of the Unicode character set (ISO646-US). + */ + @GwtIncompatible("Non-UTF-8 Charset") + public static final Charset US_ASCII = Charset.forName("US-ASCII"); + + /** + * ISO-8859-1: ISO Latin Alphabet Number 1 (ISO-LATIN-1). + */ + @GwtIncompatible("Non-UTF-8 Charset") + public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + + /** + * UTF-8: eight-bit UCS Transformation Format. + */ + public static final Charset UTF_8 = Charset.forName("UTF-8"); + + /** + * UTF-16BE: sixteen-bit UCS Transformation Format, big-endian byte order. + */ + @GwtIncompatible("Non-UTF-8 Charset") + public static final Charset UTF_16BE = Charset.forName("UTF-16BE"); + + /** + * UTF-16LE: sixteen-bit UCS Transformation Format, little-endian byte order. + */ + @GwtIncompatible("Non-UTF-8 Charset") + public static final Charset UTF_16LE = Charset.forName("UTF-16LE"); + + /** + * UTF-16: sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order + * mark. + */ + @GwtIncompatible("Non-UTF-8 Charset") + public static final Charset UTF_16 = Charset.forName("UTF-16"); + + /* + * Please do not add new Charset references to this class, unless those character encodings are + * part of the set required to be supported by all Java platform implementations! Any Charsets + * initialized here may cause unexpected delays when this class is loaded. See the Charset + * Javadocs for the list of built-in character encodings. + */ +} diff --git a/guava/src/com/google/common/base/Defaults.java b/guava/src/com/google/common/base/Defaults.java new file mode 100644 index 0000000..b3e8555 --- /dev/null +++ b/guava/src/com/google/common/base/Defaults.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * This class provides default values for all Java types, as defined by the JLS. + * + * @author Ben Yu + * @since 1.0 + */ +public final class Defaults { + private Defaults() {} + + private static final Map<Class<?>, Object> DEFAULTS; + + static { + Map<Class<?>, Object> map = new HashMap<Class<?>, Object>(); + put(map, boolean.class, false); + put(map, char.class, '\0'); + put(map, byte.class, (byte) 0); + put(map, short.class, (short) 0); + put(map, int.class, 0); + put(map, long.class, 0L); + put(map, float.class, 0f); + put(map, double.class, 0d); + DEFAULTS = Collections.unmodifiableMap(map); + } + + private static <T> void put(Map<Class<?>, Object> map, Class<T> type, T value) { + map.put(type, value); + } + + /** + * Returns the default value of {@code type} as defined by JLS --- {@code 0} for numbers, {@code + * false} for {@code boolean} and {@code '\0'} for {@code char}. For non-primitive types and + * {@code void}, null is returned. + */ + @SuppressWarnings("unchecked") + public static <T> T defaultValue(Class<T> type) { + return (T) DEFAULTS.get(type); + } +} diff --git a/guava/src/com/google/common/base/Enums.java b/guava/src/com/google/common/base/Enums.java new file mode 100644 index 0000000..6105410 --- /dev/null +++ b/guava/src/com/google/common/base/Enums.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.GwtIncompatible; + +import java.io.Serializable; +import java.lang.reflect.Field; + +import javax.annotation.Nullable; + +/** + * Utility methods for working with {@link Enum} instances. + * + * @author Steve McKay + * + * @since 9.0 + */ +@GwtCompatible(emulated = true) +@Beta +public final class Enums { + + private Enums() {} + + /** + * Returns the {@link Field} in which {@code enumValue} is defined. + * For example, to get the {@code Description} annotation on the {@code GOLF} + * constant of enum {@code Sport}, use + * {@code Enums.getField(Sport.GOLF).getAnnotation(Description.class)}. + * + * @since 12.0 + */ + @GwtIncompatible("reflection") + public static Field getField(Enum<?> enumValue) { + Class<?> clazz = enumValue.getDeclaringClass(); + try { + return clazz.getDeclaredField(enumValue.name()); + } catch (NoSuchFieldException impossible) { + throw new AssertionError(impossible); + } + } + + /** + * Returns a {@link Function} that maps an {@link Enum} name to the associated + * {@code Enum} constant. The {@code Function} will return {@code null} if the + * {@code Enum} constant does not exist. + * + * @param enumClass the {@link Class} of the {@code Enum} declaring the + * constant values. + */ + public static <T extends Enum<T>> Function<String, T> valueOfFunction(Class<T> enumClass) { + return new ValueOfFunction<T>(enumClass); + } + + /** + * A {@link Function} that maps an {@link Enum} name to the associated + * constant, or {@code null} if the constant does not exist. + */ + private static final class ValueOfFunction<T extends Enum<T>> + implements Function<String, T>, Serializable { + + private final Class<T> enumClass; + + private ValueOfFunction(Class<T> enumClass) { + this.enumClass = checkNotNull(enumClass); + } + + @Override + public T apply(String value) { + try { + return Enum.valueOf(enumClass, value); + } catch (IllegalArgumentException e) { + return null; + } + } + + @Override public boolean equals(@Nullable Object obj) { + return obj instanceof ValueOfFunction && + enumClass.equals(((ValueOfFunction) obj).enumClass); + } + + @Override public int hashCode() { + return enumClass.hashCode(); + } + + @Override public String toString() { + return "Enums.valueOf(" + enumClass + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns an optional enum constant for the given type, using {@link Enum#valueOf}. If the + * constant does not exist, {@link Optional#absent} is returned. A common use case is for parsing + * user input or falling back to a default enum constant. For example, + * {@code Enums.getIfPresent(Country.class, countryInput).or(Country.DEFAULT);} + * + * @since 12.0 + */ + public static <T extends Enum<T>> Optional<T> getIfPresent(Class<T> enumClass, String value) { + checkNotNull(enumClass); + checkNotNull(value); + try { + return Optional.of(Enum.valueOf(enumClass, value)); + } catch (IllegalArgumentException iae) { + return Optional.absent(); + } + } +} diff --git a/guava/src/com/google/common/base/Equivalence.java b/guava/src/com/google/common/base/Equivalence.java new file mode 100644 index 0000000..d039283 --- /dev/null +++ b/guava/src/com/google/common/base/Equivalence.java @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2010 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; + +import java.io.Serializable; + +import javax.annotation.Nullable; + +/** + * A strategy for determining whether two instances are considered equivalent. Examples of + * equivalences are the {@link Equivalences#identity() identity equivalence} and {@link + * Equivalences#equals equals equivalence}. + * + * @author Bob Lee + * @author Ben Yu + * @author Gregory Kick + * @since 10.0 (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility" + * >mostly source-compatible</a> since 4.0) + */ +@GwtCompatible +public abstract class Equivalence<T> { + /** + * Constructor for use by subclasses. + */ + protected Equivalence() {} + + /** + * Returns {@code true} if the given objects are considered equivalent. + * + * <p>The {@code equivalent} method implements an equivalence relation on object references: + * + * <ul> + * <li>It is <i>reflexive</i>: for any reference {@code x}, including null, {@code + * equivalent(x, x)} returns {@code true}. + * <li>It is <i>symmetric</i>: for any references {@code x} and {@code y}, {@code + * equivalent(x, y) == equivalent(y, x)}. + * <li>It is <i>transitive</i>: for any references {@code x}, {@code y}, and {@code z}, if + * {@code equivalent(x, y)} returns {@code true} and {@code equivalent(y, z)} returns {@code + * true}, then {@code equivalent(x, z)} returns {@code true}. + * <li>It is <i>consistent</i>: for any references {@code x} and {@code y}, multiple invocations + * of {@code equivalent(x, y)} consistently return {@code true} or consistently return {@code + * false} (provided that neither {@code x} nor {@code y} is modified). + * </ul> + */ + public final boolean equivalent(@Nullable T a, @Nullable T b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + return doEquivalent(a, b); + } + + /** + * Returns {@code true} if {@code a} and {@code b} are considered equivalent. + * + * <p>Called by {@link #equivalent}. {@code a} and {@code b} are not the same + * object and are not nulls. + * + * @since 10.0 (previously, subclasses would override equivalent()) + */ + protected abstract boolean doEquivalent(T a, T b); + + /** + * Returns a hash code for {@code t}. + * + * <p>The {@code hash} has the following properties: + * <ul> + * <li>It is <i>consistent</i>: for any reference {@code x}, multiple invocations of + * {@code hash(x}} consistently return the same value provided {@code x} remains unchanged + * according to the definition of the equivalence. The hash need not remain consistent from + * one execution of an application to another execution of the same application. + * <li>It is <i>distributable accross equivalence</i>: for any references {@code x} and {@code y}, + * if {@code equivalent(x, y)}, then {@code hash(x) == hash(y)}. It is <i>not</i> necessary + * that the hash be distributable accorss <i>inequivalence</i>. If {@code equivalence(x, y)} + * is false, {@code hash(x) == hash(y)} may still be true. + * <li>{@code hash(null)} is {@code 0}. + * </ul> + */ + public final int hash(@Nullable T t) { + if (t == null) { + return 0; + } + return doHash(t); + } + + /** + * Returns a hash code for non-null object {@code t}. + * + * <p>Called by {@link #hash}. + * + * @since 10.0 (previously, subclasses would override hash()) + */ + protected abstract int doHash(T t); + + /** + * Returns a new equivalence relation for {@code F} which evaluates equivalence by first applying + * {@code function} to the argument, then evaluating using {@code this}. That is, for any pair of + * non-null objects {@code x} and {@code y}, {@code + * equivalence.onResultOf(function).equivalent(a, b)} is true if and only if {@code + * equivalence.equivalent(function.apply(a), function.apply(b))} is true. + * + * <p>For example: <pre> {@code + * + * Equivalence<Person> SAME_AGE = Equivalences.equals().onResultOf(GET_PERSON_AGE); + * }</pre> + * + * <p>{@code function} will never be invoked with a null value. + * + * <p>Note that {@code function} must be consistent according to {@code this} equivalence + * relation. That is, invoking {@link Function#apply} multiple times for a given value must return + * equivalent results. + * For example, {@code Equivalences.identity().onResultOf(Functions.toStringFunction())} is broken + * because it's not guaranteed that {@link Object#toString}) always returns the same string + * instance. + * + * @since 10.0 + */ + public final <F> Equivalence<F> onResultOf(Function<F, ? extends T> function) { + return new FunctionalEquivalence<F, T>(function, this); + } + + /** + * Returns a wrapper of {@code reference} that implements + * {@link Wrapper#equals(Object) Object.equals()} such that + * {@code wrap(this, a).equals(wrap(this, b))} if and only if {@code this.equivalent(a, b)}. + * + * @since 10.0 + */ + public final <S extends T> Wrapper<S> wrap(@Nullable S reference) { + return new Wrapper<S>(this, reference); + } + + /** + * Wraps an object so that {@link #equals(Object)} and {@link #hashCode()} delegate to an + * {@link Equivalence}. + * + * <p>For example, given an {@link Equivalence} for {@link String strings} named {@code equiv} + * that tests equivalence using their lengths: + * + * <pre> {@code + * equiv.wrap("a").equals(equiv.wrap("b")) // true + * equiv.wrap("a").equals(equiv.wrap("hello")) // false + * }</pre> + * + * <p>Note in particular that an equivalence wrapper is never equal to the object it wraps. + * + * <pre> {@code + * equiv.wrap(obj).equals(obj) // always false + * }</pre> + * + * @since 10.0 + */ + public static final class Wrapper<T> implements Serializable { + private final Equivalence<? super T> equivalence; + @Nullable private final T reference; + + private Wrapper(Equivalence<? super T> equivalence, @Nullable T reference) { + this.equivalence = checkNotNull(equivalence); + this.reference = reference; + } + + /** Returns the (possibly null) reference wrapped by this instance. */ + @Nullable public T get() { + return reference; + } + + /** + * Returns {@code true} if {@link Equivalence#equivalent(Object, Object)} applied to the wrapped + * references is {@code true} and both wrappers use the {@link Object#equals(Object) same} + * equivalence. + */ + @Override public boolean equals(@Nullable Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof Wrapper) { + Wrapper<?> that = (Wrapper<?>) obj; + /* + * We cast to Equivalence<Object> here because we can't check the type of the reference held + * by the other wrapper. But, by checking that the Equivalences are equal, we know that + * whatever type it is, it is assignable to the type handled by this wrapper's equivalence. + */ + @SuppressWarnings("unchecked") + Equivalence<Object> equivalence = (Equivalence<Object>) this.equivalence; + return equivalence.equals(that.equivalence) + && equivalence.equivalent(this.reference, that.reference); + } else { + return false; + } + } + + /** + * Returns the result of {@link Equivalence#hash(Object)} applied to the the wrapped reference. + */ + @Override public int hashCode() { + return equivalence.hash(reference); + } + + /** + * Returns a string representation for this equivalence wrapper. The form of this string + * representation is not specified. + */ + @Override public String toString() { + return equivalence + ".wrap(" + reference + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns an equivalence over iterables based on the equivalence of their elements. More + * specifically, two iterables are considered equivalent if they both contain the same number of + * elements, and each pair of corresponding elements is equivalent according to + * {@code this}. Null iterables are equivalent to one another. + * + * <p>Note that this method performs a similar function for equivalences as {@link + * com.google.common.collect.Ordering#lexicographical} does for orderings. + * + * @since 10.0 + */ + @GwtCompatible(serializable = true) + public final <S extends T> Equivalence<Iterable<S>> pairwise() { + // Ideally, the returned equivalence would support Iterable<? extends T>. However, + // the need for this is so rare that it's not worth making callers deal with the ugly wildcard. + return new PairwiseEquivalence<S>(this); + } + + /** + * Returns a predicate that evaluates to true if and only if the input is + * equivalent to {@code target} according to this equivalence relation. + * + * @since 10.0 + */ + @Beta + public final Predicate<T> equivalentTo(@Nullable T target) { + return new EquivalentToPredicate<T>(this, target); + } + + private static final class EquivalentToPredicate<T> implements Predicate<T>, Serializable { + + private final Equivalence<T> equivalence; + @Nullable private final T target; + + EquivalentToPredicate(Equivalence<T> equivalence, @Nullable T target) { + this.equivalence = checkNotNull(equivalence); + this.target = target; + } + + @Override public boolean apply(@Nullable T input) { + return equivalence.equivalent(input, target); + } + + @Override public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof EquivalentToPredicate) { + EquivalentToPredicate<?> that = (EquivalentToPredicate<?>) obj; + return equivalence.equals(that.equivalence) + && Objects.equal(target, that.target); + } + return false; + } + + @Override public int hashCode() { + return Objects.hashCode(equivalence, target); + } + + @Override public String toString() { + return equivalence + ".equivalentTo(" + target + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns an equivalence that delegates to {@link Object#equals} and {@link Object#hashCode}. + * {@link Equivalence#equivalent} returns {@code true} if both values are null, or if neither + * value is null and {@link Object#equals} returns {@code true}. {@link Equivalence#hash} returns + * {@code 0} if passed a null value. + * + * @since 13.0 + * @since 8.0 (in Equivalences with null-friendly behavior) + * @since 4.0 (in Equivalences) + */ + public static Equivalence<Object> equals() { + return Equals.INSTANCE; + } + + /** + * Returns an equivalence that uses {@code ==} to compare values and {@link + * System#identityHashCode(Object)} to compute the hash code. {@link Equivalence#equivalent} + * returns {@code true} if {@code a == b}, including in the case that a and b are both null. + * + * @since 13.0 + * @since 4.0 (in Equivalences) + */ + public static Equivalence<Object> identity() { + return Identity.INSTANCE; + } + + static final class Equals extends Equivalence<Object> + implements Serializable { + + static final Equals INSTANCE = new Equals(); + + @Override protected boolean doEquivalent(Object a, Object b) { + return a.equals(b); + } + @Override public int doHash(Object o) { + return o.hashCode(); + } + + private Object readResolve() { + return INSTANCE; + } + private static final long serialVersionUID = 1; + } + + static final class Identity extends Equivalence<Object> + implements Serializable { + + static final Identity INSTANCE = new Identity(); + + @Override protected boolean doEquivalent(Object a, Object b) { + return false; + } + + @Override protected int doHash(Object o) { + return System.identityHashCode(o); + } + + private Object readResolve() { + return INSTANCE; + } + private static final long serialVersionUID = 1; + } +} diff --git a/guava/src/com/google/common/base/Equivalences.java b/guava/src/com/google/common/base/Equivalences.java new file mode 100644 index 0000000..23f947c --- /dev/null +++ b/guava/src/com/google/common/base/Equivalences.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2010 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; + +/** + * Contains static factory methods for creating {@code Equivalence} instances. + * + * <p>All methods return serializable instances. + * + * @author Bob Lee + * @author Kurt Alfred Kluever + * @author Gregory Kick + * @since 4.0 + */ +@Beta +@GwtCompatible +public final class Equivalences { + private Equivalences() {} + + /** + * Returns an equivalence that delegates to {@link Object#equals} and {@link Object#hashCode}. + * {@link Equivalence#equivalent} returns {@code true} if both values are null, or if neither + * value is null and {@link Object#equals} returns {@code true}. {@link Equivalence#hash} returns + * {@code 0} if passed a null value. + * + * @since 8.0 (present null-friendly behavior) + * @since 4.0 (otherwise) + * @deprecated This method has been moved to {@link Equivalence#equals}. This method is scheduled + * to be removed in Guava release 14.0. + */ + @Deprecated + public static Equivalence<Object> equals() { + return Equivalence.Equals.INSTANCE; + } + + /** + * Returns an equivalence that uses {@code ==} to compare values and {@link + * System#identityHashCode(Object)} to compute the hash code. {@link Equivalence#equivalent} + * returns {@code true} if {@code a == b}, including in the case that a and b are both null. + * + * @deprecated This method has been moved to {@link Equivalence#identity}. This method is schedule + * to be removed in Guava release 14.0. + */ + @Deprecated + public static Equivalence<Object> identity() { + return Equivalence.Identity.INSTANCE; + } +} diff --git a/guava/src/com/google/common/base/FinalizablePhantomReference.java b/guava/src/com/google/common/base/FinalizablePhantomReference.java new file mode 100644 index 0000000..c694bc9 --- /dev/null +++ b/guava/src/com/google/common/base/FinalizablePhantomReference.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; + +/** + * Phantom reference with a {@code finalizeReferent()} method which a background thread invokes + * after the garbage collector reclaims the referent. This is a simpler alternative to using a + * {@link ReferenceQueue}. + * + * <p>Unlike a normal phantom reference, this reference will be cleared automatically. + * + * @author Bob Lee + * @since 2.0 (imported from Google Collections Library) + */ +public abstract class FinalizablePhantomReference<T> extends PhantomReference<T> + implements FinalizableReference { + /** + * Constructs a new finalizable phantom reference. + * + * @param referent to phantom reference + * @param queue that should finalize the referent + */ + protected FinalizablePhantomReference(T referent, FinalizableReferenceQueue queue) { + super(referent, queue.queue); + queue.cleanUp(); + } +} diff --git a/guava/src/com/google/common/base/FinalizableReference.java b/guava/src/com/google/common/base/FinalizableReference.java new file mode 100644 index 0000000..ab2dec3 --- /dev/null +++ b/guava/src/com/google/common/base/FinalizableReference.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +/** + * Implemented by references that have code to run after garbage collection of their referents. + * + * @see FinalizableReferenceQueue + * @author Bob Lee + * @since 2.0 (imported from Google Collections Library) + */ +public interface FinalizableReference { + /** + * Invoked on a background thread after the referent has been garbage collected unless security + * restrictions prevented starting a background thread, in which case this method is invoked when + * new references are created. + */ + void finalizeReferent(); +} diff --git a/guava/src/com/google/common/base/FinalizableReferenceQueue.java b/guava/src/com/google/common/base/FinalizableReferenceQueue.java new file mode 100644 index 0000000..aaa5f76 --- /dev/null +++ b/guava/src/com/google/common/base/FinalizableReferenceQueue.java @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.VisibleForTesting; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A reference queue with an associated background thread that dequeues references and invokes + * {@link FinalizableReference#finalizeReferent()} on them. + * + * <p>Keep a strong reference to this object until all of the associated referents have been + * finalized. If this object is garbage collected earlier, the backing thread will not invoke {@code + * finalizeReferent()} on the remaining references. + * + * @author Bob Lee + * @since 2.0 (imported from Google Collections Library) + */ +public class FinalizableReferenceQueue { + /* + * The Finalizer thread keeps a phantom reference to this object. When the client (for example, a + * map built by MapMaker) no longer has a strong reference to this object, the garbage collector + * will reclaim it and enqueue the phantom reference. The enqueued reference will trigger the + * Finalizer to stop. + * + * If this library is loaded in the system class loader, FinalizableReferenceQueue can load + * Finalizer directly with no problems. + * + * If this library is loaded in an application class loader, it's important that Finalizer not + * have a strong reference back to the class loader. Otherwise, you could have a graph like this: + * + * Finalizer Thread runs instance of -> Finalizer.class loaded by -> Application class loader + * which loaded -> ReferenceMap.class which has a static -> FinalizableReferenceQueue instance + * + * Even if no other references to classes from the application class loader remain, the Finalizer + * thread keeps an indirect strong reference to the queue in ReferenceMap, which keeps the + * Finalizer running, and as a result, the application class loader can never be reclaimed. + * + * This means that dynamically loaded web applications and OSGi bundles can't be unloaded. + * + * If the library is loaded in an application class loader, we try to break the cycle by loading + * Finalizer in its own independent class loader: + * + * System class loader -> Application class loader -> ReferenceMap -> FinalizableReferenceQueue + * -> etc. -> Decoupled class loader -> Finalizer + * + * Now, Finalizer no longer keeps an indirect strong reference to the static + * FinalizableReferenceQueue field in ReferenceMap. The application class loader can be reclaimed + * at which point the Finalizer thread will stop and its decoupled class loader can also be + * reclaimed. + * + * If any of this fails along the way, we fall back to loading Finalizer directly in the + * application class loader. + */ + + private static final Logger logger = Logger.getLogger(FinalizableReferenceQueue.class.getName()); + + private static final String FINALIZER_CLASS_NAME = "com.google.common.base.internal.Finalizer"; + + /** Reference to Finalizer.startFinalizer(). */ + private static final Method startFinalizer; + static { + Class<?> finalizer = loadFinalizer( + new SystemLoader(), new DecoupledLoader(), new DirectLoader()); + startFinalizer = getStartFinalizer(finalizer); + } + + /** + * The actual reference queue that our background thread will poll. + */ + final ReferenceQueue<Object> queue; + + /** + * Whether or not the background thread started successfully. + */ + final boolean threadStarted; + + /** + * Constructs a new queue. + */ + @SuppressWarnings("unchecked") + public FinalizableReferenceQueue() { + // We could start the finalizer lazily, but I'd rather it blow up early. + ReferenceQueue<Object> queue; + boolean threadStarted = false; + try { + queue = (ReferenceQueue<Object>) + startFinalizer.invoke(null, FinalizableReference.class, this); + threadStarted = true; + } catch (IllegalAccessException impossible) { + throw new AssertionError(impossible); // startFinalizer() is public + } catch (Throwable t) { + logger.log(Level.INFO, "Failed to start reference finalizer thread." + + " Reference cleanup will only occur when new references are created.", t); + queue = new ReferenceQueue<Object>(); + } + + this.queue = queue; + this.threadStarted = threadStarted; + } + + /** + * Repeatedly dequeues references from the queue and invokes {@link + * FinalizableReference#finalizeReferent()} on them until the queue is empty. This method is a + * no-op if the background thread was created successfully. + */ + void cleanUp() { + if (threadStarted) { + return; + } + + Reference<?> reference; + while ((reference = queue.poll()) != null) { + /* + * This is for the benefit of phantom references. Weak and soft references will have already + * been cleared by this point. + */ + reference.clear(); + try { + ((FinalizableReference) reference).finalizeReferent(); + } catch (Throwable t) { + logger.log(Level.SEVERE, "Error cleaning up after reference.", t); + } + } + } + + /** + * Iterates through the given loaders until it finds one that can load Finalizer. + * + * @return Finalizer.class + */ + private static Class<?> loadFinalizer(FinalizerLoader... loaders) { + for (FinalizerLoader loader : loaders) { + Class<?> finalizer = loader.loadFinalizer(); + if (finalizer != null) { + return finalizer; + } + } + + throw new AssertionError(); + } + + /** + * Loads Finalizer.class. + */ + interface FinalizerLoader { + + /** + * Returns Finalizer.class or null if this loader shouldn't or can't load it. + * + * @throws SecurityException if we don't have the appropriate privileges + */ + Class<?> loadFinalizer(); + } + + /** + * Tries to load Finalizer from the system class loader. If Finalizer is in the system class path, + * we needn't create a separate loader. + */ + static class SystemLoader implements FinalizerLoader { + // This is used by the ClassLoader-leak test in FinalizableReferenceQueueTest to disable + // finding Finalizer on the system class path even if it is there. + @VisibleForTesting + static boolean disabled; + + @Override + public Class<?> loadFinalizer() { + if (disabled) { + return null; + } + ClassLoader systemLoader; + try { + systemLoader = ClassLoader.getSystemClassLoader(); + } catch (SecurityException e) { + logger.info("Not allowed to access system class loader."); + return null; + } + if (systemLoader != null) { + try { + return systemLoader.loadClass(FINALIZER_CLASS_NAME); + } catch (ClassNotFoundException e) { + // Ignore. Finalizer is simply in a child class loader. + return null; + } + } else { + return null; + } + } + } + + /** + * Try to load Finalizer in its own class loader. If Finalizer's thread had a direct reference to + * our class loader (which could be that of a dynamically loaded web application or OSGi bundle), + * it would prevent our class loader from getting garbage collected. + */ + static class DecoupledLoader implements FinalizerLoader { + private static final String LOADING_ERROR = "Could not load Finalizer in its own class loader." + + "Loading Finalizer in the current class loader instead. As a result, you will not be able" + + "to garbage collect this class loader. To support reclaiming this class loader, either" + + "resolve the underlying issue, or move Google Collections to your system class path."; + + @Override + public Class<?> loadFinalizer() { + try { + /* + * We use URLClassLoader because it's the only concrete class loader implementation in the + * JDK. If we used our own ClassLoader subclass, Finalizer would indirectly reference this + * class loader: + * + * Finalizer.class -> CustomClassLoader -> CustomClassLoader.class -> This class loader + * + * System class loader will (and must) be the parent. + */ + ClassLoader finalizerLoader = newLoader(getBaseUrl()); + return finalizerLoader.loadClass(FINALIZER_CLASS_NAME); + } catch (Exception e) { + logger.log(Level.WARNING, LOADING_ERROR, e); + return null; + } + } + + /** + * Gets URL for base of path containing Finalizer.class. + */ + URL getBaseUrl() throws IOException { + // Find URL pointing to Finalizer.class file. + String finalizerPath = FINALIZER_CLASS_NAME.replace('.', '/') + ".class"; + URL finalizerUrl = getClass().getClassLoader().getResource(finalizerPath); + if (finalizerUrl == null) { + throw new FileNotFoundException(finalizerPath); + } + + // Find URL pointing to base of class path. + String urlString = finalizerUrl.toString(); + if (!urlString.endsWith(finalizerPath)) { + throw new IOException("Unsupported path style: " + urlString); + } + urlString = urlString.substring(0, urlString.length() - finalizerPath.length()); + return new URL(finalizerUrl, urlString); + } + + /** Creates a class loader with the given base URL as its classpath. */ + URLClassLoader newLoader(URL base) { + // We use the bootstrap class loader as the parent because Finalizer by design uses + // only standard Java classes. That also means that FinalizableReferenceQueueTest + // doesn't pick up the wrong version of the Finalizer class. + return new URLClassLoader(new URL[] {base}, null); + } + } + + /** + * Loads Finalizer directly using the current class loader. We won't be able to garbage collect + * this class loader, but at least the world doesn't end. + */ + static class DirectLoader implements FinalizerLoader { + @Override + public Class<?> loadFinalizer() { + try { + return Class.forName(FINALIZER_CLASS_NAME); + } catch (ClassNotFoundException e) { + throw new AssertionError(e); + } + } + } + + /** + * Looks up Finalizer.startFinalizer(). + */ + static Method getStartFinalizer(Class<?> finalizer) { + try { + return finalizer.getMethod("startFinalizer", Class.class, Object.class); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } +} diff --git a/guava/src/com/google/common/base/FinalizableSoftReference.java b/guava/src/com/google/common/base/FinalizableSoftReference.java new file mode 100644 index 0000000..88607f4 --- /dev/null +++ b/guava/src/com/google/common/base/FinalizableSoftReference.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; + +/** + * Soft reference with a {@code finalizeReferent()} method which a background thread invokes after + * the garbage collector reclaims the referent. This is a simpler alternative to using a {@link + * ReferenceQueue}. + * + * @author Bob Lee + * @since 2.0 (imported from Google Collections Library) + */ +public abstract class FinalizableSoftReference<T> extends SoftReference<T> + implements FinalizableReference { + /** + * Constructs a new finalizable soft reference. + * + * @param referent to softly reference + * @param queue that should finalize the referent + */ + protected FinalizableSoftReference(T referent, FinalizableReferenceQueue queue) { + super(referent, queue.queue); + queue.cleanUp(); + } +} diff --git a/guava/src/com/google/common/base/FinalizableWeakReference.java b/guava/src/com/google/common/base/FinalizableWeakReference.java new file mode 100644 index 0000000..b14d023 --- /dev/null +++ b/guava/src/com/google/common/base/FinalizableWeakReference.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; + +/** + * Weak reference with a {@code finalizeReferent()} method which a background thread invokes after + * the garbage collector reclaims the referent. This is a simpler alternative to using a {@link + * ReferenceQueue}. + * + * @author Bob Lee + * @since 2.0 (imported from Google Collections Library) + */ +public abstract class FinalizableWeakReference<T> extends WeakReference<T> + implements FinalizableReference { + /** + * Constructs a new finalizable weak reference. + * + * @param referent to weakly reference + * @param queue that should finalize the referent + */ + protected FinalizableWeakReference(T referent, FinalizableReferenceQueue queue) { + super(referent, queue.queue); + queue.cleanUp(); + } +} diff --git a/guava/src/com/google/common/base/Function.java b/guava/src/com/google/common/base/Function.java new file mode 100644 index 0000000..9c29264 --- /dev/null +++ b/guava/src/com/google/common/base/Function.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; + +import javax.annotation.Nullable; + +/** + * Determines an output value based on an input value. + * + * <p>See the Guava User Guide article on <a href= + * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the use of {@code + * Function}</a>. + * + * @author Kevin Bourrillion + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public interface Function<F, T> { + /** + * Returns the result of applying this function to {@code input}. This method is <i>generally + * expected</i>, but not absolutely required, to have the following properties: + * + * <ul> + * <li>Its execution does not cause any observable side effects. + * <li>The computation is <i>consistent with equals</i>; that is, {@link Objects#equal + * Objects.equal}{@code (a, b)} implies that {@code Objects.equal(function.apply(a), + * function.apply(b))}. + * </ul> + * + * @throws NullPointerException if {@code input} is null and this function does not accept null + * arguments + */ + @Nullable T apply(@Nullable F input); + + /** + * Indicates whether another object is equal to this function. + * + * <p>Most implementations will have no reason to override the behavior of {@link Object#equals}. + * However, an implementation may also choose to return {@code true} whenever {@code object} is a + * {@link Function} that it considers <i>interchangeable</i> with this one. "Interchangeable" + * <i>typically</i> means that {@code Objects.equal(this.apply(f), that.apply(f))} is true for all + * {@code f} of type {@code F}. Note that a {@code false} result from this method does not imply + * that the functions are known <i>not</i> to be interchangeable. + */ + @Override + boolean equals(@Nullable Object object); +} diff --git a/guava/src/com/google/common/base/FunctionalEquivalence.java b/guava/src/com/google/common/base/FunctionalEquivalence.java new file mode 100644 index 0000000..a5e9c13 --- /dev/null +++ b/guava/src/com/google/common/base/FunctionalEquivalence.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; + +import java.io.Serializable; + +import javax.annotation.Nullable; + +/** + * Equivalence applied on functional result. + * + * @author Bob Lee + * @since 10.0 + */ +@Beta +@GwtCompatible +final class FunctionalEquivalence<F, T> extends Equivalence<F> + implements Serializable { + + private static final long serialVersionUID = 0; + + private final Function<F, ? extends T> function; + private final Equivalence<T> resultEquivalence; + + FunctionalEquivalence( + Function<F, ? extends T> function, Equivalence<T> resultEquivalence) { + this.function = checkNotNull(function); + this.resultEquivalence = checkNotNull(resultEquivalence); + } + + @Override protected boolean doEquivalent(F a, F b) { + return resultEquivalence.equivalent(function.apply(a), function.apply(b)); + } + + @Override protected int doHash(F a) { + return resultEquivalence.hash(function.apply(a)); + } + + @Override public boolean equals(@Nullable Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof FunctionalEquivalence) { + FunctionalEquivalence<?, ?> that = (FunctionalEquivalence<?, ?>) obj; + return function.equals(that.function) + && resultEquivalence.equals(that.resultEquivalence); + } + return false; + } + + @Override public int hashCode() { + return Objects.hashCode(function, resultEquivalence); + } + + @Override public String toString() { + return resultEquivalence + ".onResultOf(" + function + ")"; + } +} diff --git a/guava/src/com/google/common/base/Functions.java b/guava/src/com/google/common/base/Functions.java new file mode 100644 index 0000000..65fc2c6 --- /dev/null +++ b/guava/src/com/google/common/base/Functions.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; + +import java.io.Serializable; +import java.util.Map; + +import javax.annotation.Nullable; + +/** + * Static utility methods pertaining to {@code Function} instances. + * + * <p>All methods return serializable functions as long as they're given serializable parameters. + * + * <p>See the Guava User Guide article on <a href= + * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the use of {@code + * Function}</a>. + * + * @author Mike Bostock + * @author Jared Levy + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public final class Functions { + private Functions() {} + + /** + * Returns a function that calls {@code toString()} on its argument. The function does not accept + * nulls; it will throw a {@link NullPointerException} when applied to {@code null}. + * + * <p><b>Warning:</b> The returned function may not be <i>consistent with equals</i> (as + * documented at {@link Function#apply}). For example, this function yields different results for + * the two equal instances {@code ImmutableSet.of(1, 2)} and {@code ImmutableSet.of(2, 1)}. + */ + public static Function<Object, String> toStringFunction() { + return ToStringFunction.INSTANCE; + } + + // enum singleton pattern + private enum ToStringFunction implements Function<Object, String> { + INSTANCE; + + @Override + public String apply(Object o) { + checkNotNull(o); // eager for GWT. + return o.toString(); + } + + @Override public String toString() { + return "toString"; + } + } + + /** + * Returns the identity function. + */ + @SuppressWarnings("unchecked") + public static <E> Function<E, E> identity() { + return (Function<E, E>) IdentityFunction.INSTANCE; + } + + // enum singleton pattern + private enum IdentityFunction implements Function<Object, Object> { + INSTANCE; + + @Override + public Object apply(Object o) { + return o; + } + + @Override public String toString() { + return "identity"; + } + } + + /** + * Returns a function which performs a map lookup. The returned function throws an {@link + * IllegalArgumentException} if given a key that does not exist in the map. + */ + public static <K, V> Function<K, V> forMap(Map<K, V> map) { + return new FunctionForMapNoDefault<K, V>(map); + } + + private static class FunctionForMapNoDefault<K, V> implements Function<K, V>, Serializable { + final Map<K, V> map; + + FunctionForMapNoDefault(Map<K, V> map) { + this.map = checkNotNull(map); + } + + @Override + public V apply(K key) { + V result = map.get(key); + checkArgument(result != null || map.containsKey(key), "Key '%s' not present in map", key); + return result; + } + + @Override public boolean equals(@Nullable Object o) { + if (o instanceof FunctionForMapNoDefault) { + FunctionForMapNoDefault<?, ?> that = (FunctionForMapNoDefault<?, ?>) o; + return map.equals(that.map); + } + return false; + } + + @Override public int hashCode() { + return map.hashCode(); + } + + @Override public String toString() { + return "forMap(" + map + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns a function which performs a map lookup with a default value. The function created by + * this method returns {@code defaultValue} for all inputs that do not belong to the map's key + * set. + * + * @param map source map that determines the function behavior + * @param defaultValue the value to return for inputs that aren't map keys + * @return function that returns {@code map.get(a)} when {@code a} is a key, or {@code + * defaultValue} otherwise + */ + public static <K, V> Function<K, V> forMap(Map<K, ? extends V> map, @Nullable V defaultValue) { + return new ForMapWithDefault<K, V>(map, defaultValue); + } + + private static class ForMapWithDefault<K, V> implements Function<K, V>, Serializable { + final Map<K, ? extends V> map; + final V defaultValue; + + ForMapWithDefault(Map<K, ? extends V> map, @Nullable V defaultValue) { + this.map = checkNotNull(map); + this.defaultValue = defaultValue; + } + + @Override + public V apply(K key) { + V result = map.get(key); + return (result != null || map.containsKey(key)) ? result : defaultValue; + } + + @Override public boolean equals(@Nullable Object o) { + if (o instanceof ForMapWithDefault) { + ForMapWithDefault<?, ?> that = (ForMapWithDefault<?, ?>) o; + return map.equals(that.map) && Objects.equal(defaultValue, that.defaultValue); + } + return false; + } + + @Override public int hashCode() { + return Objects.hashCode(map, defaultValue); + } + + @Override public String toString() { + return "forMap(" + map + ", defaultValue=" + defaultValue + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns the composition of two functions. For {@code f: A->B} and {@code g: B->C}, composition + * is defined as the function h such that {@code h(a) == g(f(a))} for each {@code a}. + * + * @param g the second function to apply + * @param f the first function to apply + * @return the composition of {@code f} and {@code g} + * @see <a href="//en.wikipedia.org/wiki/Function_composition">function composition</a> + */ + public static <A, B, C> Function<A, C> compose(Function<B, C> g, Function<A, ? extends B> f) { + return new FunctionComposition<A, B, C>(g, f); + } + + private static class FunctionComposition<A, B, C> implements Function<A, C>, Serializable { + private final Function<B, C> g; + private final Function<A, ? extends B> f; + + public FunctionComposition(Function<B, C> g, Function<A, ? extends B> f) { + this.g = checkNotNull(g); + this.f = checkNotNull(f); + } + + @Override + public C apply(A a) { + return g.apply(f.apply(a)); + } + + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof FunctionComposition) { + FunctionComposition<?, ?, ?> that = (FunctionComposition<?, ?, ?>) obj; + return f.equals(that.f) && g.equals(that.g); + } + return false; + } + + @Override public int hashCode() { + return f.hashCode() ^ g.hashCode(); + } + + @Override public String toString() { + return g.toString() + "(" + f.toString() + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Creates a function that returns the same boolean output as the given predicate for all inputs. + * + * <p>The returned function is <i>consistent with equals</i> (as documented at {@link + * Function#apply}) if and only if {@code predicate} is itself consistent with equals. + */ + public static <T> Function<T, Boolean> forPredicate(Predicate<T> predicate) { + return new PredicateFunction<T>(predicate); + } + + /** @see Functions#forPredicate */ + private static class PredicateFunction<T> implements Function<T, Boolean>, Serializable { + private final Predicate<T> predicate; + + private PredicateFunction(Predicate<T> predicate) { + this.predicate = checkNotNull(predicate); + } + + @Override + public Boolean apply(T t) { + return predicate.apply(t); + } + + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof PredicateFunction) { + PredicateFunction<?> that = (PredicateFunction<?>) obj; + return predicate.equals(that.predicate); + } + return false; + } + + @Override public int hashCode() { + return predicate.hashCode(); + } + + @Override public String toString() { + return "forPredicate(" + predicate + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Creates a function that returns {@code value} for any input. + * + * @param value the constant value for the function to return + * @return a function that always returns {@code value} + */ + public static <E> Function<Object, E> constant(@Nullable E value) { + return new ConstantFunction<E>(value); + } + + private static class ConstantFunction<E> implements Function<Object, E>, Serializable { + private final E value; + + public ConstantFunction(@Nullable E value) { + this.value = value; + } + + @Override + public E apply(@Nullable Object from) { + return value; + } + + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof ConstantFunction) { + ConstantFunction<?> that = (ConstantFunction<?>) obj; + return Objects.equal(value, that.value); + } + return false; + } + + @Override public int hashCode() { + return (value == null) ? 0 : value.hashCode(); + } + + @Override public String toString() { + return "constant(" + value + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns a function that always returns the result of invoking {@link Supplier#get} on {@code + * supplier}, regardless of its input. + * + * @since 10.0 + */ + @Beta + public static <T> Function<Object, T> forSupplier(Supplier<T> supplier) { + return new SupplierFunction<T>(supplier); + } + + /** @see Functions#forSupplier*/ + private static class SupplierFunction<T> implements Function<Object, T>, Serializable { + + private final Supplier<T> supplier; + + private SupplierFunction(Supplier<T> supplier) { + this.supplier = checkNotNull(supplier); + } + + @Override public T apply(@Nullable Object input) { + return supplier.get(); + } + + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof SupplierFunction) { + SupplierFunction<?> that = (SupplierFunction<?>) obj; + return this.supplier.equals(that.supplier); + } + return false; + } + + @Override public int hashCode() { + return supplier.hashCode(); + } + + @Override public String toString() { + return "forSupplier(" + supplier + ")"; + } + + private static final long serialVersionUID = 0; + } +} diff --git a/guava/src/com/google/common/base/Joiner.java b/guava/src/com/google/common/base/Joiner.java new file mode 100644 index 0000000..9391550 --- /dev/null +++ b/guava/src/com/google/common/base/Joiner.java @@ -0,0 +1,562 @@ +/* + * Copyright (C) 2008 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; + +import java.io.IOException; +import java.util.AbstractList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import javax.annotation.CheckReturnValue; +import javax.annotation.Nullable; + +/** + * An object which joins pieces of text (specified as an array, {@link Iterable}, varargs or even a + * {@link Map}) with a separator. It either appends the results to an {@link Appendable} or returns + * them as a {@link String}. Example: <pre> {@code + * + * Joiner joiner = Joiner.on("; ").skipNulls(); + * . . . + * return joiner.join("Harry", null, "Ron", "Hermione");}</pre> + * + * This returns the string {@code "Harry; Ron; Hermione"}. Note that all input elements are + * converted to strings using {@link Object#toString()} before being appended. + * + * <p>If neither {@link #skipNulls()} nor {@link #useForNull(String)} is specified, the joining + * methods will throw {@link NullPointerException} if any given element is null. + * + * <p><b>Warning: joiner instances are always immutable</b>; a configuration method such as {@code + * useForNull} has no effect on the instance it is invoked on! You must store and use the new joiner + * instance returned by the method. This makes joiners thread-safe, and safe to store as {@code + * static final} constants. <pre> {@code + * + * // Bad! Do not do this! + * Joiner joiner = Joiner.on(','); + * joiner.skipNulls(); // does nothing! + * return joiner.join("wrong", null, "wrong");}</pre> + * + * <p>See the Guava User Guide article on <a href= + * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#Joiner">{@code Joiner}</a>. + * + * @author Kevin Bourrillion + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public class Joiner { + /** + * Returns a joiner which automatically places {@code separator} between consecutive elements. + */ + public static Joiner on(String separator) { + return new Joiner(separator); + } + + /** + * Returns a joiner which automatically places {@code separator} between consecutive elements. + */ + public static Joiner on(char separator) { + return new Joiner(String.valueOf(separator)); + } + + private final String separator; + + private Joiner(String separator) { + this.separator = checkNotNull(separator); + } + + private Joiner(Joiner prototype) { + this.separator = prototype.separator; + } + + /** + * <b>Deprecated.</b> + * + * @since 11.0 + * @deprecated use {@link #appendTo(Appendable, Iterator)} by casting {@code parts} to + * {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not + * {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b> + */ + @Beta + @Deprecated + public + final <A extends Appendable, I extends Object & Iterable<?> & Iterator<?>> A + appendTo(A appendable, I parts) throws IOException { + return appendTo(appendable, (Iterator<?>) parts); + } + + /** + * Appends the string representation of each of {@code parts}, using the previously configured + * separator between each, to {@code appendable}. + */ + public <A extends Appendable> A appendTo(A appendable, Iterable<?> parts) throws IOException { + return appendTo(appendable, parts.iterator()); + } + + /** + * Appends the string representation of each of {@code parts}, using the previously configured + * separator between each, to {@code appendable}. + * + * @since 11.0 + */ + public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException { + checkNotNull(appendable); + if (parts.hasNext()) { + appendable.append(toString(parts.next())); + while (parts.hasNext()) { + appendable.append(separator); + appendable.append(toString(parts.next())); + } + } + return appendable; + } + + /** + * Appends the string representation of each of {@code parts}, using the previously configured + * separator between each, to {@code appendable}. + */ + public final <A extends Appendable> A appendTo(A appendable, Object[] parts) throws IOException { + return appendTo(appendable, Arrays.asList(parts)); + } + + /** + * Appends to {@code appendable} the string representation of each of the remaining arguments. + */ + public final <A extends Appendable> A appendTo( + A appendable, @Nullable Object first, @Nullable Object second, Object... rest) + throws IOException { + return appendTo(appendable, iterable(first, second, rest)); + } + + /** + * <b>Deprecated.</b> + * + * @since 11.0 + * @deprecated use {@link #appendTo(StringBuilder, Iterator)} by casting {@code parts} to + * {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not + * {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b> + */ + @Beta + @Deprecated + public + final <I extends Object & Iterable<?> & Iterator<?>> StringBuilder + appendTo(StringBuilder builder, I parts) { + return appendTo(builder, (Iterator<?>) parts); + } + + /** + * Appends the string representation of each of {@code parts}, using the previously configured + * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable, + * Iterable)}, except that it does not throw {@link IOException}. + */ + public final StringBuilder appendTo(StringBuilder builder, Iterable<?> parts) { + return appendTo(builder, parts.iterator()); + } + + /** + * Appends the string representation of each of {@code parts}, using the previously configured + * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable, + * Iterable)}, except that it does not throw {@link IOException}. + * + * @since 11.0 + */ + public final StringBuilder appendTo(StringBuilder builder, Iterator<?> parts) { + try { + appendTo((Appendable) builder, parts); + } catch (IOException impossible) { + throw new AssertionError(impossible); + } + return builder; + } + + /** + * Appends the string representation of each of {@code parts}, using the previously configured + * separator between each, to {@code builder}. Identical to {@link #appendTo(Appendable, + * Iterable)}, except that it does not throw {@link IOException}. + */ + public final StringBuilder appendTo(StringBuilder builder, Object[] parts) { + return appendTo(builder, Arrays.asList(parts)); + } + + /** + * Appends to {@code builder} the string representation of each of the remaining arguments. + * Identical to {@link #appendTo(Appendable, Object, Object, Object...)}, except that it does not + * throw {@link IOException}. + */ + public final StringBuilder appendTo( + StringBuilder builder, @Nullable Object first, @Nullable Object second, Object... rest) { + return appendTo(builder, iterable(first, second, rest)); + } + + /** + * <b>Deprecated.</b> + * + * @since 11.0 + * @deprecated use {@link #join(Iterator)} by casting {@code parts} to + * {@code Iterator<?>}, or better yet, by implementing only {@code Iterator} and not + * {@code Iterable}. <b>This method is scheduled for deletion in June 2013.</b> + */ + @Beta + @Deprecated + public + final <I extends Object & Iterable<?> & Iterator<?>> String join(I parts) { + return join((Iterator<?>) parts); + } + + /** + * Returns a string containing the string representation of each of {@code parts}, using the + * previously configured separator between each. + */ + public final String join(Iterable<?> parts) { + return join(parts.iterator()); + } + + /** + * Returns a string containing the string representation of each of {@code parts}, using the + * previously configured separator between each. + * + * @since 11.0 + */ + public final String join(Iterator<?> parts) { + return appendTo(new StringBuilder(), parts).toString(); + } + + /** + * Returns a string containing the string representation of each of {@code parts}, using the + * previously configured separator between each. + */ + public final String join(Object[] parts) { + return join(Arrays.asList(parts)); + } + + /** + * Returns a string containing the string representation of each argument, using the previously + * configured separator between each. + */ + public final String join(@Nullable Object first, @Nullable Object second, Object... rest) { + return join(iterable(first, second, rest)); + } + + /** + * Returns a joiner with the same behavior as this one, except automatically substituting {@code + * nullText} for any provided null elements. + */ + @CheckReturnValue + public Joiner useForNull(final String nullText) { + checkNotNull(nullText); + return new Joiner(this) { + @Override CharSequence toString(Object part) { + return (part == null) ? nullText : Joiner.this.toString(part); + } + + @Override public Joiner useForNull(String nullText) { + checkNotNull(nullText); // weird: just to satisfy NullPointerTester. + throw new UnsupportedOperationException("already specified useForNull"); + } + + @Override public Joiner skipNulls() { + throw new UnsupportedOperationException("already specified useForNull"); + } + }; + } + + /** + * Returns a joiner with the same behavior as this joiner, except automatically skipping over any + * provided null elements. + */ + @CheckReturnValue + public Joiner skipNulls() { + return new Joiner(this) { + @Override public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) + throws IOException { + checkNotNull(appendable, "appendable"); + checkNotNull(parts, "parts"); + while (parts.hasNext()) { + Object part = parts.next(); + if (part != null) { + appendable.append(Joiner.this.toString(part)); + break; + } + } + while (parts.hasNext()) { + Object part = parts.next(); + if (part != null) { + appendable.append(separator); + appendable.append(Joiner.this.toString(part)); + } + } + return appendable; + } + + @Override public Joiner useForNull(String nullText) { + checkNotNull(nullText); // weird: just to satisfy NullPointerTester. + throw new UnsupportedOperationException("already specified skipNulls"); + } + + @Override public MapJoiner withKeyValueSeparator(String kvs) { + checkNotNull(kvs); // weird: just to satisfy NullPointerTester. + throw new UnsupportedOperationException("can't use .skipNulls() with maps"); + } + }; + } + + /** + * Returns a {@code MapJoiner} using the given key-value separator, and the same configuration as + * this {@code Joiner} otherwise. + */ + @CheckReturnValue + public MapJoiner withKeyValueSeparator(String keyValueSeparator) { + return new MapJoiner(this, keyValueSeparator); + } + + /** + * An object that joins map entries in the same manner as {@code Joiner} joins iterables and + * arrays. Like {@code Joiner}, it is thread-safe and immutable. + * + * <p>In addition to operating on {@code Map} instances, {@code MapJoiner} can operate on {@code + * Multimap} entries in two distinct modes: + * + * <ul> + * <li>To output a separate entry for each key-value pair, pass {@code multimap.entries()} to a + * {@code MapJoiner} method that accepts entries as input, and receive output of the form + * {@code key1=A&key1=B&key2=C}. + * <li>To output a single entry for each key, pass {@code multimap.asMap()} to a {@code MapJoiner} + * method that accepts a map as input, and receive output of the form {@code + * key1=[A, B]&key2=C}. + * </ul> + * + * @since 2.0 (imported from Google Collections Library) + */ + public final static class MapJoiner { + private final Joiner joiner; + private final String keyValueSeparator; + + private MapJoiner(Joiner joiner, String keyValueSeparator) { + this.joiner = joiner; // only "this" is ever passed, so don't checkNotNull + this.keyValueSeparator = checkNotNull(keyValueSeparator); + } + + /** + * Appends the string representation of each entry of {@code map}, using the previously + * configured separator and key-value separator, to {@code appendable}. + */ + public <A extends Appendable> A appendTo(A appendable, Map<?, ?> map) throws IOException { + return appendTo(appendable, map.entrySet()); + } + + /** + * Appends the string representation of each entry of {@code map}, using the previously + * configured separator and key-value separator, to {@code builder}. Identical to {@link + * #appendTo(Appendable, Map)}, except that it does not throw {@link IOException}. + */ + public StringBuilder appendTo(StringBuilder builder, Map<?, ?> map) { + return appendTo(builder, map.entrySet()); + } + + /** + * Returns a string containing the string representation of each entry of {@code map}, using the + * previously configured separator and key-value separator. + */ + public String join(Map<?, ?> map) { + return join(map.entrySet()); + } + + /** + * <b>Deprecated.</b> + * + * @since 11.0 + * @deprecated use {@link #appendTo(Appendable, Iterator)} by casting {@code entries} to + * {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only + * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion + * in June 2013.</b> + */ + @Beta + @Deprecated + public + <A extends Appendable, + I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>> + A appendTo(A appendable, I entries) throws IOException { + Iterator<? extends Entry<?, ?>> iterator = entries; + return appendTo(appendable, iterator); + } + + /** + * Appends the string representation of each entry in {@code entries}, using the previously + * configured separator and key-value separator, to {@code appendable}. + * + * @since 10.0 + */ + @Beta + public <A extends Appendable> A appendTo(A appendable, Iterable<? extends Entry<?, ?>> entries) + throws IOException { + return appendTo(appendable, entries.iterator()); + } + + /** + * Appends the string representation of each entry in {@code entries}, using the previously + * configured separator and key-value separator, to {@code appendable}. + * + * @since 11.0 + */ + @Beta + public <A extends Appendable> A appendTo(A appendable, Iterator<? extends Entry<?, ?>> parts) + throws IOException { + checkNotNull(appendable); + if (parts.hasNext()) { + Entry<?, ?> entry = parts.next(); + appendable.append(joiner.toString(entry.getKey())); + appendable.append(keyValueSeparator); + appendable.append(joiner.toString(entry.getValue())); + while (parts.hasNext()) { + appendable.append(joiner.separator); + Entry<?, ?> e = parts.next(); + appendable.append(joiner.toString(e.getKey())); + appendable.append(keyValueSeparator); + appendable.append(joiner.toString(e.getValue())); + } + } + return appendable; + } + + /** + * <b>Deprecated.</b> + * + * @since 11.0 + * @deprecated use {@link #appendTo(StringBuilder, Iterator)} by casting {@code entries} to + * {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only + * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion + * in June 2013.</b> + */ + @Beta + @Deprecated + public + <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>> + StringBuilder appendTo(StringBuilder builder, I entries) throws IOException { + Iterator<? extends Entry<?, ?>> iterator = entries; + return appendTo(builder, iterator); + } + + /** + * Appends the string representation of each entry in {@code entries}, using the previously + * configured separator and key-value separator, to {@code builder}. Identical to {@link + * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}. + * + * @since 10.0 + */ + @Beta + public StringBuilder appendTo(StringBuilder builder, Iterable<? extends Entry<?, ?>> entries) { + return appendTo(builder, entries.iterator()); + } + + /** + * Appends the string representation of each entry in {@code entries}, using the previously + * configured separator and key-value separator, to {@code builder}. Identical to {@link + * #appendTo(Appendable, Iterable)}, except that it does not throw {@link IOException}. + * + * @since 11.0 + */ + @Beta + public StringBuilder appendTo(StringBuilder builder, Iterator<? extends Entry<?, ?>> entries) { + try { + appendTo((Appendable) builder, entries); + } catch (IOException impossible) { + throw new AssertionError(impossible); + } + return builder; + } + + /** + * <b>Deprecated.</b> + * + * @since 11.0 + * @deprecated use {@link #join(Iterator)} by casting {@code entries} to + * {@code Iterator<? extends Entry<?, ?>>}, or better yet, by implementing only + * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled for deletion + * in June 2013.</b> + */ + @Beta + @Deprecated + public + <I extends Object & Iterable<? extends Entry<?, ?>> & Iterator<? extends Entry<?, ?>>> + String join(I entries) throws IOException { + Iterator<? extends Entry<?, ?>> iterator = entries; + return join(iterator); + } + + /** + * Returns a string containing the string representation of each entry in {@code entries}, using + * the previously configured separator and key-value separator. + * + * @since 10.0 + */ + @Beta + public String join(Iterable<? extends Entry<?, ?>> entries) { + return join(entries.iterator()); + } + + /** + * Returns a string containing the string representation of each entry in {@code entries}, using + * the previously configured separator and key-value separator. + * + * @since 11.0 + */ + @Beta + public String join(Iterator<? extends Entry<?, ?>> entries) { + return appendTo(new StringBuilder(), entries).toString(); + } + + /** + * Returns a map joiner with the same behavior as this one, except automatically substituting + * {@code nullText} for any provided null keys or values. + */ + @CheckReturnValue + public MapJoiner useForNull(String nullText) { + return new MapJoiner(joiner.useForNull(nullText), keyValueSeparator); + } + } + + CharSequence toString(Object part) { + checkNotNull(part); // checkNotNull for GWT (do not optimize). + return (part instanceof CharSequence) ? (CharSequence) part : part.toString(); + } + + private static Iterable<Object> iterable( + final Object first, final Object second, final Object[] rest) { + checkNotNull(rest); + return new AbstractList<Object>() { + @Override public int size() { + return rest.length + 2; + } + + @Override public Object get(int index) { + switch (index) { + case 0: + return first; + case 1: + return second; + default: + return rest[index - 2]; + } + } + }; + } +} diff --git a/guava/src/com/google/common/base/MediumCharMatcher.java b/guava/src/com/google/common/base/MediumCharMatcher.java new file mode 100644 index 0000000..f55ad5d --- /dev/null +++ b/guava/src/com/google/common/base/MediumCharMatcher.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2012 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.VisibleForTesting; + +/** + * An immutable version of CharMatcher for medium-sized sets of characters that uses a hash table + * with linear probing to check for matches. + * + * @author Christopher Swenson + */ +@GwtCompatible +final class MediumCharMatcher extends CharMatcher { + static final int MAX_SIZE = 1023; + private final char[] table; + private final boolean containsZero; + private final long filter; + + private MediumCharMatcher(char[] table, long filter, boolean containsZero, + String description) { + super(description); + this.table = table; + this.filter = filter; + this.containsZero = containsZero; + } + + private boolean checkFilter(int c) { + return 1 == (1 & (filter >> c)); + } + + // This is all essentially copied from ImmutableSet, but we have to duplicate because + // of dependencies. + + // Represents how tightly we can pack things, as a maximum. + private static final double DESIRED_LOAD_FACTOR = 0.5; + + /** + * Returns an array size suitable for the backing array of a hash table that + * uses open addressing with linear probing in its implementation. The + * returned size is the smallest power of two that can hold setSize elements + * with the desired load factor. + */ + @VisibleForTesting static int chooseTableSize(int setSize) { + if (setSize == 1) { + return 2; + } + // Correct the size for open addressing to match desired load factor. + // Round up to the next highest power of 2. + int tableSize = Integer.highestOneBit(setSize - 1) << 1; + while (tableSize * DESIRED_LOAD_FACTOR < setSize) { + tableSize <<= 1; + } + return tableSize; + } + + // This method is thread-safe, since if any two threads execute it simultaneously, all + // that will happen is that they compute the same data structure twice, but nothing will ever + // be incorrect. + @Override + public CharMatcher precomputed() { + return this; + } + + static CharMatcher from(char[] chars, String description) { + // Compute the filter. + long filter = 0; + int size = chars.length; + boolean containsZero = (chars[0] == 0); + // Compute the filter. + for (char c : chars) { + filter |= 1L << c; + } + // Compute the hash table. + char[] table = new char[chooseTableSize(size)]; + int mask = table.length - 1; + for (char c : chars) { + int index = c & mask; + while (true) { + // Check for empty. + if (table[index] == 0) { + table[index] = c; + break; + } + // Linear probing. + index = (index + 1) & mask; + } + } + return new MediumCharMatcher(table, filter, containsZero, description); + } + + @Override + public boolean matches(char c) { + if (c == 0) { + return containsZero; + } + if (!checkFilter(c)) { + return false; + } + int mask = table.length - 1; + int startingIndex = c & mask; + int index = startingIndex; + do { + // Check for empty. + if (table[index] == 0) { + return false; + // Check for match. + } else if (table[index] == c) { + return true; + } else { + // Linear probing. + index = (index + 1) & mask; + } + // Check to see if we wrapped around the whole table. + } while (index != startingIndex); + return false; + } +} diff --git a/guava/src/com/google/common/base/Objects.java b/guava/src/com/google/common/base/Objects.java new file mode 100644 index 0000000..e1c79a3 --- /dev/null +++ b/guava/src/com/google/common/base/Objects.java @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import javax.annotation.Nullable; + +/** + * Helper functions that can operate on any {@code Object}. + * + * <p>See the Guava User Guide on <a + * href="http://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained">writing + * {@code Object} methods with {@code Objects}</a>. + * + * @author Laurence Gonsalves + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public final class Objects { + private Objects() {} + + /** + * Determines whether two possibly-null objects are equal. Returns: + * + * <ul> + * <li>{@code true} if {@code a} and {@code b} are both null. + * <li>{@code true} if {@code a} and {@code b} are both non-null and they are + * equal according to {@link Object#equals(Object)}. + * <li>{@code false} in all other situations. + * </ul> + * + * <p>This assumes that any non-null objects passed to this function conform + * to the {@code equals()} contract. + */ + public static boolean equal(@Nullable Object a, @Nullable Object b) { + return a == b || (a != null && a.equals(b)); + } + + /** + * Generates a hash code for multiple values. The hash code is generated by + * calling {@link Arrays#hashCode(Object[])}. + * + * <p>This is useful for implementing {@link Object#hashCode()}. For example, + * in an object that has three properties, {@code x}, {@code y}, and + * {@code z}, one could write: + * <pre> + * public int hashCode() { + * return Objects.hashCode(getX(), getY(), getZ()); + * }</pre> + * + * <b>Warning</b>: When a single object is supplied, the returned hash code + * does not equal the hash code of that object. + */ + public static int hashCode(@Nullable Object... objects) { + return Arrays.hashCode(objects); + } + + /** + * Creates an instance of {@link ToStringHelper}. + * + * <p>This is helpful for implementing {@link Object#toString()}. + * Specification by example: <pre> {@code + * // Returns "ClassName{}" + * Objects.toStringHelper(this) + * .toString(); + * + * // Returns "ClassName{x=1}" + * Objects.toStringHelper(this) + * .add("x", 1) + * .toString(); + * + * // Returns "MyObject{x=1}" + * Objects.toStringHelper("MyObject") + * .add("x", 1) + * .toString(); + * + * // Returns "ClassName{x=1, y=foo}" + * Objects.toStringHelper(this) + * .add("x", 1) + * .add("y", "foo") + * .toString(); + * }} + * + * // Returns "ClassName{x=1}" + * Objects.toStringHelper(this) + * .omitNullValues() + * .add("x", 1) + * .add("y", null) + * .toString(); + * }}</pre> + * + * <p>Note that in GWT, class names are often obfuscated. + * + * @param self the object to generate the string for (typically {@code this}), + * used only for its class name + * @since 2.0 + */ + public static ToStringHelper toStringHelper(Object self) { + return new ToStringHelper(simpleName(self.getClass())); + } + + /** + * Creates an instance of {@link ToStringHelper} in the same manner as + * {@link Objects#toStringHelper(Object)}, but using the name of {@code clazz} + * instead of using an instance's {@link Object#getClass()}. + * + * <p>Note that in GWT, class names are often obfuscated. + * + * @param clazz the {@link Class} of the instance + * @since 7.0 (source-compatible since 2.0) + */ + public static ToStringHelper toStringHelper(Class<?> clazz) { + return new ToStringHelper(simpleName(clazz)); + } + + /** + * Creates an instance of {@link ToStringHelper} in the same manner as + * {@link Objects#toStringHelper(Object)}, but using {@code className} instead + * of using an instance's {@link Object#getClass()}. + * + * @param className the name of the instance type + * @since 7.0 (source-compatible since 2.0) + */ + public static ToStringHelper toStringHelper(String className) { + return new ToStringHelper(className); + } + + /** + * {@link Class#getSimpleName()} is not GWT compatible yet, so we + * provide our own implementation. + */ + private static String simpleName(Class<?> clazz) { + String name = clazz.getName(); + + // the nth anonymous class has a class name ending in "Outer$n" + // and local inner classes have names ending in "Outer.$1Inner" + name = name.replaceAll("\\$[0-9]+", "\\$"); + + // we want the name of the inner class all by its lonesome + int start = name.lastIndexOf('$'); + + // if this isn't an inner class, just find the start of the + // top level class name. + if (start == -1) { + start = name.lastIndexOf('.'); + } + return name.substring(start + 1); + } + + /** + * Returns the first of two given parameters that is not {@code null}, if + * either is, or otherwise throws a {@link NullPointerException}. + * + * <p><b>Note:</b> if {@code first} is represented as an {@code Optional<T>}, + * this can be accomplished with {@code first.or(second)}. That approach also + * allows for lazy evaluation of the fallback instance, using + * {@code first.or(Supplier)}. + * + * @return {@code first} if {@code first} is not {@code null}, or + * {@code second} if {@code first} is {@code null} and {@code second} is + * not {@code null} + * @throws NullPointerException if both {@code first} and {@code second} were + * {@code null} + * @since 3.0 + */ + public static <T> T firstNonNull(@Nullable T first, @Nullable T second) { + return first != null ? first : checkNotNull(second); + } + + /** + * Support class for {@link Objects#toStringHelper}. + * + * @author Jason Lee + * @since 2.0 + */ + public static final class ToStringHelper { + private final String className; + private final List<ValueHolder> valueHolders = + new LinkedList<ValueHolder>(); + private boolean omitNullValues = false; + + /** + * Use {@link Objects#toStringHelper(Object)} to create an instance. + */ + private ToStringHelper(String className) { + this.className = checkNotNull(className); + } + + /** + * When called, the formatted output returned by {@link #toString()} will + * ignore {@code null} values. + * + * @since 12.0 + */ + @Beta + public ToStringHelper omitNullValues() { + omitNullValues = true; + return this; + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. If {@code value} is {@code null}, the string {@code "null"} + * is used, unless {@link #omitNullValues()} is called, in which case this + * name/value pair will not be added. + */ + public ToStringHelper add(String name, @Nullable Object value) { + checkNotNull(name); + addHolder(value).builder.append(name).append('=').append(value); + return this; + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, boolean value) { + checkNameAndAppend(name).append(value); + return this; + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, char value) { + checkNameAndAppend(name).append(value); + return this; + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, double value) { + checkNameAndAppend(name).append(value); + return this; + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, float value) { + checkNameAndAppend(name).append(value); + return this; + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, int value) { + checkNameAndAppend(name).append(value); + return this; + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, long value) { + checkNameAndAppend(name).append(value); + return this; + } + + private StringBuilder checkNameAndAppend(String name) { + checkNotNull(name); + return addHolder().builder.append(name).append('='); + } + + /** + * Adds an unnamed value to the formatted output. + * + * <p>It is strongly encouraged to use {@link #add(String, Object)} instead + * and give value a readable name. + */ + public ToStringHelper addValue(@Nullable Object value) { + addHolder(value).builder.append(value); + return this; + } + + /** + * Adds an unnamed value to the formatted output. + * + * <p>It is strongly encouraged to use {@link #add(String, boolean)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(boolean value) { + addHolder().builder.append(value); + return this; + } + + /** + * Adds an unnamed value to the formatted output. + * + * <p>It is strongly encouraged to use {@link #add(String, char)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(char value) { + addHolder().builder.append(value); + return this; + } + + /** + * Adds an unnamed value to the formatted output. + * + * <p>It is strongly encouraged to use {@link #add(String, double)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(double value) { + addHolder().builder.append(value); + return this; + } + + /** + * Adds an unnamed value to the formatted output. + * + * <p>It is strongly encouraged to use {@link #add(String, float)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(float value) { + addHolder().builder.append(value); + return this; + } + + /** + * Adds an unnamed value to the formatted output. + * + * <p>It is strongly encouraged to use {@link #add(String, int)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(int value) { + addHolder().builder.append(value); + return this; + } + + /** + * Adds an unnamed value to the formatted output. + * + * <p>It is strongly encouraged to use {@link #add(String, long)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(long value) { + addHolder().builder.append(value); + return this; + } + + /** + * Returns a string in the format specified by {@link + * Objects#toStringHelper(Object)}. + */ + @Override public String toString() { + // create a copy to keep it consistent in case value changes + boolean omitNullValuesSnapshot = omitNullValues; + boolean needsSeparator = false; + StringBuilder builder = new StringBuilder(32).append(className) + .append('{'); + for (ValueHolder valueHolder : valueHolders) { + if (!omitNullValuesSnapshot || !valueHolder.isNull) { + if (needsSeparator) { + builder.append(", "); + } else { + needsSeparator = true; + } + // must explicitly cast it, otherwise GWT tests might fail because + // it tries to access StringBuilder.append(StringBuilder), which is + // a private method + // TODO(user): change once 5904010 is fixed + CharSequence sequence = valueHolder.builder; + builder.append(sequence); + } + } + return builder.append('}').toString(); + } + + private ValueHolder addHolder() { + ValueHolder valueHolder = new ValueHolder(); + valueHolders.add(valueHolder); + return valueHolder; + } + + private ValueHolder addHolder(@Nullable Object value) { + ValueHolder valueHolder = addHolder(); + valueHolder.isNull = (value == null); + return valueHolder; + } + + private static final class ValueHolder { + final StringBuilder builder = new StringBuilder(); + boolean isNull; + } + } +} diff --git a/guava/src/com/google/common/base/Optional.java b/guava/src/com/google/common/base/Optional.java new file mode 100644 index 0000000..8cd7cda --- /dev/null +++ b/guava/src/com/google/common/base/Optional.java @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.Set; + +import javax.annotation.Nullable; + +/** + * An immutable object that may contain a non-null reference to another object. Each + * instance of this type either contains a non-null reference, or contains nothing (in + * which case we say that the reference is "absent"); it is never said to "contain {@code + * null}". + * + * <p>A non-null {@code Optional<T>} reference can be used as a replacement for a nullable + * {@code T} reference. It allows you to represent "a {@code T} that must be present" and + * a "a {@code T} that might be absent" as two distinct types in your program, which can + * aid clarity. + * + * <p>Some uses of this class include + * + * <ul> + * <li>As a method return type, as an alternative to returning {@code null} to indicate + * that no value was available + * <li>To distinguish between "unknown" (for example, not present in a map) and "known to + * have no value" (present in the map, with value {@code Optional.absent()}) + * <li>To wrap nullable references for storage in a collection that does not support + * {@code null} (though there are + * <a href="http://code.google.com/p/guava-libraries/wiki/LivingWithNullHostileCollections"> + * several other approaches to this</a> that should be considered first) + * </ul> + * + * <p>A common alternative to using this class is to find or create a suitable + * <a href="http://en.wikipedia.org/wiki/Null_Object_pattern">null object</a> for the + * type in question. + * + * <p>This class is not intended as a direct analogue of any existing "option" or "maybe" + * construct from other programming environments, though it may bear some similarities. + * + * <p>See the Guava User Guide article on <a + * href="http://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional"> + * using {@code Optional}</a>. + * + * @param <T> the type of instance that can be contained. {@code Optional} is naturally + * covariant on this type, so it is safe to cast an {@code Optional<T>} to {@code + * Optional<S>} for any supertype {@code S} of {@code T}. + * @author Kurt Alfred Kluever + * @author Kevin Bourrillion + * @since 10.0 + */ +@GwtCompatible(serializable = true) +public abstract class Optional<T> implements Serializable { + /** + * Returns an {@code Optional} instance with no contained reference. + */ + @SuppressWarnings("unchecked") + public static <T> Optional<T> absent() { + return (Optional<T>) Absent.INSTANCE; + } + + /** + * Returns an {@code Optional} instance containing the given non-null reference. + */ + public static <T> Optional<T> of(T reference) { + return new Present<T>(checkNotNull(reference)); + } + + /** + * If {@code nullableReference} is non-null, returns an {@code Optional} instance containing that + * reference; otherwise returns {@link Optional#absent}. + */ + public static <T> Optional<T> fromNullable(@Nullable T nullableReference) { + return (nullableReference == null) + ? Optional.<T>absent() + : new Present<T>(nullableReference); + } + + Optional() {} + + /** + * Returns {@code true} if this holder contains a (non-null) instance. + */ + public abstract boolean isPresent(); + + /** + * Returns the contained instance, which must be present. If the instance might be + * absent, use {@link #or(Object)} or {@link #orNull} instead. + * + * @throws IllegalStateException if the instance is absent ({@link #isPresent} returns + * {@code false}) + */ + public abstract T get(); + + /** + * Returns the contained instance if it is present; {@code defaultValue} otherwise. If + * no default value should be required because the instance is known to be present, use + * {@link #get()} instead. For a default value of {@code null}, use {@link #orNull}. + * + * <p>Note about generics: The signature {@code public T or(T defaultValue)} is overly + * restrictive. However, the ideal signature, {@code public <S super T> S or(S)}, is not legal + * Java. As a result, some sensible operations involving subtypes are compile errors: + * <pre> {@code + * + * Optional<Integer> optionalInt = getSomeOptionalInt(); + * Number value = optionalInt.or(0.5); // error + * + * FluentIterable<? extends Number> numbers = getSomeNumbers(); + * Optional<? extends Number> first = numbers.first(); + * Number value = first.or(0.5); // error}</pre> + * + * As a workaround, it is always safe to cast an {@code Optional<? extends T>} to {@code + * Optional<T>}. Casting either of the above example {@code Optional} instances to {@code + * Optional<Number>} (where {@code Number} is the desired output type) solves the problem: + * <pre> {@code + * + * Optional<Number> optionalInt = (Optional) getSomeOptionalInt(); + * Number value = optionalInt.or(0.5); // fine + * + * FluentIterable<? extends Number> numbers = getSomeNumbers(); + * Optional<Number> first = (Optional) numbers.first(); + * Number value = first.or(0.5); // fine}</pre> + */ + public abstract T or(T defaultValue); + + /** + * Returns this {@code Optional} if it has a value present; {@code secondChoice} + * otherwise. + */ + @Beta + public abstract Optional<T> or(Optional<? extends T> secondChoice); + + /** + * Returns the contained instance if it is present; {@code supplier.get()} otherwise. If the + * supplier returns {@code null}, a {@link NullPointerException} is thrown. + * + * @throws NullPointerException if the supplier returns {@code null} + */ + @Beta + public abstract T or(Supplier<? extends T> supplier); + + /** + * Returns the contained instance if it is present; {@code null} otherwise. If the + * instance is known to be present, use {@link #get()} instead. + */ + @Nullable + public abstract T orNull(); + + /** + * Returns an immutable singleton {@link Set} whose only element is the contained instance + * if it is present; an empty immutable {@link Set} otherwise. + * + * @since 11.0 + */ + public abstract Set<T> asSet(); + + /** + * If the instance is present, it is transformed with the given {@link Function}; otherwise, + * {@link Optional#absent} is returned. If the function returns {@code null}, a + * {@link NullPointerException} is thrown. + * + * @throws NullPointerException if the function returns {@code null} + * + * @since 12.0 + */ + @Beta + public abstract <V> Optional<V> transform(Function<? super T, V> function); + + /** + * Returns {@code true} if {@code object} is an {@code Optional} instance, and either + * the contained references are {@linkplain Object#equals equal} to each other or both + * are absent. Note that {@code Optional} instances of differing parameterized types can + * be equal. + */ + @Override + public abstract boolean equals(@Nullable Object object); + + /** + * Returns a hash code for this instance. + */ + @Override + public abstract int hashCode(); + + /** + * Returns a string representation for this instance. The form of this string + * representation is unspecified. + */ + @Override + public abstract String toString(); + + /** + * Returns the value of each present instance from the supplied {@code optionals}, in order, + * skipping over occurrences of {@link Optional#absent}. Iterators are unmodifiable and are + * evaluated lazily. + * + * @since 11.0 (generics widened in 13.0) + */ + @Beta + public static <T> Iterable<T> presentInstances( + final Iterable<? extends Optional<? extends T>> optionals) { + checkNotNull(optionals); + return new Iterable<T>() { + @Override + public Iterator<T> iterator() { + return new AbstractIterator<T>() { + private final Iterator<? extends Optional<? extends T>> iterator = + checkNotNull(optionals.iterator()); + + @Override + protected T computeNext() { + while (iterator.hasNext()) { + Optional<? extends T> optional = iterator.next(); + if (optional.isPresent()) { + return optional.get(); + } + } + return endOfData(); + } + }; + }; + }; + } + + private static final long serialVersionUID = 0; +} diff --git a/guava/src/com/google/common/base/PairwiseEquivalence.java b/guava/src/com/google/common/base/PairwiseEquivalence.java new file mode 100644 index 0000000..23ab539 --- /dev/null +++ b/guava/src/com/google/common/base/PairwiseEquivalence.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; + +import java.io.Serializable; +import java.util.Iterator; + +import javax.annotation.Nullable; + +@GwtCompatible(serializable = true) +final class PairwiseEquivalence<T> extends Equivalence<Iterable<T>> + implements Serializable { + + final Equivalence<? super T> elementEquivalence; + + PairwiseEquivalence(Equivalence<? super T> elementEquivalence) { + this.elementEquivalence = Preconditions.checkNotNull(elementEquivalence); + } + + @Override + protected boolean doEquivalent(Iterable<T> iterableA, Iterable<T> iterableB) { + Iterator<T> iteratorA = iterableA.iterator(); + Iterator<T> iteratorB = iterableB.iterator(); + + while (iteratorA.hasNext() && iteratorB.hasNext()) { + if (!elementEquivalence.equivalent(iteratorA.next(), iteratorB.next())) { + return false; + } + } + + return !iteratorA.hasNext() && !iteratorB.hasNext(); + } + + @Override + protected int doHash(Iterable<T> iterable) { + int hash = 78721; + for (T element : iterable) { + hash = hash * 24943 + elementEquivalence.hash(element); + } + return hash; + } + + @Override + public boolean equals(@Nullable Object object) { + if (object instanceof PairwiseEquivalence) { + PairwiseEquivalence<?> that = (PairwiseEquivalence<?>) object; + return this.elementEquivalence.equals(that.elementEquivalence); + } + + return false; + } + + @Override + public int hashCode() { + return elementEquivalence.hashCode() ^ 0x46a3eb07; + } + + @Override + public String toString() { + return elementEquivalence + ".pairwise()"; + } + + private static final long serialVersionUID = 1; +} diff --git a/guava/src/com/google/common/base/Platform.java b/guava/src/com/google/common/base/Platform.java new file mode 100644 index 0000000..dcbe06c --- /dev/null +++ b/guava/src/com/google/common/base/Platform.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; + +/** + * Methods factored out so that they can be emulated differently in GWT. + * + * @author Jesse Wilson + */ +@GwtCompatible(emulated = true) +final class Platform { + private Platform() {} + + /** Returns a thread-local 1024-char array. */ + static char[] charBufferFromThreadLocal() { + return DEST_TL.get(); + } + + /** Calls {@link System#nanoTime()}. */ + static long systemNanoTime() { + return System.nanoTime(); + } + + /** + * A thread-local destination buffer to keep us from creating new buffers. + * The starting size is 1024 characters. If we grow past this we don't + * put it back in the threadlocal, we just keep going and grow as needed. + */ + private static final ThreadLocal<char[]> DEST_TL = new ThreadLocal<char[]>() { + @Override + protected char[] initialValue() { + return new char[1024]; + } + }; + + static CharMatcher precomputeCharMatcher(CharMatcher matcher) { + return matcher.precomputedInternal(); + } +} diff --git a/guava/src/com/google/common/base/Preconditions.java b/guava/src/com/google/common/base/Preconditions.java new file mode 100644 index 0000000..802a309 --- /dev/null +++ b/guava/src/com/google/common/base/Preconditions.java @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.VisibleForTesting; + +import java.util.NoSuchElementException; + +import javax.annotation.Nullable; + +/** + * Simple static methods to be called at the start of your own methods to verify + * correct arguments and state. This allows constructs such as + * <pre> + * if (count <= 0) { + * throw new IllegalArgumentException("must be positive: " + count); + * }</pre> + * + * to be replaced with the more compact + * <pre> + * checkArgument(count > 0, "must be positive: %s", count);</pre> + * + * Note that the sense of the expression is inverted; with {@code Preconditions} + * you declare what you expect to be <i>true</i>, just as you do with an + * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html"> + * {@code assert}</a> or a JUnit {@code assertTrue} call. + * + * <p><b>Warning:</b> only the {@code "%s"} specifier is recognized as a + * placeholder in these messages, not the full range of {@link + * String#format(String, Object[])} specifiers. + * + * <p>Take care not to confuse precondition checking with other similar types + * of checks! Precondition exceptions -- including those provided here, but also + * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link + * UnsupportedOperationException} and others -- are used to signal that the + * <i>calling method</i> has made an error. This tells the caller that it should + * not have invoked the method when it did, with the arguments it did, or + * perhaps ever. Postcondition or other invariant failures should not throw + * these types of exceptions. + * + * <p>See the Guava User Guide on <a href= + * "http://code.google.com/p/guava-libraries/wiki/PreconditionsExplained"> + * using {@code Preconditions}</a>. + * + * @author Kevin Bourrillion + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public final class Preconditions { + private Preconditions() {} + + /** + * Ensures the truth of an expression involving one or more parameters to the + * calling method. + * + * @param expression a boolean expression + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument(boolean expression) { + if (!expression) { + throw new IllegalArgumentException(); + } + } + + /** + * Ensures the truth of an expression involving one or more parameters to the + * calling method. + * + * @param expression a boolean expression + * @param errorMessage the exception message to use if the check fails; will + * be converted to a string using {@link String#valueOf(Object)} + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument( + boolean expression, @Nullable Object errorMessage) { + if (!expression) { + throw new IllegalArgumentException(String.valueOf(errorMessage)); + } + } + + /** + * Ensures the truth of an expression involving one or more parameters to the + * calling method. + * + * @param expression a boolean expression + * @param errorMessageTemplate a template for the exception message should the + * check fail. The message is formed by replacing each {@code %s} + * placeholder in the template with an argument. These are matched by + * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. + * Unmatched arguments will be appended to the formatted message in square + * braces. Unmatched placeholders will be left as-is. + * @param errorMessageArgs the arguments to be substituted into the message + * template. Arguments are converted to strings using + * {@link String#valueOf(Object)}. + * @throws IllegalArgumentException if {@code expression} is false + * @throws NullPointerException if the check fails and either {@code + * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let + * this happen) + */ + public static void checkArgument(boolean expression, + @Nullable String errorMessageTemplate, + @Nullable Object... errorMessageArgs) { + if (!expression) { + throw new IllegalArgumentException( + format(errorMessageTemplate, errorMessageArgs)); + } + } + + /** + * Ensures the truth of an expression involving the state of the calling + * instance, but not involving any parameters to the calling method. + * + * @param expression a boolean expression + * @throws IllegalStateException if {@code expression} is false + */ + public static void checkState(boolean expression) { + if (!expression) { + throw new IllegalStateException(); + } + } + + /** + * Ensures the truth of an expression involving the state of the calling + * instance, but not involving any parameters to the calling method. + * + * @param expression a boolean expression + * @param errorMessage the exception message to use if the check fails; will + * be converted to a string using {@link String#valueOf(Object)} + * @throws IllegalStateException if {@code expression} is false + */ + public static void checkState( + boolean expression, @Nullable Object errorMessage) { + if (!expression) { + throw new IllegalStateException(String.valueOf(errorMessage)); + } + } + + /** + * Ensures the truth of an expression involving the state of the calling + * instance, but not involving any parameters to the calling method. + * + * @param expression a boolean expression + * @param errorMessageTemplate a template for the exception message should the + * check fail. The message is formed by replacing each {@code %s} + * placeholder in the template with an argument. These are matched by + * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. + * Unmatched arguments will be appended to the formatted message in square + * braces. Unmatched placeholders will be left as-is. + * @param errorMessageArgs the arguments to be substituted into the message + * template. Arguments are converted to strings using + * {@link String#valueOf(Object)}. + * @throws IllegalStateException if {@code expression} is false + * @throws NullPointerException if the check fails and either {@code + * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let + * this happen) + */ + public static void checkState(boolean expression, + @Nullable String errorMessageTemplate, + @Nullable Object... errorMessageArgs) { + if (!expression) { + throw new IllegalStateException( + format(errorMessageTemplate, errorMessageArgs)); + } + } + + /** + * Ensures that an object reference passed as a parameter to the calling + * method is not null. + * + * @param reference an object reference + * @return the non-null reference that was validated + * @throws NullPointerException if {@code reference} is null + */ + public static <T> T checkNotNull(T reference) { + if (reference == null) { + throw new NullPointerException(); + } + return reference; + } + + /** + * Ensures that an object reference passed as a parameter to the calling + * method is not null. + * + * @param reference an object reference + * @param errorMessage the exception message to use if the check fails; will + * be converted to a string using {@link String#valueOf(Object)} + * @return the non-null reference that was validated + * @throws NullPointerException if {@code reference} is null + */ + public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) { + if (reference == null) { + throw new NullPointerException(String.valueOf(errorMessage)); + } + return reference; + } + + /** + * Ensures that an object reference passed as a parameter to the calling + * method is not null. + * + * @param reference an object reference + * @param errorMessageTemplate a template for the exception message should the + * check fail. The message is formed by replacing each {@code %s} + * placeholder in the template with an argument. These are matched by + * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. + * Unmatched arguments will be appended to the formatted message in square + * braces. Unmatched placeholders will be left as-is. + * @param errorMessageArgs the arguments to be substituted into the message + * template. Arguments are converted to strings using + * {@link String#valueOf(Object)}. + * @return the non-null reference that was validated + * @throws NullPointerException if {@code reference} is null + */ + public static <T> T checkNotNull(T reference, + @Nullable String errorMessageTemplate, + @Nullable Object... errorMessageArgs) { + if (reference == null) { + // If either of these parameters is null, the right thing happens anyway + throw new NullPointerException( + format(errorMessageTemplate, errorMessageArgs)); + } + return reference; + } + + /* + * All recent hotspots (as of 2009) *really* like to have the natural code + * + * if (guardExpression) { + * throw new BadException(messageExpression); + * } + * + * refactored so that messageExpression is moved to a separate + * String-returning method. + * + * if (guardExpression) { + * throw new BadException(badMsg(...)); + * } + * + * The alternative natural refactorings into void or Exception-returning + * methods are much slower. This is a big deal - we're talking factors of + * 2-8 in microbenchmarks, not just 10-20%. (This is a hotspot optimizer + * bug, which should be fixed, but that's a separate, big project). + * + * The coding pattern above is heavily used in java.util, e.g. in ArrayList. + * There is a RangeCheckMicroBenchmark in the JDK that was used to test this. + * + * But the methods in this class want to throw different exceptions, + * depending on the args, so it appears that this pattern is not directly + * applicable. But we can use the ridiculous, devious trick of throwing an + * exception in the middle of the construction of another exception. + * Hotspot is fine with that. + */ + + /** + * Ensures that {@code index} specifies a valid <i>element</i> in an array, + * list or string of size {@code size}. An element index may range from zero, + * inclusive, to {@code size}, exclusive. + * + * @param index a user-supplied index identifying an element of an array, list + * or string + * @param size the size of that array, list or string + * @return the value of {@code index} + * @throws IndexOutOfBoundsException if {@code index} is negative or is not + * less than {@code size} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static int checkElementIndex(int index, int size) { + return checkElementIndex(index, size, "index"); + } + + /** + * Ensures that {@code index} specifies a valid <i>element</i> in an array, + * list or string of size {@code size}. An element index may range from zero, + * inclusive, to {@code size}, exclusive. + * + * @param index a user-supplied index identifying an element of an array, list + * or string + * @param size the size of that array, list or string + * @param desc the text to use to describe this index in an error message + * @return the value of {@code index} + * @throws IndexOutOfBoundsException if {@code index} is negative or is not + * less than {@code size} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static int checkElementIndex( + int index, int size, @Nullable String desc) { + // Carefully optimized for execution by hotspot (explanatory comment above) + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(badElementIndex(index, size, desc)); + } + return index; + } + + private static String badElementIndex(int index, int size, String desc) { + if (index < 0) { + return format("%s (%s) must not be negative", desc, index); + } else if (size < 0) { + throw new IllegalArgumentException("negative size: " + size); + } else { // index >= size + return format("%s (%s) must be less than size (%s)", desc, index, size); + } + } + + /** + * Ensures that {@code index} specifies a valid <i>position</i> in an array, + * list or string of size {@code size}. A position index may range from zero + * to {@code size}, inclusive. + * + * @param index a user-supplied index identifying a position in an array, list + * or string + * @param size the size of that array, list or string + * @return the value of {@code index} + * @throws IndexOutOfBoundsException if {@code index} is negative or is + * greater than {@code size} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static int checkPositionIndex(int index, int size) { + return checkPositionIndex(index, size, "index"); + } + + /** + * Ensures that {@code index} specifies a valid <i>position</i> in an array, + * list or string of size {@code size}. A position index may range from zero + * to {@code size}, inclusive. + * + * @param index a user-supplied index identifying a position in an array, list + * or string + * @param size the size of that array, list or string + * @param desc the text to use to describe this index in an error message + * @return the value of {@code index} + * @throws IndexOutOfBoundsException if {@code index} is negative or is + * greater than {@code size} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static int checkPositionIndex( + int index, int size, @Nullable String desc) { + // Carefully optimized for execution by hotspot (explanatory comment above) + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); + } + return index; + } + + private static String badPositionIndex(int index, int size, String desc) { + if (index < 0) { + return format("%s (%s) must not be negative", desc, index); + } else if (size < 0) { + throw new IllegalArgumentException("negative size: " + size); + } else { // index > size + return format("%s (%s) must not be greater than size (%s)", + desc, index, size); + } + } + + /** + * Ensures that {@code start} and {@code end} specify a valid <i>positions</i> + * in an array, list or string of size {@code size}, and are in order. A + * position index may range from zero to {@code size}, inclusive. + * + * @param start a user-supplied index identifying a starting position in an + * array, list or string + * @param end a user-supplied index identifying a ending position in an array, + * list or string + * @param size the size of that array, list or string + * @throws IndexOutOfBoundsException if either index is negative or is + * greater than {@code size}, or if {@code end} is less than {@code start} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static void checkPositionIndexes(int start, int end, int size) { + // Carefully optimized for execution by hotspot (explanatory comment above) + if (start < 0 || end < start || end > size) { + throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); + } + } + + private static String badPositionIndexes(int start, int end, int size) { + if (start < 0 || start > size) { + return badPositionIndex(start, size, "start index"); + } + if (end < 0 || end > size) { + return badPositionIndex(end, size, "end index"); + } + // end < start + return format("end index (%s) must not be less than start index (%s)", + end, start); + } + + /** + * Substitutes each {@code %s} in {@code template} with an argument. These + * are matched by position - the first {@code %s} gets {@code args[0]}, etc. + * If there are more arguments than placeholders, the unmatched arguments will + * be appended to the end of the formatted message in square braces. + * + * @param template a non-null string containing 0 or more {@code %s} + * placeholders. + * @param args the arguments to be substituted into the message + * template. Arguments are converted to strings using + * {@link String#valueOf(Object)}. Arguments can be null. + */ + @VisibleForTesting static String format(String template, + @Nullable Object... args) { + template = String.valueOf(template); // null -> "null" + + // start substituting the arguments into the '%s' placeholders + StringBuilder builder = new StringBuilder( + template.length() + 16 * args.length); + int templateStart = 0; + int i = 0; + while (i < args.length) { + int placeholderStart = template.indexOf("%s", templateStart); + if (placeholderStart == -1) { + break; + } + builder.append(template.substring(templateStart, placeholderStart)); + builder.append(args[i++]); + templateStart = placeholderStart + 2; + } + builder.append(template.substring(templateStart)); + + // if we run out of placeholders, append the extra args in square braces + if (i < args.length) { + builder.append(" ["); + builder.append(args[i++]); + while (i < args.length) { + builder.append(", "); + builder.append(args[i++]); + } + builder.append(']'); + } + + return builder.toString(); + } +} diff --git a/guava/src/com/google/common/base/Predicate.java b/guava/src/com/google/common/base/Predicate.java new file mode 100644 index 0000000..89a8c36 --- /dev/null +++ b/guava/src/com/google/common/base/Predicate.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; + +import javax.annotation.Nullable; + +/** + * Determines a true or false value for a given input. + * + * <p>See the Guava User Guide article on <a href= + * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the use of {@code + * Predicate}</a>. + * + * @author Kevin Bourrillion + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public interface Predicate<T> { + /** + * Returns the result of applying this predicate to {@code input}. This method is <i>generally + * expected</i>, but not absolutely required, to have the following properties: + * + * <ul> + * <li>Its execution does not cause any observable side effects. + * <li>The computation is <i>consistent with equals</i>; that is, {@link Objects#equal + * Objects.equal}{@code (a, b)} implies that {@code predicate.apply(a) == + * predicate.apply(b))}. + * </ul> + * + * @throws NullPointerException if {@code input} is null and this predicate does not accept null + * arguments + */ + boolean apply(@Nullable T input); + + /** + * Indicates whether another object is equal to this predicate. + * + * <p>Most implementations will have no reason to override the behavior of {@link Object#equals}. + * However, an implementation may also choose to return {@code true} whenever {@code object} is a + * {@link Predicate} that it considers <i>interchangeable</i> with this one. "Interchangeable" + * <i>typically</i> means that {@code this.apply(t) == that.apply(t)} for all {@code t} of type + * {@code T}). Note that a {@code false} result from this method does not imply that the + * predicates are known <i>not</i> to be interchangeable. + */ + @Override + boolean equals(@Nullable Object object); +} diff --git a/guava/src/com/google/common/base/Predicates.java b/guava/src/com/google/common/base/Predicates.java new file mode 100644 index 0000000..5c42c55 --- /dev/null +++ b/guava/src/com/google/common/base/Predicates.java @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.GwtIncompatible; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +/** + * Static utility methods pertaining to {@code Predicate} instances. + * + * <p>All methods returns serializable predicates as long as they're given + * serializable parameters. + * + * <p>See the Guava User Guide article on <a href= + * "http://code.google.com/p/guava-libraries/wiki/FunctionalExplained">the + * use of {@code Predicate}</a>. + * + * @author Kevin Bourrillion + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible(emulated = true) +public final class Predicates { + private Predicates() {} + + // TODO(kevinb): considering having these implement a VisitablePredicate + // interface which specifies an accept(PredicateVisitor) method. + + /** + * Returns a predicate that always evaluates to {@code true}. + */ + @GwtCompatible(serializable = true) + public static <T> Predicate<T> alwaysTrue() { + return ObjectPredicate.ALWAYS_TRUE.withNarrowedType(); + } + + /** + * Returns a predicate that always evaluates to {@code false}. + */ + @GwtCompatible(serializable = true) + public static <T> Predicate<T> alwaysFalse() { + return ObjectPredicate.ALWAYS_FALSE.withNarrowedType(); + } + + /** + * Returns a predicate that evaluates to {@code true} if the object reference + * being tested is null. + */ + @GwtCompatible(serializable = true) + public static <T> Predicate<T> isNull() { + return ObjectPredicate.IS_NULL.withNarrowedType(); + } + + /** + * Returns a predicate that evaluates to {@code true} if the object reference + * being tested is not null. + */ + @GwtCompatible(serializable = true) + public static <T> Predicate<T> notNull() { + return ObjectPredicate.NOT_NULL.withNarrowedType(); + } + + /** + * Returns a predicate that evaluates to {@code true} if the given predicate + * evaluates to {@code false}. + */ + public static <T> Predicate<T> not(Predicate<T> predicate) { + return new NotPredicate<T>(predicate); + } + + /** + * Returns a predicate that evaluates to {@code true} if each of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a false + * predicate is found. It defensively copies the iterable passed in, so future + * changes to it won't alter the behavior of this predicate. If {@code + * components} is empty, the returned predicate will always evaluate to {@code + * true}. + */ + public static <T> Predicate<T> and( + Iterable<? extends Predicate<? super T>> components) { + return new AndPredicate<T>(defensiveCopy(components)); + } + + /** + * Returns a predicate that evaluates to {@code true} if each of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a false + * predicate is found. It defensively copies the array passed in, so future + * changes to it won't alter the behavior of this predicate. If {@code + * components} is empty, the returned predicate will always evaluate to {@code + * true}. + */ + public static <T> Predicate<T> and(Predicate<? super T>... components) { + return new AndPredicate<T>(defensiveCopy(components)); + } + + /** + * Returns a predicate that evaluates to {@code true} if both of its + * components evaluate to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a false + * predicate is found. + */ + public static <T> Predicate<T> and(Predicate<? super T> first, + Predicate<? super T> second) { + return new AndPredicate<T>(Predicates.<T>asList( + checkNotNull(first), checkNotNull(second))); + } + + /** + * Returns a predicate that evaluates to {@code true} if any one of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a + * true predicate is found. It defensively copies the iterable passed in, so + * future changes to it won't alter the behavior of this predicate. If {@code + * components} is empty, the returned predicate will always evaluate to {@code + * false}. + */ + public static <T> Predicate<T> or( + Iterable<? extends Predicate<? super T>> components) { + return new OrPredicate<T>(defensiveCopy(components)); + } + + /** + * Returns a predicate that evaluates to {@code true} if any one of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a + * true predicate is found. It defensively copies the array passed in, so + * future changes to it won't alter the behavior of this predicate. If {@code + * components} is empty, the returned predicate will always evaluate to {@code + * false}. + */ + public static <T> Predicate<T> or(Predicate<? super T>... components) { + return new OrPredicate<T>(defensiveCopy(components)); + } + + /** + * Returns a predicate that evaluates to {@code true} if either of its + * components evaluates to {@code true}. The components are evaluated in + * order, and evaluation will be "short-circuited" as soon as a + * true predicate is found. + */ + public static <T> Predicate<T> or( + Predicate<? super T> first, Predicate<? super T> second) { + return new OrPredicate<T>(Predicates.<T>asList( + checkNotNull(first), checkNotNull(second))); + } + + /** + * Returns a predicate that evaluates to {@code true} if the object being + * tested {@code equals()} the given target or both are null. + */ + public static <T> Predicate<T> equalTo(@Nullable T target) { + return (target == null) + ? Predicates.<T>isNull() + : new IsEqualToPredicate<T>(target); + } + + /** + * Returns a predicate that evaluates to {@code true} if the object being + * tested is an instance of the given class. If the object being tested + * is {@code null} this predicate evaluates to {@code false}. + * + * <p>If you want to filter an {@code Iterable} to narrow its type, consider + * using {@link com.google.common.collect.Iterables#filter(Iterable, Class)} + * in preference. + * + * <p><b>Warning:</b> contrary to the typical assumptions about predicates (as + * documented at {@link Predicate#apply}), the returned predicate may not be + * <i>consistent with equals</i>. For example, {@code + * instanceOf(ArrayList.class)} will yield different results for the two equal + * instances {@code Lists.newArrayList(1)} and {@code Arrays.asList(1)}. + */ + @GwtIncompatible("Class.isInstance") + public static Predicate<Object> instanceOf(Class<?> clazz) { + return new InstanceOfPredicate(clazz); + } + + /** + * Returns a predicate that evaluates to {@code true} if the class being + * tested is assignable from the given class. The returned predicate + * does not allow null inputs. + * + * @since 10.0 + */ + @GwtIncompatible("Class.isAssignableFrom") + @Beta + public static Predicate<Class<?>> assignableFrom(Class<?> clazz) { + return new AssignableFromPredicate(clazz); + } + + /** + * Returns a predicate that evaluates to {@code true} if the object reference + * being tested is a member of the given collection. It does not defensively + * copy the collection passed in, so future changes to it will alter the + * behavior of the predicate. + * + * <p>This method can technically accept any {@code Collection<?>}, but using + * a typed collection helps prevent bugs. This approach doesn't block any + * potential users since it is always possible to use {@code + * Predicates.<Object>in()}. + * + * @param target the collection that may contain the function input + */ + public static <T> Predicate<T> in(Collection<? extends T> target) { + return new InPredicate<T>(target); + } + + /** + * Returns the composition of a function and a predicate. For every {@code x}, + * the generated predicate returns {@code predicate(function(x))}. + * + * @return the composition of the provided function and predicate + */ + public static <A, B> Predicate<A> compose( + Predicate<B> predicate, Function<A, ? extends B> function) { + return new CompositionPredicate<A, B>(predicate, function); + } + + /** + * Returns a predicate that evaluates to {@code true} if the + * {@code CharSequence} being tested contains any match for the given + * regular expression pattern. The test used is equivalent to + * {@code Pattern.compile(pattern).matcher(arg).find()} + * + * @throws java.util.regex.PatternSyntaxException if the pattern is invalid + * @since 3.0 + */ + @GwtIncompatible(value = "java.util.regex.Pattern") + public static Predicate<CharSequence> containsPattern(String pattern) { + return new ContainsPatternPredicate(pattern); + } + + /** + * Returns a predicate that evaluates to {@code true} if the + * {@code CharSequence} being tested contains any match for the given + * regular expression pattern. The test used is equivalent to + * {@code pattern.matcher(arg).find()} + * + * @since 3.0 + */ + @GwtIncompatible(value = "java.util.regex.Pattern") + public static Predicate<CharSequence> contains(Pattern pattern) { + return new ContainsPatternPredicate(pattern); + } + + // End public API, begin private implementation classes. + + // Package private for GWT serialization. + enum ObjectPredicate implements Predicate<Object> { + ALWAYS_TRUE { + @Override public boolean apply(@Nullable Object o) { + return true; + } + }, + ALWAYS_FALSE { + @Override public boolean apply(@Nullable Object o) { + return false; + } + }, + IS_NULL { + @Override public boolean apply(@Nullable Object o) { + return o == null; + } + }, + NOT_NULL { + @Override public boolean apply(@Nullable Object o) { + return o != null; + } + }; + + @SuppressWarnings("unchecked") // these Object predicates work for any T + <T> Predicate<T> withNarrowedType() { + return (Predicate<T>) this; + } + } + + /** @see Predicates#not(Predicate) */ + private static class NotPredicate<T> implements Predicate<T>, Serializable { + final Predicate<T> predicate; + + NotPredicate(Predicate<T> predicate) { + this.predicate = checkNotNull(predicate); + } + @Override + public boolean apply(T t) { + return !predicate.apply(t); + } + @Override public int hashCode() { + return ~predicate.hashCode(); + } + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof NotPredicate) { + NotPredicate<?> that = (NotPredicate<?>) obj; + return predicate.equals(that.predicate); + } + return false; + } + @Override public String toString() { + return "Not(" + predicate.toString() + ")"; + } + private static final long serialVersionUID = 0; + } + + private static final Joiner COMMA_JOINER = Joiner.on(","); + + /** @see Predicates#and(Iterable) */ + private static class AndPredicate<T> implements Predicate<T>, Serializable { + private final List<? extends Predicate<? super T>> components; + + private AndPredicate(List<? extends Predicate<? super T>> components) { + this.components = components; + } + @Override + public boolean apply(T t) { + // Avoid using the Iterator to avoid generating garbage (issue 820). + for (int i = 0; i < components.size(); i++) { + if (!components.get(i).apply(t)) { + return false; + } + } + return true; + } + @Override public int hashCode() { + // add a random number to avoid collisions with OrPredicate + return components.hashCode() + 0x12472c2c; + } + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof AndPredicate) { + AndPredicate<?> that = (AndPredicate<?>) obj; + return components.equals(that.components); + } + return false; + } + @Override public String toString() { + return "And(" + COMMA_JOINER.join(components) + ")"; + } + private static final long serialVersionUID = 0; + } + + /** @see Predicates#or(Iterable) */ + private static class OrPredicate<T> implements Predicate<T>, Serializable { + private final List<? extends Predicate<? super T>> components; + + private OrPredicate(List<? extends Predicate<? super T>> components) { + this.components = components; + } + @Override + public boolean apply(T t) { + // Avoid using the Iterator to avoid generating garbage (issue 820). + for (int i = 0; i < components.size(); i++) { + if (components.get(i).apply(t)) { + return true; + } + } + return false; + } + @Override public int hashCode() { + // add a random number to avoid collisions with AndPredicate + return components.hashCode() + 0x053c91cf; + } + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof OrPredicate) { + OrPredicate<?> that = (OrPredicate<?>) obj; + return components.equals(that.components); + } + return false; + } + @Override public String toString() { + return "Or(" + COMMA_JOINER.join(components) + ")"; + } + private static final long serialVersionUID = 0; + } + + /** @see Predicates#equalTo(Object) */ + private static class IsEqualToPredicate<T> + implements Predicate<T>, Serializable { + private final T target; + + private IsEqualToPredicate(T target) { + this.target = target; + } + @Override + public boolean apply(T t) { + return target.equals(t); + } + @Override public int hashCode() { + return target.hashCode(); + } + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof IsEqualToPredicate) { + IsEqualToPredicate<?> that = (IsEqualToPredicate<?>) obj; + return target.equals(that.target); + } + return false; + } + @Override public String toString() { + return "IsEqualTo(" + target + ")"; + } + private static final long serialVersionUID = 0; + } + + /** @see Predicates#instanceOf(Class) */ + @GwtIncompatible("Class.isInstance") + private static class InstanceOfPredicate + implements Predicate<Object>, Serializable { + private final Class<?> clazz; + + private InstanceOfPredicate(Class<?> clazz) { + this.clazz = checkNotNull(clazz); + } + @Override + public boolean apply(@Nullable Object o) { + return clazz.isInstance(o); + } + @Override public int hashCode() { + return clazz.hashCode(); + } + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof InstanceOfPredicate) { + InstanceOfPredicate that = (InstanceOfPredicate) obj; + return clazz == that.clazz; + } + return false; + } + @Override public String toString() { + return "IsInstanceOf(" + clazz.getName() + ")"; + } + private static final long serialVersionUID = 0; + } + + /** @see Predicates#assignableFrom(Class) */ + @GwtIncompatible("Class.isAssignableFrom") + private static class AssignableFromPredicate + implements Predicate<Class<?>>, Serializable { + private final Class<?> clazz; + + private AssignableFromPredicate(Class<?> clazz) { + this.clazz = checkNotNull(clazz); + } + @Override + public boolean apply(Class<?> input) { + return clazz.isAssignableFrom(input); + } + @Override public int hashCode() { + return clazz.hashCode(); + } + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof AssignableFromPredicate) { + AssignableFromPredicate that = (AssignableFromPredicate) obj; + return clazz == that.clazz; + } + return false; + } + @Override public String toString() { + return "IsAssignableFrom(" + clazz.getName() + ")"; + } + private static final long serialVersionUID = 0; + } + + /** @see Predicates#in(Collection) */ + private static class InPredicate<T> implements Predicate<T>, Serializable { + private final Collection<?> target; + + private InPredicate(Collection<?> target) { + this.target = checkNotNull(target); + } + + @Override + public boolean apply(T t) { + try { + return target.contains(t); + } catch (NullPointerException e) { + return false; + } catch (ClassCastException e) { + return false; + } + } + + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof InPredicate) { + InPredicate<?> that = (InPredicate<?>) obj; + return target.equals(that.target); + } + return false; + } + + @Override public int hashCode() { + return target.hashCode(); + } + + @Override public String toString() { + return "In(" + target + ")"; + } + private static final long serialVersionUID = 0; + } + + /** @see Predicates#compose(Predicate, Function) */ + private static class CompositionPredicate<A, B> + implements Predicate<A>, Serializable { + final Predicate<B> p; + final Function<A, ? extends B> f; + + private CompositionPredicate(Predicate<B> p, Function<A, ? extends B> f) { + this.p = checkNotNull(p); + this.f = checkNotNull(f); + } + + @Override + public boolean apply(A a) { + return p.apply(f.apply(a)); + } + + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof CompositionPredicate) { + CompositionPredicate<?, ?> that = (CompositionPredicate<?, ?>) obj; + return f.equals(that.f) && p.equals(that.p); + } + return false; + } + + @Override public int hashCode() { + return f.hashCode() ^ p.hashCode(); + } + + @Override public String toString() { + return p.toString() + "(" + f.toString() + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * @see Predicates#contains(Pattern) + * @see Predicates#containsPattern(String) + */ + @GwtIncompatible("Only used by other GWT-incompatible code.") + private static class ContainsPatternPredicate + implements Predicate<CharSequence>, Serializable { + final Pattern pattern; + + ContainsPatternPredicate(Pattern pattern) { + this.pattern = checkNotNull(pattern); + } + + ContainsPatternPredicate(String patternStr) { + this(Pattern.compile(patternStr)); + } + + @Override + public boolean apply(CharSequence t) { + return pattern.matcher(t).find(); + } + + @Override public int hashCode() { + // Pattern uses Object.hashCode, so we have to reach + // inside to build a hashCode consistent with equals. + + return Objects.hashCode(pattern.pattern(), pattern.flags()); + } + + @Override public boolean equals(@Nullable Object obj) { + if (obj instanceof ContainsPatternPredicate) { + ContainsPatternPredicate that = (ContainsPatternPredicate) obj; + + // Pattern uses Object (identity) equality, so we have to reach + // inside to compare individual fields. + return Objects.equal(pattern.pattern(), that.pattern.pattern()) + && Objects.equal(pattern.flags(), that.pattern.flags()); + } + return false; + } + + @Override public String toString() { + return Objects.toStringHelper(this) + .add("pattern", pattern) + .add("pattern.flags", Integer.toHexString(pattern.flags())) + .toString(); + } + + private static final long serialVersionUID = 0; + } + + @SuppressWarnings("unchecked") + private static <T> List<Predicate<? super T>> asList( + Predicate<? super T> first, Predicate<? super T> second) { + return Arrays.<Predicate<? super T>>asList(first, second); + } + + private static <T> List<T> defensiveCopy(T... array) { + return defensiveCopy(Arrays.asList(array)); + } + + static <T> List<T> defensiveCopy(Iterable<T> iterable) { + ArrayList<T> list = new ArrayList<T>(); + for (T element : iterable) { + list.add(checkNotNull(element)); + } + return list; + } +} diff --git a/guava/src/com/google/common/base/Present.java b/guava/src/com/google/common/base/Present.java new file mode 100644 index 0000000..aa1ddc5 --- /dev/null +++ b/guava/src/com/google/common/base/Present.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.GwtCompatible; + +import java.util.Collections; +import java.util.Set; + +import javax.annotation.Nullable; + +/** + * Implementation of an {@link Optional} containing a reference. + */ +@GwtCompatible +final class Present<T> extends Optional<T> { + private final T reference; + + Present(T reference) { + this.reference = reference; + } + + @Override public boolean isPresent() { + return true; + } + + @Override public T get() { + return reference; + } + + @Override public T or(T defaultValue) { + checkNotNull(defaultValue, "use orNull() instead of or(null)"); + return reference; + } + + @Override public Optional<T> or(Optional<? extends T> secondChoice) { + checkNotNull(secondChoice); + return this; + } + + @Override public T or(Supplier<? extends T> supplier) { + checkNotNull(supplier); + return reference; + } + + @Override public T orNull() { + return reference; + } + + @Override public Set<T> asSet() { + return Collections.singleton(reference); + } + + @Override public <V> Optional<V> transform(Function<? super T, V> function) { + return new Present<V>(checkNotNull(function.apply(reference), + "Transformation function cannot return null.")); + } + + @Override public boolean equals(@Nullable Object object) { + if (object instanceof Present) { + Present<?> other = (Present<?>) object; + return reference.equals(other.reference); + } + return false; + } + + @Override public int hashCode() { + return 0x598df91c + reference.hashCode(); + } + + @Override public String toString() { + return "Optional.of(" + reference + ")"; + } + + private static final long serialVersionUID = 0; +} diff --git a/guava/src/com/google/common/base/SmallCharMatcher.java b/guava/src/com/google/common/base/SmallCharMatcher.java new file mode 100644 index 0000000..b62a488 --- /dev/null +++ b/guava/src/com/google/common/base/SmallCharMatcher.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2012 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.VisibleForTesting; + +/** + * An immutable small version of CharMatcher that uses an efficient hash table implementation, with + * non-power-of-2 sizing to try to use no reprobing, if possible. + * + * @author Christopher Swenson + */ +@GwtCompatible +final class SmallCharMatcher extends CharMatcher { + static final int MAX_SIZE = 63; + static final int MAX_TABLE_SIZE = 128; + private final boolean reprobe; + private final char[] table; + private final boolean containsZero; + final long filter; + + private SmallCharMatcher(char[] table, long filter, boolean containsZero, + boolean reprobe, String description) { + super(description); + this.table = table; + this.filter = filter; + this.containsZero = containsZero; + this.reprobe = reprobe; + } + + private boolean checkFilter(int c) { + return 1 == (1 & (filter >> c)); + } + + @Override + public CharMatcher precomputed() { + return this; + } + + @VisibleForTesting + static char[] buildTable(int modulus, char[] allChars, boolean reprobe) { + char[] table = new char[modulus]; + for (int i = 0; i < allChars.length; i++) { + char c = allChars[i]; + int index = c % modulus; + if (index < 0) { + index += modulus; + } + if ((table[index] != 0) && !reprobe) { + return null; + } else if (reprobe) { + while (table[index] != 0) { + index = (index + 1) % modulus; + } + } + table[index] = c; + } + return table; + } + + static CharMatcher from(char[] chars, String description) { + long filter = 0; + int size = chars.length; + boolean containsZero = false; + boolean reprobe = false; + containsZero = chars[0] == 0; + + // Compute the filter. + for (char c : chars) { + filter |= 1L << c; + } + char[] table = null; + for (int i = size; i < MAX_TABLE_SIZE; i++) { + table = buildTable(i, chars, false); + if (table != null) { + break; + } + } + // Compute the hash table. + if (table == null) { + table = buildTable(MAX_TABLE_SIZE, chars, true); + reprobe = true; + } + return new SmallCharMatcher(table, filter, containsZero, reprobe, description); + } + + @Override + public boolean matches(char c) { + if (c == 0) { + return containsZero; + } + if (!checkFilter(c)) { + return false; + } + int index = c % table.length; + if (index < 0) { + index += table.length; + } + while (true) { + // Check for empty. + if (table[index] == 0) { + return false; + } else if (table[index] == c) { + return true; + } else if (reprobe) { + // Linear probing will terminate eventually. + index = (index + 1) % table.length; + } else { + return false; + } + } + } +} diff --git a/guava/src/com/google/common/base/Splitter.java b/guava/src/com/google/common/base/Splitter.java new file mode 100644 index 0000000..a1c236c --- /dev/null +++ b/guava/src/com/google/common/base/Splitter.java @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2009 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.GwtIncompatible; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.CheckReturnValue; + +/** + * An object that divides strings (or other instances of {@code CharSequence}) + * into substrings, by recognizing a <i>separator</i> (a.k.a. "delimiter") + * which can be expressed as a single character, literal string, regular + * expression, {@code CharMatcher}, or by using a fixed substring length. This + * class provides the complementary functionality to {@link Joiner}. + * + * <p>Here is the most basic example of {@code Splitter} usage: <pre> {@code + * + * Splitter.on(',').split("foo,bar")}</pre> + * + * This invocation returns an {@code Iterable<String>} containing {@code "foo"} + * and {@code "bar"}, in that order. + * + * <p>By default {@code Splitter}'s behavior is very simplistic: <pre> {@code + * + * Splitter.on(',').split("foo,,bar, quux")}</pre> + * + * This returns an iterable containing {@code ["foo", "", "bar", " quux"]}. + * Notice that the splitter does not assume that you want empty strings removed, + * or that you wish to trim whitespace. If you want features like these, simply + * ask for them: <pre> {@code + * + * private static final Splitter MY_SPLITTER = Splitter.on(',') + * .trimResults() + * .omitEmptyStrings();}</pre> + * + * Now {@code MY_SPLITTER.split("foo, ,bar, quux,")} returns an iterable + * containing just {@code ["foo", "bar", "quux"]}. Note that the order in which + * the configuration methods are called is never significant; for instance, + * trimming is always applied first before checking for an empty result, + * regardless of the order in which the {@link #trimResults()} and + * {@link #omitEmptyStrings()} methods were invoked. + * + * <p><b>Warning: splitter instances are always immutable</b>; a configuration + * method such as {@code omitEmptyStrings} has no effect on the instance it + * is invoked on! You must store and use the new splitter instance returned by + * the method. This makes splitters thread-safe, and safe to store as {@code + * static final} constants (as illustrated above). <pre> {@code + * + * // Bad! Do not do this! + * Splitter splitter = Splitter.on('/'); + * splitter.trimResults(); // does nothing! + * return splitter.split("wrong / wrong / wrong");}</pre> + * + * The separator recognized by the splitter does not have to be a single + * literal character as in the examples above. See the methods {@link + * #on(String)}, {@link #on(Pattern)} and {@link #on(CharMatcher)} for examples + * of other ways to specify separators. + * + * <p><b>Note:</b> this class does not mimic any of the quirky behaviors of + * similar JDK methods; for instance, it does not silently discard trailing + * separators, as does {@link String#split(String)}, nor does it have a default + * behavior of using five particular whitespace characters as separators, like + * {@link java.util.StringTokenizer}. + * + * <p>See the Guava User Guide article on <a href= + * "http://code.google.com/p/guava-libraries/wiki/StringsExplained#Splitter"> + * {@code Splitter}</a>. + * + * @author Julien Silland + * @author Jesse Wilson + * @author Kevin Bourrillion + * @author Louis Wasserman + * @since 1.0 + */ +@GwtCompatible(emulated = true) +public final class Splitter { + private final CharMatcher trimmer; + private final boolean omitEmptyStrings; + private final Strategy strategy; + private final int limit; + + private Splitter(Strategy strategy) { + this(strategy, false, CharMatcher.NONE, Integer.MAX_VALUE); + } + + private Splitter(Strategy strategy, boolean omitEmptyStrings, + CharMatcher trimmer, int limit) { + this.strategy = strategy; + this.omitEmptyStrings = omitEmptyStrings; + this.trimmer = trimmer; + this.limit = limit; + } + + /** + * Returns a splitter that uses the given single-character separator. For + * example, {@code Splitter.on(',').split("foo,,bar")} returns an iterable + * containing {@code ["foo", "", "bar"]}. + * + * @param separator the character to recognize as a separator + * @return a splitter, with default settings, that recognizes that separator + */ + public static Splitter on(char separator) { + return on(CharMatcher.is(separator)); + } + + /** + * Returns a splitter that considers any single character matched by the + * given {@code CharMatcher} to be a separator. For example, {@code + * Splitter.on(CharMatcher.anyOf(";,")).split("foo,;bar,quux")} returns an + * iterable containing {@code ["foo", "", "bar", "quux"]}. + * + * @param separatorMatcher a {@link CharMatcher} that determines whether a + * character is a separator + * @return a splitter, with default settings, that uses this matcher + */ + public static Splitter on(final CharMatcher separatorMatcher) { + checkNotNull(separatorMatcher); + + return new Splitter(new Strategy() { + @Override public SplittingIterator iterator( + Splitter splitter, final CharSequence toSplit) { + return new SplittingIterator(splitter, toSplit) { + @Override int separatorStart(int start) { + return separatorMatcher.indexIn(toSplit, start); + } + + @Override int separatorEnd(int separatorPosition) { + return separatorPosition + 1; + } + }; + } + }); + } + + /** + * Returns a splitter that uses the given fixed string as a separator. For + * example, {@code Splitter.on(", ").split("foo, bar, baz,qux")} returns an + * iterable containing {@code ["foo", "bar", "baz,qux"]}. + * + * @param separator the literal, nonempty string to recognize as a separator + * @return a splitter, with default settings, that recognizes that separator + */ + public static Splitter on(final String separator) { + checkArgument(separator.length() != 0, + "The separator may not be the empty string."); + + return new Splitter(new Strategy() { + @Override public SplittingIterator iterator( + Splitter splitter, CharSequence toSplit) { + return new SplittingIterator(splitter, toSplit) { + @Override public int separatorStart(int start) { + int delimeterLength = separator.length(); + + positions: + for (int p = start, last = toSplit.length() - delimeterLength; + p <= last; p++) { + for (int i = 0; i < delimeterLength; i++) { + if (toSplit.charAt(i + p) != separator.charAt(i)) { + continue positions; + } + } + return p; + } + return -1; + } + + @Override public int separatorEnd(int separatorPosition) { + return separatorPosition + separator.length(); + } + }; + } + }); + } + + /** + * Returns a splitter that considers any subsequence matching {@code + * pattern} to be a separator. For example, {@code + * Splitter.on(Pattern.compile("\r?\n")).split(entireFile)} splits a string + * into lines whether it uses DOS-style or UNIX-style line terminators. + * + * @param separatorPattern the pattern that determines whether a subsequence + * is a separator. This pattern may not match the empty string. + * @return a splitter, with default settings, that uses this pattern + * @throws IllegalArgumentException if {@code separatorPattern} matches the + * empty string + */ + @GwtIncompatible("java.util.regex") + public static Splitter on(final Pattern separatorPattern) { + checkNotNull(separatorPattern); + checkArgument(!separatorPattern.matcher("").matches(), + "The pattern may not match the empty string: %s", separatorPattern); + + return new Splitter(new Strategy() { + @Override public SplittingIterator iterator( + final Splitter splitter, CharSequence toSplit) { + final Matcher matcher = separatorPattern.matcher(toSplit); + return new SplittingIterator(splitter, toSplit) { + @Override public int separatorStart(int start) { + return matcher.find(start) ? matcher.start() : -1; + } + + @Override public int separatorEnd(int separatorPosition) { + return matcher.end(); + } + }; + } + }); + } + + /** + * Returns a splitter that considers any subsequence matching a given + * pattern (regular expression) to be a separator. For example, {@code + * Splitter.onPattern("\r?\n").split(entireFile)} splits a string into lines + * whether it uses DOS-style or UNIX-style line terminators. This is + * equivalent to {@code Splitter.on(Pattern.compile(pattern))}. + * + * @param separatorPattern the pattern that determines whether a subsequence + * is a separator. This pattern may not match the empty string. + * @return a splitter, with default settings, that uses this pattern + * @throws java.util.regex.PatternSyntaxException if {@code separatorPattern} + * is a malformed expression + * @throws IllegalArgumentException if {@code separatorPattern} matches the + * empty string + */ + @GwtIncompatible("java.util.regex") + public static Splitter onPattern(String separatorPattern) { + return on(Pattern.compile(separatorPattern)); + } + + /** + * Returns a splitter that divides strings into pieces of the given length. + * For example, {@code Splitter.fixedLength(2).split("abcde")} returns an + * iterable containing {@code ["ab", "cd", "e"]}. The last piece can be + * smaller than {@code length} but will never be empty. + * + * @param length the desired length of pieces after splitting + * @return a splitter, with default settings, that can split into fixed sized + * pieces + */ + public static Splitter fixedLength(final int length) { + checkArgument(length > 0, "The length may not be less than 1"); + + return new Splitter(new Strategy() { + @Override public SplittingIterator iterator( + final Splitter splitter, CharSequence toSplit) { + return new SplittingIterator(splitter, toSplit) { + @Override public int separatorStart(int start) { + int nextChunkStart = start + length; + return (nextChunkStart < toSplit.length() ? nextChunkStart : -1); + } + + @Override public int separatorEnd(int separatorPosition) { + return separatorPosition; + } + }; + } + }); + } + + /** + * Returns a splitter that behaves equivalently to {@code this} splitter, but + * automatically omits empty strings from the results. For example, {@code + * Splitter.on(',').omitEmptyStrings().split(",a,,,b,c,,")} returns an + * iterable containing only {@code ["a", "b", "c"]}. + * + * <p>If either {@code trimResults} option is also specified when creating a + * splitter, that splitter always trims results first before checking for + * emptiness. So, for example, {@code + * Splitter.on(':').omitEmptyStrings().trimResults().split(": : : ")} returns + * an empty iterable. + * + * <p>Note that it is ordinarily not possible for {@link #split(CharSequence)} + * to return an empty iterable, but when using this option, it can (if the + * input sequence consists of nothing but separators). + * + * @return a splitter with the desired configuration + */ + @CheckReturnValue + public Splitter omitEmptyStrings() { + return new Splitter(strategy, true, trimmer, limit); + } + + /** + * Returns a splitter that behaves equivalently to {@code this} splitter but + * stops splitting after it reaches the limit. + * The limit defines the maximum number of items returned by the iterator. + * + * <p>For example, + * {@code Splitter.on(',').limit(3).split("a,b,c,d")} returns an iterable + * containing {@code ["a", "b", "c,d"]}. When omitting empty strings, the + * omitted strings do no count. Hence, + * {@code Splitter.on(',').limit(3).omitEmptyStrings().split("a,,,b,,,c,d")} + * returns an iterable containing {@code ["a", "b", "c,d"}. + * When trim is requested, all entries, including the last are trimmed. Hence + * {@code Splitter.on(',').limit(3).trimResults().split(" a , b , c , d ")} + * results in @{code ["a", "b", "c , d"]}. + * + * @param limit the maximum number of items returns + * @return a splitter with the desired configuration + * @since 9.0 + */ + @CheckReturnValue + public Splitter limit(int limit) { + checkArgument(limit > 0, "must be greater than zero: %s", limit); + return new Splitter(strategy, omitEmptyStrings, trimmer, limit); + } + + /** + * Returns a splitter that behaves equivalently to {@code this} splitter, but + * automatically removes leading and trailing {@linkplain + * CharMatcher#WHITESPACE whitespace} from each returned substring; equivalent + * to {@code trimResults(CharMatcher.WHITESPACE)}. For example, {@code + * Splitter.on(',').trimResults().split(" a, b ,c ")} returns an iterable + * containing {@code ["a", "b", "c"]}. + * + * @return a splitter with the desired configuration + */ + @CheckReturnValue + public Splitter trimResults() { + return trimResults(CharMatcher.WHITESPACE); + } + + /** + * Returns a splitter that behaves equivalently to {@code this} splitter, but + * removes all leading or trailing characters matching the given {@code + * CharMatcher} from each returned substring. For example, {@code + * Splitter.on(',').trimResults(CharMatcher.is('_')).split("_a ,_b_ ,c__")} + * returns an iterable containing {@code ["a ", "b_ ", "c"]}. + * + * @param trimmer a {@link CharMatcher} that determines whether a character + * should be removed from the beginning/end of a subsequence + * @return a splitter with the desired configuration + */ + // TODO(kevinb): throw if a trimmer was already specified! + @CheckReturnValue + public Splitter trimResults(CharMatcher trimmer) { + checkNotNull(trimmer); + return new Splitter(strategy, omitEmptyStrings, trimmer, limit); + } + + /** + * Splits {@code sequence} into string components and makes them available + * through an {@link Iterator}, which may be lazily evaluated. + * + * @param sequence the sequence of characters to split + * @return an iteration over the segments split from the parameter. + */ + public Iterable<String> split(final CharSequence sequence) { + checkNotNull(sequence); + + return new Iterable<String>() { + @Override public Iterator<String> iterator() { + return spliterator(sequence); + } + @Override public String toString() { + return Joiner.on(", ") + .appendTo(new StringBuilder().append('['), this) + .append(']') + .toString(); + } + }; + } + + private Iterator<String> spliterator(CharSequence sequence) { + return strategy.iterator(this, sequence); + } + + /** + * Returns a {@code MapSplitter} which splits entries based on this splitter, + * and splits entries into keys and values using the specified separator. + * + * @since 10.0 + */ + @CheckReturnValue + @Beta + public MapSplitter withKeyValueSeparator(String separator) { + return withKeyValueSeparator(on(separator)); + } + + /** + * Returns a {@code MapSplitter} which splits entries based on this splitter, + * and splits entries into keys and values using the specified key-value + * splitter. + * + * @since 10.0 + */ + @CheckReturnValue + @Beta + public MapSplitter withKeyValueSeparator(Splitter keyValueSplitter) { + return new MapSplitter(this, keyValueSplitter); + } + + /** + * An object that splits strings into maps as {@code Splitter} splits + * iterables and lists. Like {@code Splitter}, it is thread-safe and + * immutable. + * + * @since 10.0 + */ + @Beta + public static final class MapSplitter { + private static final String INVALID_ENTRY_MESSAGE = + "Chunk [%s] is not a valid entry"; + private final Splitter outerSplitter; + private final Splitter entrySplitter; + + private MapSplitter(Splitter outerSplitter, Splitter entrySplitter) { + this.outerSplitter = outerSplitter; // only "this" is passed + this.entrySplitter = checkNotNull(entrySplitter); + } + + /** + * Splits {@code sequence} into substrings, splits each substring into + * an entry, and returns an unmodifiable map with each of the entries. For + * example, <code> + * Splitter.on(';').trimResults().withKeyValueSeparator("=>") + * .split("a=>b ; c=>b") + * </code> will return a mapping from {@code "a"} to {@code "b"} and + * {@code "c"} to {@code b}. + * + * <p>The returned map preserves the order of the entries from + * {@code sequence}. + * + * @throws IllegalArgumentException if the specified sequence does not split + * into valid map entries, or if there are duplicate keys + */ + public Map<String, String> split(CharSequence sequence) { + Map<String, String> map = new LinkedHashMap<String, String>(); + for (String entry : outerSplitter.split(sequence)) { + Iterator<String> entryFields = entrySplitter.spliterator(entry); + + checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry); + String key = entryFields.next(); + checkArgument(!map.containsKey(key), "Duplicate key [%s] found.", key); + + checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry); + String value = entryFields.next(); + map.put(key, value); + + checkArgument(!entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry); + } + return Collections.unmodifiableMap(map); + } + } + + private interface Strategy { + Iterator<String> iterator(Splitter splitter, CharSequence toSplit); + } + + private abstract static class SplittingIterator extends AbstractIterator<String> { + final CharSequence toSplit; + final CharMatcher trimmer; + final boolean omitEmptyStrings; + + /** + * Returns the first index in {@code toSplit} at or after {@code start} + * that contains the separator. + */ + abstract int separatorStart(int start); + + /** + * Returns the first index in {@code toSplit} after {@code + * separatorPosition} that does not contain a separator. This method is only + * invoked after a call to {@code separatorStart}. + */ + abstract int separatorEnd(int separatorPosition); + + int offset = 0; + int limit; + + protected SplittingIterator(Splitter splitter, CharSequence toSplit) { + this.trimmer = splitter.trimmer; + this.omitEmptyStrings = splitter.omitEmptyStrings; + this.limit = splitter.limit; + this.toSplit = toSplit; + } + + @Override protected String computeNext() { + /* + * The returned string will be from the end of the last match to the + * beginning of the next one. nextStart is the start position of the + * returned substring, while offset is the place to start looking for a + * separator. + */ + int nextStart = offset; + while (offset != -1) { + int start = nextStart; + int end; + + int separatorPosition = separatorStart(offset); + if (separatorPosition == -1) { + end = toSplit.length(); + offset = -1; + } else { + end = separatorPosition; + offset = separatorEnd(separatorPosition); + } + if (offset == nextStart) { + /* + * This occurs when some pattern has an empty match, even if it + * doesn't match the empty string -- for example, if it requires + * lookahead or the like. The offset must be increased to look for + * separators beyond this point, without changing the start position + * of the next returned substring -- so nextStart stays the same. + */ + offset++; + if (offset >= toSplit.length()) { + offset = -1; + } + continue; + } + + while (start < end && trimmer.matches(toSplit.charAt(start))) { + start++; + } + while (end > start && trimmer.matches(toSplit.charAt(end - 1))) { + end--; + } + + if (omitEmptyStrings && start == end) { + // Don't include the (unused) separator in next split string. + nextStart = offset; + continue; + } + + if (limit == 1) { + // The limit has been reached, return the rest of the string as the + // final item. This is tested after empty string removal so that + // empty strings do not count towards the limit. + end = toSplit.length(); + offset = -1; + // Since we may have changed the end, we need to trim it again. + while (end > start && trimmer.matches(toSplit.charAt(end - 1))) { + end--; + } + } else { + limit--; + } + + return toSplit.subSequence(start, end).toString(); + } + return endOfData(); + } + } +} diff --git a/guava/src/com/google/common/base/Stopwatch.java b/guava/src/com/google/common/base/Stopwatch.java new file mode 100644 index 0000000..9e1b6f6 --- /dev/null +++ b/guava/src/com/google/common/base/Stopwatch.java @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2008 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.util.concurrent.TimeUnit.MICROSECONDS; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.GwtIncompatible; + +import java.util.concurrent.TimeUnit; + +/** + * An object that measures elapsed time in nanoseconds. It is useful to measure + * elapsed time using this class instead of direct calls to {@link + * System#nanoTime} for a few reasons: + * + * <ul> + * <li>An alternate time source can be substituted, for testing or performance + * reasons. + * <li>As documented by {@code nanoTime}, the value returned has no absolute + * meaning, and can only be interpreted as relative to another timestamp + * returned by {@code nanoTime} at a different time. {@code Stopwatch} is a + * more effective abstraction because it exposes only these relative values, + * not the absolute ones. + * </ul> + * + * <p>Basic usage: + * <pre> + * Stopwatch stopwatch = new Stopwatch().{@link #start start}(); + * doSomething(); + * stopwatch.{@link #stop stop}(); // optional + * + * long millis = stopwatch.{@link #elapsedMillis elapsedMillis}(); + * + * log.info("that took: " + stopwatch); // formatted string like "12.3 ms" + * </pre> + * + * <p>Stopwatch methods are not idempotent; it is an error to start or stop a + * stopwatch that is already in the desired state. + * + * <p>When testing code that uses this class, use the {@linkplain + * #Stopwatch(Ticker) alternate constructor} to supply a fake or mock ticker. + * <!-- TODO(kevinb): restore the "such as" --> This allows you to + * simulate any valid behavior of the stopwatch. + * + * <p><b>Note:</b> This class is not thread-safe. + * + * @author Kevin Bourrillion + * @since 10.0 + */ +@Beta +@GwtCompatible(emulated=true) +public final class Stopwatch { + private final Ticker ticker; + private boolean isRunning; + private long elapsedNanos; + private long startTick; + + /** + * Creates (but does not start) a new stopwatch using {@link System#nanoTime} + * as its time source. + */ + public Stopwatch() { + this(Ticker.systemTicker()); + } + + /** + * Creates (but does not start) a new stopwatch, using the specified time + * source. + */ + public Stopwatch(Ticker ticker) { + this.ticker = checkNotNull(ticker); + } + + /** + * Returns {@code true} if {@link #start()} has been called on this stopwatch, + * and {@link #stop()} has not been called since the last call to {@code + * start()}. + */ + public boolean isRunning() { + return isRunning; + } + + /** + * Starts the stopwatch. + * + * @return this {@code Stopwatch} instance + * @throws IllegalStateException if the stopwatch is already running. + */ + public Stopwatch start() { + checkState(!isRunning); + isRunning = true; + startTick = ticker.read(); + return this; + } + + /** + * Stops the stopwatch. Future reads will return the fixed duration that had + * elapsed up to this point. + * + * @return this {@code Stopwatch} instance + * @throws IllegalStateException if the stopwatch is already stopped. + */ + public Stopwatch stop() { + long tick = ticker.read(); + checkState(isRunning); + isRunning = false; + elapsedNanos += tick - startTick; + return this; + } + + /** + * Sets the elapsed time for this stopwatch to zero, + * and places it in a stopped state. + * + * @return this {@code Stopwatch} instance + */ + public Stopwatch reset() { + elapsedNanos = 0; + isRunning = false; + return this; + } + + private long elapsedNanos() { + return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos; + } + + /** + * Returns the current elapsed time shown on this stopwatch, expressed + * in the desired time unit, with any fraction rounded down. + * + * <p>Note that the overhead of measurement can be more than a microsecond, so + * it is generally not useful to specify {@link TimeUnit#NANOSECONDS} + * precision here. + */ + public long elapsedTime(TimeUnit desiredUnit) { + return desiredUnit.convert(elapsedNanos(), NANOSECONDS); + } + + /** + * Returns the current elapsed time shown on this stopwatch, expressed + * in milliseconds, with any fraction rounded down. This is identical to + * {@code elapsedTime(TimeUnit.MILLISECONDS}. + */ + public long elapsedMillis() { + return elapsedTime(MILLISECONDS); + } + + /** + * Returns a string representation of the current elapsed time. + */ + @GwtIncompatible("String.format()") + @Override public String toString() { + return toString(4); + } + + /** + * Returns a string representation of the current elapsed time, choosing an + * appropriate unit and using the specified number of significant figures. + * For example, at the instant when {@code elapsedTime(NANOSECONDS)} would + * return {1234567}, {@code toString(4)} returns {@code "1.235 ms"}. + * + * @deprecated Use {@link #toString()} instead. This method is scheduled + * to be removed in Guava release 15.0. + */ + @Deprecated + @GwtIncompatible("String.format()") + public String toString(int significantDigits) { + long nanos = elapsedNanos(); + + TimeUnit unit = chooseUnit(nanos); + double value = (double) nanos / NANOSECONDS.convert(1, unit); + + // Too bad this functionality is not exposed as a regular method call + return String.format("%." + significantDigits + "g %s", + value, abbreviate(unit)); + } + + private static TimeUnit chooseUnit(long nanos) { + if (SECONDS.convert(nanos, NANOSECONDS) > 0) { + return SECONDS; + } + if (MILLISECONDS.convert(nanos, NANOSECONDS) > 0) { + return MILLISECONDS; + } + if (MICROSECONDS.convert(nanos, NANOSECONDS) > 0) { + return MICROSECONDS; + } + return NANOSECONDS; + } + + private static String abbreviate(TimeUnit unit) { + switch (unit) { + case NANOSECONDS: + return "ns"; + case MICROSECONDS: + return "\u03bcs"; // μs + case MILLISECONDS: + return "ms"; + case SECONDS: + return "s"; + default: + throw new AssertionError(); + } + } +} diff --git a/guava/src/com/google/common/base/Strings.java b/guava/src/com/google/common/base/Strings.java new file mode 100644 index 0000000..45007fd --- /dev/null +++ b/guava/src/com/google/common/base/Strings.java @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2010 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.VisibleForTesting; + +import java.util.Formatter; + +import javax.annotation.Nullable; + +/** + * Static utility methods pertaining to {@code String} or {@code CharSequence} + * instances. + * + * @author Kevin Bourrillion + * @since 3.0 + */ +@GwtCompatible +public final class Strings { + private Strings() {} + + /** + * Returns the given string if it is non-null; the empty string otherwise. + * + * @param string the string to test and possibly return + * @return {@code string} itself if it is non-null; {@code ""} if it is null + */ + public static String nullToEmpty(@Nullable String string) { + return (string == null) ? "" : string; + } + + /** + * Returns the given string if it is nonempty; {@code null} otherwise. + * + * @param string the string to test and possibly return + * @return {@code string} itself if it is nonempty; {@code null} if it is + * empty or null + */ + public static @Nullable String emptyToNull(@Nullable String string) { + return isNullOrEmpty(string) ? null : string; + } + + /** + * Returns {@code true} if the given string is null or is the empty string. + * + * <p>Consider normalizing your string references with {@link #nullToEmpty}. + * If you do, you can use {@link String#isEmpty()} instead of this + * method, and you won't need special null-safe forms of methods like {@link + * String#toUpperCase} either. Or, if you'd like to normalize "in the other + * direction," converting empty strings to {@code null}, you can use {@link + * #emptyToNull}. + * + * @param string a string reference to check + * @return {@code true} if the string is null or is the empty string + */ + public static boolean isNullOrEmpty(@Nullable String string) { + return string == null || string.length() == 0; // string.isEmpty() in Java 6 + } + + /** + * Returns a string, of length at least {@code minLength}, consisting of + * {@code string} prepended with as many copies of {@code padChar} as are + * necessary to reach that length. For example, + * + * <ul> + * <li>{@code padStart("7", 3, '0')} returns {@code "007"} + * <li>{@code padStart("2010", 3, '0')} returns {@code "2010"} + * </ul> + * + * <p>See {@link Formatter} for a richer set of formatting capabilities. + * + * @param string the string which should appear at the end of the result + * @param minLength the minimum length the resulting string must have. Can be + * zero or negative, in which case the input string is always returned. + * @param padChar the character to insert at the beginning of the result until + * the minimum length is reached + * @return the padded string + */ + public static String padStart(String string, int minLength, char padChar) { + checkNotNull(string); // eager for GWT. + if (string.length() >= minLength) { + return string; + } + StringBuilder sb = new StringBuilder(minLength); + for (int i = string.length(); i < minLength; i++) { + sb.append(padChar); + } + sb.append(string); + return sb.toString(); + } + + /** + * Returns a string, of length at least {@code minLength}, consisting of + * {@code string} appended with as many copies of {@code padChar} as are + * necessary to reach that length. For example, + * + * <ul> + * <li>{@code padEnd("4.", 5, '0')} returns {@code "4.000"} + * <li>{@code padEnd("2010", 3, '!')} returns {@code "2010"} + * </ul> + * + * <p>See {@link Formatter} for a richer set of formatting capabilities. + * + * @param string the string which should appear at the beginning of the result + * @param minLength the minimum length the resulting string must have. Can be + * zero or negative, in which case the input string is always returned. + * @param padChar the character to append to the end of the result until the + * minimum length is reached + * @return the padded string + */ + public static String padEnd(String string, int minLength, char padChar) { + checkNotNull(string); // eager for GWT. + if (string.length() >= minLength) { + return string; + } + StringBuilder sb = new StringBuilder(minLength); + sb.append(string); + for (int i = string.length(); i < minLength; i++) { + sb.append(padChar); + } + return sb.toString(); + } + + /** + * Returns a string consisting of a specific number of concatenated copies of + * an input string. For example, {@code repeat("hey", 3)} returns the string + * {@code "heyheyhey"}. + * + * @param string any non-null string + * @param count the number of times to repeat it; a nonnegative integer + * @return a string containing {@code string} repeated {@code count} times + * (the empty string if {@code count} is zero) + * @throws IllegalArgumentException if {@code count} is negative + */ + public static String repeat(String string, int count) { + checkNotNull(string); // eager for GWT. + + if (count <= 1) { + checkArgument(count >= 0, "invalid count: %s", count); + return (count == 0) ? "" : string; + } + + // IF YOU MODIFY THE CODE HERE, you must update StringsRepeatBenchmark + final int len = string.length(); + final long longSize = (long) len * (long) count; + final int size = (int) longSize; + if (size != longSize) { + throw new ArrayIndexOutOfBoundsException("Required array size too large: " + + String.valueOf(longSize)); + } + + final char[] array = new char[size]; + string.getChars(0, len, array, 0); + int n; + for (n = len; n < size - n; n <<= 1) { + System.arraycopy(array, 0, array, n, n); + } + System.arraycopy(array, 0, array, n, size - n); + return new String(array); + } + + /** + * Returns the longest string {@code prefix} such that + * {@code a.toString().startsWith(prefix) && b.toString().startsWith(prefix)}, + * taking care not to split surrogate pairs. If {@code a} and {@code b} have + * no common prefix, returns the empty string. + * + * @since 11.0 + */ + public static String commonPrefix(CharSequence a, CharSequence b) { + checkNotNull(a); + checkNotNull(b); + + int maxPrefixLength = Math.min(a.length(), b.length()); + int p = 0; + while (p < maxPrefixLength && a.charAt(p) == b.charAt(p)) { + p++; + } + if (validSurrogatePairAt(a, p - 1) || validSurrogatePairAt(b, p - 1)) { + p--; + } + return a.subSequence(0, p).toString(); + } + + /** + * Returns the longest string {@code suffix} such that + * {@code a.toString().endsWith(suffix) && b.toString().endsWith(suffix)}, + * taking care not to split surrogate pairs. If {@code a} and {@code b} have + * no common suffix, returns the empty string. + * + * @since 11.0 + */ + public static String commonSuffix(CharSequence a, CharSequence b) { + checkNotNull(a); + checkNotNull(b); + + int maxSuffixLength = Math.min(a.length(), b.length()); + int s = 0; + while (s < maxSuffixLength + && a.charAt(a.length() - s - 1) == b.charAt(b.length() - s - 1)) { + s++; + } + if (validSurrogatePairAt(a, a.length() - s - 1) + || validSurrogatePairAt(b, b.length() - s - 1)) { + s--; + } + return a.subSequence(a.length() - s, a.length()).toString(); + } + + /** + * True when a valid surrogate pair starts at the given {@code index} in the + * given {@code string}. Out-of-range indexes return false. + */ + @VisibleForTesting + static boolean validSurrogatePairAt(CharSequence string, int index) { + return index >= 0 && index <= (string.length() - 2) + && Character.isHighSurrogate(string.charAt(index)) + && Character.isLowSurrogate(string.charAt(index + 1)); + } +} diff --git a/guava/src/com/google/common/base/Supplier.java b/guava/src/com/google/common/base/Supplier.java new file mode 100644 index 0000000..ab8b908 --- /dev/null +++ b/guava/src/com/google/common/base/Supplier.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; + +/** + * A class that can supply objects of a single type. Semantically, this could + * be a factory, generator, builder, closure, or something else entirely. No + * guarantees are implied by this interface. + * + * @author Harry Heymann + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public interface Supplier<T> { + /** + * Retrieves an instance of the appropriate type. The returned object may or + * may not be a new instance, depending on the implementation. + * + * @return an instance of the appropriate type + */ + T get(); +} diff --git a/guava/src/com/google/common/base/Suppliers.java b/guava/src/com/google/common/base/Suppliers.java new file mode 100644 index 0000000..add5117 --- /dev/null +++ b/guava/src/com/google/common/base/Suppliers.java @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.VisibleForTesting; + +import java.io.Serializable; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; + +/** + * Useful suppliers. + * + * <p>All methods return serializable suppliers as long as they're given + * serializable parameters. + * + * @author Laurence Gonsalves + * @author Harry Heymann + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public final class Suppliers { + private Suppliers() {} + + /** + * Returns a new supplier which is the composition of the provided function + * and supplier. In other words, the new supplier's value will be computed by + * retrieving the value from {@code supplier}, and then applying + * {@code function} to that value. Note that the resulting supplier will not + * call {@code supplier} or invoke {@code function} until it is called. + */ + public static <F, T> Supplier<T> compose( + Function<? super F, T> function, Supplier<F> supplier) { + Preconditions.checkNotNull(function); + Preconditions.checkNotNull(supplier); + return new SupplierComposition<F, T>(function, supplier); + } + + private static class SupplierComposition<F, T> + implements Supplier<T>, Serializable { + final Function<? super F, T> function; + final Supplier<F> supplier; + + SupplierComposition(Function<? super F, T> function, Supplier<F> supplier) { + this.function = function; + this.supplier = supplier; + } + + @Override + public T get() { + return function.apply(supplier.get()); + } + + @Override + public String toString() { + return "Suppliers.compose(" + function + ", " + supplier + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns a supplier which caches the instance retrieved during the first + * call to {@code get()} and returns that value on subsequent calls to + * {@code get()}. See: + * <a href="http://en.wikipedia.org/wiki/Memoization">memoization</a> + * + * <p>The returned supplier is thread-safe. The supplier's serialized form + * does not contain the cached value, which will be recalculated when {@code + * get()} is called on the reserialized instance. + * + * <p>If {@code delegate} is an instance created by an earlier call to {@code + * memoize}, it is returned directly. + */ + public static <T> Supplier<T> memoize(Supplier<T> delegate) { + return (delegate instanceof MemoizingSupplier) + ? delegate + : new MemoizingSupplier<T>(Preconditions.checkNotNull(delegate)); + } + + @VisibleForTesting + static class MemoizingSupplier<T> implements Supplier<T>, Serializable { + final Supplier<T> delegate; + transient volatile boolean initialized; + // "value" does not need to be volatile; visibility piggy-backs + // on volatile read of "initialized". + transient T value; + + MemoizingSupplier(Supplier<T> delegate) { + this.delegate = delegate; + } + + @Override + public T get() { + // A 2-field variant of Double Checked Locking. + if (!initialized) { + synchronized (this) { + if (!initialized) { + T t = delegate.get(); + value = t; + initialized = true; + return t; + } + } + } + return value; + } + + @Override + public String toString() { + return "Suppliers.memoize(" + delegate + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns a supplier that caches the instance supplied by the delegate and + * removes the cached value after the specified time has passed. Subsequent + * calls to {@code get()} return the cached value if the expiration time has + * not passed. After the expiration time, a new value is retrieved, cached, + * and returned. See: + * <a href="http://en.wikipedia.org/wiki/Memoization">memoization</a> + * + * <p>The returned supplier is thread-safe. The supplier's serialized form + * does not contain the cached value, which will be recalculated when {@code + * get()} is called on the reserialized instance. + * + * @param duration the length of time after a value is created that it + * should stop being returned by subsequent {@code get()} calls + * @param unit the unit that {@code duration} is expressed in + * @throws IllegalArgumentException if {@code duration} is not positive + * @since 2.0 + */ + public static <T> Supplier<T> memoizeWithExpiration( + Supplier<T> delegate, long duration, TimeUnit unit) { + return new ExpiringMemoizingSupplier<T>(delegate, duration, unit); + } + + @VisibleForTesting static class ExpiringMemoizingSupplier<T> + implements Supplier<T>, Serializable { + final Supplier<T> delegate; + final long durationNanos; + transient volatile T value; + // The special value 0 means "not yet initialized". + transient volatile long expirationNanos; + + ExpiringMemoizingSupplier( + Supplier<T> delegate, long duration, TimeUnit unit) { + this.delegate = Preconditions.checkNotNull(delegate); + this.durationNanos = unit.toNanos(duration); + Preconditions.checkArgument(duration > 0); + } + + @Override + public T get() { + // Another variant of Double Checked Locking. + // + // We use two volatile reads. We could reduce this to one by + // putting our fields into a holder class, but (at least on x86) + // the extra memory consumption and indirection are more + // expensive than the extra volatile reads. + long nanos = expirationNanos; + long now = Platform.systemNanoTime(); + if (nanos == 0 || now - nanos >= 0) { + synchronized (this) { + if (nanos == expirationNanos) { // recheck for lost race + T t = delegate.get(); + value = t; + nanos = now + durationNanos; + // In the very unlikely event that nanos is 0, set it to 1; + // no one will notice 1 ns of tardiness. + expirationNanos = (nanos == 0) ? 1 : nanos; + return t; + } + } + } + return value; + } + + @Override + public String toString() { + // This is a little strange if the unit the user provided was not NANOS, + // but we don't want to store the unit just for toString + return "Suppliers.memoizeWithExpiration(" + delegate + ", " + + durationNanos + ", NANOS)"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns a supplier that always supplies {@code instance}. + */ + public static <T> Supplier<T> ofInstance(@Nullable T instance) { + return new SupplierOfInstance<T>(instance); + } + + private static class SupplierOfInstance<T> + implements Supplier<T>, Serializable { + final T instance; + + SupplierOfInstance(@Nullable T instance) { + this.instance = instance; + } + + @Override + public T get() { + return instance; + } + + @Override + public String toString() { + return "Suppliers.ofInstance(" + instance + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns a supplier whose {@code get()} method synchronizes on + * {@code delegate} before calling it, making it thread-safe. + */ + public static <T> Supplier<T> synchronizedSupplier(Supplier<T> delegate) { + return new ThreadSafeSupplier<T>(Preconditions.checkNotNull(delegate)); + } + + private static class ThreadSafeSupplier<T> + implements Supplier<T>, Serializable { + final Supplier<T> delegate; + + ThreadSafeSupplier(Supplier<T> delegate) { + this.delegate = delegate; + } + + @Override + public T get() { + synchronized (delegate) { + return delegate.get(); + } + } + + @Override + public String toString() { + return "Suppliers.synchronizedSupplier(" + delegate + ")"; + } + + private static final long serialVersionUID = 0; + } + + /** + * Returns a function that accepts a supplier and returns the result of + * invoking {@link Supplier#get} on that supplier. + * + * @since 8.0 + */ + @Beta + @SuppressWarnings("unchecked") // SupplierFunction works for any T. + public static <T> Function<Supplier<T>, T> supplierFunction() { + return (Function) SupplierFunction.INSTANCE; + } + + private enum SupplierFunction implements Function<Supplier<?>, Object> { + INSTANCE; + + @Override + public Object apply(Supplier<?> input) { + return input.get(); + } + + @Override + public String toString() { + return "Suppliers.supplierFunction()"; + } + } +} diff --git a/guava/src/com/google/common/base/Throwables.java b/guava/src/com/google/common/base/Throwables.java new file mode 100644 index 0000000..5e4d6ec --- /dev/null +++ b/guava/src/com/google/common/base/Throwables.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.Beta; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.Nullable; + +/** + * Static utility methods pertaining to instances of {@link Throwable}. + * + * <p>See the Guava User Guide entry on <a href= + * "http://code.google.com/p/guava-libraries/wiki/ThrowablesExplained"> + * Throwables</a>. + * + * @author Kevin Bourrillion + * @author Ben Yu + * @since 1.0 + */ +public final class Throwables { + private Throwables() {} + + /** + * Propagates {@code throwable} exactly as-is, if and only if it is an + * instance of {@code declaredType}. Example usage: + * <pre> + * try { + * someMethodThatCouldThrowAnything(); + * } catch (IKnowWhatToDoWithThisException e) { + * handle(e); + * } catch (Throwable t) { + * Throwables.propagateIfInstanceOf(t, IOException.class); + * Throwables.propagateIfInstanceOf(t, SQLException.class); + * throw Throwables.propagate(t); + * } + * </pre> + */ + public static <X extends Throwable> void propagateIfInstanceOf( + @Nullable Throwable throwable, Class<X> declaredType) throws X { + // Check for null is needed to avoid frequent JNI calls to isInstance(). + if (throwable != null && declaredType.isInstance(throwable)) { + throw declaredType.cast(throwable); + } + } + + /** + * Propagates {@code throwable} exactly as-is, if and only if it is an + * instance of {@link RuntimeException} or {@link Error}. Example usage: + * <pre> + * try { + * someMethodThatCouldThrowAnything(); + * } catch (IKnowWhatToDoWithThisException e) { + * handle(e); + * } catch (Throwable t) { + * Throwables.propagateIfPossible(t); + * throw new RuntimeException("unexpected", t); + * } + * </pre> + */ + public static void propagateIfPossible(@Nullable Throwable throwable) { + propagateIfInstanceOf(throwable, Error.class); + propagateIfInstanceOf(throwable, RuntimeException.class); + } + + /** + * Propagates {@code throwable} exactly as-is, if and only if it is an + * instance of {@link RuntimeException}, {@link Error}, or + * {@code declaredType}. Example usage: + * <pre> + * try { + * someMethodThatCouldThrowAnything(); + * } catch (IKnowWhatToDoWithThisException e) { + * handle(e); + * } catch (Throwable t) { + * Throwables.propagateIfPossible(t, OtherException.class); + * throw new RuntimeException("unexpected", t); + * } + * </pre> + * + * @param throwable the Throwable to possibly propagate + * @param declaredType the single checked exception type declared by the + * calling method + */ + public static <X extends Throwable> void propagateIfPossible( + @Nullable Throwable throwable, Class<X> declaredType) throws X { + propagateIfInstanceOf(throwable, declaredType); + propagateIfPossible(throwable); + } + + /** + * Propagates {@code throwable} exactly as-is, if and only if it is an + * instance of {@link RuntimeException}, {@link Error}, {@code declaredType1}, + * or {@code declaredType2}. In the unlikely case that you have three or more + * declared checked exception types, you can handle them all by invoking these + * methods repeatedly. See usage example in {@link + * #propagateIfPossible(Throwable, Class)}. + * + * @param throwable the Throwable to possibly propagate + * @param declaredType1 any checked exception type declared by the calling + * method + * @param declaredType2 any other checked exception type declared by the + * calling method + */ + public static <X1 extends Throwable, X2 extends Throwable> + void propagateIfPossible(@Nullable Throwable throwable, + Class<X1> declaredType1, Class<X2> declaredType2) throws X1, X2 { + checkNotNull(declaredType2); + propagateIfInstanceOf(throwable, declaredType1); + propagateIfPossible(throwable, declaredType2); + } + + /** + * Propagates {@code throwable} as-is if it is an instance of + * {@link RuntimeException} or {@link Error}, or else as a last resort, wraps + * it in a {@code RuntimeException} then propagates. + * <p> + * This method always throws an exception. The {@code RuntimeException} return + * type is only for client code to make Java type system happy in case a + * return value is required by the enclosing method. Example usage: + * <pre> + * T doSomething() { + * try { + * return someMethodThatCouldThrowAnything(); + * } catch (IKnowWhatToDoWithThisException e) { + * return handle(e); + * } catch (Throwable t) { + * throw Throwables.propagate(t); + * } + * } + * </pre> + * + * @param throwable the Throwable to propagate + * @return nothing will ever be returned; this return type is only for your + * convenience, as illustrated in the example above + */ + public static RuntimeException propagate(Throwable throwable) { + propagateIfPossible(checkNotNull(throwable)); + throw new RuntimeException(throwable); + } + + /** + * Returns the innermost cause of {@code throwable}. The first throwable in a + * chain provides context from when the error or exception was initially + * detected. Example usage: + * <pre> + * assertEquals("Unable to assign a customer id", + * Throwables.getRootCause(e).getMessage()); + * </pre> + */ + public static Throwable getRootCause(Throwable throwable) { + Throwable cause; + while ((cause = throwable.getCause()) != null) { + throwable = cause; + } + return throwable; + } + + /** + * Gets a {@code Throwable} cause chain as a list. The first entry in the + * list will be {@code throwable} followed by its cause hierarchy. Note + * that this is a snapshot of the cause chain and will not reflect + * any subsequent changes to the cause chain. + * + * <p>Here's an example of how it can be used to find specific types + * of exceptions in the cause chain: + * + * <pre> + * Iterables.filter(Throwables.getCausalChain(e), IOException.class)); + * </pre> + * + * @param throwable the non-null {@code Throwable} to extract causes from + * @return an unmodifiable list containing the cause chain starting with + * {@code throwable} + */ + @Beta // TODO(kevinb): decide best return type + public static List<Throwable> getCausalChain(Throwable throwable) { + checkNotNull(throwable); + List<Throwable> causes = new ArrayList<Throwable>(4); + while (throwable != null) { + causes.add(throwable); + throwable = throwable.getCause(); + } + return Collections.unmodifiableList(causes); + } + + /** + * Returns a string containing the result of + * {@link Throwable#toString() toString()}, followed by the full, recursive + * stack trace of {@code throwable}. Note that you probably should not be + * parsing the resulting string; if you need programmatic access to the stack + * frames, you can call {@link Throwable#getStackTrace()}. + */ + public static String getStackTraceAsString(Throwable throwable) { + StringWriter stringWriter = new StringWriter(); + throwable.printStackTrace(new PrintWriter(stringWriter)); + return stringWriter.toString(); + } +} diff --git a/guava/src/com/google/common/base/Ticker.java b/guava/src/com/google/common/base/Ticker.java new file mode 100644 index 0000000..6c34aef --- /dev/null +++ b/guava/src/com/google/common/base/Ticker.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; + +/** + * A time source; returns a time value representing the number of nanoseconds elapsed since some + * fixed but arbitrary point in time. Note that most users should use {@link Stopwatch} instead of + * interacting with this class directly. + * + * <p><b>Warning:</b> this interface can only be used to measure elapsed time, not wall time. + * + * @author Kevin Bourrillion + * @since 10.0 + * (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility" + * >mostly source-compatible</a> since 9.0) + */ +@Beta +@GwtCompatible +public abstract class Ticker { + /** + * Constructor for use by subclasses. + */ + protected Ticker() {} + + /** + * Returns the number of nanoseconds elapsed since this ticker's fixed + * point of reference. + */ + public abstract long read(); + + /** + * A ticker that reads the current time using {@link System#nanoTime}. + * + * @since 10.0 + */ + public static Ticker systemTicker() { + return SYSTEM_TICKER; + } + + private static final Ticker SYSTEM_TICKER = new Ticker() { + @Override + public long read() { + return Platform.systemNanoTime(); + } + }; +} diff --git a/guava/src/com/google/common/base/internal/Finalizer.java b/guava/src/com/google/common/base/internal/Finalizer.java new file mode 100644 index 0000000..0934aa6 --- /dev/null +++ b/guava/src/com/google/common/base/internal/Finalizer.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2008 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base.internal; + +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Thread that finalizes referents. All references should implement + * {@code com.google.common.base.FinalizableReference}. + * + * <p>While this class is public, we consider it to be *internal* and not part + * of our published API. It is public so we can access it reflectively across + * class loaders in secure environments. + * + * <p>This class can't depend on other Google Collections code. If we were + * to load this class in the same class loader as the rest of + * Google Collections, this thread would keep an indirect strong reference + * to the class loader and prevent it from being garbage collected. This + * poses a problem for environments where you want to throw away the class + * loader. For example, dynamically reloading a web application or unloading + * an OSGi bundle. + * + * <p>{@code com.google.common.base.FinalizableReferenceQueue} loads this class + * in its own class loader. That way, this class doesn't prevent the main + * class loader from getting garbage collected, and this class can detect when + * the main class loader has been garbage collected and stop itself. + */ +public class Finalizer implements Runnable { + + private static final Logger logger + = Logger.getLogger(Finalizer.class.getName()); + + /** Name of FinalizableReference.class. */ + private static final String FINALIZABLE_REFERENCE + = "com.google.common.base.FinalizableReference"; + + /** + * Starts the Finalizer thread. FinalizableReferenceQueue calls this method + * reflectively. + * + * @param finalizableReferenceClass FinalizableReference.class + * @param frq reference to instance of FinalizableReferenceQueue that started + * this thread + * @return ReferenceQueue which Finalizer will poll + */ + public static ReferenceQueue<Object> startFinalizer( + Class<?> finalizableReferenceClass, Object frq) { + /* + * We use FinalizableReference.class for two things: + * + * 1) To invoke FinalizableReference.finalizeReferent() + * + * 2) To detect when FinalizableReference's class loader has to be garbage + * collected, at which point, Finalizer can stop running + */ + if (!finalizableReferenceClass.getName().equals(FINALIZABLE_REFERENCE)) { + throw new IllegalArgumentException( + "Expected " + FINALIZABLE_REFERENCE + "."); + } + + Finalizer finalizer = new Finalizer(finalizableReferenceClass, frq); + Thread thread = new Thread(finalizer); + thread.setName(Finalizer.class.getName()); + thread.setDaemon(true); + + try { + if (inheritableThreadLocals != null) { + inheritableThreadLocals.set(thread, null); + } + } catch (Throwable t) { + logger.log(Level.INFO, "Failed to clear thread local values inherited" + + " by reference finalizer thread.", t); + } + + thread.start(); + return finalizer.queue; + } + + private final WeakReference<Class<?>> finalizableReferenceClassReference; + private final PhantomReference<Object> frqReference; + private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); + + private static final Field inheritableThreadLocals + = getInheritableThreadLocalsField(); + + /** Constructs a new finalizer thread. */ + private Finalizer(Class<?> finalizableReferenceClass, Object frq) { + this.finalizableReferenceClassReference + = new WeakReference<Class<?>>(finalizableReferenceClass); + + // Keep track of the FRQ that started us so we know when to stop. + this.frqReference = new PhantomReference<Object>(frq, queue); + } + + /** + * Loops continuously, pulling references off the queue and cleaning them up. + */ + @SuppressWarnings("InfiniteLoopStatement") + @Override + public void run() { + try { + while (true) { + try { + cleanUp(queue.remove()); + } catch (InterruptedException e) { /* ignore */ } + } + } catch (ShutDown shutDown) { /* ignore */ } + } + + /** + * Cleans up a single reference. Catches and logs all throwables. + */ + private void cleanUp(Reference<?> reference) throws ShutDown { + Method finalizeReferentMethod = getFinalizeReferentMethod(); + do { + /* + * This is for the benefit of phantom references. Weak and soft + * references will have already been cleared by this point. + */ + reference.clear(); + + if (reference == frqReference) { + /* + * The client no longer has a reference to the + * FinalizableReferenceQueue. We can stop. + */ + throw new ShutDown(); + } + + try { + finalizeReferentMethod.invoke(reference); + } catch (Throwable t) { + logger.log(Level.SEVERE, "Error cleaning up after reference.", t); + } + + /* + * Loop as long as we have references available so as not to waste + * CPU looking up the Method over and over again. + */ + } while ((reference = queue.poll()) != null); + } + + /** + * Looks up FinalizableReference.finalizeReferent() method. + */ + private Method getFinalizeReferentMethod() throws ShutDown { + Class<?> finalizableReferenceClass + = finalizableReferenceClassReference.get(); + if (finalizableReferenceClass == null) { + /* + * FinalizableReference's class loader was reclaimed. While there's a + * chance that other finalizable references could be enqueued + * subsequently (at which point the class loader would be resurrected + * by virtue of us having a strong reference to it), we should pretty + * much just shut down and make sure we don't keep it alive any longer + * than necessary. + */ + throw new ShutDown(); + } + try { + return finalizableReferenceClass.getMethod("finalizeReferent"); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + public static Field getInheritableThreadLocalsField() { + try { + Field inheritableThreadLocals + = Thread.class.getDeclaredField("inheritableThreadLocals"); + inheritableThreadLocals.setAccessible(true); + return inheritableThreadLocals; + } catch (Throwable t) { + logger.log(Level.INFO, "Couldn't access Thread.inheritableThreadLocals." + + " Reference finalizer threads will inherit thread local" + + " values."); + return null; + } + } + + /** Indicates that it's time to shut down the Finalizer. */ + @SuppressWarnings("serial") // Never serialized or thrown out of this class. + private static class ShutDown extends Exception {} +} diff --git a/guava/src/com/google/common/base/package-info.java b/guava/src/com/google/common/base/package-info.java new file mode 100644 index 0000000..66e7177 --- /dev/null +++ b/guava/src/com/google/common/base/package-info.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Basic utility libraries and interfaces. + * + * <p>This package is a part of the open-source + * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>. + * + * <h2>Contents</h2> + * + * <h3>String-related utilities</h3> + * + * <ul> + * <li>{@link com.google.common.base.Ascii} + * <li>{@link com.google.common.base.CaseFormat} + * <li>{@link com.google.common.base.CharMatcher} + * <li>{@link com.google.common.base.Charsets} + * <li>{@link com.google.common.base.Joiner} + * <li>{@link com.google.common.base.Splitter} + * <li>{@link com.google.common.base.Strings} + * </ul> + * + * <h3>Function types</h3> + * + * <ul> + * <li>{@link com.google.common.base.Function}, + * {@link com.google.common.base.Functions} + * <li>{@link com.google.common.base.Predicate}, + * {@link com.google.common.base.Predicates} + * <li>{@link com.google.common.base.Equivalence}, + * {@link com.google.common.base.Equivalences} + * <li>{@link com.google.common.base.Supplier}, + * {@link com.google.common.base.Suppliers} + * </ul> + * + * <h3>Other</h3> + * + * <ul> + * <li>{@link com.google.common.base.Defaults} + * <li>{@link com.google.common.base.Enums} + * <li>{@link com.google.common.base.Objects} + * <li>{@link com.google.common.base.Optional} + * <li>{@link com.google.common.base.Preconditions} + * <li>{@link com.google.common.base.Stopwatch} + * <li>{@link com.google.common.base.Throwables} + * </ul> + * + */ +@ParametersAreNonnullByDefault +package com.google.common.base; + +import javax.annotation.ParametersAreNonnullByDefault; |