clone of Guava 28.1

This commit is contained in:
Jörg Prante 2020-01-19 15:34:00 +01:00
commit 3ab350bb93
569 changed files with 162570 additions and 0 deletions

12
.gitignore vendored Normal file
View file

@ -0,0 +1,12 @@
/data
/work
/logs
/.idea
/target
.DS_Store
*.iml
/.settings
/.classpath
/.project
/.gradle
/build

3
.travis.yml Normal file
View file

@ -0,0 +1,3 @@
language: java
jdk:
- openjdk11

202
LICENSE.txt Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

29
README.adoc Normal file
View file

@ -0,0 +1,29 @@
# xbib Guava
This is xbib Guava, a build of Google Guava with the following differences to the
original [Google Guava Library](https://github.com/google/guava):
- forked master branch on November 21, 2019 ("28.1+")
- removed all external annotations, so this library does not have any dependencies
- removed duplicate JDK classes (LongAdder, Striped64)
- replaced sun.misc.Unsafe dependent classes with safe versions (LongAdders, UnsignedBytes, LittleEndianByteArray, AbstractFuture)
- the guava failureaccess dependency is included
- removed listenablefuture empty dependency hack
- compiled under and for Java 11 and with a module info for JPMS (module org.xbib.guava)
- Gradle as build system
All credits belong to the original authors
## License
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

163
build.gradle Normal file
View file

@ -0,0 +1,163 @@
plugins {
id "io.codearte.nexus-staging" version "0.21.1"
}
apply plugin: 'java'
apply plugin: 'maven'
repositories {
mavenCentral()
}
compileJava {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
compileTestJava {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:all"
}
test {
testLogging {
showStandardStreams = false
exceptionFormat = 'full'
}
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier 'javadoc'
}
artifacts {
archives sourcesJar, javadocJar
}
ext {
user = 'xbib'
projectName = 'guava'
projectDescription = 'Guava for Java'
scmUrl = 'https://github.com/xbib/guava'
scmConnection = 'scm:git:git://github.com/xbib/guava.git'
scmDeveloperConnection = 'scm:git:git://github.com/xbib/guava.git'
}
task sonatypeUpload(type: Upload) {
group = 'publish'
configuration = configurations.archives
uploadDescriptor = true
repositories {
if (project.hasProperty('ossrhUsername')) {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
repository(url: uri(ossrhReleaseUrl)) {
authentication(userName: ossrhUsername, password: ossrhPassword)
}
snapshotRepository(url: uri(ossrhSnapshotUrl)) {
authentication(userName: ossrhUsername, password: ossrhPassword)
}
pom.project {
groupId project.group
artifactId project.name
version project.version
name project.name
description projectDescription
packaging 'jar'
inceptionYear '2019'
url scmUrl
organization {
name 'xbib'
url 'http://xbib.org'
}
developers {
developer {
id user
name 'Jörg Prante'
email 'joergprante@gmail.com'
url 'https://github.com/jprante'
}
}
scm {
url scmUrl
connection scmConnection
developerConnection scmDeveloperConnection
}
licenses {
license {
name 'The Apache License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
}
}
}
}
}
nexusStaging {
packageGroup = "org.xbib"
}
/*
spotbugs {
effort = "max"
reportLevel = "low"
}
tasks.withType(com.github.spotbugs.SpotBugsTask) {
ignoreFailures = true
reports {
xml.enabled = false
html.enabled = true
}
}
pmd {
toolVersion = '6.11.0'
ruleSets = ['category/java/bestpractices.xml']
}
tasks.withType(Pmd) {
ignoreFailures = true
reports {
xml.enabled = true
html.enabled = true
}
}
checkstyle {
toolVersion = '8.26'
configFile = rootProject.file('config/checkstyle/checkstyle.xml')
ignoreFailures = true
checkstyleMain {
source = sourceSets.main.allSource
}
}
tasks.withType(Checkstyle) {
ignoreFailures = true
reports {
xml.enabled = true
html.enabled = true
}
}
sonarqube {
properties {
property "sonar.projectName", "${project.group} ${project.name}"
property "sonar.sourceEncoding", "UTF-8"
property "sonar.tests", "src/test/java"
property "sonar.scm.provider", "git"
}
}
*/

View file

@ -0,0 +1,177 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="SuppressionFilter">
<property name="file" value="${config_loc}/suppressions.xml"/>
</module>
<module name="SuppressWarningsFilter"/>
<module name="SeverityMatchFilter">
<property name="severity" value="info"/>
<property name="acceptOnMatch" value="false"/>
</module>
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>
<module name="LineLength">
<property name="max" value="120"/>
<property name="ignorePattern" value="^[ \t]*\*.*@.*$"/>
</module>
<module name="TreeWalker">
<property name="tabWidth" value="4"/>
<module name="SuppressWarningsHolder"/>
<module name="Indentation">
<property name="forceStrictCondition" value="true"/>
</module>
<module name="ConstantName"/>
<module name="FinalParameters">
<property name="tokens" value="METHOD_DEF, CTOR_DEF, LITERAL_CATCH, FOR_EACH_CLAUSE"/>
</module>
<module name="FinalLocalVariable">
<property name="validateEnhancedForLoopVariable" value="true"/>
</module>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName">
<property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
</module>
<module name="MethodName"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<module name="MethodLength">
<property name="tokens" value="METHOD_DEF"/>
<property name="max" value="100"/>
</module>
<module name="EmptyForInitializerPad"/>
<module name="MethodParamPad"/>
<module name="NoWhitespaceBefore"/>
<module name="WhitespaceAfter">
<property name="tokens" value="COMMA, SEMI, LITERAL_IF, LITERAL_ELSE, LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, DO_WHILE"/>
</module>
<module name="NoWhitespaceAfter">
<property name="tokens" value="INC, DEC, UNARY_MINUS, UNARY_PLUS, BNOT, LNOT, DOT, TYPECAST, ARRAY_DECLARATOR, INDEX_OP, METHOD_REF"/>
<property name="allowLineBreaks" value="false"/>
</module>
<module name="WhitespaceAround">
<property name="allowEmptyLambdas" value="true"/>
</module>
<module name="SingleSpaceSeparator"/>
<module name="OperatorWrap">
<property name="option" value="eol"/>
</module>
<module name="NeedBraces"/>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<module name="NestedTryDepth">
<property name="max" value="2"/>
</module>
<module name="CovariantEquals"/>
<module name="LeftCurly">
<property name="option" value="nl"/>
</module>
<module name="RightCurly">
<property name="option" value="alone"/>
<property name="tokens" value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"/>
</module>
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="DefaultComesLast"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<module name="StringLiteralEquality"/>
<module name="PackageDeclaration"/>
<module name="FallThrough"/>
<module name="FinalClass"/>
<module name="MutableException"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
<property name="tokens" value="IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF, STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF"/>
</module>
<module name="TodoComment">
<property name="severity" value="info"/>
<property name="format" value="TODO"/>
</module>
<module name="UpperEll"/>
<module name="IllegalType">
<property name="legalAbstractClassNames"
value="AbstractBeanDefinition, AbstractEntry"/>
<property name="illegalClassNames"
value="java.util.GregorianCalendar, java.util.Vector"/>
</module>
<module name="DescendantToken">
<property name="tokens" value="LITERAL_ASSERT"/>
<property name="limitedTokens"
value="ASSIGN,DEC,INC,POST_DEC,POST_INC,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,DIV_ASSIGN,MOD_ASSIGN,BSR_ASSIGN,SR_ASSIGN,SL_ASSIGN,BAND_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,METHOD_CALL"/>
<property name="maximumNumber" value="2"/>
</module>
<module name="Regexp">
<property name="format" value="[ \t]+$"/>
<property name="illegalPattern" value="true"/>
<property name="message" value="Trailing whitespace"/>
</module>
<module name="JavadocMethod">
<property name="allowUndeclaredRTE" value="true"/>
</module>
</module>
</module>

View file

@ -0,0 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.0//EN"
"https://checkstyle.org/dtds/suppressions_1_0.dtd">
<suppressions>
<suppress files=".*generated-src.*" checks="."/>
</suppressions>

3
gradle.properties Normal file
View file

@ -0,0 +1,3 @@
group = org.xbib
name = guava
version = 28.1

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,6 @@
#Sat Nov 23 21:29:06 CET 2019
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

188
gradlew vendored Executable file
View file

@ -0,0 +1,188 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

100
gradlew.bat vendored Normal file
View file

@ -0,0 +1,100 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

1
settings.gradle Normal file
View file

@ -0,0 +1 @@
rootProject.name = name

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2010 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Signifies that a public API (public class, method or field) is subject to incompatible changes,
* or even removal, in a future release. An API bearing this annotation is exempt from any
* compatibility guarantees made by its containing library. Note that the presence of this
* annotation implies nothing about the quality or performance of the API in question, only the fact
* that it is not "API-frozen."
*
* <p>It is generally safe for <i>applications</i> to depend on beta APIs, at the cost of some extra
* work during upgrades. However it is generally inadvisable for <i>libraries</i> (which get
* included on users' CLASSPATHs, outside the library developers' control) to do so.
*
*
* @author Kevin Bourrillion
*/
@Retention(RetentionPolicy.CLASS)
@Target({
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.FIELD,
ElementType.METHOD,
ElementType.TYPE
})
@Documented
@GwtCompatible
public @interface Beta {}

View file

@ -0,0 +1,86 @@
/*
* Copyright (C) 2009 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* The presence of this annotation on a type indicates that the type may be used with the <a
* href="http://code.google.com/webtoolkit/">Google Web Toolkit</a> (GWT). When applied to a method,
* the return type of the method is GWT compatible. It's useful to indicate that an instance created
* by factory methods has a GWT serializable type. In the following example,
*
* <pre>
* {@literal @}GwtCompatible
* class Lists {
* ...
* {@literal @}GwtCompatible(serializable = true)
* {@literal static <E> List<E>} newArrayList(E... elements) {
* ...
* }
* }
* </pre>
*
* <p>The return value of {@code Lists.newArrayList(E[])} has GWT serializable type. It is also
* useful in specifying contracts of interface methods. In the following example,
*
* <pre>
* {@literal @}GwtCompatible
* interface ListFactory {
* ...
* {@literal @}GwtCompatible(serializable = true)
* {@literal <E> List<E>} newArrayList(E... elements);
* }
* </pre>
*
* <p>The {@code newArrayList(E[])} method of all implementations of {@code ListFactory} is expected
* to return a value with a GWT serializable type.
*
* <p>Note that a {@code GwtCompatible} type may have some {@link GwtIncompatible} methods.
*
*
* @author Charles Fry
* @author Hayward Chan
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@GwtCompatible
public @interface GwtCompatible {
/**
* When {@code true}, the annotated type or the type of the method return value is GWT
* serializable.
*
* @see <a href=
* "http://code.google.com/webtoolkit/doc/latest/DevGuideServerCommunication.html#DevGuideSerializableTypes">
* Documentation about GWT serialization</a>
*/
boolean serializable() default false;
/**
* When {@code true}, the annotated type is emulated in GWT. The emulated source (also known as
* super-source) is different from the implementation used by the JVM.
*
* @see <a href=
* "http://code.google.com/webtoolkit/doc/latest/DevGuideOrganizingProjects.html#DevGuideModules">
* Documentation about GWT emulated source</a>
*/
boolean emulated() default false;
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2009 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* The presence of this annotation on an API indicates that the method may <em>not</em> be used with
* the <a href="http://www.gwtproject.org/">Google Web Toolkit</a> (GWT).
*
* <p>This annotation behaves identically to <a href=
* "http://www.gwtproject.org/javadoc/latest/com/google/gwt/core/shared/GwtIncompatible.html">the
* {@code @GwtIncompatible} annotation in GWT itself</a>.
*
* @author Charles Fry
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Documented
@GwtCompatible
public @interface GwtIncompatible {
/**
* Describes why the annotated element is incompatible with GWT. Since this is generally due to a
* dependence on a type/method which GWT doesn't support, it is sufficient to simply reference the
* unsupported type/method. E.g. "Class.isInstance".
*
* <p>As of Guava 20.0, this value is optional. We encourage authors who wish to describe why an
* API is {@code @GwtIncompatible} to instead leave an implementation comment.
*/
String value() default "";
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (C) 2006 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.annotations;
/**
* Annotates a program element that exists, or is more widely visible than otherwise necessary, only
* for use in test code.
*
* @author Johannes Henkel
*/
@GwtCompatible
public @interface VisibleForTesting {
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import java.util.Collections;
import java.util.Set;
/** Implementation of an {@link Optional} not containing a reference. */
@GwtCompatible
final class Absent<T> extends Optional<T> {
static final Absent<Object> INSTANCE = new Absent<>();
@SuppressWarnings("unchecked") // implementation is "fully variant"
static <T> Optional<T> withType() {
return (Optional<T>) INSTANCE;
}
private Absent() {}
@Override
public boolean isPresent() {
return false;
}
@Override
public T get() {
throw new IllegalStateException("Optional.get() cannot be called on an absent value");
}
@Override
public T or(T defaultValue) {
return checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)");
}
@SuppressWarnings("unchecked") // safe covariant cast
@Override
public Optional<T> or(Optional<? extends T> secondChoice) {
return (Optional<T>) checkNotNull(secondChoice);
}
@Override
public T or(Supplier<? extends T> supplier) {
return checkNotNull(
supplier.get(), "use Optional.orNull() instead of a Supplier that returns null");
}
@Override
public T orNull() {
return null;
}
@Override
public Set<T> asSet() {
return Collections.emptySet();
}
@Override
public <V> Optional<V> transform(Function<? super T, V> function) {
checkNotNull(function);
return Optional.absent();
}
@Override
public boolean equals(Object object) {
return object == this;
}
@Override
public int hashCode() {
return 0x79a31aac;
}
@Override
public String toString() {
return "Optional.absent()";
}
private Object readResolve() {
return INSTANCE;
}
private static final long serialVersionUID = 0;
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.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;
T result = next;
next = null;
return result;
}
@Override
public final void remove() {
throw new UnsupportedOperationException();
}
}

View file

@ -0,0 +1,635 @@
/*
* 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;
/**
* 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 Catherine 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;
/** A bit mask which selects the bit encoding ASCII character case. */
private static final char CASE_MASK = 0x20;
/**
* 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();
for (int i = 0; i < length; i++) {
if (isUpperCase(string.charAt(i))) {
char[] chars = string.toCharArray();
for (; i < length; i++) {
char c = chars[i];
if (isUpperCase(c)) {
chars[i] = (char) (c ^ CASE_MASK);
}
}
return String.valueOf(chars);
}
}
return string;
}
/**
* Returns a copy of the input character sequence in which all {@linkplain #isUpperCase(char)
* uppercase ASCII characters} have been converted to lowercase. All other characters are copied
* without modification.
*
* @since 14.0
*/
public static String toLowerCase(CharSequence chars) {
if (chars instanceof String) {
return toLowerCase((String) chars);
}
char[] newChars = new char[chars.length()];
for (int i = 0; i < newChars.length; i++) {
newChars[i] = toLowerCase(chars.charAt(i));
}
return String.valueOf(newChars);
}
/**
* 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 ^ CASE_MASK) : 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();
for (int i = 0; i < length; i++) {
if (isLowerCase(string.charAt(i))) {
char[] chars = string.toCharArray();
for (; i < length; i++) {
char c = chars[i];
if (isLowerCase(c)) {
chars[i] = (char) (c ^ CASE_MASK);
}
}
return String.valueOf(chars);
}
}
return string;
}
/**
* Returns a copy of the input character sequence in which all {@linkplain #isLowerCase(char)
* lowercase ASCII characters} have been converted to uppercase. All other characters are copied
* without modification.
*
* @since 14.0
*/
public static String toUpperCase(CharSequence chars) {
if (chars instanceof String) {
return toUpperCase((String) chars);
}
char[] newChars = new char[chars.length()];
for (int i = 0; i < newChars.length; i++) {
newChars[i] = toUpperCase(chars.charAt(i));
}
return String.valueOf(newChars);
}
/**
* 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 ^ CASE_MASK) : 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) {
// Note: This was benchmarked against the alternate expression "(char)(c - 'a') < 26" (Nov '13)
// and found to perform at least as well, or better.
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');
}
/**
* Truncates the given character sequence to the given maximum length. If the length of the
* sequence is greater than {@code maxLength}, the returned string will be exactly {@code
* maxLength} chars in length and will end with the given {@code truncationIndicator}. Otherwise,
* the sequence will be returned as a string with no changes to the content.
*
* <p>Examples:
*
* <pre>{@code
* Ascii.truncate("foobar", 7, "..."); // returns "foobar"
* Ascii.truncate("foobar", 5, "..."); // returns "fo..."
* }</pre>
*
* <p><b>Note:</b> This method <i>may</i> work with certain non-ASCII text but is not safe for use
* with arbitrary Unicode text. It is mostly intended for use with text that is known to be safe
* for use with it (such as all-ASCII text) and for simple debugging text. When using this method,
* consider the following:
*
* <ul>
* <li>it may split surrogate pairs
* <li>it may split characters and combining characters
* <li>it does not consider word boundaries
* <li>if truncating for display to users, there are other considerations that must be taken
* into account
* <li>the appropriate truncation indicator may be locale-dependent
* <li>it is safe to use non-ASCII characters in the truncation indicator
* </ul>
*
*
* @throws IllegalArgumentException if {@code maxLength} is less than the length of {@code
* truncationIndicator}
* @since 16.0
*/
public static String truncate(CharSequence seq, int maxLength, String truncationIndicator) {
checkNotNull(seq);
// length to truncate the sequence to, not including the truncation indicator
int truncationLength = maxLength - truncationIndicator.length();
// in this worst case, this allows a maxLength equal to the length of the truncationIndicator,
// meaning that a string will be truncated to just the truncation indicator itself
checkArgument(
truncationLength >= 0,
"maxLength (%s) must be >= length of the truncation indicator (%s)",
maxLength,
truncationIndicator.length());
if (seq.length() <= maxLength) {
String string = seq.toString();
if (string.length() <= maxLength) {
return string;
}
// if the length of the toString() result was > maxLength for some reason, truncate that
seq = string;
}
return new StringBuilder(maxLength)
.append(seq, 0, truncationLength)
.append(truncationIndicator)
.toString();
}
/**
* Indicates whether the contents of the given character sequences {@code s1} and {@code s2} are
* equal, ignoring the case of any ASCII alphabetic characters between {@code 'a'} and {@code 'z'}
* or {@code 'A'} and {@code 'Z'} inclusive.
*
* <p>This method is significantly faster than {@link String#equalsIgnoreCase} and should be used
* in preference if at least one of the parameters is known to contain only ASCII characters.
*
* <p>Note however that this method does not always behave identically to expressions such as:
*
* <ul>
* <li>{@code string.toUpperCase().equals("UPPER CASE ASCII")}
* <li>{@code string.toLowerCase().equals("lower case ascii")}
* </ul>
*
* <p>due to case-folding of some non-ASCII characters (which does not occur in {@link
* String#equalsIgnoreCase}). However in almost all cases that ASCII strings are used, the author
* probably wanted the behavior provided by this method rather than the subtle and sometimes
* surprising behavior of {@code toUpperCase()} and {@code toLowerCase()}.
*
* @since 16.0
*/
public static boolean equalsIgnoreCase(CharSequence s1, CharSequence s2) {
// Calling length() is the null pointer check (so do it before we can exit early).
int length = s1.length();
if (s1 == s2) {
return true;
}
if (length != s2.length()) {
return false;
}
for (int i = 0; i < length; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 == c2) {
continue;
}
int alphaIndex = getAlphaIndex(c1);
// This was also benchmarked using '&' to avoid branching (but always evaluate the rhs),
// however this showed no obvious improvement.
if (alphaIndex < 26 && alphaIndex == getAlphaIndex(c2)) {
continue;
}
return false;
}
return true;
}
/**
* Returns the non-negative index value of the alpha character {@code c}, regardless of case. Ie,
* 'a'/'A' returns 0 and 'z'/'Z' returns 25. Non-alpha characters return a value of 26 or greater.
*/
private static int getAlphaIndex(char c) {
// Fold upper-case ASCII to lower-case and make zero-indexed and unsigned (by casting to char).
return (char) ((c | CASE_MASK) - 'a');
}
}

View file

@ -0,0 +1,213 @@
/*
* 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 static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import java.io.Serializable;
/**
* Utility class for converting between various ASCII case formats. Behavior is undefined for
* non-ASCII input.
*
* @author Mike Bostock
* @since 1.0
*/
@GwtCompatible
public enum CaseFormat {
/** Hyphenated variable naming convention, e.g., "lower-hyphen". */
LOWER_HYPHEN(CharMatcher.is('-'), "-") {
@Override
String normalizeWord(String word) {
return Ascii.toLowerCase(word);
}
@Override
String convert(CaseFormat format, String s) {
if (format == LOWER_UNDERSCORE) {
return s.replace('-', '_');
}
if (format == UPPER_UNDERSCORE) {
return Ascii.toUpperCase(s.replace('-', '_'));
}
return super.convert(format, s);
}
},
/** C++ variable naming convention, e.g., "lower_underscore". */
LOWER_UNDERSCORE(CharMatcher.is('_'), "_") {
@Override
String normalizeWord(String word) {
return Ascii.toLowerCase(word);
}
@Override
String convert(CaseFormat format, String s) {
if (format == LOWER_HYPHEN) {
return s.replace('_', '-');
}
if (format == UPPER_UNDERSCORE) {
return Ascii.toUpperCase(s);
}
return super.convert(format, s);
}
},
/** Java variable naming convention, e.g., "lowerCamel". */
LOWER_CAMEL(CharMatcher.inRange('A', 'Z'), "") {
@Override
String normalizeWord(String word) {
return firstCharOnlyToUpper(word);
}
@Override
String normalizeFirstWord(String word) {
return Ascii.toLowerCase(word);
}
},
/** Java and C++ class naming convention, e.g., "UpperCamel". */
UPPER_CAMEL(CharMatcher.inRange('A', 'Z'), "") {
@Override
String normalizeWord(String word) {
return firstCharOnlyToUpper(word);
}
},
/** Java and C++ constant naming convention, e.g., "UPPER_UNDERSCORE". */
UPPER_UNDERSCORE(CharMatcher.is('_'), "_") {
@Override
String normalizeWord(String word) {
return Ascii.toUpperCase(word);
}
@Override
String convert(CaseFormat format, String s) {
if (format == LOWER_HYPHEN) {
return Ascii.toLowerCase(s.replace('_', '-'));
}
if (format == LOWER_UNDERSCORE) {
return Ascii.toLowerCase(s);
}
return super.convert(format, s);
}
};
private final CharMatcher wordBoundary;
private final String wordSeparator;
CaseFormat(CharMatcher wordBoundary, String wordSeparator) {
this.wordBoundary = wordBoundary;
this.wordSeparator = wordSeparator;
}
/**
* Converts the specified {@code String str} from this format to the specified {@code format}. A
* "best effort" approach is taken; if {@code str} does not conform to the assumed format, then
* the behavior of this method is undefined but we make a reasonable effort at converting anyway.
*/
public final String to(CaseFormat format, String str) {
checkNotNull(format);
checkNotNull(str);
return (format == this) ? str : convert(format, str);
}
/** Enum values can override for performance reasons. */
String convert(CaseFormat format, String s) {
// 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();
}
return (i == 0)
? format.normalizeFirstWord(s)
: out.append(format.normalizeWord(s.substring(i))).toString();
}
/**
* Returns a {@code Converter} that converts strings from this format to {@code targetFormat}.
*
* @since 16.0
*/
public Converter<String, String> converterTo(CaseFormat targetFormat) {
return new StringConverter(this, targetFormat);
}
private static final class StringConverter extends Converter<String, String>
implements Serializable {
private final CaseFormat sourceFormat;
private final CaseFormat targetFormat;
StringConverter(CaseFormat sourceFormat, CaseFormat targetFormat) {
this.sourceFormat = checkNotNull(sourceFormat);
this.targetFormat = checkNotNull(targetFormat);
}
@Override
protected String doForward(String s) {
return sourceFormat.to(targetFormat, s);
}
@Override
protected String doBackward(String s) {
return targetFormat.to(sourceFormat, s);
}
@Override
public boolean equals(Object object) {
if (object instanceof StringConverter) {
StringConverter that = (StringConverter) object;
return sourceFormat.equals(that.sourceFormat) && targetFormat.equals(that.targetFormat);
}
return false;
}
@Override
public int hashCode() {
return sourceFormat.hashCode() ^ targetFormat.hashCode();
}
@Override
public String toString() {
return sourceFormat + ".converterTo(" + targetFormat + ")";
}
private static final long serialVersionUID = 0L;
}
abstract String normalizeWord(String word);
String normalizeFirstWord(String word) {
return normalizeWord(word);
}
private static String firstCharOnlyToUpper(String word) {
return word.isEmpty()
? word
: Ascii.toUpperCase(word.charAt(0)) + Ascii.toLowerCase(word.substring(1));
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,102 @@
/*
* 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="https://github.com/google/guava/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).
*
* <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use {@link
* java.nio.charset.StandardCharsets#US_ASCII} instead.
*
*/
@GwtIncompatible // Charset not supported by GWT
public static final Charset US_ASCII = Charset.forName("US-ASCII");
/**
* ISO-8859-1: ISO Latin Alphabet Number 1 (ISO-LATIN-1).
*
* <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use {@link
* java.nio.charset.StandardCharsets#ISO_8859_1} instead.
*
*/
public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
/**
* UTF-8: eight-bit UCS Transformation Format.
*
* <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use {@link
* java.nio.charset.StandardCharsets#UTF_8} instead.
*
*/
public static final Charset UTF_8 = Charset.forName("UTF-8");
/**
* UTF-16BE: sixteen-bit UCS Transformation Format, big-endian byte order.
*
* <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use {@link
* java.nio.charset.StandardCharsets#UTF_16BE} instead.
*
*/
@GwtIncompatible // Charset not supported by GWT
public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
/**
* UTF-16LE: sixteen-bit UCS Transformation Format, little-endian byte order.
*
* <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use {@link
* java.nio.charset.StandardCharsets#UTF_16LE} instead.
*
*/
@GwtIncompatible // Charset not supported by GWT
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.
*
* <p><b>Note for Java 7 and later:</b> this constant should be treated as deprecated; use {@link
* java.nio.charset.StandardCharsets#UTF_16} instead.
*
*/
@GwtIncompatible // Charset not supported by GWT
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.
*/
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2016 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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;
/**
* The subset of the {@link java.util.regex.Matcher} API which is used by this package, and also
* shared with the {@code re2j} library. For internal use only. Please refer to the {@code Matcher}
* javadoc for details.
*/
@GwtCompatible
abstract class CommonMatcher {
public abstract boolean matches();
public abstract boolean find();
public abstract boolean find(int index);
public abstract String replaceAll(String replacement);
public abstract int end();
public abstract int start();
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (C) 2016 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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;
/**
* The subset of the {@link java.util.regex.Pattern} API which is used by this package, and also
* shared with the {@code re2j} library. For internal use only. Please refer to the {@code Pattern}
* javadoc for details.
*/
@GwtCompatible
abstract class CommonPattern {
public abstract CommonMatcher matcher(CharSequence t);
public abstract String pattern();
public abstract int flags();
// Re-declare this as abstract to force subclasses to override.
@Override
public abstract String toString();
public static CommonPattern compile(String pattern) {
return Platform.compilePattern(pattern);
}
public static boolean isPcreLike() {
return Platform.patternCompilerIsPcreLike();
}
}

View file

@ -0,0 +1,506 @@
/*
* 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.GwtCompatible;
import java.io.Serializable;
import java.util.Iterator;
/**
* A function from {@code A} to {@code B} with an associated <i>reverse</i> function from {@code B}
* to {@code A}; used for converting back and forth between <i>different representations of the same
* information</i>.
*
* <h3>Invertibility</h3>
*
* <p>The reverse operation <b>may</b> be a strict <i>inverse</i> (meaning that {@code
* converter.reverse().convert(converter.convert(a)).equals(a)} is always true). However, it is very
* common (perhaps <i>more</i> common) for round-trip conversion to be <i>lossy</i>. Consider an
* example round-trip using {@link com.google.common.primitives.Doubles#stringConverter}:
*
* <ol>
* <li>{@code stringConverter().convert("1.00")} returns the {@code Double} value {@code 1.0}
* <li>{@code stringConverter().reverse().convert(1.0)} returns the string {@code "1.0"} --
* <i>not</i> the same string ({@code "1.00"}) we started with
* </ol>
*
* <p>Note that it should still be the case that the round-tripped and original objects are
* <i>similar</i>.
*
* <h3>Nullability</h3>
*
* <p>A converter always converts {@code null} to {@code null} and non-null references to non-null
* references. It would not make sense to consider {@code null} and a non-null reference to be
* "different representations of the same information", since one is distinguishable from
* <i>missing</i> information and the other is not. The {@link #convert} method handles this null
* behavior for all converters; implementations of {@link #doForward} and {@link #doBackward} are
* guaranteed to never be passed {@code null}, and must never return {@code null}.
*
*
* <h3>Common ways to use</h3>
*
* <p>Getting a converter:
*
* <ul>
* <li>Use a provided converter implementation, such as {@link Enums#stringConverter}, {@link
* com.google.common.primitives.Ints#stringConverter Ints.stringConverter} or the {@linkplain
* #reverse reverse} views of these.
* <li>Convert between specific preset values using {@link
* com.google.common.collect.Maps#asConverter Maps.asConverter}. For example, use this to
* create a "fake" converter for a unit test. It is unnecessary (and confusing) to <i>mock</i>
* the {@code Converter} type using a mocking framework.
* <li>Extend this class and implement its {@link #doForward} and {@link #doBackward} methods.
* <li><b>Java 8 users:</b> you may prefer to pass two lambda expressions or method references to
* the {@link #from from} factory method.
* </ul>
*
* <p>Using a converter:
*
* <ul>
* <li>Convert one instance in the "forward" direction using {@code converter.convert(a)}.
* <li>Convert multiple instances "forward" using {@code converter.convertAll(as)}.
* <li>Convert in the "backward" direction using {@code converter.reverse().convert(b)} or {@code
* converter.reverse().convertAll(bs)}.
* <li>Use {@code converter} or {@code converter.reverse()} anywhere a {@link
* java.util.function.Function} is accepted (for example {@link java.util.stream.Stream#map
* Stream.map}).
* <li><b>Do not</b> call {@link #doForward} or {@link #doBackward} directly; these exist only to
* be overridden.
* </ul>
*
* <h3>Example</h3>
*
* <pre>
* return new Converter&lt;Integer, String&gt;() {
* protected String doForward(Integer i) {
* return Integer.toHexString(i);
* }
*
* protected Integer doBackward(String s) {
* return parseUnsignedInt(s, 16);
* }
* };</pre>
*
* <p>An alternative using Java 8:
*
* <pre>{@code
* return Converter.from(
* Integer::toHexString,
* s -> parseUnsignedInt(s, 16));
* }</pre>
*
* @author Mike Ward
* @author Kurt Alfred Kluever
* @author Gregory Kick
* @since 16.0
*/
@GwtCompatible
public abstract class Converter<A, B> implements Function<A, B> {
private final boolean handleNullAutomatically;
// We lazily cache the reverse view to avoid allocating on every call to reverse().
private transient Converter<B, A> reverse;
/** Constructor for use by subclasses. */
protected Converter() {
this(true);
}
/** Constructor used only by {@code LegacyConverter} to suspend automatic null-handling. */
Converter(boolean handleNullAutomatically) {
this.handleNullAutomatically = handleNullAutomatically;
}
// SPI methods (what subclasses must implement)
/**
* Returns a representation of {@code a} as an instance of type {@code B}. If {@code a} cannot be
* converted, an unchecked exception (such as {@link IllegalArgumentException}) should be thrown.
*
* @param a the instance to convert; will never be null
* @return the converted instance; <b>must not</b> be null
*/
protected abstract B doForward(A a);
/**
* Returns a representation of {@code b} as an instance of type {@code A}. If {@code b} cannot be
* converted, an unchecked exception (such as {@link IllegalArgumentException}) should be thrown.
*
* @param b the instance to convert; will never be null
* @return the converted instance; <b>must not</b> be null
* @throws UnsupportedOperationException if backward conversion is not implemented; this should be
* very rare. Note that if backward conversion is not only unimplemented but
* unimplement<i>able</i> (for example, consider a {@code Converter<Chicken, ChickenNugget>}),
* then this is not logically a {@code Converter} at all, and should just implement {@link
* Function}.
*/
protected abstract A doBackward(B b);
// API (consumer-side) methods
/**
* Returns a representation of {@code a} as an instance of type {@code B}.
*
* @return the converted value; is null <i>if and only if</i> {@code a} is null
*/
public final B convert(A a) {
return correctedDoForward(a);
}
B correctedDoForward(A a) {
if (handleNullAutomatically) {
// TODO(kevinb): we shouldn't be checking for a null result at runtime. Assert?
return a == null ? null : checkNotNull(doForward(a));
} else {
return doForward(a);
}
}
A correctedDoBackward(B b) {
if (handleNullAutomatically) {
// TODO(kevinb): we shouldn't be checking for a null result at runtime. Assert?
return b == null ? null : checkNotNull(doBackward(b));
} else {
return doBackward(b);
}
}
/**
* Returns an iterable that applies {@code convert} to each element of {@code fromIterable}. The
* conversion is done lazily.
*
* <p>The returned iterable's iterator supports {@code remove()} if the input iterator does. After
* a successful {@code remove()} call, {@code fromIterable} no longer contains the corresponding
* element.
*/
public Iterable<B> convertAll(final Iterable<? extends A> fromIterable) {
checkNotNull(fromIterable, "fromIterable");
return new Iterable<B>() {
@Override
public Iterator<B> iterator() {
return new Iterator<B>() {
private final Iterator<? extends A> fromIterator = fromIterable.iterator();
@Override
public boolean hasNext() {
return fromIterator.hasNext();
}
@Override
public B next() {
return convert(fromIterator.next());
}
@Override
public void remove() {
fromIterator.remove();
}
};
}
};
}
/**
* Returns the reversed view of this converter, which converts {@code this.convert(a)} back to a
* value roughly equivalent to {@code a}.
*
* <p>The returned converter is serializable if {@code this} converter is.
*
* <p><b>Note:</b> you should not override this method. It is non-final for legacy reasons.
*/
public Converter<B, A> reverse() {
Converter<B, A> result = reverse;
return (result == null) ? reverse = new ReverseConverter<>(this) : result;
}
private static final class ReverseConverter<A, B> extends Converter<B, A>
implements Serializable {
final Converter<A, B> original;
ReverseConverter(Converter<A, B> original) {
this.original = original;
}
/*
* These gymnastics are a little confusing. Basically this class has neither legacy nor
* non-legacy behavior; it just needs to let the behavior of the backing converter shine
* through. So, we override the correctedDo* methods, after which the do* methods should never
* be reached.
*/
@Override
protected A doForward(B b) {
throw new AssertionError();
}
@Override
protected B doBackward(A a) {
throw new AssertionError();
}
@Override
A correctedDoForward(B b) {
return original.correctedDoBackward(b);
}
@Override
B correctedDoBackward(A a) {
return original.correctedDoForward(a);
}
@Override
public Converter<A, B> reverse() {
return original;
}
@Override
public boolean equals(Object object) {
if (object instanceof ReverseConverter) {
ReverseConverter<?, ?> that = (ReverseConverter<?, ?>) object;
return this.original.equals(that.original);
}
return false;
}
@Override
public int hashCode() {
return ~original.hashCode();
}
@Override
public String toString() {
return original + ".reverse()";
}
private static final long serialVersionUID = 0L;
}
/**
* Returns a converter whose {@code convert} method applies {@code secondConverter} to the result
* of this converter. Its {@code reverse} method applies the converters in reverse order.
*
* <p>The returned converter is serializable if {@code this} converter and {@code secondConverter}
* are.
*/
public final <C> Converter<A, C> andThen(Converter<B, C> secondConverter) {
return doAndThen(secondConverter);
}
/** Package-private non-final implementation of andThen() so only we can override it. */
<C> Converter<A, C> doAndThen(Converter<B, C> secondConverter) {
return new ConverterComposition<>(this, checkNotNull(secondConverter));
}
private static final class ConverterComposition<A, B, C> extends Converter<A, C>
implements Serializable {
final Converter<A, B> first;
final Converter<B, C> second;
ConverterComposition(Converter<A, B> first, Converter<B, C> second) {
this.first = first;
this.second = second;
}
/*
* These gymnastics are a little confusing. Basically this class has neither legacy nor
* non-legacy behavior; it just needs to let the behaviors of the backing converters shine
* through (which might even differ from each other!). So, we override the correctedDo* methods,
* after which the do* methods should never be reached.
*/
@Override
protected C doForward(A a) {
throw new AssertionError();
}
@Override
protected A doBackward(C c) {
throw new AssertionError();
}
@Override
C correctedDoForward(A a) {
return second.correctedDoForward(first.correctedDoForward(a));
}
@Override
A correctedDoBackward(C c) {
return first.correctedDoBackward(second.correctedDoBackward(c));
}
@Override
public boolean equals(Object object) {
if (object instanceof ConverterComposition) {
ConverterComposition<?, ?, ?> that = (ConverterComposition<?, ?, ?>) object;
return this.first.equals(that.first) && this.second.equals(that.second);
}
return false;
}
@Override
public int hashCode() {
return 31 * first.hashCode() + second.hashCode();
}
@Override
public String toString() {
return first + ".andThen(" + second + ")";
}
private static final long serialVersionUID = 0L;
}
/**
* @deprecated Provided to satisfy the {@code Function} interface; use {@link #convert} instead.
*/
@Deprecated
@Override
public final B apply(A a) {
return convert(a);
}
/**
* Indicates whether another object is equal to this converter.
*
* <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 Converter} that it considers <i>interchangeable</i> with this one. "Interchangeable"
* <i>typically</i> means that {@code Objects.equal(this.convert(a), that.convert(a))} is true for
* all {@code a} of type {@code A} (and similarly for {@code reverse}). Note that a {@code false}
* result from this method does not imply that the converters are known <i>not</i> to be
* interchangeable.
*/
@Override
public boolean equals(Object object) {
return super.equals(object);
}
// Static converters
/**
* Returns a converter based on separate forward and backward functions. This is useful if the
* function instances already exist, or so that you can supply lambda expressions. If those
* circumstances don't apply, you probably don't need to use this; subclass {@code Converter} and
* implement its {@link #doForward} and {@link #doBackward} methods directly.
*
* <p>These functions will never be passed {@code null} and must not under any circumstances
* return {@code null}. If a value cannot be converted, the function should throw an unchecked
* exception (typically, but not necessarily, {@link IllegalArgumentException}).
*
* <p>The returned converter is serializable if both provided functions are.
*
* @since 17.0
*/
public static <A, B> Converter<A, B> from(
Function<? super A, ? extends B> forwardFunction,
Function<? super B, ? extends A> backwardFunction) {
return new FunctionBasedConverter<>(forwardFunction, backwardFunction);
}
private static final class FunctionBasedConverter<A, B> extends Converter<A, B>
implements Serializable {
private final Function<? super A, ? extends B> forwardFunction;
private final Function<? super B, ? extends A> backwardFunction;
private FunctionBasedConverter(
Function<? super A, ? extends B> forwardFunction,
Function<? super B, ? extends A> backwardFunction) {
this.forwardFunction = checkNotNull(forwardFunction);
this.backwardFunction = checkNotNull(backwardFunction);
}
@Override
protected B doForward(A a) {
return forwardFunction.apply(a);
}
@Override
protected A doBackward(B b) {
return backwardFunction.apply(b);
}
@Override
public boolean equals(Object object) {
if (object instanceof FunctionBasedConverter) {
FunctionBasedConverter<?, ?> that = (FunctionBasedConverter<?, ?>) object;
return this.forwardFunction.equals(that.forwardFunction)
&& this.backwardFunction.equals(that.backwardFunction);
}
return false;
}
@Override
public int hashCode() {
return forwardFunction.hashCode() * 31 + backwardFunction.hashCode();
}
@Override
public String toString() {
return "Converter.from(" + forwardFunction + ", " + backwardFunction + ")";
}
}
/** Returns a serializable converter that always converts or reverses an object to itself. */
@SuppressWarnings("unchecked") // implementation is "fully variant"
public static <T> Converter<T, T> identity() {
return (IdentityConverter<T>) IdentityConverter.INSTANCE;
}
/**
* A converter that always converts or reverses an object to itself. Note that T is now a
* "pass-through type".
*/
private static final class IdentityConverter<T> extends Converter<T, T> implements Serializable {
static final IdentityConverter<?> INSTANCE = new IdentityConverter<>();
@Override
protected T doForward(T t) {
return t;
}
@Override
protected T doBackward(T t) {
return t;
}
@Override
public IdentityConverter<T> reverse() {
return this;
}
@Override
<S> Converter<T, S> doAndThen(Converter<T, S> otherConverter) {
return checkNotNull(otherConverter, "otherConverter");
}
/*
* We *could* override convertAll() to return its input, but it's a rather pointless
* optimization and opened up a weird type-safety problem.
*/
@Override
public String toString() {
return "Converter.identity()";
}
private Object readResolve() {
return INSTANCE;
}
private static final long serialVersionUID = 0L;
}
}

View file

@ -0,0 +1,62 @@
/*
* 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.GwtIncompatible;
/**
* This class provides default values for all Java types, as defined by the JLS.
*
* @author Ben Yu
* @since 1.0
*/
@GwtIncompatible
public final class Defaults {
private Defaults() {}
private static final Double DOUBLE_DEFAULT = Double.valueOf(0d);
private static final Float FLOAT_DEFAULT = Float.valueOf(0f);
/**
* 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}, {@code null} is returned.
*/
@SuppressWarnings("unchecked")
public static <T> T defaultValue(Class<T> type) {
checkNotNull(type);
if (type == boolean.class) {
return (T) Boolean.FALSE;
} else if (type == char.class) {
return (T) Character.valueOf('\0');
} else if (type == byte.class) {
return (T) Byte.valueOf((byte) 0);
} else if (type == short.class) {
return (T) Short.valueOf((short) 0);
} else if (type == int.class) {
return (T) Integer.valueOf(0);
} else if (type == long.class) {
return (T) Long.valueOf(0L);
} else if (type == float.class) {
return (T) FLOAT_DEFAULT;
} else if (type == double.class) {
return (T) DOUBLE_DEFAULT;
} else {
return null;
}
}
}

View file

@ -0,0 +1,150 @@
/*
* 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 com.google.common.annotations.GwtIncompatible;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
/**
* Utility methods for working with {@link Enum} instances.
*
* @author Steve McKay
* @since 9.0
*/
@GwtCompatible(emulated = true)
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 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);
return Platform.getEnumIfPresent(enumClass, value);
}
@GwtIncompatible // java.lang.ref.WeakReference
private static final Map<Class<? extends Enum<?>>, Map<String, WeakReference<? extends Enum<?>>>>
enumConstantCache = new WeakHashMap<>();
@GwtIncompatible // java.lang.ref.WeakReference
private static <T extends Enum<T>> Map<String, WeakReference<? extends Enum<?>>> populateCache(
Class<T> enumClass) {
Map<String, WeakReference<? extends Enum<?>>> result = new HashMap<>();
for (T enumInstance : EnumSet.allOf(enumClass)) {
result.put(enumInstance.name(), new WeakReference<Enum<?>>(enumInstance));
}
enumConstantCache.put(enumClass, result);
return result;
}
@GwtIncompatible // java.lang.ref.WeakReference
static <T extends Enum<T>> Map<String, WeakReference<? extends Enum<?>>> getEnumConstants(
Class<T> enumClass) {
synchronized (enumConstantCache) {
Map<String, WeakReference<? extends Enum<?>>> constants = enumConstantCache.get(enumClass);
if (constants == null) {
constants = populateCache(enumClass);
}
return constants;
}
}
/**
* Returns a converter that converts between strings and {@code enum} values of type {@code
* enumClass} using {@link Enum#valueOf(Class, String)} and {@link Enum#name()}. The converter
* will throw an {@code IllegalArgumentException} if the argument is not the name of any enum
* constant in the specified enum.
*
* @since 16.0
*/
public static <T extends Enum<T>> Converter<String, T> stringConverter(final Class<T> enumClass) {
return new StringConverter<T>(enumClass);
}
private static final class StringConverter<T extends Enum<T>> extends Converter<String, T>
implements Serializable {
private final Class<T> enumClass;
StringConverter(Class<T> enumClass) {
this.enumClass = checkNotNull(enumClass);
}
@Override
protected T doForward(String value) {
return Enum.valueOf(enumClass, value);
}
@Override
protected String doBackward(T enumValue) {
return enumValue.name();
}
@Override
public boolean equals(Object object) {
if (object instanceof StringConverter) {
StringConverter<?> that = (StringConverter<?>) object;
return this.enumClass.equals(that.enumClass);
}
return false;
}
@Override
public int hashCode() {
return enumClass.hashCode();
}
@Override
public String toString() {
return "Enums.stringConverter(" + enumClass.getName() + ".class)";
}
private static final long serialVersionUID = 0L;
}
}

View file

@ -0,0 +1,374 @@
/*
* Copyright (C) 2010 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import java.io.Serializable;
import java.util.function.BiPredicate;
/**
* A strategy for determining whether two instances are considered equivalent, and for computing
* hash codes in a manner consistent with that equivalence. Two examples of equivalences are the
* {@linkplain #identity() identity equivalence} and the {@linkplain #equals "equals" equivalence}.
*
* @author Bob Lee
* @author Ben Yu
* @author Gregory Kick
* @since 10.0 (<a href="https://github.com/google/guava/wiki/Compatibility">mostly
* source-compatible</a> since 4.0)
*/
@GwtCompatible
public abstract class Equivalence<T> implements BiPredicate<T, T> {
/** Constructor for use by subclasses. */
protected Equivalence() {}
/**
* Returns {@code true} if the given objects are considered equivalent.
*
* <p>This method describes an <i>equivalence relation</i> on object references, meaning that for
* all references {@code x}, {@code y}, and {@code z} (any of which may be null):
*
* <ul>
* <li>{@code equivalent(x, x)} is true (<i>reflexive</i> property)
* <li>{@code equivalent(x, y)} and {@code equivalent(y, x)} each return the same result
* (<i>symmetric</i> property)
* <li>If {@code equivalent(x, y)} and {@code equivalent(y, z)} are both true, then {@code
* equivalent(x, z)} is also true (<i>transitive</i> property)
* </ul>
*
* <p>Note that all calls to {@code equivalent(x, y)} are expected to return the same result as
* long as neither {@code x} nor {@code y} is modified.
*/
public final boolean equivalent(T a, T b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
return doEquivalent(a, b);
}
/**
* @deprecated Provided only to satisfy the {@link BiPredicate} interface; use {@link #equivalent}
* instead.
* @since 21.0
*/
@Deprecated
@Override
public final boolean test(T t, T u) {
return equivalent(t, u);
}
/**
* Implemented by the user to determine whether {@code a} and {@code b} are considered equivalent,
* subject to the requirements specified in {@link #equivalent}.
*
* <p>This method should not be called except by {@link #equivalent}. When {@link #equivalent}
* calls this method, {@code a} and {@code b} are guaranteed to be distinct, non-null instances.
*
* @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 across 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 across <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(T t) {
if (t == null) {
return 0;
}
return doHash(t);
}
/**
* Implemented by the user to return a hash code for {@code t}, subject to the requirements
* specified in {@link #hash}.
*
* <p>This method should not be called except by {@link #hash}. When {@link #hash} calls this
* method, {@code t} is guaranteed to be non-null.
*
* @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 = Equivalence.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
* Equivalence.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<>(function, this);
}
/**
* Returns a wrapper of {@code reference} that implements {@link Wrapper#equals(Object)
* Object.equals()} such that {@code wrap(a).equals(wrap(b))} if and only if {@code equivalent(a,
* b)}.
*
* @since 10.0
*/
public final <S extends T> Wrapper<S> wrap(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;
private final T reference;
private Wrapper(Equivalence<? super T> equivalence, T reference) {
this.equivalence = checkNotNull(equivalence);
this.reference = reference;
}
/** Returns the (possibly null) reference wrapped by this instance. */
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(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Wrapper) {
Wrapper<?> that = (Wrapper<?>) obj; // note: not necessarily a Wrapper<T>
if (this.equivalence.equals(that.equivalence)) {
/*
* We'll accept that as sufficient "proof" that either equivalence should be able to
* handle either reference, so it's safe to circumvent compile-time type checking.
*/
@SuppressWarnings("unchecked")
Equivalence<Object> equivalence = (Equivalence<Object>) this.equivalence;
return equivalence.equivalent(this.reference, that.reference);
}
}
return false;
}
/** Returns the result of {@link Equivalence#hash(Object)} applied to 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
*/
public final Predicate<T> equivalentTo(T target) {
return new EquivalentToPredicate<T>(this, target);
}
private static final class EquivalentToPredicate<T> implements Predicate<T>, Serializable {
private final Equivalence<T> equivalence;
private final T target;
EquivalentToPredicate(Equivalence<T> equivalence, T target) {
this.equivalence = checkNotNull(equivalence);
this.target = target;
}
@Override
public boolean apply(T input) {
return equivalence.equivalent(input, target);
}
@Override
public boolean equals(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
protected 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;
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (C) 2016 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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;
/**
* Holder for extra methods of {@code Objects} only in web. Intended to be empty for regular
* version.
*/
@GwtCompatible(emulated = true)
abstract class ExtraObjectsMethodsForWeb {}

View file

@ -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 com.google.common.annotations.GwtIncompatible;
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
*/
@GwtIncompatible
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();
}
}

View file

@ -0,0 +1,34 @@
/*
* 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.GwtIncompatible;
/**
* Implemented by references that have code to run after garbage collection of their referents.
*
* @see FinalizableReferenceQueue
* @author Bob Lee
* @since 2.0
*/
@GwtIncompatible
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();
}

View file

@ -0,0 +1,350 @@
/*
* 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.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Method;
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.
*
* <p>As an example of how this is used, imagine you have a class {@code MyServer} that creates a a
* {@link java.net.ServerSocket ServerSocket}, and you would like to ensure that the {@code
* ServerSocket} is closed even if the {@code MyServer} object is garbage-collected without calling
* its {@code close} method. You <em>could</em> use a finalizer to accomplish this, but that has a
* number of well-known problems. Here is how you might use this class instead:
*
* <pre>{@code
* public class MyServer implements Closeable {
* private static final FinalizableReferenceQueue frq = new FinalizableReferenceQueue();
* // You might also share this between several objects.
*
* private static final Set<Reference<?>> references = Sets.newConcurrentHashSet();
* // This ensures that the FinalizablePhantomReference itself is not garbage-collected.
*
* private final ServerSocket serverSocket;
*
* private MyServer(...) {
* ...
* this.serverSocket = new ServerSocket(...);
* ...
* }
*
* public static MyServer create(...) {
* MyServer myServer = new MyServer(...);
* final ServerSocket serverSocket = myServer.serverSocket;
* Reference<?> reference = new FinalizablePhantomReference<MyServer>(myServer, frq) {
* public void finalizeReferent() {
* references.remove(this):
* if (!serverSocket.isClosed()) {
* ...log a message about how nobody called close()...
* try {
* serverSocket.close();
* } catch (IOException e) {
* ...
* }
* }
* }
* };
* references.add(reference);
* return myServer;
* }
*
* public void close() {
* serverSocket.close();
* }
* }
* }</pre>
*
* @author Bob Lee
* @since 2.0
*/
@GwtIncompatible
public class FinalizableReferenceQueue implements Closeable {
/*
* 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.
*
* NOTE: The tests for this behavior (FinalizableReferenceQueueClassLoaderUnloadingTest) fail
* strangely when run in JDK 9. We are considering this a known issue. Please see
* https://github.com/google/guava/issues/3086 for more information.
*/
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;
final PhantomReference<Object> frqRef;
/** Whether or not the background thread started successfully. */
final boolean threadStarted;
/** Constructs a new queue. */
public FinalizableReferenceQueue() {
// We could start the finalizer lazily, but I'd rather it blow up early.
queue = new ReferenceQueue<>();
frqRef = new PhantomReference<Object>(this, queue);
boolean threadStarted = false;
try {
startFinalizer.invoke(null, FinalizableReference.class, queue, frqRef);
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);
}
this.threadStarted = threadStarted;
}
@Override
public void close() {
frqRef.enqueue();
cleanUp();
}
/**
* Repeatedly dequeues references from the queue and invokes {@link
* FinalizableReference#finalizeReferent()} on them until the queue is empty. This method is a
* 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 Guava 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, ReferenceQueue.class, PhantomReference.class);
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
}

View file

@ -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 com.google.common.annotations.GwtIncompatible;
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
*/
@GwtIncompatible
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();
}
}

View file

@ -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 com.google.common.annotations.GwtIncompatible;
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
*/
@GwtIncompatible
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();
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import com.google.common.annotations.GwtCompatible;
/**
* Legacy version of {@link java.util.function.Function java.util.function.Function}.
*
* <p>The {@link Functions} class provides common functions and related utilities.
*
* <p>As this interface extends {@code java.util.function.Function}, an instance of this type can be
* used as a {@code java.util.function.Function} directly. To use a {@code
* java.util.function.Function} in a context where a {@code com.google.common.base.Function} is
* needed, use {@code function::apply}.
*
* <p>This interface is now a legacy type. Use {@code java.util.function.Function} (or the
* appropriate primitive specialization such as {@code ToIntFunction}) instead whenever possible.
* Otherwise, at least reduce <i>explicit</i> dependencies on this type by using lambda expressions
* or method references instead of classes, leaving your code easier to migrate in the future.
*
* <p>See the Guava User Guide article on <a
* href="https://github.com/google/guava/wiki/FunctionalExplained">the use of {@code Function}</a>.
*
* @author Kevin Bourrillion
* @since 2.0
*/
@GwtCompatible
@FunctionalInterface
public interface Function<F, T> extends java.util.function.Function<F, T> {
@Override
T apply(F input);
/**
* <i>May</i> return {@code true} if {@code object} is a {@code Function} that behaves identically
* to this function.
*
* <p><b>Warning: do not depend</b> on the behavior of this method.
*
* <p>Historically, {@code Function} instances in this library have implemented this method to
* recognize certain cases where distinct {@code Function} instances would in fact behave
* identically. However, as code migrates to {@code java.util.function}, that behavior will
* disappear. It is best not to depend on it.
*/
@Override
boolean equals(Object object);
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.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;
/**
* 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(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 + ")";
}
}

View file

@ -0,0 +1,400 @@
/*
* 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.GwtCompatible;
import java.io.Serializable;
import java.util.Map;
/**
* Static utility methods pertaining to {@code com.google.common.base.Function} instances; see that
* class for information about migrating to {@code java.util.function}.
*
* <p>All methods return serializable functions as long as they're given serializable parameters.
*
* <p>See the Guava User Guide article on <a
* href="https://github.com/google/guava/wiki/FunctionalExplained">the use of {@code Function}</a>.
*
* @author Mike Bostock
* @author Jared Levy
* @since 2.0
*/
@GwtCompatible
public final class Functions {
private Functions() {}
/**
* A function equivalent to the method reference {@code Object::toString}, for users not yet using
* Java 8. The function simply invokes {@code toString} on its argument and returns the result. It
* throws a {@link NullPointerException} on null input.
*
* <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)}.
*
* <p><b>Warning:</b> as with all function types in this package, avoid depending on the specific
* {@code equals}, {@code hashCode} or {@code toString} behavior of the returned function. A
* future migration to {@code java.util.function} will not preserve this behavior.
*
* <p><b>For Java 8 users:</b> use the method reference {@code Object::toString} instead. In the
* future, when this class requires Java 8, this method will be deprecated. See {@link Function}
* for more important information about the Java 8 transition.
*/
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 "Functions.toStringFunction()";
}
}
/** Returns the identity function. */
// implementation is "fully variant"; E has become a "pass-through" type
@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 "Functions.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. See also {@link
* #forMap(Map, Object)}, which returns a default value in this case.
*
* <p>Note: if {@code map} is a {@link com.google.common.collect.BiMap BiMap} (or can be one), you
* can use {@link com.google.common.collect.Maps#asConverter Maps.asConverter} instead to get a
* function that also supports reverse conversion.
*
* <p><b>Java 8 users:</b> if you are okay with {@code null} being returned for an unrecognized
* key (instead of an exception being thrown), you can use the method reference {@code map::get}
* instead.
*/
public static <K, V> Function<K, V> forMap(Map<K, V> map) {
return new FunctionForMapNoDefault<>(map);
}
/**
* 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. See also {@link #forMap(Map)}, which throws an exception in this case.
*
* <p><b>Java 8 users:</b> you can just write the lambda expression {@code k ->
* map.getOrDefault(k, defaultValue)} instead.
*
* @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, V defaultValue) {
return new ForMapWithDefault<>(map, defaultValue);
}
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(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 "Functions.forMap(" + map + ")";
}
private static final long serialVersionUID = 0;
}
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, 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(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() {
// TODO(cpovirk): maybe remove "defaultValue=" to make this look like the method call does
return "Functions.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}.
*
* <p><b>Java 8 users:</b> use {@code g.compose(f)} or (probably clearer) {@code f.andThen(g)}
* instead.
*
* @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<>(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(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() {
// TODO(cpovirk): maybe make this look like the method call does ("Functions.compose(...)")
return g + "(" + f + ")";
}
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.
*
* <p><b>Java 8 users:</b> use the method reference {@code predicate::test} instead.
*/
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(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 "Functions.forPredicate(" + predicate + ")";
}
private static final long serialVersionUID = 0;
}
/**
* Returns a function that ignores its input and always returns {@code value}.
*
* <p><b>Java 8 users:</b> use the lambda expression {@code o -> value} instead.
*
* @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(E value) {
return new ConstantFunction<E>(value);
}
private static class ConstantFunction<E> implements Function<Object, E>, Serializable {
private final E value;
public ConstantFunction(E value) {
this.value = value;
}
@Override
public E apply(Object from) {
return value;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ConstantFunction) {
ConstantFunction<?> that = (ConstantFunction<?>) obj;
return Objects.equal(value, that.value);
}
return false;
}
@Override
public int hashCode() {
return (value == null) ? 0 : value.hashCode();
}
@Override
public String toString() {
return "Functions.constant(" + value + ")";
}
private static final long serialVersionUID = 0;
}
/**
* Returns a function that ignores its input and returns the result of {@code supplier.get()}.
*
* <p><b>Java 8 users:</b> use the lambda expression {@code o -> supplier.get()} instead.
*
* @since 10.0
*/
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(Object input) {
return supplier.get();
}
@Override
public boolean equals(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 "Functions.forSupplier(" + supplier + ")";
}
private static final long serialVersionUID = 0;
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright (C) 2016 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import com.google.common.annotations.GwtIncompatible;
import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** A regex pattern implementation which is backed by the {@link Pattern}. */
@GwtIncompatible
final class JdkPattern extends CommonPattern implements Serializable {
private final Pattern pattern;
JdkPattern(Pattern pattern) {
this.pattern = Preconditions.checkNotNull(pattern);
}
@Override
public CommonMatcher matcher(CharSequence t) {
return new JdkMatcher(pattern.matcher(t));
}
@Override
public String pattern() {
return pattern.pattern();
}
@Override
public int flags() {
return pattern.flags();
}
@Override
public String toString() {
return pattern.toString();
}
private static final class JdkMatcher extends CommonMatcher {
final Matcher matcher;
JdkMatcher(Matcher matcher) {
this.matcher = Preconditions.checkNotNull(matcher);
}
@Override
public boolean matches() {
return matcher.matches();
}
@Override
public boolean find() {
return matcher.find();
}
@Override
public boolean find(int index) {
return matcher.find(index);
}
@Override
public String replaceAll(String replacement) {
return matcher.replaceAll(replacement);
}
@Override
public int end() {
return matcher.end();
}
@Override
public int start() {
return matcher.start();
}
}
private static final long serialVersionUID = 0;
}

View file

@ -0,0 +1,462 @@
/*
* Copyright (C) 2008 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.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;
/**
* 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>
*
* <p>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="https://github.com/google/guava/wiki/StringsExplained#joiner">{@code Joiner}</a>.
*
* @author Kevin Bourrillion
* @since 2.0
*/
@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;
}
/**
* 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, Object first, Object second, Object... rest)
throws IOException {
return appendTo(appendable, iterable(first, second, rest));
}
/**
* 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, Object first, Object second, Object... rest) {
return appendTo(builder, iterable(first, second, rest));
}
/**
* 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(Object first, 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.
*/
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) {
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.
*/
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) {
throw new UnsupportedOperationException("already specified skipNulls");
}
@Override
public MapJoiner withKeyValueSeparator(String kvs) {
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.
*
* @since 20.0
*/
public MapJoiner withKeyValueSeparator(char keyValueSeparator) {
return withKeyValueSeparator(String.valueOf(keyValueSeparator));
}
/**
* Returns a {@code MapJoiner} using the given key-value separator, and the same configuration as
* this {@code Joiner} otherwise.
*/
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
*/
public static final 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());
}
/**
* 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;
}
/**
* 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;
}
/**
* 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());
}
/**
* 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.
*/
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];
}
}
};
}
}

View file

@ -0,0 +1,373 @@
/*
* Copyright (C) 2014 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.Arrays;
/**
* Helper functions that operate on any {@code Object}, and are not already provided in {@link
* java.util.Objects}.
*
* <p>See the Guava User Guide on <a
* href="https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained">writing {@code Object}
* methods with {@code MoreObjects}</a>.
*
* @author Laurence Gonsalves
* @since 18.0 (since 2.0 as {@code Objects})
*/
@GwtCompatible
public final class MoreObjects {
/**
* Returns the first of two given parameters that is not {@code null}, if either is, or otherwise
* throws a {@link NullPointerException}.
*
* <p>To find the first non-null element in an iterable, use {@code Iterables.find(iterable,
* Predicates.notNull())}. For varargs, use {@code Iterables.find(Arrays.asList(a, b, c, ...),
* Predicates.notNull())}, static importing as necessary.
*
* <p><b>Note:</b> if {@code first} is represented as an {@link Optional}, this can be
* accomplished with {@link Optional#or(Object) first.or(second)}. That approach also allows for
* lazy evaluation of the fallback instance, using {@link Optional#or(Supplier)
* first.or(supplier)}.
*
* <p><b>Java 9 users:</b> use {@code java.util.Objects.requireNonNullElse(first, second)}
* instead.
*
* @return {@code first} if it is non-null; otherwise {@code second} if it is non-null
* @throws NullPointerException if both {@code first} and {@code second} are null
* @since 18.0 (since 3.0 as {@code Objects.firstNonNull()}).
*/
public static <T> T firstNonNull(T first, T second) {
if (first != null) {
return first;
}
if (second != null) {
return second;
}
throw new NullPointerException("Both parameters are null");
}
/**
* Creates an instance of {@link ToStringHelper}.
*
* <p>This is helpful for implementing {@link Object#toString()}. Specification by example:
*
* <pre>{@code
* // Returns "ClassName{}"
* MoreObjects.toStringHelper(this)
* .toString();
*
* // Returns "ClassName{x=1}"
* MoreObjects.toStringHelper(this)
* .add("x", 1)
* .toString();
*
* // Returns "MyObject{x=1}"
* MoreObjects.toStringHelper("MyObject")
* .add("x", 1)
* .toString();
*
* // Returns "ClassName{x=1, y=foo}"
* MoreObjects.toStringHelper(this)
* .add("x", 1)
* .add("y", "foo")
* .toString();
*
* // Returns "ClassName{x=1}"
* MoreObjects.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 18.0 (since 2.0 as {@code Objects.toStringHelper()}).
*/
public static ToStringHelper toStringHelper(Object self) {
return new ToStringHelper(self.getClass().getSimpleName());
}
/**
* Creates an instance of {@link ToStringHelper} in the same manner as {@link
* #toStringHelper(Object)}, but using the simple 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 18.0 (since 7.0 as {@code Objects.toStringHelper()}).
*/
public static ToStringHelper toStringHelper(Class<?> clazz) {
return new ToStringHelper(clazz.getSimpleName());
}
/**
* Creates an instance of {@link ToStringHelper} in the same manner as {@link
* #toStringHelper(Object)}, but using {@code className} instead of using an instance's {@link
* Object#getClass()}.
*
* @param className the name of the instance type
* @since 18.0 (since 7.0 as {@code Objects.toStringHelper()}).
*/
public static ToStringHelper toStringHelper(String className) {
return new ToStringHelper(className);
}
/**
* Support class for {@link MoreObjects#toStringHelper}.
*
* @author Jason Lee
* @since 18.0 (since 2.0 as {@code Objects.ToStringHelper}).
*/
public static final class ToStringHelper {
private final String className;
private final ValueHolder holderHead = new ValueHolder();
private ValueHolder holderTail = holderHead;
private boolean omitNullValues = false;
/** Use {@link MoreObjects#toStringHelper(Object)} to create an instance. */
private ToStringHelper(String className) {
this.className = checkNotNull(className);
}
/**
* Configures the {@link ToStringHelper} so {@link #toString()} will ignore properties with null
* value. The order of calling this method, relative to the {@code add()}/{@code addValue()}
* methods, is not significant.
*
* @since 18.0 (since 12.0 as {@code Objects.ToStringHelper.omitNullValues()}).
*/
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, Object value) {
return addHolder(name, value);
}
/**
* Adds a name/value pair to the formatted output in {@code name=value} format.
*
* @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
*/
public ToStringHelper add(String name, boolean value) {
return addHolder(name, String.valueOf(value));
}
/**
* Adds a name/value pair to the formatted output in {@code name=value} format.
*
* @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
*/
public ToStringHelper add(String name, char value) {
return addHolder(name, String.valueOf(value));
}
/**
* Adds a name/value pair to the formatted output in {@code name=value} format.
*
* @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
*/
public ToStringHelper add(String name, double value) {
return addHolder(name, String.valueOf(value));
}
/**
* Adds a name/value pair to the formatted output in {@code name=value} format.
*
* @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
*/
public ToStringHelper add(String name, float value) {
return addHolder(name, String.valueOf(value));
}
/**
* Adds a name/value pair to the formatted output in {@code name=value} format.
*
* @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
*/
public ToStringHelper add(String name, int value) {
return addHolder(name, String.valueOf(value));
}
/**
* Adds a name/value pair to the formatted output in {@code name=value} format.
*
* @since 18.0 (since 11.0 as {@code Objects.ToStringHelper.add()}).
*/
public ToStringHelper add(String name, long value) {
return addHolder(name, String.valueOf(value));
}
/**
* 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(Object value) {
return addHolder(value);
}
/**
* 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 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
*/
public ToStringHelper addValue(boolean value) {
return addHolder(String.valueOf(value));
}
/**
* 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 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
*/
public ToStringHelper addValue(char value) {
return addHolder(String.valueOf(value));
}
/**
* 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 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
*/
public ToStringHelper addValue(double value) {
return addHolder(String.valueOf(value));
}
/**
* 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 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
*/
public ToStringHelper addValue(float value) {
return addHolder(String.valueOf(value));
}
/**
* 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 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
*/
public ToStringHelper addValue(int value) {
return addHolder(String.valueOf(value));
}
/**
* 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 18.0 (since 11.0 as {@code Objects.ToStringHelper.addValue()}).
*/
public ToStringHelper addValue(long value) {
return addHolder(String.valueOf(value));
}
/**
* Returns a string in the format specified by {@link MoreObjects#toStringHelper(Object)}.
*
* <p>After calling this method, you can keep adding more properties to later call toString()
* again and get a more complete representation of the same object; but properties cannot be
* removed, so this only allows limited reuse of the helper instance. The helper allows
* duplication of properties (multiple name/value pairs with the same name can be added).
*/
@Override
public String toString() {
// create a copy to keep it consistent in case value changes
boolean omitNullValuesSnapshot = omitNullValues;
String nextSeparator = "";
StringBuilder builder = new StringBuilder(32).append(className).append('{');
for (ValueHolder valueHolder = holderHead.next;
valueHolder != null;
valueHolder = valueHolder.next) {
Object value = valueHolder.value;
if (!omitNullValuesSnapshot || value != null) {
builder.append(nextSeparator);
nextSeparator = ", ";
if (valueHolder.name != null) {
builder.append(valueHolder.name).append('=');
}
if (value != null && value.getClass().isArray()) {
Object[] objectArray = {value};
String arrayString = Arrays.deepToString(objectArray);
builder.append(arrayString, 1, arrayString.length() - 1);
} else {
builder.append(value);
}
}
}
return builder.append('}').toString();
}
private ValueHolder addHolder() {
ValueHolder valueHolder = new ValueHolder();
holderTail = holderTail.next = valueHolder;
return valueHolder;
}
private ToStringHelper addHolder(Object value) {
ValueHolder valueHolder = addHolder();
valueHolder.value = value;
return this;
}
private ToStringHelper addHolder(String name, Object value) {
ValueHolder valueHolder = addHolder();
valueHolder.value = value;
valueHolder.name = checkNotNull(name);
return this;
}
private static final class ValueHolder {
String name;
Object value;
ValueHolder next;
}
}
private MoreObjects() {}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import com.google.common.annotations.GwtCompatible;
import java.util.Arrays;
/**
* Helper functions that can operate on any {@code Object}.
*
* <p>See the Guava User Guide on <a
* href="https://github.com/google/guava/wiki/CommonObjectUtilitiesExplained">writing {@code Object}
* methods with {@code Objects}</a>.
*
* @author Laurence Gonsalves
* @since 2.0
*/
@GwtCompatible
public final class Objects extends ExtraObjectsMethodsForWeb {
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.
*
* <p><b>Note for Java 7 and later:</b> This method should be treated as deprecated; use {@link
* java.util.Objects#equals} instead.
*/
public static boolean equal(Object a, 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[])}. Note that array arguments to this method, with the exception of a
* single Object array, do not get any special handling; their hash codes are based on identity
* and not contents.
*
* <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>{@code
* public int hashCode() {
* return Objects.hashCode(getX(), getY(), getZ());
* }
* }</pre>
*
* <p><b>Warning:</b> When a single object is supplied, the returned hash code does not equal the
* hash code of that object.
*
* <p><b>Note for Java 7 and later:</b> This method should be treated as deprecated; use {@link
* java.util.Objects#hash} instead.
*/
public static int hashCode(Object ... objects) {
return Arrays.hashCode(objects);
}
}

View file

@ -0,0 +1,356 @@
/*
* 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;
/**
* 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="https://github.com/google/guava/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><b>Comparison to {@code java.util.Optional} (JDK 8 and higher):</b> A new {@code Optional}
* class was added for Java 8. The two classes are extremely similar, but incompatible (they cannot
* share a common supertype). <i>All</i> known differences are listed either here or with the
* relevant methods below.
*
* <ul>
* <li>This class is serializable; {@code java.util.Optional} is not.
* <li>{@code java.util.Optional} has the additional methods {@code ifPresent}, {@code filter},
* {@code flatMap}, and {@code orElseThrow}.
* <li>{@code java.util} offers the primitive-specialized versions {@code OptionalInt}, {@code
* OptionalLong} and {@code OptionalDouble}, the use of which is recommended; Guava does not
* have these.
* </ul>
*
* <p><b>There are no plans to deprecate this class in the foreseeable future.</b> However, we do
* gently recommend that you prefer the new, standard Java class whenever possible.
*
* <p>See the Guava User Guide article on <a
* href="https://github.com/google/guava/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.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method is equivalent to Java 8's
* {@code Optional.empty}.
*/
public static <T> Optional<T> absent() {
return Absent.withType();
}
/**
* Returns an {@code Optional} instance containing the given non-null reference. To have {@code
* null} treated as {@link #absent}, use {@link #fromNullable} instead.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> no differences.
*
* @throws NullPointerException if {@code reference} is null
*/
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}.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method is equivalent to Java 8's
* {@code Optional.ofNullable}.
*/
public static <T> Optional<T> fromNullable(T nullableReference) {
return (nullableReference == null) ? Optional.<T>absent() : new Present<T>(nullableReference);
}
/**
* Returns the equivalent {@code com.google.common.base.Optional} value to the given {@code
* java.util.Optional}, or {@code null} if the argument is null.
*
* @since 21.0
*/
public static <T> Optional<T> fromJavaUtil(
java.util.Optional<T> javaUtilOptional) {
return (javaUtilOptional == null) ? null : fromNullable(javaUtilOptional.orElse(null));
}
/**
* Returns the equivalent {@code java.util.Optional} value to the given {@code
* com.google.common.base.Optional}, or {@code null} if the argument is null.
*
* <p>If {@code googleOptional} is known to be non-null, use {@code googleOptional.toJavaUtil()}
* instead.
*
* <p>Unfortunately, the method reference {@code Optional::toJavaUtil} will not work, because it
* could refer to either the static or instance version of this method. Write out the lambda
* expression {@code o -> Optional.toJavaUtil(o)} instead.
*
* @since 21.0
*/
public static <T> java.util.Optional<T> toJavaUtil(
Optional<T> googleOptional) {
return googleOptional == null ? null : googleOptional.toJavaUtil();
}
/**
* Returns the equivalent {@code java.util.Optional} value to this optional.
*
* <p>Unfortunately, the method reference {@code Optional::toJavaUtil} will not work, because it
* could refer to either the static or instance version of this method. Write out the lambda
* expression {@code o -> o.toJavaUtil()} instead.
*
* @since 21.0
*/
public java.util.Optional<T> toJavaUtil() {
return java.util.Optional.ofNullable(orNull());
}
Optional() {}
/**
* Returns {@code true} if this holder contains a (non-null) instance.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> no differences.
*/
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.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> when the value is absent, this method
* throws {@link IllegalStateException}, whereas the Java 8 counterpart throws {@link
* java.util.NoSuchElementException NoSuchElementException}.
*
* @throws IllegalStateException if the instance is absent ({@link #isPresent} returns {@code
* false}); depending on this <i>specific</i> exception type (over the more general {@link
* RuntimeException}) is discouraged
*/
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>
*
* <p>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>
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method is similar to Java 8's {@code
* Optional.orElse}, but will not accept {@code null} as a {@code defaultValue} ({@link #orNull}
* must be used instead). As a result, the value returned by this method is guaranteed non-null,
* which is not the case for the {@code java.util} equivalent.
*/
public abstract T or(T defaultValue);
/**
* Returns this {@code Optional} if it has a value present; {@code secondChoice} otherwise.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method has no equivalent in Java 8's
* {@code Optional} class; write {@code thisOptional.isPresent() ? thisOptional : secondChoice}
* instead.
*/
public abstract Optional<T> or(Optional<? extends T> secondChoice);
/**
* Returns the contained instance if it is present; {@code supplier.get()} otherwise.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method is similar to Java 8's {@code
* Optional.orElseGet}, except when {@code supplier} returns {@code null}. In this case this
* method throws an exception, whereas the Java 8 method returns the {@code null} to the caller.
*
* @throws NullPointerException if this optional's value is absent and 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.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method is equivalent to Java 8's
* {@code Optional.orElse(null)}.
*/
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.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method has no equivalent in Java 8's
* {@code Optional} class. However, this common usage:
*
* <pre>{@code
* for (Foo foo : possibleFoo.asSet()) {
* doSomethingWith(foo);
* }
* }</pre>
*
* ... can be replaced with:
*
* <pre>{@code
* possibleFoo.ifPresent(foo -> doSomethingWith(foo));
* }</pre>
*
* <p><b>Java 9 users:</b> some use cases can be written with calls to {@code optional.stream()}.
*
* @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.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method is similar to Java 8's {@code
* Optional.map}, except when {@code function} returns {@code null}. In this case this method
* throws an exception, whereas the Java 8 method returns {@code Optional.absent()}.
*
* @throws NullPointerException if the function returns {@code null}
* @since 12.0
*/
public abstract <V> Optional<V> transform(Function<? super T, V> function);
/**
* Returns {@code true} if {@code object} is an {@code Optional} instance, and either the
* contained references are {@linkplain Object#equals equal} to each other or both are absent.
* Note that {@code Optional} instances of differing parameterized types can be equal.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> no differences.
*/
@Override
public abstract boolean equals(Object object);
/**
* Returns a hash code for this instance.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this class leaves the specific choice of
* hash code unspecified, unlike the Java 8 equivalent.
*/
@Override
public abstract int hashCode();
/**
* Returns a string representation for this instance.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this class leaves the specific string
* representation unspecified, unlike the Java 8 equivalent.
*/
@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.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method has no equivalent in Java 8's
* {@code Optional} class; use {@code
* optionals.stream().filter(Optional::isPresent).map(Optional::get)} instead.
*
* <p><b>Java 9 users:</b> use {@code optionals.stream().flatMap(Optional::stream)} instead.
*
* @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;
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import com.google.common.annotations.GwtCompatible;
import java.io.Serializable;
import java.util.Iterator;
@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(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;
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2016 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import com.google.common.annotations.GwtIncompatible;
/**
* Pluggable interface for compiling a regex pattern. By default this package uses the {@code
* java.util.regex} library, but an alternate implementation can be supplied using the {@link
* java.util.ServiceLoader} mechanism.
*/
@GwtIncompatible
interface PatternCompiler {
/**
* Compiles the given pattern.
*
* @throws IllegalArgumentException if the pattern is invalid
*/
CommonPattern compile(String pattern);
/**
* Returns {@code true} if the regex implementation behaves like Perl -- notably, by supporting
* possessive quantifiers but also being susceptible to catastrophic backtracking.
*/
boolean isPcreLike();
}

View file

@ -0,0 +1,121 @@
/*
* 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.Strings.lenientFormat;
import static java.lang.Boolean.parseBoolean;
import com.google.common.annotations.GwtCompatible;
import java.lang.ref.WeakReference;
import java.util.Locale;
import java.util.ServiceConfigurationError;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
/**
* Methods factored out so that they can be emulated differently in GWT.
*
* @author Jesse Wilson
*/
@GwtCompatible(emulated = true)
final class Platform {
private static final Logger logger = Logger.getLogger(Platform.class.getName());
private static final PatternCompiler patternCompiler = loadPatternCompiler();
private Platform() {}
/** Calls {@link System#nanoTime()}. */
@SuppressWarnings("GoodTime") // reading system time without TimeSource
static long systemNanoTime() {
return System.nanoTime();
}
static CharMatcher precomputeCharMatcher(CharMatcher matcher) {
return matcher.precomputedInternal();
}
static <T extends Enum<T>> Optional<T> getEnumIfPresent(Class<T> enumClass, String value) {
WeakReference<? extends Enum<?>> ref = Enums.getEnumConstants(enumClass).get(value);
return ref == null ? Optional.<T>absent() : Optional.of(enumClass.cast(ref.get()));
}
static String formatCompact4Digits(double value) {
return String.format(Locale.ROOT, "%.4g", value);
}
static boolean stringIsNullOrEmpty(String string) {
return string == null || string.isEmpty();
}
static String nullToEmpty(String string) {
return (string == null) ? "" : string;
}
static String emptyToNull(String string) {
return stringIsNullOrEmpty(string) ? null : string;
}
static CommonPattern compilePattern(String pattern) {
Preconditions.checkNotNull(pattern);
return patternCompiler.compile(pattern);
}
static boolean patternCompilerIsPcreLike() {
return patternCompiler.isPcreLike();
}
private static PatternCompiler loadPatternCompiler() {
return new JdkPatternCompiler();
}
private static void logPatternCompilerError(ServiceConfigurationError e) {
logger.log(Level.WARNING, "Error loading regex compiler, falling back to next option", e);
}
private static final class JdkPatternCompiler implements PatternCompiler {
@Override
public CommonPattern compile(String pattern) {
return new JdkPattern(Pattern.compile(pattern));
}
@Override
public boolean isPcreLike() {
return true;
}
}
private static final String GWT_RPC_PROPERTY_NAME = "guava.gwt.emergency_reenable_rpc";
static void checkGwtRpcEnabled() {
if (!parseBoolean(System.getProperty(GWT_RPC_PROPERTY_NAME, "true"))) {
throw new UnsupportedOperationException(
lenientFormat(
"We are removing GWT-RPC support for Guava types. You can temporarily reenable"
+ " support by setting the system property %s to true. For more about system"
+ " properties, see %s. For more about Guava's GWT-RPC support, see %s.",
GWT_RPC_PROPERTY_NAME,
"https://stackoverflow.com/q/5189914/28465",
"https://groups.google.com/d/msg/guava-announce/zHZTFg7YF3o/rQNnwdHeEwAJ"));
}
logger.log(
java.util.logging.Level.WARNING,
"In January 2020, we will remove GWT-RPC support for Guava types. You are seeing this"
+ " warning because you are sending a Guava type over GWT-RPC, which will break. You"
+ " can identify which type by looking at the class name in the attached stack trace.",
new Throwable());
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import com.google.common.annotations.GwtCompatible;
/**
* Legacy version of {@link java.util.function.Predicate java.util.function.Predicate}. Determines a
* true or false value for a given input.
*
* <p>As this interface extends {@code java.util.function.Predicate}, an instance of this type may
* be used as a {@code Predicate} directly. To use a {@code java.util.function.Predicate} where a
* {@code com.google.common.base.Predicate} is expected, use the method reference {@code
* predicate::test}.
*
* <p>This interface is now a legacy type. Use {@code java.util.function.Predicate} (or the
* appropriate primitive specialization such as {@code IntPredicate}) instead whenever possible.
* Otherwise, at least reduce <i>explicit</i> dependencies on this type by using lambda expressions
* or method references instead of classes, leaving your code easier to migrate in the future.
*
* <p>The {@link Predicates} class provides common predicates and related utilities.
*
* <p>See the Guava User Guide article on <a
* href="https://github.com/google/guava/wiki/FunctionalExplained">the use of {@code Predicate}</a>.
*
* @author Kevin Bourrillion
* @since 2.0
*/
@FunctionalInterface
@GwtCompatible
public interface Predicate<T> extends java.util.function.Predicate<T> {
/**
* Returns the result of applying this predicate to {@code input} (Java 8 users, see notes in the
* class documentation above). 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(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(Object object);
@Override
default boolean test(T input) {
return apply(input);
}
}

View file

@ -0,0 +1,702 @@
/*
* 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;
/**
* Static utility methods pertaining to {@code Predicate} instances.
*
* <p>All methods return serializable predicates as long as they're given serializable parameters.
*
* <p>See the Guava User Guide article on <a
* href="https://github.com/google/guava/wiki/FunctionalExplained">the use of {@code Predicate}</a>.
*
* @author Kevin Bourrillion
* @since 2.0
*/
@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}.
*/
@SafeVarargs
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}.
*/
@SafeVarargs
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(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 to
* (is a subtype of) {@code clazz}. Example:
*
* <pre>{@code
* List<Class<?>> classes = Arrays.asList(
* Object.class, String.class, Number.class, Long.class);
* return Iterables.filter(classes, subtypeOf(Number.class));
* }</pre>
*
* The code above returns an iterable containing {@code Number.class} and {@code Long.class}.
*
* @since 20.0 (since 10.0 under the incorrect name {@code assignableFrom})
*/
@GwtIncompatible // Class.isAssignableFrom
@Beta
public static Predicate<Class<?>> subtypeOf(Class<?> clazz) {
return new SubtypeOfPredicate(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<>(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 IllegalArgumentException if the pattern is invalid
* @since 3.0
*/
@GwtIncompatible // Only used by other GWT-incompatible code.
public static Predicate<CharSequence> containsPattern(String pattern) {
return new ContainsPatternFromStringPredicate(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(new JdkPattern(pattern));
}
// End public API, begin private implementation classes.
// Package private for GWT serialization.
enum ObjectPredicate implements Predicate<Object> {
/** @see Predicates#alwaysTrue() */
ALWAYS_TRUE {
@Override
public boolean apply(Object o) {
return true;
}
@Override
public String toString() {
return "Predicates.alwaysTrue()";
}
},
/** @see Predicates#alwaysFalse() */
ALWAYS_FALSE {
@Override
public boolean apply(Object o) {
return false;
}
@Override
public String toString() {
return "Predicates.alwaysFalse()";
}
},
/** @see Predicates#isNull() */
IS_NULL {
@Override
public boolean apply(Object o) {
return o == null;
}
@Override
public String toString() {
return "Predicates.isNull()";
}
},
/** @see Predicates#notNull() */
NOT_NULL {
@Override
public boolean apply(Object o) {
return o != null;
}
@Override
public String toString() {
return "Predicates.notNull()";
}
};
@SuppressWarnings("unchecked") // safe contravariant cast
<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(Object obj) {
if (obj instanceof NotPredicate) {
NotPredicate<?> that = (NotPredicate<?>) obj;
return predicate.equals(that.predicate);
}
return false;
}
@Override
public String toString() {
return "Predicates.not(" + predicate + ")";
}
private static final long serialVersionUID = 0;
}
/** @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(Object obj) {
if (obj instanceof AndPredicate) {
AndPredicate<?> that = (AndPredicate<?>) obj;
return components.equals(that.components);
}
return false;
}
@Override
public String toString() {
return toStringHelper("and", 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(Object obj) {
if (obj instanceof OrPredicate) {
OrPredicate<?> that = (OrPredicate<?>) obj;
return components.equals(that.components);
}
return false;
}
@Override
public String toString() {
return toStringHelper("or", components);
}
private static final long serialVersionUID = 0;
}
private static String toStringHelper(String methodName, Iterable<?> components) {
StringBuilder builder = new StringBuilder("Predicates.").append(methodName).append('(');
boolean first = true;
for (Object o : components) {
if (!first) {
builder.append(',');
}
builder.append(o);
first = false;
}
return builder.append(')').toString();
}
/** @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(Object obj) {
if (obj instanceof IsEqualToPredicate) {
IsEqualToPredicate<?> that = (IsEqualToPredicate<?>) obj;
return target.equals(that.target);
}
return false;
}
@Override
public String toString() {
return "Predicates.equalTo(" + 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(Object o) {
return clazz.isInstance(o);
}
@Override
public int hashCode() {
return clazz.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof InstanceOfPredicate) {
InstanceOfPredicate that = (InstanceOfPredicate) obj;
return clazz == that.clazz;
}
return false;
}
@Override
public String toString() {
return "Predicates.instanceOf(" + clazz.getName() + ")";
}
private static final long serialVersionUID = 0;
}
/** @see Predicates#subtypeOf(Class) */
@GwtIncompatible // Class.isAssignableFrom
private static class SubtypeOfPredicate implements Predicate<Class<?>>, Serializable {
private final Class<?> clazz;
private SubtypeOfPredicate(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(Object obj) {
if (obj instanceof SubtypeOfPredicate) {
SubtypeOfPredicate that = (SubtypeOfPredicate) obj;
return clazz == that.clazz;
}
return false;
}
@Override
public String toString() {
return "Predicates.subtypeOf(" + 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 | ClassCastException e) {
return false;
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof InPredicate) {
InPredicate<?> that = (InPredicate<?>) obj;
return target.equals(that.target);
}
return false;
}
@Override
public int hashCode() {
return target.hashCode();
}
@Override
public String toString() {
return "Predicates.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(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() {
// TODO(cpovirk): maybe make this look like the method call does ("Predicates.compose(...)")
return p + "(" + f + ")";
}
private static final long serialVersionUID = 0;
}
/** @see Predicates#contains(Pattern) */
@GwtIncompatible // Only used by other GWT-incompatible code.
private static class ContainsPatternPredicate implements Predicate<CharSequence>, Serializable {
final CommonPattern pattern;
ContainsPatternPredicate(CommonPattern pattern) {
this.pattern = checkNotNull(pattern);
}
@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(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())
&& pattern.flags() == that.pattern.flags();
}
return false;
}
@Override
public String toString() {
String patternString =
MoreObjects.toStringHelper(pattern)
.add("pattern", pattern.pattern())
.add("pattern.flags", pattern.flags())
.toString();
return "Predicates.contains(" + patternString + ")";
}
private static final long serialVersionUID = 0;
}
/** @see Predicates#containsPattern(String) */
@GwtIncompatible // Only used by other GWT-incompatible code.
private static class ContainsPatternFromStringPredicate extends ContainsPatternPredicate {
ContainsPatternFromStringPredicate(String string) {
super(Platform.compilePattern(string));
}
@Override
public String toString() {
return "Predicates.containsPattern(" + pattern.pattern() + ")";
}
private static final long serialVersionUID = 0;
}
private static <T> List<Predicate<? super T>> asList(
Predicate<? super T> first, Predicate<? super T> second) {
// TODO(kevinb): understand why we still get a warning despite @SafeVarargs!
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;
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import java.util.Collections;
import java.util.Set;
/** Implementation of an {@link Optional} containing a reference. */
@GwtCompatible
final class Present<T> extends Optional<T> {
private final T reference;
Present(T reference) {
this.reference = reference;
}
@Override
public boolean isPresent() {
return true;
}
@Override
public T get() {
return reference;
}
@Override
public T or(T defaultValue) {
checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)");
return reference;
}
@Override
public Optional<T> or(Optional<? extends T> secondChoice) {
checkNotNull(secondChoice);
return this;
}
@Override
public T or(Supplier<? extends T> supplier) {
checkNotNull(supplier);
return reference;
}
@Override
public T orNull() {
return reference;
}
@Override
public Set<T> asSet() {
return Collections.singleton(reference);
}
@Override
public <V> Optional<V> transform(Function<? super T, V> function) {
return new Present<V>(
checkNotNull(
function.apply(reference),
"the Function passed to Optional.transform() must not return null."));
}
@Override
public boolean equals(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;
}

View file

@ -0,0 +1,146 @@
/*
* Copyright (C) 2012 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher.NamedFastMatcher;
import java.util.BitSet;
/**
* An immutable version of CharMatcher for smallish sets of characters that uses a hash table with
* linear probing to check for matches.
*
* @author Christopher Swenson
*/
@GwtIncompatible // no precomputation is done in GWT
final class SmallCharMatcher extends NamedFastMatcher {
static final int MAX_SIZE = 1023;
private final char[] table;
private final boolean containsZero;
private final long filter;
private SmallCharMatcher(char[] table, long filter, boolean containsZero, String description) {
super(description);
this.table = table;
this.filter = filter;
this.containsZero = containsZero;
}
private static final int C1 = 0xcc9e2d51;
private static final int C2 = 0x1b873593;
/*
* This method was rewritten in Java from an intermediate step of the Murmur hash function in
* http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp, which contained the
* following header:
*
* MurmurHash3 was written by Austin Appleby, and is placed in the public domain. The author
* hereby disclaims copyright to this source code.
*/
static int smear(int hashCode) {
return C2 * Integer.rotateLeft(hashCode * C1, 15);
}
private boolean checkFilter(int c) {
return 1 == (1 & (filter >> c));
}
// This is all essentially copied from ImmutableSet, but we have to duplicate because
// of dependencies.
// Represents how tightly we can pack things, as a maximum.
private static final double DESIRED_LOAD_FACTOR = 0.5;
/**
* Returns an array size suitable for the backing array of a hash table that uses open addressing
* with linear probing in its implementation. The returned size is the smallest power of two that
* can hold setSize elements with the desired load factor.
*/
@VisibleForTesting
static int chooseTableSize(int setSize) {
if (setSize == 1) {
return 2;
}
// Correct the size for open addressing to match desired load factor.
// Round up to the next highest power of 2.
int tableSize = Integer.highestOneBit(setSize - 1) << 1;
while (tableSize * DESIRED_LOAD_FACTOR < setSize) {
tableSize <<= 1;
}
return tableSize;
}
static CharMatcher from(BitSet chars, String description) {
// Compute the filter.
long filter = 0;
int size = chars.cardinality();
boolean containsZero = chars.get(0);
// Compute the hash table.
char[] table = new char[chooseTableSize(size)];
int mask = table.length - 1;
for (int c = chars.nextSetBit(0); c != -1; c = chars.nextSetBit(c + 1)) {
// Compute the filter at the same time.
filter |= 1L << c;
int index = smear(c) & mask;
while (true) {
// Check for empty.
if (table[index] == 0) {
table[index] = (char) c;
break;
}
// Linear probing.
index = (index + 1) & mask;
}
}
return new SmallCharMatcher(table, filter, containsZero, description);
}
@Override
public boolean matches(char c) {
if (c == 0) {
return containsZero;
}
if (!checkFilter(c)) {
return false;
}
int mask = table.length - 1;
int startingIndex = smear(c) & mask;
int index = startingIndex;
do {
if (table[index] == 0) { // Check for empty.
return false;
} else if (table[index] == c) { // Check for match.
return true;
} else { // Linear probing.
index = (index + 1) & mask;
}
// Check to see if we wrapped around the whole table.
} while (index != startingIndex);
return false;
}
@Override
void setBits(BitSet table) {
if (containsZero) {
table.set(0);
}
for (char c : this.table) {
if (c != 0) {
table.set(c);
}
}
}
}

View file

@ -0,0 +1,633 @@
/*
* 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.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* Extracts non-overlapping substrings from an input string, typically by recognizing appearances of
* a <i>separator</i> sequence. This separator can be specified as a single {@linkplain #on(char)
* character}, fixed {@linkplain #on(String) string}, {@linkplain #onPattern regular expression} or
* {@link #on(CharMatcher) CharMatcher} instance. Or, instead of using a separator at all, a
* splitter can extract adjacent substrings of a given {@linkplain #fixedLength fixed length}.
*
* <p>For example, this expression:
*
* <pre>{@code
* Splitter.on(',').split("foo,bar,qux")
* }</pre>
*
* ... produces an {@code Iterable} containing {@code "foo"}, {@code "bar"} and {@code "qux"}, in
* that order.
*
* <p>By default, {@code Splitter}'s behavior is simplistic and unassuming. The following
* expression:
*
* <pre>{@code
* Splitter.on(',').split(" foo,,, bar ,")
* }</pre>
*
* ... yields the substrings {@code [" foo", "", "", " bar ", ""]}. If this is not the desired
* behavior, use configuration methods to obtain a <i>new</i> splitter instance with modified
* behavior:
*
* <pre>{@code
* private static final Splitter MY_SPLITTER = Splitter.on(',')
* .trimResults()
* .omitEmptyStrings();
* }</pre>
*
* <p>Now {@code MY_SPLITTER.split("foo,,, bar ,")} returns just {@code ["foo", "bar"]}. Note that
* the order in which these configuration methods are called is never significant.
*
* <p><b>Warning:</b> Splitter instances are immutable. Invoking a configuration method has no
* effect on the receiving instance; you must store and use the new splitter instance it returns
* instead.
*
* <pre>{@code
* // Do NOT do this
* Splitter splitter = Splitter.on('/');
* splitter.trimResults(); // does nothing!
* return splitter.split("wrong / wrong / wrong");
* }</pre>
*
* <p>For separator-based splitters that do not use {@code omitEmptyStrings}, an input string
* containing {@code n} occurrences of the separator naturally yields an iterable of size {@code n +
* 1}. So if the separator does not occur anywhere in the input, a single substring is returned
* containing the entire input. Consequently, all splitters split the empty string to {@code [""]}
* (note: even fixed-length splitters).
*
* <p>Splitter instances are thread-safe immutable, and are therefore safe to store as {@code static
* final} constants.
*
* <p>The {@link Joiner} class provides the inverse operation to splitting, but note that a
* round-trip between the two should be assumed to be lossy.
*
* <p>See the Guava User Guide article on <a
* href="https://github.com/google/guava/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")} returns an iterable containing {@code ["foo",
* "bar,baz"]}.
*
* @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.");
if (separator.length() == 1) {
return Splitter.on(separator.charAt(0));
}
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 separatorLength = separator.length();
positions:
for (int p = start, last = toSplit.length() - separatorLength; p <= last; p++) {
for (int i = 0; i < separatorLength; 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(Pattern separatorPattern) {
return on(new JdkPattern(separatorPattern));
}
private static Splitter on(final CommonPattern 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 CommonMatcher 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 IllegalArgumentException if {@code separatorPattern} matches the empty string or is a
* malformed expression
*/
@GwtIncompatible // java.util.regex
public static Splitter onPattern(String separatorPattern) {
return on(Platform.compilePattern(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.
*
* <p><b>Note:</b> if {@link #fixedLength} is used in conjunction with {@link #limit}, the final
* split piece <i>may be longer than the specified fixed length</i>. This is because the splitter
* will <i>stop splitting when the limit is reached</i>, and just return the final piece as-is.
*
* <p><b>Exception:</b> for consistency with separator-based splitters, {@code split("")} does not
* yield an empty iterable, but an iterable containing {@code ""}. This is the only case in which
* {@code Iterables.size(split(input))} does not equal {@code IntMath.divide(input.length(),
* length, CEILING)}. To avoid this behavior, use {@code omitEmptyStrings}.
*
* @param length the desired length of pieces after splitting, a positive integer
* @return a splitter, with default settings, that can split into fixed sized pieces
* @throws IllegalArgumentException if {@code length} is zero or negative
*/
public static Splitter fixedLength(final int length) {
checkArgument(length > 0, "The length may not be less than 1");
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
*/
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,
* or the maximum size of the list returned by {@link #splitToList}.
*
* <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 not
* 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 are
* trimmed, including the last. Hence {@code Splitter.on(',').limit(3).trimResults().split(" a , b
* , c , d ")} results in {@code ["a", "b", "c , d"]}.
*
* @param maxItems the maximum number of items returned
* @return a splitter with the desired configuration
* @since 9.0
*/
public Splitter limit(int maxItems) {
checkArgument(maxItems > 0, "must be greater than zero: %s", maxItems);
return new Splitter(strategy, omitEmptyStrings, trimmer, maxItems);
}
/**
* 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
*/
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!
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. If you want an eagerly computed {@link List}, use
* {@link #splitToList(CharSequence)}. Java 8 users may prefer {@link #splitToStream} instead.
*
* @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 splittingIterator(sequence);
}
@Override
public String toString() {
return Joiner.on(", ")
.appendTo(new StringBuilder().append('['), this)
.append(']')
.toString();
}
};
}
private Iterator<String> splittingIterator(CharSequence sequence) {
return strategy.iterator(this, sequence);
}
/**
* Splits {@code sequence} into string components and returns them as an immutable list. If you
* want an {@link Iterable} which may be lazily evaluated, use {@link #split(CharSequence)}.
*
* @param sequence the sequence of characters to split
* @return an immutable list of the segments split from the parameter
* @since 15.0
*/
public List<String> splitToList(CharSequence sequence) {
checkNotNull(sequence);
Iterator<String> iterator = splittingIterator(sequence);
List<String> result = new ArrayList<>();
while (iterator.hasNext()) {
result.add(iterator.next());
}
return Collections.unmodifiableList(result);
}
/**
* Splits {@code sequence} into string components and makes them available through an {@link
* Stream}, which may be lazily evaluated. If you want an eagerly computed {@link List}, use
* {@link #splitToList(CharSequence)}.
*
* @param sequence the sequence of characters to split
* @return a stream over the segments split from the parameter
* @since NEXT
*/
@Beta
public Stream<String> splitToStream(CharSequence sequence) {
// Can't use Streams.stream() from base
return StreamSupport.stream(split(sequence).spliterator(), false);
}
/**
* 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
*/
@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 separator.
*
* @since 14.0
*/
@Beta
public MapSplitter withKeyValueSeparator(char separator) {
return withKeyValueSeparator(on(separator));
}
/**
* Returns a {@code MapSplitter} which splits entries based on this splitter, and splits entries
* into keys and values using the specified key-value splitter.
*
* <p>Note: Any configuration option configured on this splitter, such as {@link #trimResults},
* does not change the behavior of the {@code keyValueSplitter}.
*
* <p>Example:
*
* <pre>{@code
* String toSplit = " x -> y, z-> a ";
* Splitter outerSplitter = Splitter.on(',').trimResults();
* MapSplitter mapSplitter = outerSplitter.withKeyValueSeparator(Splitter.on("->"));
* Map<String, String> result = mapSplitter.split(toSplit);
* assertThat(result).isEqualTo(ImmutableMap.of("x ", " y", "z", " a"));
* }</pre>
*
* @since 10.0
*/
@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. The common way to build instances is by
* providing an additional {@linkplain Splitter#withKeyValueSeparator key-value separator} to
* {@link Splitter}.
*
* @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")} 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<>();
for (String entry : outerSplitter.split(sequence)) {
Iterator<String> entryFields = entrySplitter.splittingIterator(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();
}
}
}

View file

@ -0,0 +1,136 @@
/*
* Copyright (C) 2012 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import com.google.common.annotations.GwtIncompatible;
/**
* Represents a {@linkplain System#getProperties() standard system property}.
*
* @author Kurt Alfred Kluever
* @since 15.0
*/
@GwtIncompatible // java.lang.System#getProperty
public enum StandardSystemProperty {
/** Java Runtime Environment version. */
JAVA_VERSION("java.version"),
/** Java Runtime Environment vendor. */
JAVA_VENDOR("java.vendor"),
/** Java vendor URL. */
JAVA_VENDOR_URL("java.vendor.url"),
/** Java installation directory. */
JAVA_HOME("java.home"),
/** Java Virtual Machine specification version. */
JAVA_VM_SPECIFICATION_VERSION("java.vm.specification.version"),
/** Java Virtual Machine specification vendor. */
JAVA_VM_SPECIFICATION_VENDOR("java.vm.specification.vendor"),
/** Java Virtual Machine specification name. */
JAVA_VM_SPECIFICATION_NAME("java.vm.specification.name"),
/** Java Virtual Machine implementation version. */
JAVA_VM_VERSION("java.vm.version"),
/** Java Virtual Machine implementation vendor. */
JAVA_VM_VENDOR("java.vm.vendor"),
/** Java Virtual Machine implementation name. */
JAVA_VM_NAME("java.vm.name"),
/** Java Runtime Environment specification version. */
JAVA_SPECIFICATION_VERSION("java.specification.version"),
/** Java Runtime Environment specification vendor. */
JAVA_SPECIFICATION_VENDOR("java.specification.vendor"),
/** Java Runtime Environment specification name. */
JAVA_SPECIFICATION_NAME("java.specification.name"),
/** Java class format version number. */
JAVA_CLASS_VERSION("java.class.version"),
/** Java class path. */
JAVA_CLASS_PATH("java.class.path"),
/** List of paths to search when loading libraries. */
JAVA_LIBRARY_PATH("java.library.path"),
/** Default temp file path. */
JAVA_IO_TMPDIR("java.io.tmpdir"),
/** Name of JIT compiler to use. */
JAVA_COMPILER("java.compiler"),
/** Path of extension directory or directories. */
JAVA_EXT_DIRS("java.ext.dirs"),
/** Operating system name. */
OS_NAME("os.name"),
/** Operating system architecture. */
OS_ARCH("os.arch"),
/** Operating system version. */
OS_VERSION("os.version"),
/** File separator ("/" on UNIX). */
FILE_SEPARATOR("file.separator"),
/** Path separator (":" on UNIX). */
PATH_SEPARATOR("path.separator"),
/** Line separator ("\n" on UNIX). */
LINE_SEPARATOR("line.separator"),
/** User's account name. */
USER_NAME("user.name"),
/** User's home directory. */
USER_HOME("user.home"),
/** User's current working directory. */
USER_DIR("user.dir");
private final String key;
StandardSystemProperty(String key) {
this.key = key;
}
/** Returns the key used to lookup this system property. */
public String key() {
return key;
}
/**
* Returns the current value for this system property by delegating to {@link
* System#getProperty(String)}.
*/
public String value() {
return System.getProperty(key);
}
/** Returns a string representation of this system property. */
@Override
public String toString() {
return key() + "=" + value();
}
}

View file

@ -0,0 +1,265 @@
/*
* 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.DAYS;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MICROSECONDS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import java.time.Duration;
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>{@code
* Stopwatch stopwatch = Stopwatch.createStarted();
* doSomething();
* stopwatch.stop(); // optional
*
* Duration duration = stopwatch.elapsed();
*
* log.info("time: " + 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 {@link #createUnstarted(Ticker)} or {@link
* #createStarted(Ticker)} to supply a fake or mock ticker. This allows you to simulate any valid
* behavior of the stopwatch.
*
* <p><b>Note:</b> This class is not thread-safe.
*
* <p><b>Warning for Android users:</b> a stopwatch with default behavior may not continue to keep
* time while the device is asleep. Instead, create one like this:
*
* <pre>{@code
* Stopwatch.createStarted(
* new Ticker() {
* public long read() {
* return android.os.SystemClock.elapsedRealtimeNanos();
* }
* });
* }</pre>
*
* @author Kevin Bourrillion
* @since 10.0
*/
@GwtCompatible(emulated = true)
@SuppressWarnings("GoodTime") // lots of violations
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.
*
* @since 15.0
*/
public static Stopwatch createUnstarted() {
return new Stopwatch();
}
/**
* Creates (but does not start) a new stopwatch, using the specified time source.
*
* @since 15.0
*/
public static Stopwatch createUnstarted(Ticker ticker) {
return new Stopwatch(ticker);
}
/**
* Creates (and starts) a new stopwatch using {@link System#nanoTime} as its time source.
*
* @since 15.0
*/
public static Stopwatch createStarted() {
return new Stopwatch().start();
}
/**
* Creates (and starts) a new stopwatch, using the specified time source.
*
* @since 15.0
*/
public static Stopwatch createStarted(Ticker ticker) {
return new Stopwatch(ticker).start();
}
Stopwatch() {
this.ticker = Ticker.systemTicker();
}
Stopwatch(Ticker ticker) {
this.ticker = checkNotNull(ticker, "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, "This stopwatch is already running.");
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, "This stopwatch is already stopped.");
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><b>Note:</b> the overhead of measurement can be more than a microsecond, so it is generally
* not useful to specify {@link TimeUnit#NANOSECONDS} precision here.
*
* <p>It is generally not a good idea to use an ambiguous, unitless {@code long} to represent
* elapsed time. Therefore, we recommend using {@link #elapsed()} instead, which returns a
* strongly-typed {@link Duration} instance.
*
* @since 14.0 (since 10.0 as {@code elapsedTime()})
*/
public long elapsed(TimeUnit desiredUnit) {
return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
}
/**
* Returns the current elapsed time shown on this stopwatch as a {@link Duration}. Unlike {@link
* #elapsed(TimeUnit)}, this method does not lose any precision due to rounding.
*
* @since 22.0
*/
@GwtIncompatible
public Duration elapsed() {
return Duration.ofNanos(elapsedNanos());
}
/** Returns a string representation of the current elapsed time. */
@Override
public String toString() {
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 Platform.formatCompact4Digits(value) + " " + abbreviate(unit);
}
private static TimeUnit chooseUnit(long nanos) {
if (DAYS.convert(nanos, NANOSECONDS) > 0) {
return DAYS;
}
if (HOURS.convert(nanos, NANOSECONDS) > 0) {
return HOURS;
}
if (MINUTES.convert(nanos, NANOSECONDS) > 0) {
return MINUTES;
}
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";
case MINUTES:
return "min";
case HOURS:
return "h";
case DAYS:
return "d";
default:
throw new AssertionError();
}
}
}

View file

@ -0,0 +1,311 @@
/*
* 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 static java.util.logging.Level.WARNING;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.VisibleForTesting;
import java.util.logging.Logger;
/**
* 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(String string) {
return Platform.nullToEmpty(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 String emptyToNull(String string) {
return Platform.emptyToNull(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(String string) {
return Platform.stringIsNullOrEmpty(string);
}
/**
* 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 java.util.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 java.util.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: " + 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));
}
/**
* Returns the given {@code template} string with each occurrence of {@code "%s"} replaced with
* the corresponding argument value from {@code args}; or, if the placeholder and argument counts
* do not match, returns a best-effort form of that string. Will not throw an exception under
* normal conditions.
*
* <p><b>Note:</b> For most string-formatting needs, use {@link String#format String.format},
* {@link java.io.PrintWriter#format PrintWriter.format}, and related methods. These support the
* full range of <a
* href="https://docs.oracle.com/javase/9/docs/api/java/util/Formatter.html#syntax">format
* specifiers</a>, and alert you to usage errors by throwing {@link
* java.util.IllegalFormatException}.
*
* <p>In certain cases, such as outputting debugging information or constructing a message to be
* used for another unchecked exception, an exception during string formatting would serve little
* purpose except to supplant the real information you were trying to provide. These are the cases
* this method is made for; it instead generates a best-effort string with all supplied argument
* values present. This method is also useful in environments such as GWT where {@code
* String.format} is not available. As an example, method implementations of the {@link
* Preconditions} class use this formatter, for both of the reasons just discussed.
*
* <p><b>Warning:</b> Only the exact two-character placeholder sequence {@code "%s"} is
* recognized.
*
* @param template a string containing zero or more {@code "%s"} placeholder sequences. {@code
* null} is treated as the four-character string {@code "null"}.
* @param args the arguments to be substituted into the message template. The first argument
* specified is substituted for the first occurrence of {@code "%s"} in the template, and so
* forth. A {@code null} argument is converted to the four-character string {@code "null"};
* non-null values are converted to strings using {@link Object#toString()}.
* @since 25.1
*/
// TODO(diamondm) consider using Arrays.toString() for array parameters
public static String lenientFormat(String template, Object ... args) {
template = String.valueOf(template); // null -> "null"
if (args == null) {
args = new Object[] {"(Object[])null"};
} else {
for (int i = 0; i < args.length; i++) {
args[i] = lenientToString(args[i]);
}
}
// 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, templateStart, placeholderStart);
builder.append(args[i++]);
templateStart = placeholderStart + 2;
}
builder.append(template, templateStart, template.length());
// 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();
}
private static String lenientToString(Object o) {
try {
return String.valueOf(o);
} catch (Exception e) {
// Default toString() behavior - see Object.toString()
String objectToString =
o.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(o));
// Logger is created inline with fixed name to avoid forcing Proguard to create another class.
Logger.getLogger("com.google.common.base.Strings")
.log(WARNING, "Exception during lenientFormat for " + objectToString, e);
return "<" + objectToString + " threw " + e.getClass().getName() + ">";
}
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.base;
import com.google.common.annotations.GwtCompatible;
/**
* Legacy version of {@link java.util.function.Supplier java.util.function.Supplier}. Semantically,
* this could be a factory, generator, builder, closure, or something else entirely. No guarantees
* are implied by this interface.
*
* <p>The {@link Suppliers} class provides common suppliers and related utilities.
*
* <p>As this interface extends {@code java.util.function.Supplier}, an instance of this type can be
* used as a {@code java.util.function.Supplier} directly. To use a {@code
* java.util.function.Supplier} in a context where a {@code com.google.common.base.Supplier} is
* needed, use {@code supplier::get}.
*
* <p>See the Guava User Guide article on <a
* href="https://github.com/google/guava/wiki/FunctionalExplained">the use of {@code Function}</a>.
*
* @author Harry Heymann
* @since 2.0
*/
@GwtCompatible
@FunctionalInterface
public interface Supplier<T> extends java.util.function.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
*/
@Override
T get();
}

View file

@ -0,0 +1,364 @@
/*
* 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.GwtCompatible;
import com.google.common.annotations.VisibleForTesting;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
/**
* 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
*/
@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) {
return new SupplierComposition<>(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 = checkNotNull(function);
this.supplier = checkNotNull(supplier);
}
@Override
public T get() {
return function.apply(supplier.get());
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SupplierComposition) {
SupplierComposition<?, ?> that = (SupplierComposition<?, ?>) obj;
return function.equals(that.function) && supplier.equals(that.supplier);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(function, supplier);
}
@Override
public String toString() {
return "Suppliers.compose(" + function + ", " + supplier + ")";
}
private static final long serialVersionUID = 0;
}
/**
* 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 delegate's {@code get()} method will be invoked at
* most once unless the underlying {@code get()} throws an exception. 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>When the underlying delegate throws an exception then this memoizing supplier will keep
* delegating calls until it returns valid data.
*
* <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) {
if (delegate instanceof NonSerializableMemoizingSupplier
|| delegate instanceof MemoizingSupplier) {
return delegate;
}
return delegate instanceof Serializable
? new MemoizingSupplier<T>(delegate)
: new NonSerializableMemoizingSupplier<T>(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 = checkNotNull(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("
+ (initialized ? "<supplier that returned " + value + ">" : delegate)
+ ")";
}
private static final long serialVersionUID = 0;
}
@VisibleForTesting
static class NonSerializableMemoizingSupplier<T> implements Supplier<T> {
volatile Supplier<T> delegate;
volatile boolean initialized;
// "value" does not need to be volatile; visibility piggy-backs
// on volatile read of "initialized".
T value;
NonSerializableMemoizingSupplier(Supplier<T> delegate) {
this.delegate = checkNotNull(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;
// Release the delegate to GC.
delegate = null;
return t;
}
}
}
return value;
}
@Override
public String toString() {
Supplier<T> delegate = this.delegate;
return "Suppliers.memoize("
+ (delegate == null ? "<supplier that returned " + value + ">" : delegate)
+ ")";
}
}
/**
* 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. The actual memoization does not happen when the underlying delegate throws an
* exception.
*
* <p>When the underlying delegate throws an exception then this memoizing supplier will keep
* delegating calls until it returns valid data.
*
* @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
*/
@SuppressWarnings("GoodTime") // should accept a java.time.Duration
public static <T> Supplier<T> memoizeWithExpiration(
Supplier<T> delegate, long duration, TimeUnit unit) {
return new ExpiringMemoizingSupplier<T>(delegate, duration, unit);
}
@VisibleForTesting
@SuppressWarnings("GoodTime") // lots of violations
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 = checkNotNull(delegate);
this.durationNanos = unit.toNanos(duration);
checkArgument(duration > 0, "duration (%s %s) must be > 0", duration, unit);
}
@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(T instance) {
return new SupplierOfInstance<T>(instance);
}
private static class SupplierOfInstance<T> implements Supplier<T>, Serializable {
final T instance;
SupplierOfInstance(T instance) {
this.instance = instance;
}
@Override
public T get() {
return instance;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SupplierOfInstance) {
SupplierOfInstance<?> that = (SupplierOfInstance<?>) obj;
return Objects.equal(instance, that.instance);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(instance);
}
@Override
public String toString() {
return "Suppliers.ofInstance(" + instance + ")";
}
private static final long serialVersionUID = 0;
}
/**
* 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>(delegate);
}
private static class ThreadSafeSupplier<T> implements Supplier<T>, Serializable {
final Supplier<T> delegate;
ThreadSafeSupplier(Supplier<T> delegate) {
this.delegate = checkNotNull(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.
*
* <p><b>Java 8 users:</b> use the method reference {@code Supplier::get} instead.
*
* @since 8.0
*/
public static <T> Function<Supplier<T>, T> supplierFunction() {
@SuppressWarnings("unchecked") // implementation is "fully variant"
SupplierFunction<T> sf = (SupplierFunction<T>) SupplierFunctionImpl.INSTANCE;
return sf;
}
private interface SupplierFunction<T> extends Function<Supplier<T>, T> {}
private enum SupplierFunctionImpl implements SupplierFunction<Object> {
INSTANCE;
// Note: This makes T a "pass-through type"
@Override
public Object apply(Supplier<Object> input) {
return input.get();
}
@Override
public String toString() {
return "Suppliers.supplierFunction()";
}
}
}

View file

@ -0,0 +1,536 @@
/*
* 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 static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Static utility methods pertaining to instances of {@link Throwable}.
*
* <p>See the Guava User Guide entry on <a
* href="https://github.com/google/guava/wiki/ThrowablesExplained">Throwables</a>.
*
* @author Kevin Bourrillion
* @author Ben Yu
* @since 1.0
*/
@GwtCompatible(emulated = true)
public final class Throwables {
private Throwables() {}
/**
* Throws {@code throwable} if it is an instance of {@code declaredType}. Example usage:
*
* <pre>
* for (Foo foo : foos) {
* try {
* foo.bar();
* } catch (BarException | RuntimeException | Error t) {
* failure = t;
* }
* }
* if (failure != null) {
* throwIfInstanceOf(failure, BarException.class);
* throwIfUnchecked(failure);
* throw new AssertionError(failure);
* }
* </pre>
*
* @since 20.0
*/
@GwtIncompatible // Class.cast, Class.isInstance
public static <X extends Throwable> void throwIfInstanceOf(
Throwable throwable, Class<X> declaredType) throws X {
checkNotNull(throwable);
if (declaredType.isInstance(throwable)) {
throw declaredType.cast(throwable);
}
}
/**
* 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>
*
* @deprecated Use {@link #throwIfInstanceOf}, which has the same behavior but rejects {@code
* null}.
*/
@Deprecated
@GwtIncompatible // throwIfInstanceOf
public static <X extends Throwable> void propagateIfInstanceOf(
Throwable throwable, Class<X> declaredType) throws X {
if (throwable != null) {
throwIfInstanceOf(throwable, declaredType);
}
}
/**
* Throws {@code throwable} if it is a {@link RuntimeException} or {@link Error}. Example usage:
*
* <pre>
* for (Foo foo : foos) {
* try {
* foo.bar();
* } catch (RuntimeException | Error t) {
* failure = t;
* }
* }
* if (failure != null) {
* throwIfUnchecked(failure);
* throw new AssertionError(failure);
* }
* </pre>
*
* @since 20.0
*/
public static void throwIfUnchecked(Throwable throwable) {
checkNotNull(throwable);
if (throwable instanceof RuntimeException) {
throw (RuntimeException) throwable;
}
if (throwable instanceof Error) {
throw (Error) 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>
*
* @deprecated Use {@link #throwIfUnchecked}, which has the same behavior but rejects {@code
* null}.
*/
@Deprecated
@GwtIncompatible
public static void propagateIfPossible(Throwable throwable) {
if (throwable != null) {
throwIfUnchecked(throwable);
}
}
/**
* 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
*/
@GwtIncompatible // propagateIfInstanceOf
public static <X extends Throwable> void propagateIfPossible(
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
*/
@GwtIncompatible // propagateIfInstanceOf
public static <X1 extends Throwable, X2 extends Throwable> void propagateIfPossible(
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} and then propagates.
*
* <p>This method always throws an exception. The {@code RuntimeException} return type allows
* client code to signal to the compiler that statements after the call are unreachable. 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
* @deprecated Use {@code throw e} or {@code throw new RuntimeException(e)} directly, or use a
* combination of {@link #throwIfUnchecked} and {@code throw new RuntimeException(e)}. For
* background on the deprecation, read <a href="https://goo.gl/Ivn2kc">Why we deprecated
* {@code Throwables.propagate}</a>.
*/
@GwtIncompatible
@Deprecated
public static RuntimeException propagate(Throwable throwable) {
throwIfUnchecked(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>
*
* @throws IllegalArgumentException if there is a loop in the causal chain
*/
public static Throwable getRootCause(Throwable throwable) {
// Keep a second pointer that slowly walks the causal chain. If the fast pointer ever catches
// the slower pointer, then there's a loop.
Throwable slowPointer = throwable;
boolean advanceSlowPointer = false;
Throwable cause;
while ((cause = throwable.getCause()) != null) {
throwable = cause;
if (throwable == slowPointer) {
throw new IllegalArgumentException("Loop in causal chain detected.", throwable);
}
if (advanceSlowPointer) {
slowPointer = slowPointer.getCause();
}
advanceSlowPointer = !advanceSlowPointer; // only advance every other iteration
}
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}
* @throws IllegalArgumentException if there is a loop in the causal chain
*/
@Beta // TODO(kevinb): decide best return type
public static List<Throwable> getCausalChain(Throwable throwable) {
checkNotNull(throwable);
List<Throwable> causes = new ArrayList<>(4);
causes.add(throwable);
// Keep a second pointer that slowly walks the causal chain. If the fast pointer ever catches
// the slower pointer, then there's a loop.
Throwable slowPointer = throwable;
boolean advanceSlowPointer = false;
Throwable cause;
while ((cause = throwable.getCause()) != null) {
throwable = cause;
causes.add(throwable);
if (throwable == slowPointer) {
throw new IllegalArgumentException("Loop in causal chain detected.", throwable);
}
if (advanceSlowPointer) {
slowPointer = slowPointer.getCause();
}
advanceSlowPointer = !advanceSlowPointer; // only advance every other iteration
}
return Collections.unmodifiableList(causes);
}
/**
* Returns {@code throwable}'s cause, cast to {@code expectedCauseType}.
*
* <p>Prefer this method instead of manually casting an exception's cause. For example, {@code
* (IOException) e.getCause()} throws a {@link ClassCastException} that discards the original
* exception {@code e} if the cause is not an {@link IOException}, but {@code
* Throwables.getCauseAs(e, IOException.class)} keeps {@code e} as the {@link
* ClassCastException}'s cause.
*
* @throws ClassCastException if the cause cannot be cast to the expected type. The {@code
* ClassCastException}'s cause is {@code throwable}.
* @since 22.0
*/
@Beta
@GwtIncompatible // Class.cast(Object)
public static <X extends Throwable> X getCauseAs(
Throwable throwable, Class<X> expectedCauseType) {
try {
return expectedCauseType.cast(throwable.getCause());
} catch (ClassCastException e) {
e.initCause(throwable);
throw e;
}
}
/**
* 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()}.
*/
@GwtIncompatible // java.io.PrintWriter, java.io.StringWriter
public static String getStackTraceAsString(Throwable throwable) {
StringWriter stringWriter = new StringWriter();
throwable.printStackTrace(new PrintWriter(stringWriter));
return stringWriter.toString();
}
/**
* Returns the stack trace of {@code throwable}, possibly providing slower iteration over the full
* trace but faster iteration over parts of the trace. Here, "slower" and "faster" are defined in
* comparison to the normal way to access the stack trace, {@link Throwable#getStackTrace()
* throwable.getStackTrace()}. Note, however, that this method's special implementation is not
* available for all platforms and configurations. If that implementation is unavailable, this
* method falls back to {@code getStackTrace}. Callers that require the special implementation can
* check its availability with {@link #lazyStackTraceIsLazy()}.
*
* <p>The expected (but not guaranteed) performance of the special implementation differs from
* {@code getStackTrace} in one main way: The {@code lazyStackTrace} call itself returns quickly
* by delaying the per-stack-frame work until each element is accessed. Roughly speaking:
*
* <ul>
* <li>{@code getStackTrace} takes {@code stackSize} time to return but then negligible time to
* retrieve each element of the returned list.
* <li>{@code lazyStackTrace} takes negligible time to return but then {@code 1/stackSize} time
* to retrieve each element of the returned list (probably slightly more than {@code
* 1/stackSize}).
* </ul>
*
* <p>Note: The special implementation does not respect calls to {@link Throwable#setStackTrace
* throwable.setStackTrace}. Instead, it always reflects the original stack trace from the
* exception's creation.
*
* @since 19.0
*/
// TODO(cpovirk): Say something about the possibility that List access could fail at runtime?
@Beta
@GwtIncompatible // lazyStackTraceIsLazy, jlaStackTrace
// TODO(cpovirk): Consider making this available under GWT (slow implementation only).
public static List<StackTraceElement> lazyStackTrace(Throwable throwable) {
return lazyStackTraceIsLazy()
? jlaStackTrace(throwable)
: unmodifiableList(asList(throwable.getStackTrace()));
}
/**
* Returns whether {@link #lazyStackTrace} will use the special implementation described in its
* documentation.
*
* @since 19.0
*/
@Beta
@GwtIncompatible // getStackTraceElementMethod
public static boolean lazyStackTraceIsLazy() {
return getStackTraceElementMethod != null && getStackTraceDepthMethod != null;
}
@GwtIncompatible // invokeAccessibleNonThrowingMethod
private static List<StackTraceElement> jlaStackTrace(final Throwable t) {
checkNotNull(t);
/*
* TODO(cpovirk): Consider optimizing iterator() to catch IOOBE instead of doing bounds checks.
*
* TODO(cpovirk): Consider the UnsignedBytes pattern if it performs faster and doesn't cause
* AOSP grief.
*/
return new AbstractList<StackTraceElement>() {
@Override
public StackTraceElement get(int n) {
return (StackTraceElement)
invokeAccessibleNonThrowingMethod(getStackTraceElementMethod, jla, t, n);
}
@Override
public int size() {
return (Integer) invokeAccessibleNonThrowingMethod(getStackTraceDepthMethod, jla, t);
}
};
}
@GwtIncompatible // java.lang.reflect
private static Object invokeAccessibleNonThrowingMethod(
Method method, Object receiver, Object... params) {
try {
return method.invoke(receiver, params);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw propagate(e.getCause());
}
}
/** JavaLangAccess class name to load using reflection */
@GwtIncompatible // not used by GWT emulation
private static final String JAVA_LANG_ACCESS_CLASSNAME = "sun.misc.JavaLangAccess";
/** SharedSecrets class name to load using reflection */
@GwtIncompatible // not used by GWT emulation
@VisibleForTesting
static final String SHARED_SECRETS_CLASSNAME = "sun.misc.SharedSecrets";
/** Access to some fancy internal JVM internals. */
@GwtIncompatible // java.lang.reflect
private static final Object jla = getJLA();
/**
* The "getStackTraceElementMethod" method, only available on some JDKs so we use reflection to
* find it when available. When this is null, use the slow way.
*/
@GwtIncompatible // java.lang.reflect
private static final Method getStackTraceElementMethod =
(jla == null) ? null : getGetMethod();
/**
* The "getStackTraceDepth" method, only available on some JDKs so we use reflection to find it
* when available. When this is null, use the slow way.
*/
@GwtIncompatible // java.lang.reflect
private static final Method getStackTraceDepthMethod =
(jla == null) ? null : getSizeMethod();
/**
* Returns the JavaLangAccess class that is present in all Sun JDKs. It is not allowed in
* AppEngine, and not present in non-Sun JDKs.
*/
@GwtIncompatible // java.lang.reflect
private static Object getJLA() {
try {
/*
* We load sun.misc.* classes using reflection since Android doesn't support these classes and
* would result in compilation failure if we directly refer to these classes.
*/
Class<?> sharedSecrets = Class.forName(SHARED_SECRETS_CLASSNAME, false, null);
Method langAccess = sharedSecrets.getMethod("getJavaLangAccess");
return langAccess.invoke(null);
} catch (ThreadDeath death) {
throw death;
} catch (Throwable t) {
/*
* This is not one of AppEngine's allowed classes, so even in Sun JDKs, this can fail with
* a NoClassDefFoundError. Other apps might deny access to sun.misc packages.
*/
return null;
}
}
/**
* Returns the Method that can be used to resolve an individual StackTraceElement, or null if that
* method cannot be found (it is only to be found in fairly recent JDKs).
*/
@GwtIncompatible // java.lang.reflect
private static Method getGetMethod() {
return getJlaMethod("getStackTraceElement", Throwable.class, int.class);
}
/**
* Returns the Method that can be used to return the size of a stack, or null if that method
* cannot be found (it is only to be found in fairly recent JDKs).
*
* <p>See <a href="https://github.com/google/guava/issues/2887">Throwables#lazyStackTrace throws
* UnsupportedOperationException</a>.
*/
@GwtIncompatible // java.lang.reflect
private static Method getSizeMethod() {
try {
Method getStackTraceDepth = getJlaMethod("getStackTraceDepth", Throwable.class);
if (getStackTraceDepth == null) {
return null;
}
getStackTraceDepth.invoke(getJLA(), new Throwable());
return getStackTraceDepth;
} catch (UnsupportedOperationException | IllegalAccessException | InvocationTargetException e) {
return null;
}
}
@GwtIncompatible // java.lang.reflect
private static Method getJlaMethod(String name, Class<?>... parameterTypes)
throws ThreadDeath {
try {
return Class.forName(JAVA_LANG_ACCESS_CLASSNAME, false, null).getMethod(name, parameterTypes);
} catch (ThreadDeath death) {
throw death;
} catch (Throwable t) {
/*
* Either the JavaLangAccess class itself is not found, or the method is not supported on the
* JVM.
*/
return null;
}
}
}

View file

@ -0,0 +1,54 @@
/*
* 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;
/**
* 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="https://github.com/google/guava/wiki/Compatibility">mostly
* source-compatible</a> since 9.0)
*/
@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();
}
};
}

View file

@ -0,0 +1,201 @@
/*
* Copyright (C) 2013 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.checkPositionIndexes;
import static java.lang.Character.MAX_SURROGATE;
import static java.lang.Character.MIN_SURROGATE;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
/**
* Low-level, high-performance utility methods related to the {@linkplain Charsets#UTF_8 UTF-8}
* character encoding. UTF-8 is defined in section D92 of <a
* href="http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf">The Unicode Standard Core
* Specification, Chapter 3</a>.
*
* <p>The variant of UTF-8 implemented by this class is the restricted definition of UTF-8
* introduced in Unicode 3.1. One implication of this is that it rejects <a
* href="http://www.unicode.org/versions/corrigendum1.html">"non-shortest form"</a> byte sequences,
* even though the JDK decoder may accept them.
*
* @author Martin Buchholz
* @author Clément Roux
* @since 16.0
*/
@Beta
@GwtCompatible(emulated = true)
public final class Utf8 {
/**
* Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string, this
* method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in both
* time and space.
*
* @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
* surrogates)
*/
public static int encodedLength(CharSequence sequence) {
// Warning to maintainers: this implementation is highly optimized.
int utf16Length = sequence.length();
int utf8Length = utf16Length;
int i = 0;
// This loop optimizes for pure ASCII.
while (i < utf16Length && sequence.charAt(i) < 0x80) {
i++;
}
// This loop optimizes for chars less than 0x800.
for (; i < utf16Length; i++) {
char c = sequence.charAt(i);
if (c < 0x800) {
utf8Length += ((0x7f - c) >>> 31); // branch free!
} else {
utf8Length += encodedLengthGeneral(sequence, i);
break;
}
}
if (utf8Length < utf16Length) {
// Necessary and sufficient condition for overflow because of maximum 3x expansion
throw new IllegalArgumentException(
"UTF-8 length does not fit in int: " + (utf8Length + (1L << 32)));
}
return utf8Length;
}
private static int encodedLengthGeneral(CharSequence sequence, int start) {
int utf16Length = sequence.length();
int utf8Length = 0;
for (int i = start; i < utf16Length; i++) {
char c = sequence.charAt(i);
if (c < 0x800) {
utf8Length += (0x7f - c) >>> 31; // branch free!
} else {
utf8Length += 2;
// jdk7+: if (Character.isSurrogate(c)) {
if (MIN_SURROGATE <= c && c <= MAX_SURROGATE) {
// Check that we have a well-formed surrogate pair.
if (Character.codePointAt(sequence, i) == c) {
throw new IllegalArgumentException(unpairedSurrogateMsg(i));
}
i++;
}
}
}
return utf8Length;
}
/**
* Returns {@code true} if {@code bytes} is a <i>well-formed</i> UTF-8 byte sequence according to
* Unicode 6.0. Note that this is a stronger criterion than simply whether the bytes can be
* decoded. For example, some versions of the JDK decoder will accept "non-shortest form" byte
* sequences, but encoding never reproduces these. Such byte sequences are <i>not</i> considered
* well-formed.
*
* <p>This method returns {@code true} if and only if {@code Arrays.equals(bytes, new
* String(bytes, UTF_8).getBytes(UTF_8))} does, but is more efficient in both time and space.
*/
public static boolean isWellFormed(byte[] bytes) {
return isWellFormed(bytes, 0, bytes.length);
}
/**
* Returns whether the given byte array slice is a well-formed UTF-8 byte sequence, as defined by
* {@link #isWellFormed(byte[])}. Note that this can be false even when {@code
* isWellFormed(bytes)} is true.
*
* @param bytes the input buffer
* @param off the offset in the buffer of the first byte to read
* @param len the number of bytes to read from the buffer
*/
public static boolean isWellFormed(byte[] bytes, int off, int len) {
int end = off + len;
checkPositionIndexes(off, end, bytes.length);
// Look for the first non-ASCII character.
for (int i = off; i < end; i++) {
if (bytes[i] < 0) {
return isWellFormedSlowPath(bytes, i, end);
}
}
return true;
}
private static boolean isWellFormedSlowPath(byte[] bytes, int off, int end) {
int index = off;
while (true) {
int byte1;
// Optimize for interior runs of ASCII bytes.
do {
if (index >= end) {
return true;
}
} while ((byte1 = bytes[index++]) >= 0);
if (byte1 < (byte) 0xE0) {
// Two-byte form.
if (index == end) {
return false;
}
// Simultaneously check for illegal trailing-byte in leading position
// and overlong 2-byte form.
if (byte1 < (byte) 0xC2 || bytes[index++] > (byte) 0xBF) {
return false;
}
} else if (byte1 < (byte) 0xF0) {
// Three-byte form.
if (index + 1 >= end) {
return false;
}
int byte2 = bytes[index++];
if (byte2 > (byte) 0xBF
// Overlong? 5 most significant bits must not all be zero.
|| (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
// Check for illegal surrogate codepoints.
|| (byte1 == (byte) 0xED && (byte) 0xA0 <= byte2)
// Third byte trailing-byte test.
|| bytes[index++] > (byte) 0xBF) {
return false;
}
} else {
// Four-byte form.
if (index + 2 >= end) {
return false;
}
int byte2 = bytes[index++];
if (byte2 > (byte) 0xBF
// Check that 1 <= plane <= 16. Tricky optimized form of:
// if (byte1 > (byte) 0xF4
// || byte1 == (byte) 0xF0 && byte2 < (byte) 0x90
// || byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
|| (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
// Third byte trailing-byte test
|| bytes[index++] > (byte) 0xBF
// Fourth byte trailing-byte test
|| bytes[index++] > (byte) 0xBF) {
return false;
}
}
}
}
private static String unpairedSurrogateMsg(int i) {
return "Unpaired surrogate at index " + i;
}
private Utf8() {}
}

View file

@ -0,0 +1,504 @@
/*
* Copyright (C) 2013 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.Strings.lenientFormat;
import com.google.common.annotations.GwtCompatible;
/**
* Static convenience methods that serve the same purpose as Java language <a
* href="https://docs.oracle.com/javase/8/docs/technotes/guides/language/assert.html">assertions</a>,
* except that they are always enabled. These methods should be used instead of Java assertions
* whenever there is a chance the check may fail "in real life". Example:
*
* <pre>{@code
* Bill bill = remoteService.getLastUnpaidBill();
*
* // In case bug 12345 happens again we'd rather just die
* Verify.verify(bill.status() == Status.UNPAID,
* "Unexpected bill status: %s", bill.status());
* }</pre>
*
* <h3>Comparison to alternatives</h3>
*
* <p><b>Note:</b> In some cases the differences explained below can be subtle. When it's unclear
* which approach to use, <b>don't worry</b> too much about it; just pick something that seems
* reasonable and it will be fine.
*
* <ul>
* <li>If checking whether the <i>caller</i> has violated your method or constructor's contract
* (such as by passing an invalid argument), use the utilities of the {@link Preconditions}
* class instead.
* <li>If checking an <i>impossible</i> condition (which <i>cannot</i> happen unless your own
* class or its <i>trusted</i> dependencies is badly broken), this is what ordinary Java
* assertions are for. Note that assertions are not enabled by default; they are essentially
* considered "compiled comments."
* <li>An explicit {@code if/throw} (as illustrated below) is always acceptable; we still
* recommend using our {@link VerifyException} exception type. Throwing a plain {@link
* RuntimeException} is frowned upon.
* <li>Use of {@link java.util.Objects#requireNonNull(Object)} is generally discouraged, since
* {@link #verifyNotNull(Object)} and {@link Preconditions#checkNotNull(Object)} perform the
* same function with more clarity.
* </ul>
*
* <h3>Warning about performance</h3>
*
* <p>Remember that parameter values for message construction must all be computed eagerly, and
* autoboxing and varargs array creation may happen as well, even when the verification succeeds and
* the message ends up unneeded. Performance-sensitive verification checks should continue to use
* usual form:
*
* <pre>{@code
* Bill bill = remoteService.getLastUnpaidBill();
* if (bill.status() != Status.UNPAID) {
* throw new VerifyException("Unexpected bill status: " + bill.status());
* }
* }</pre>
*
* <h3>Only {@code %s} is supported</h3>
*
* <p>As with {@link Preconditions}, {@code Verify} uses {@link Strings#lenientFormat} to format
* error message template strings. This only supports the {@code "%s"} specifier, not the full range
* of {@link java.util.Formatter} specifiers. However, note that if the number of arguments does not
* match the number of occurrences of {@code "%s"} in the format string, {@code Verify} will still
* behave as expected, and will still include all argument values in the error message; the message
* will simply not be formatted exactly as intended.
*
* <h3>More information</h3>
*
* See <a href="https://github.com/google/guava/wiki/ConditionalFailuresExplained">Conditional
* failures explained</a> in the Guava User Guide for advice on when this class should be used.
*
* @since 17.0
*/
@GwtCompatible
public final class Verify {
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with no
* message otherwise.
*
* @throws VerifyException if {@code expression} is {@code false}
* @see Preconditions#checkState Preconditions.checkState()
*/
public static void verify(boolean expression) {
if (!expression) {
throw new VerifyException();
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* @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 VerifyException if {@code expression} is {@code false}
* @see Preconditions#checkState Preconditions.checkState()
*/
public static void verify(
boolean expression,
String errorMessageTemplate,
Object ... errorMessageArgs) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, errorMessageArgs));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(boolean expression, String errorMessageTemplate, char p1) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(boolean expression, String errorMessageTemplate, int p1) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(boolean expression, String errorMessageTemplate, long p1) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, Object p1) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, char p1, char p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, int p1, char p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, long p1, char p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, Object p1, char p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, char p1, int p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, int p1, int p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, long p1, int p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, Object p1, int p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, char p1, long p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, int p1, long p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, long p1, long p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, Object p1, long p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, char p1, Object p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, int p1, Object p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression, String errorMessageTemplate, long p1, Object p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression,
String errorMessageTemplate,
Object p1,
Object p2) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression,
String errorMessageTemplate,
Object p1,
Object p2,
Object p3) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2, p3));
}
}
/**
* Ensures that {@code expression} is {@code true}, throwing a {@code VerifyException} with a
* custom message otherwise.
*
* <p>See {@link #verify(boolean, String, Object...)} for details.
*
* @since 23.1 (varargs overload since 17.0)
*/
public static void verify(
boolean expression,
String errorMessageTemplate,
Object p1,
Object p2,
Object p3,
Object p4) {
if (!expression) {
throw new VerifyException(lenientFormat(errorMessageTemplate, p1, p2, p3, p4));
}
}
/**
* Ensures that {@code reference} is non-null, throwing a {@code VerifyException} with a default
* message otherwise.
*
* @return {@code reference}, guaranteed to be non-null, for convenience
* @throws VerifyException if {@code reference} is {@code null}
* @see Preconditions#checkNotNull Preconditions.checkNotNull()
*/
public static <T> T verifyNotNull(T reference) {
return verifyNotNull(reference, "expected a non-null reference");
}
/**
* Ensures that {@code reference} is non-null, throwing a {@code VerifyException} with a custom
* message otherwise.
*
* @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 {@code reference}, guaranteed to be non-null, for convenience
* @throws VerifyException if {@code reference} is {@code null}
* @see Preconditions#checkNotNull Preconditions.checkNotNull()
*/
public static <T> T verifyNotNull(
T reference,
String errorMessageTemplate,
Object ... errorMessageArgs) {
verify(reference != null, errorMessageTemplate, errorMessageArgs);
return reference;
}
// TODO(kevinb): consider <T> T verifySingleton(Iterable<T>) to take over for
// Iterables.getOnlyElement()
private Verify() {}
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2013 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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;
/**
* Exception thrown upon the failure of a <a
* href="https://github.com/google/guava/wiki/ConditionalFailuresExplained">verification check</a>,
* including those performed by the convenience methods of the {@link Verify} class.
*
* @since 17.0
*/
@GwtCompatible
public class VerifyException extends RuntimeException {
/** Constructs a {@code VerifyException} with no message. */
public VerifyException() {}
/** Constructs a {@code VerifyException} with the message {@code message}. */
public VerifyException(String message) {
super(message);
}
/**
* Constructs a {@code VerifyException} with the cause {@code cause} and a message that is {@code
* null} if {@code cause} is null, and {@code cause.toString()} otherwise.
*
* @since 19.0
*/
public VerifyException(Throwable cause) {
super(cause);
}
/**
* Constructs a {@code VerifyException} with the message {@code message} and the cause {@code
* cause}.
*
* @since 19.0
*/
public VerifyException(String message, Throwable cause) {
super(message, cause);
}
}

View file

@ -0,0 +1,234 @@
/*
* 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.Constructor;
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 Guava code. If we were to load this class in the same class
* loader as the rest of Guava, 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 queue a reference queue that the thread will poll.
* @param frqReference a phantom reference to the FinalizableReferenceQueue, which will be queued
* either when the FinalizableReferenceQueue is no longer referenced anywhere, or when its
* close() method is called.
*/
public static void startFinalizer(
Class<?> finalizableReferenceClass,
ReferenceQueue<Object> queue,
PhantomReference<Object> frqReference) {
/*
* 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, queue, frqReference);
String threadName = Finalizer.class.getName();
Thread thread = null;
if (bigThreadConstructor != null) {
try {
boolean inheritThreadLocals = false;
long defaultStackSize = 0;
thread =
bigThreadConstructor.newInstance(
(ThreadGroup) null, finalizer, threadName, defaultStackSize, inheritThreadLocals);
} catch (Throwable t) {
logger.log(
Level.INFO, "Failed to create a thread without inherited thread-local values", t);
}
}
if (thread == null) {
thread = new Thread((ThreadGroup) null, finalizer, threadName);
}
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();
}
private final WeakReference<Class<?>> finalizableReferenceClassReference;
private final PhantomReference<Object> frqReference;
private final ReferenceQueue<Object> queue;
// By preference, we will use the Thread constructor that has an `inheritThreadLocals` parameter.
// But before Java 9, our only way not to inherit ThreadLocals is to zap them after the thread
// is created, by accessing a private field.
private static final Constructor<Thread> bigThreadConstructor =
getBigThreadConstructor();
private static final Field inheritableThreadLocals =
(bigThreadConstructor == null) ? getInheritableThreadLocalsField() : null;
/** Constructs a new finalizer thread. */
private Finalizer(
Class<?> finalizableReferenceClass,
ReferenceQueue<Object> queue,
PhantomReference<Object> frqReference) {
this.queue = queue;
this.finalizableReferenceClassReference =
new WeakReference<Class<?>>(finalizableReferenceClass);
// Keep track of the FRQ that started us so we know when to stop.
this.frqReference = frqReference;
}
/** Loops continuously, pulling references off the queue and cleaning them up. */
@SuppressWarnings("InfiniteLoopStatement")
@Override
public void run() {
while (true) {
try {
if (!cleanUp(queue.remove())) {
break;
}
} catch (InterruptedException e) {
// ignore
}
}
}
/**
* Cleans up a single reference. Catches and logs all throwables.
*
* @return true if the caller should continue, false if the associated FinalizableReferenceQueue
* is no longer referenced.
*/
private boolean cleanUp(Reference<?> reference) {
Method finalizeReferentMethod = getFinalizeReferentMethod();
if (finalizeReferentMethod == null) {
return false;
}
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.
*/
return false;
}
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);
return true;
}
/** Looks up FinalizableReference.finalizeReferent() method. */
private Method getFinalizeReferentMethod() {
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.
*/
return null;
}
try {
return finalizableReferenceClass.getMethod("finalizeReferent");
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
private 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;
}
}
private static Constructor<Thread> getBigThreadConstructor() {
try {
return Thread.class.getConstructor(
ThreadGroup.class, Runnable.class, String.class, long.class, boolean.class);
} catch (Throwable t) {
// Probably pre Java 9. We'll fall back to Thread.inheritableThreadLocals.
return null;
}
}
}

View file

@ -0,0 +1,265 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtCompatible;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
/**
* This class provides a skeletal implementation of the {@code Cache} interface to minimize the
* effort required to implement this interface.
*
* <p>To implement a cache, the programmer needs only to extend this class and provide an
* implementation for the {@link #put} and {@link #getIfPresent} methods. {@link #getAllPresent} is
* implemented in terms of {@link #getIfPresent}; {@link #putAll} is implemented in terms of {@link
* #put}, {@link #invalidateAll(Iterable)} is implemented in terms of {@link #invalidate}. The
* method {@link #cleanUp} is a no-op. All other methods throw an {@link
* UnsupportedOperationException}.
*
* @author Charles Fry
* @since 10.0
*/
@GwtCompatible
public abstract class AbstractCache<K, V> implements Cache<K, V> {
/** Constructor for use by subclasses. */
protected AbstractCache() {}
/** @since 11.0 */
@Override
public V get(K key, Callable<? extends V> valueLoader) throws ExecutionException {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*
* <p>This implementation of {@code getAllPresent} lacks any insight into the internal cache data
* structure, and is thus forced to return the query keys instead of the cached keys. This is only
* possible with an unsafe cast which requires {@code keys} to actually be of type {@code K}.
*
* @since 11.0
*/
@Override
public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) {
Map<K, V> result = Maps.newLinkedHashMap();
for (Object key : keys) {
if (!result.containsKey(key)) {
@SuppressWarnings("unchecked")
K castKey = (K) key;
V value = getIfPresent(key);
if (value != null) {
result.put(castKey, value);
}
}
}
return ImmutableMap.copyOf(result);
}
/** @since 11.0 */
@Override
public void put(K key, V value) {
throw new UnsupportedOperationException();
}
/** @since 12.0 */
@Override
public void putAll(Map<? extends K, ? extends V> m) {
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public void cleanUp() {}
@Override
public long size() {
throw new UnsupportedOperationException();
}
@Override
public void invalidate(Object key) {
throw new UnsupportedOperationException();
}
/** @since 11.0 */
@Override
public void invalidateAll(Iterable<?> keys) {
for (Object key : keys) {
invalidate(key);
}
}
@Override
public void invalidateAll() {
throw new UnsupportedOperationException();
}
@Override
public CacheStats stats() {
throw new UnsupportedOperationException();
}
@Override
public ConcurrentMap<K, V> asMap() {
throw new UnsupportedOperationException();
}
/**
* Accumulates statistics during the operation of a {@link Cache} for presentation by {@link
* Cache#stats}. This is solely intended for consumption by {@code Cache} implementors.
*
* @since 10.0
*/
public interface StatsCounter {
/**
* Records cache hits. This should be called when a cache request returns a cached value.
*
* @param count the number of hits to record
* @since 11.0
*/
void recordHits(int count);
/**
* Records cache misses. This should be called when a cache request returns a value that was not
* found in the cache. This method should be called by the loading thread, as well as by threads
* blocking on the load. Multiple concurrent calls to {@link Cache} lookup methods with the same
* key on an absent value should result in a single call to either {@code recordLoadSuccess} or
* {@code recordLoadException} and multiple calls to this method, despite all being served by
* the results of a single load operation.
*
* @param count the number of misses to record
* @since 11.0
*/
void recordMisses(int count);
/**
* Records the successful load of a new entry. This should be called when a cache request causes
* an entry to be loaded, and the loading completes successfully. In contrast to {@link
* #recordMisses}, this method should only be called by the loading thread.
*
* @param loadTime the number of nanoseconds the cache spent computing or retrieving the new
* value
*/
@SuppressWarnings("GoodTime") // should accept a java.time.Duration
void recordLoadSuccess(long loadTime);
/**
* Records the failed load of a new entry. This should be called when a cache request causes an
* entry to be loaded, but an exception is thrown while loading the entry. In contrast to {@link
* #recordMisses}, this method should only be called by the loading thread.
*
* @param loadTime the number of nanoseconds the cache spent computing or retrieving the new
* value prior to an exception being thrown
*/
@SuppressWarnings("GoodTime") // should accept a java.time.Duration
void recordLoadException(long loadTime);
/**
* Records the eviction of an entry from the cache. This should only been called when an entry
* is evicted due to the cache's eviction strategy, and not as a result of manual {@linkplain
* Cache#invalidate invalidations}.
*/
void recordEviction();
/**
* Returns a snapshot of this counter's values. Note that this may be an inconsistent view, as
* it may be interleaved with update operations.
*/
CacheStats snapshot();
}
/**
* A thread-safe {@link StatsCounter} implementation for use by {@link Cache} implementors.
*
* @since 10.0
*/
public static final class SimpleStatsCounter implements StatsCounter {
private final LongAddable hitCount = LongAddables.create();
private final LongAddable missCount = LongAddables.create();
private final LongAddable loadSuccessCount = LongAddables.create();
private final LongAddable loadExceptionCount = LongAddables.create();
private final LongAddable totalLoadTime = LongAddables.create();
private final LongAddable evictionCount = LongAddables.create();
/** Constructs an instance with all counts initialized to zero. */
public SimpleStatsCounter() {}
/** @since 11.0 */
@Override
public void recordHits(int count) {
hitCount.add(count);
}
/** @since 11.0 */
@Override
public void recordMisses(int count) {
missCount.add(count);
}
@SuppressWarnings("GoodTime") // b/122668874
@Override
public void recordLoadSuccess(long loadTime) {
loadSuccessCount.increment();
totalLoadTime.add(loadTime);
}
@SuppressWarnings("GoodTime") // b/122668874
@Override
public void recordLoadException(long loadTime) {
loadExceptionCount.increment();
totalLoadTime.add(loadTime);
}
@Override
public void recordEviction() {
evictionCount.increment();
}
@Override
public CacheStats snapshot() {
return new CacheStats(
negativeToMaxValue(hitCount.sum()),
negativeToMaxValue(missCount.sum()),
negativeToMaxValue(loadSuccessCount.sum()),
negativeToMaxValue(loadExceptionCount.sum()),
negativeToMaxValue(totalLoadTime.sum()),
negativeToMaxValue(evictionCount.sum()));
}
/** Returns {@code value}, if non-negative. Otherwise, returns {@link Long#MAX_VALUE}. */
private static long negativeToMaxValue(long value) {
return (value >= 0) ? value : Long.MAX_VALUE;
}
/** Increments all counters by the values in {@code other}. */
public void incrementBy(StatsCounter other) {
CacheStats otherStats = other.snapshot();
hitCount.add(otherStats.hitCount());
missCount.add(otherStats.missCount());
loadSuccessCount.add(otherStats.loadSuccessCount());
loadExceptionCount.add(otherStats.loadExceptionCount());
totalLoadTime.add(otherStats.totalLoadTime());
evictionCount.add(otherStats.evictionCount());
}
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
/**
* This class provides a skeletal implementation of the {@code Cache} interface to minimize the
* effort required to implement this interface.
*
* <p>To implement a cache, the programmer needs only to extend this class and provide an
* implementation for the {@link #get(Object)} and {@link #getIfPresent} methods. {@link
* #getUnchecked}, {@link #get(Object, Callable)}, and {@link #getAll} are implemented in terms of
* {@code get}; {@link #getAllPresent} is implemented in terms of {@code getIfPresent}; {@link
* #putAll} is implemented in terms of {@link #put}, {@link #invalidateAll(Iterable)} is implemented
* in terms of {@link #invalidate}. The method {@link #cleanUp} is a no-op. All other methods throw
* an {@link UnsupportedOperationException}.
*
* @author Charles Fry
* @since 11.0
*/
@GwtIncompatible
public abstract class AbstractLoadingCache<K, V> extends AbstractCache<K, V>
implements LoadingCache<K, V> {
/** Constructor for use by subclasses. */
protected AbstractLoadingCache() {}
@Override
public V getUnchecked(K key) {
try {
return get(key);
} catch (ExecutionException e) {
throw new UncheckedExecutionException(e.getCause());
}
}
@Override
public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
Map<K, V> result = Maps.newLinkedHashMap();
for (K key : keys) {
if (!result.containsKey(key)) {
result.put(key, get(key));
}
}
return ImmutableMap.copyOf(result);
}
@Override
public final V apply(K key) {
return getUnchecked(key);
}
@Override
public void refresh(K key) {
throw new UnsupportedOperationException();
}
}

View file

@ -0,0 +1,169 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtCompatible;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ExecutionError;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
/**
* A semi-persistent mapping from keys to values. Cache entries are manually added using {@link
* #get(Object, Callable)} or {@link #put(Object, Object)}, and are stored in the cache until either
* evicted or manually invalidated. The common way to build instances is using {@link CacheBuilder}.
*
* <p>Implementations of this interface are expected to be thread-safe, and can be safely accessed
* by multiple concurrent threads.
*
* @author Charles Fry
* @since 10.0
*/
@GwtCompatible
public interface Cache<K, V> {
/**
* Returns the value associated with {@code key} in this cache, or {@code null} if there is no
* cached value for {@code key}.
*
* @since 11.0
*/
V getIfPresent(Object key);
/**
* Returns the value associated with {@code key} in this cache, obtaining that value from {@code
* loader} if necessary. The method improves upon the conventional "if cached, return; otherwise
* create, cache and return" pattern. For further improvements, use {@link LoadingCache} and its
* {@link LoadingCache#get(Object) get(K)} method instead of this one.
*
* <p>Among the improvements that this method and {@code LoadingCache.get(K)} both provide are:
*
* <ul>
* <li>{@linkplain LoadingCache#get(Object) awaiting the result of a pending load} rather than
* starting a redundant one
* <li>eliminating the error-prone caching boilerplate
* <li>tracking load {@linkplain #stats statistics}
* </ul>
*
* <p>Among the further improvements that {@code LoadingCache} can provide but this method cannot:
*
* <ul>
* <li>consolidation of the loader logic to {@linkplain CacheBuilder#build(CacheLoader) a single
* authoritative location}
* <li>{@linkplain LoadingCache#refresh refreshing of entries}, including {@linkplain
* CacheBuilder#refreshAfterWrite automated refreshing}
* <li>{@linkplain LoadingCache#getAll bulk loading requests}, including {@linkplain
* CacheLoader#loadAll bulk loading implementations}
* </ul>
*
* <p><b>Warning:</b> For any given key, every {@code loader} used with it should compute the same
* value. Otherwise, a call that passes one {@code loader} may return the result of another call
* with a differently behaving {@code loader}. For example, a call that requests a short timeout
* for an RPC may wait for a similar call that requests a long timeout, or a call by an
* unprivileged user may return a resource accessible only to a privileged user making a similar
* call. To prevent this problem, create a key object that includes all values that affect the
* result of the query. Or use {@code LoadingCache.get(K)}, which lacks the ability to refer to
* state other than that in the key.
*
* <p><b>Warning:</b> as with {@link CacheLoader#load}, {@code loader} <b>must not</b> return
* {@code null}; it may either return a non-null value or throw an exception.
*
* <p>No observable state associated with this cache is modified until loading completes.
*
* @throws ExecutionException if a checked exception was thrown while loading the value
* @throws UncheckedExecutionException if an unchecked exception was thrown while loading the
* value
* @throws ExecutionError if an error was thrown while loading the value
* @since 11.0
*/
V get(K key, Callable<? extends V> loader) throws ExecutionException;
/**
* Returns a map of the values associated with {@code keys} in this cache. The returned map will
* only contain entries which are already present in the cache.
*
* @since 11.0
*/
ImmutableMap<K, V> getAllPresent(Iterable<?> keys);
/**
* Associates {@code value} with {@code key} in this cache. If the cache previously contained a
* value associated with {@code key}, the old value is replaced by {@code value}.
*
* <p>Prefer {@link #get(Object, Callable)} when using the conventional "if cached, return;
* otherwise create, cache and return" pattern.
*
* @since 11.0
*/
void put(K key, V value);
/**
* Copies all of the mappings from the specified map to the cache. The effect of this call is
* equivalent to that of calling {@code put(k, v)} on this map once for each mapping from key
* {@code k} to value {@code v} in the specified map. The behavior of this operation is undefined
* if the specified map is modified while the operation is in progress.
*
* @since 12.0
*/
void putAll(Map<? extends K, ? extends V> m);
/** Discards any cached value for key {@code key}. */
void invalidate(Object key);
/**
* Discards any cached values for keys {@code keys}.
*
* @since 11.0
*/
void invalidateAll(Iterable<?> keys);
/** Discards all entries in the cache. */
void invalidateAll();
/** Returns the approximate number of entries in this cache. */
long size();
/**
* Returns a current snapshot of this cache's cumulative statistics, or a set of default values if
* the cache is not recording statistics. All statistics begin at zero and never decrease over the
* lifetime of the cache.
*
* <p><b>Warning:</b> this cache may not be recording statistical data. For example, a cache
* created using {@link CacheBuilder} only does so if the {@link CacheBuilder#recordStats} method
* was called. If statistics are not being recorded, a {@code CacheStats} instance with zero for
* all values is returned.
*
*/
CacheStats stats();
/**
* Returns a view of the entries stored in this cache as a thread-safe map. Modifications made to
* the map directly affect the cache.
*
* <p>Iterators from the returned map are at least <i>weakly consistent</i>: they are safe for
* concurrent use, but if the cache is modified (including by eviction) after the iterator is
* created, it is undefined which of the changes (if any) will be reflected in that iterator.
*/
ConcurrentMap<K, V> asMap();
/**
* Performs any pending maintenance operations needed by the cache. Exactly which activities are
* performed -- if any -- is implementation-dependent.
*/
void cleanUp();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,480 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.Splitter;
import com.google.common.cache.LocalCache.Strength;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
/**
* A specification of a {@link CacheBuilder} configuration.
*
* <p>{@code CacheBuilderSpec} supports parsing configuration off of a string, which makes it
* especially useful for command-line configuration of a {@code CacheBuilder}.
*
* <p>The string syntax is a series of comma-separated keys or key-value pairs, each corresponding
* to a {@code CacheBuilder} method.
*
* <ul>
* <li>{@code concurrencyLevel=[integer]}: sets {@link CacheBuilder#concurrencyLevel}.
* <li>{@code initialCapacity=[integer]}: sets {@link CacheBuilder#initialCapacity}.
* <li>{@code maximumSize=[long]}: sets {@link CacheBuilder#maximumSize}.
* <li>{@code maximumWeight=[long]}: sets {@link CacheBuilder#maximumWeight}.
* <li>{@code expireAfterAccess=[duration]}: sets {@link CacheBuilder#expireAfterAccess}.
* <li>{@code expireAfterWrite=[duration]}: sets {@link CacheBuilder#expireAfterWrite}.
* <li>{@code refreshAfterWrite=[duration]}: sets {@link CacheBuilder#refreshAfterWrite}.
* <li>{@code weakKeys}: sets {@link CacheBuilder#weakKeys}.
* <li>{@code softValues}: sets {@link CacheBuilder#softValues}.
* <li>{@code weakValues}: sets {@link CacheBuilder#weakValues}.
* <li>{@code recordStats}: sets {@link CacheBuilder#recordStats}.
* </ul>
*
* <p>The set of supported keys will grow as {@code CacheBuilder} evolves, but existing keys will
* never be removed.
*
* <p>Durations are represented by an integer, followed by one of "d", "h", "m", or "s",
* representing days, hours, minutes, or seconds respectively. (There is currently no syntax to
* request expiration in milliseconds, microseconds, or nanoseconds.)
*
* <p>Whitespace before and after commas and equal signs is ignored. Keys may not be repeated; it is
* also illegal to use the following pairs of keys in a single value:
*
* <ul>
* <li>{@code maximumSize} and {@code maximumWeight}
* <li>{@code softValues} and {@code weakValues}
* </ul>
*
* <p>{@code CacheBuilderSpec} does not support configuring {@code CacheBuilder} methods with
* non-value parameters. These must be configured in code.
*
* <p>A new {@code CacheBuilder} can be instantiated from a {@code CacheBuilderSpec} using {@link
* CacheBuilder#from(CacheBuilderSpec)} or {@link CacheBuilder#from(String)}.
*
* @author Adam Winer
* @since 12.0
*/
@SuppressWarnings("GoodTime") // lots of violations (nanosecond math)
@GwtIncompatible
public final class CacheBuilderSpec {
/** Parses a single value. */
private interface ValueParser {
void parse(CacheBuilderSpec spec, String key, String value);
}
/** Splits each key-value pair. */
private static final Splitter KEYS_SPLITTER = Splitter.on(',').trimResults();
/** Splits the key from the value. */
private static final Splitter KEY_VALUE_SPLITTER = Splitter.on('=').trimResults();
/** Map of names to ValueParser. */
private static final ImmutableMap<String, ValueParser> VALUE_PARSERS =
ImmutableMap.<String, ValueParser>builder()
.put("initialCapacity", new InitialCapacityParser())
.put("maximumSize", new MaximumSizeParser())
.put("maximumWeight", new MaximumWeightParser())
.put("concurrencyLevel", new ConcurrencyLevelParser())
.put("weakKeys", new KeyStrengthParser(Strength.WEAK))
.put("softValues", new ValueStrengthParser(Strength.SOFT))
.put("weakValues", new ValueStrengthParser(Strength.WEAK))
.put("recordStats", new RecordStatsParser())
.put("expireAfterAccess", new AccessDurationParser())
.put("expireAfterWrite", new WriteDurationParser())
.put("refreshAfterWrite", new RefreshDurationParser())
.put("refreshInterval", new RefreshDurationParser())
.build();
@VisibleForTesting Integer initialCapacity;
@VisibleForTesting Long maximumSize;
@VisibleForTesting Long maximumWeight;
@VisibleForTesting Integer concurrencyLevel;
@VisibleForTesting Strength keyStrength;
@VisibleForTesting Strength valueStrength;
@VisibleForTesting Boolean recordStats;
@VisibleForTesting long writeExpirationDuration;
@VisibleForTesting TimeUnit writeExpirationTimeUnit;
@VisibleForTesting long accessExpirationDuration;
@VisibleForTesting TimeUnit accessExpirationTimeUnit;
@VisibleForTesting long refreshDuration;
@VisibleForTesting TimeUnit refreshTimeUnit;
/** Specification; used for toParseableString(). */
private final String specification;
private CacheBuilderSpec(String specification) {
this.specification = specification;
}
/**
* Creates a CacheBuilderSpec from a string.
*
* @param cacheBuilderSpecification the string form
*/
public static CacheBuilderSpec parse(String cacheBuilderSpecification) {
CacheBuilderSpec spec = new CacheBuilderSpec(cacheBuilderSpecification);
if (!cacheBuilderSpecification.isEmpty()) {
for (String keyValuePair : KEYS_SPLITTER.split(cacheBuilderSpecification)) {
List<String> keyAndValue = ImmutableList.copyOf(KEY_VALUE_SPLITTER.split(keyValuePair));
checkArgument(!keyAndValue.isEmpty(), "blank key-value pair");
checkArgument(
keyAndValue.size() <= 2,
"key-value pair %s with more than one equals sign",
keyValuePair);
// Find the ValueParser for the current key.
String key = keyAndValue.get(0);
ValueParser valueParser = VALUE_PARSERS.get(key);
checkArgument(valueParser != null, "unknown key %s", key);
String value = keyAndValue.size() == 1 ? null : keyAndValue.get(1);
valueParser.parse(spec, key, value);
}
}
return spec;
}
/** Returns a CacheBuilderSpec that will prevent caching. */
public static CacheBuilderSpec disableCaching() {
// Maximum size of zero is one way to block caching
return CacheBuilderSpec.parse("maximumSize=0");
}
/** Returns a CacheBuilder configured according to this instance's specification. */
CacheBuilder<Object, Object> toCacheBuilder() {
CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder();
if (initialCapacity != null) {
builder.initialCapacity(initialCapacity);
}
if (maximumSize != null) {
builder.maximumSize(maximumSize);
}
if (maximumWeight != null) {
builder.maximumWeight(maximumWeight);
}
if (concurrencyLevel != null) {
builder.concurrencyLevel(concurrencyLevel);
}
if (keyStrength != null) {
switch (keyStrength) {
case WEAK:
builder.weakKeys();
break;
default:
throw new AssertionError();
}
}
if (valueStrength != null) {
switch (valueStrength) {
case SOFT:
builder.softValues();
break;
case WEAK:
builder.weakValues();
break;
default:
throw new AssertionError();
}
}
if (recordStats != null && recordStats) {
builder.recordStats();
}
if (writeExpirationTimeUnit != null) {
builder.expireAfterWrite(writeExpirationDuration, writeExpirationTimeUnit);
}
if (accessExpirationTimeUnit != null) {
builder.expireAfterAccess(accessExpirationDuration, accessExpirationTimeUnit);
}
if (refreshTimeUnit != null) {
builder.refreshAfterWrite(refreshDuration, refreshTimeUnit);
}
return builder;
}
/**
* Returns a string that can be used to parse an equivalent {@code CacheBuilderSpec}. The order
* and form of this representation is not guaranteed, except that reparsing its output will
* produce a {@code CacheBuilderSpec} equal to this instance.
*/
public String toParsableString() {
return specification;
}
/**
* Returns a string representation for this CacheBuilderSpec instance. The form of this
* representation is not guaranteed.
*/
@Override
public String toString() {
return MoreObjects.toStringHelper(this).addValue(toParsableString()).toString();
}
@Override
public int hashCode() {
return Objects.hashCode(
initialCapacity,
maximumSize,
maximumWeight,
concurrencyLevel,
keyStrength,
valueStrength,
recordStats,
durationInNanos(writeExpirationDuration, writeExpirationTimeUnit),
durationInNanos(accessExpirationDuration, accessExpirationTimeUnit),
durationInNanos(refreshDuration, refreshTimeUnit));
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof CacheBuilderSpec)) {
return false;
}
CacheBuilderSpec that = (CacheBuilderSpec) obj;
return Objects.equal(initialCapacity, that.initialCapacity)
&& Objects.equal(maximumSize, that.maximumSize)
&& Objects.equal(maximumWeight, that.maximumWeight)
&& Objects.equal(concurrencyLevel, that.concurrencyLevel)
&& Objects.equal(keyStrength, that.keyStrength)
&& Objects.equal(valueStrength, that.valueStrength)
&& Objects.equal(recordStats, that.recordStats)
&& Objects.equal(
durationInNanos(writeExpirationDuration, writeExpirationTimeUnit),
durationInNanos(that.writeExpirationDuration, that.writeExpirationTimeUnit))
&& Objects.equal(
durationInNanos(accessExpirationDuration, accessExpirationTimeUnit),
durationInNanos(that.accessExpirationDuration, that.accessExpirationTimeUnit))
&& Objects.equal(
durationInNanos(refreshDuration, refreshTimeUnit),
durationInNanos(that.refreshDuration, that.refreshTimeUnit));
}
/**
* Converts an expiration duration/unit pair into a single Long for hashing and equality. Uses
* nanos to match CacheBuilder implementation.
*/
private static Long durationInNanos(long duration, TimeUnit unit) {
return (unit == null) ? null : unit.toNanos(duration);
}
/** Base class for parsing integers. */
abstract static class IntegerParser implements ValueParser {
protected abstract void parseInteger(CacheBuilderSpec spec, int value);
@Override
public void parse(CacheBuilderSpec spec, String key, String value) {
checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key);
try {
parseInteger(spec, Integer.parseInt(value));
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
format("key %s value set to %s, must be integer", key, value), e);
}
}
}
/** Base class for parsing integers. */
abstract static class LongParser implements ValueParser {
protected abstract void parseLong(CacheBuilderSpec spec, long value);
@Override
public void parse(CacheBuilderSpec spec, String key, String value) {
checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key);
try {
parseLong(spec, Long.parseLong(value));
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
format("key %s value set to %s, must be integer", key, value), e);
}
}
}
/** Parse initialCapacity */
static class InitialCapacityParser extends IntegerParser {
@Override
protected void parseInteger(CacheBuilderSpec spec, int value) {
checkArgument(
spec.initialCapacity == null,
"initial capacity was already set to ",
spec.initialCapacity);
spec.initialCapacity = value;
}
}
/** Parse maximumSize */
static class MaximumSizeParser extends LongParser {
@Override
protected void parseLong(CacheBuilderSpec spec, long value) {
checkArgument(spec.maximumSize == null, "maximum size was already set to ", spec.maximumSize);
checkArgument(
spec.maximumWeight == null, "maximum weight was already set to ", spec.maximumWeight);
spec.maximumSize = value;
}
}
/** Parse maximumWeight */
static class MaximumWeightParser extends LongParser {
@Override
protected void parseLong(CacheBuilderSpec spec, long value) {
checkArgument(
spec.maximumWeight == null, "maximum weight was already set to ", spec.maximumWeight);
checkArgument(spec.maximumSize == null, "maximum size was already set to ", spec.maximumSize);
spec.maximumWeight = value;
}
}
/** Parse concurrencyLevel */
static class ConcurrencyLevelParser extends IntegerParser {
@Override
protected void parseInteger(CacheBuilderSpec spec, int value) {
checkArgument(
spec.concurrencyLevel == null,
"concurrency level was already set to ",
spec.concurrencyLevel);
spec.concurrencyLevel = value;
}
}
/** Parse weakKeys */
static class KeyStrengthParser implements ValueParser {
private final Strength strength;
public KeyStrengthParser(Strength strength) {
this.strength = strength;
}
@Override
public void parse(CacheBuilderSpec spec, String key, String value) {
checkArgument(value == null, "key %s does not take values", key);
checkArgument(spec.keyStrength == null, "%s was already set to %s", key, spec.keyStrength);
spec.keyStrength = strength;
}
}
/** Parse weakValues and softValues */
static class ValueStrengthParser implements ValueParser {
private final Strength strength;
public ValueStrengthParser(Strength strength) {
this.strength = strength;
}
@Override
public void parse(CacheBuilderSpec spec, String key, String value) {
checkArgument(value == null, "key %s does not take values", key);
checkArgument(
spec.valueStrength == null, "%s was already set to %s", key, spec.valueStrength);
spec.valueStrength = strength;
}
}
/** Parse recordStats */
static class RecordStatsParser implements ValueParser {
@Override
public void parse(CacheBuilderSpec spec, String key, String value) {
checkArgument(value == null, "recordStats does not take values");
checkArgument(spec.recordStats == null, "recordStats already set");
spec.recordStats = true;
}
}
/** Base class for parsing times with durations */
abstract static class DurationParser implements ValueParser {
protected abstract void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit);
@Override
public void parse(CacheBuilderSpec spec, String key, String value) {
checkArgument(value != null && !value.isEmpty(), "value of key %s omitted", key);
try {
char lastChar = value.charAt(value.length() - 1);
TimeUnit timeUnit;
switch (lastChar) {
case 'd':
timeUnit = TimeUnit.DAYS;
break;
case 'h':
timeUnit = TimeUnit.HOURS;
break;
case 'm':
timeUnit = TimeUnit.MINUTES;
break;
case 's':
timeUnit = TimeUnit.SECONDS;
break;
default:
throw new IllegalArgumentException(
format(
"key %s invalid format. was %s, must end with one of [dDhHmMsS]", key, value));
}
long duration = Long.parseLong(value.substring(0, value.length() - 1));
parseDuration(spec, duration, timeUnit);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
format("key %s value set to %s, must be integer", key, value));
}
}
}
/** Parse expireAfterAccess */
static class AccessDurationParser extends DurationParser {
@Override
protected void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit) {
checkArgument(spec.accessExpirationTimeUnit == null, "expireAfterAccess already set");
spec.accessExpirationDuration = duration;
spec.accessExpirationTimeUnit = unit;
}
}
/** Parse expireAfterWrite */
static class WriteDurationParser extends DurationParser {
@Override
protected void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit) {
checkArgument(spec.writeExpirationTimeUnit == null, "expireAfterWrite already set");
spec.writeExpirationDuration = duration;
spec.writeExpirationTimeUnit = unit;
}
}
/** Parse refreshAfterWrite */
static class RefreshDurationParser extends DurationParser {
@Override
protected void parseDuration(CacheBuilderSpec spec, long duration, TimeUnit unit) {
checkArgument(spec.refreshTimeUnit == null, "refreshAfterWrite already set");
spec.refreshDuration = duration;
spec.refreshTimeUnit = unit;
}
}
private static String format(String format, Object... args) {
return String.format(Locale.ROOT, format, args);
}
}

View file

@ -0,0 +1,251 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListenableFutureTask;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
/**
* Computes or retrieves values, based on a key, for use in populating a {@link LoadingCache}.
*
* <p>Most implementations will only need to implement {@link #load}. Other methods may be
* overridden as desired.
*
* <p>Usage example:
*
* <pre>{@code
* CacheLoader<Key, Graph> loader = new CacheLoader<Key, Graph>() {
* public Graph load(Key key) throws AnyException {
* return createExpensiveGraph(key);
* }
* };
* LoadingCache<Key, Graph> cache = CacheBuilder.newBuilder().build(loader);
* }</pre>
*
* <p>Since this example doesn't support reloading or bulk loading, it can also be specified much
* more simply:
*
* <pre>{@code
* CacheLoader<Key, Graph> loader = CacheLoader.from(key -> createExpensiveGraph(key));
* }</pre>
*
* @author Charles Fry
* @since 10.0
*/
@GwtCompatible(emulated = true)
public abstract class CacheLoader<K, V> {
/** Constructor for use by subclasses. */
protected CacheLoader() {}
/**
* Computes or retrieves the value corresponding to {@code key}.
*
* @param key the non-null key whose value should be loaded
* @return the value associated with {@code key}; <b>must not be null</b>
* @throws Exception if unable to load the result
* @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
* treated like any other {@code Exception} in all respects except that, when it is caught,
* the thread's interrupt status is set
*/
public abstract V load(K key) throws Exception;
/**
* Computes or retrieves a replacement value corresponding to an already-cached {@code key}. This
* method is called when an existing cache entry is refreshed by {@link
* CacheBuilder#refreshAfterWrite}, or through a call to {@link LoadingCache#refresh}.
*
* <p>This implementation synchronously delegates to {@link #load}. It is recommended that it be
* overridden with an asynchronous implementation when using {@link
* CacheBuilder#refreshAfterWrite}.
*
* <p><b>Note:</b> <i>all exceptions thrown by this method will be logged and then swallowed</i>.
*
* @param key the non-null key whose value should be loaded
* @param oldValue the non-null old value corresponding to {@code key}
* @return the future new value associated with {@code key}; <b>must not be null, must not return
* null</b>
* @throws Exception if unable to reload the result
* @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
* treated like any other {@code Exception} in all respects except that, when it is caught,
* the thread's interrupt status is set
* @since 11.0
*/
@GwtIncompatible // Futures
public ListenableFuture<V> reload(K key, V oldValue) throws Exception {
checkNotNull(key);
checkNotNull(oldValue);
return Futures.immediateFuture(load(key));
}
/**
* Computes or retrieves the values corresponding to {@code keys}. This method is called by {@link
* LoadingCache#getAll}.
*
* <p>If the returned map doesn't contain all requested {@code keys} then the entries it does
* contain will be cached, but {@code getAll} will throw an exception. If the returned map
* contains extra keys not present in {@code keys} then all returned entries will be cached, but
* only the entries for {@code keys} will be returned from {@code getAll}.
*
* <p>This method should be overridden when bulk retrieval is significantly more efficient than
* many individual lookups. Note that {@link LoadingCache#getAll} will defer to individual calls
* to {@link LoadingCache#get} if this method is not overridden.
*
* @param keys the unique, non-null keys whose values should be loaded
* @return a map from each key in {@code keys} to the value associated with that key; <b>may not
* contain null values</b>
* @throws Exception if unable to load the result
* @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
* treated like any other {@code Exception} in all respects except that, when it is caught,
* the thread's interrupt status is set
* @since 11.0
*/
public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
// This will be caught by getAll(), causing it to fall back to multiple calls to
// LoadingCache.get
throw new UnsupportedLoadingOperationException();
}
/**
* Returns a cache loader that uses {@code function} to load keys, without supporting either
* reloading or bulk loading. This allows creating a cache loader using a lambda expression.
*
* @param function the function to be used for loading values; must never return {@code null}
* @return a cache loader that loads values by passing each key to {@code function}
*/
public static <K, V> CacheLoader<K, V> from(Function<K, V> function) {
return new FunctionToCacheLoader<>(function);
}
/**
* Returns a cache loader based on an <i>existing</i> supplier instance. Note that there's no need
* to create a <i>new</i> supplier just to pass it in here; just subclass {@code CacheLoader} and
* implement {@link #load load} instead.
*
* @param supplier the supplier to be used for loading values; must never return {@code null}
* @return a cache loader that loads values by calling {@link Supplier#get}, irrespective of the
* key
*/
public static <V> CacheLoader<Object, V> from(Supplier<V> supplier) {
return new SupplierToCacheLoader<V>(supplier);
}
private static final class FunctionToCacheLoader<K, V> extends CacheLoader<K, V>
implements Serializable {
private final Function<K, V> computingFunction;
public FunctionToCacheLoader(Function<K, V> computingFunction) {
this.computingFunction = checkNotNull(computingFunction);
}
@Override
public V load(K key) {
return computingFunction.apply(checkNotNull(key));
}
private static final long serialVersionUID = 0;
}
/**
* Returns a {@code CacheLoader} which wraps {@code loader}, executing calls to {@link
* CacheLoader#reload} using {@code executor}.
*
* <p>This method is useful only when {@code loader.reload} has a synchronous implementation, such
* as {@linkplain #reload the default implementation}.
*
* @since 17.0
*/
@GwtIncompatible // Executor + Futures
public static <K, V> CacheLoader<K, V> asyncReloading(
final CacheLoader<K, V> loader, final Executor executor) {
checkNotNull(loader);
checkNotNull(executor);
return new CacheLoader<K, V>() {
@Override
public V load(K key) throws Exception {
return loader.load(key);
}
@Override
public ListenableFuture<V> reload(final K key, final V oldValue) throws Exception {
ListenableFutureTask<V> task =
ListenableFutureTask.create(
new Callable<V>() {
@Override
public V call() throws Exception {
return loader.reload(key, oldValue).get();
}
});
executor.execute(task);
return task;
}
@Override
public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
return loader.loadAll(keys);
}
};
}
private static final class SupplierToCacheLoader<V> extends CacheLoader<Object, V>
implements Serializable {
private final Supplier<V> computingSupplier;
public SupplierToCacheLoader(Supplier<V> computingSupplier) {
this.computingSupplier = checkNotNull(computingSupplier);
}
@Override
public V load(Object key) {
checkNotNull(key);
return computingSupplier.get();
}
private static final long serialVersionUID = 0;
}
/**
* Exception thrown by {@code loadAll()} to indicate that it is not supported.
*
* @since 19.0
*/
public static final class UnsupportedLoadingOperationException
extends UnsupportedOperationException {
// Package-private because this should only be thrown by loadAll() when it is not overridden.
// Cache implementors may want to catch it but should not need to be able to throw it.
UnsupportedLoadingOperationException() {}
}
/**
* Thrown to indicate that an invalid response was returned from a call to {@link CacheLoader}.
*
* @since 11.0
*/
public static final class InvalidCacheLoadException extends RuntimeException {
public InvalidCacheLoadException(String message) {
super(message);
}
}
}

View file

@ -0,0 +1,303 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.math.LongMath.saturatedAdd;
import static com.google.common.math.LongMath.saturatedSubtract;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import java.util.concurrent.Callable;
/**
* Statistics about the performance of a {@link Cache}. Instances of this class are immutable.
*
* <p>Cache statistics are incremented according to the following rules:
*
* <ul>
* <li>When a cache lookup encounters an existing cache entry {@code hitCount} is incremented.
* <li>When a cache lookup first encounters a missing cache entry, a new entry is loaded.
* <ul>
* <li>After successfully loading an entry {@code missCount} and {@code loadSuccessCount}
* are incremented, and the total loading time, in nanoseconds, is added to {@code
* totalLoadTime}.
* <li>When an exception is thrown while loading an entry, {@code missCount} and {@code
* loadExceptionCount} are incremented, and the total loading time, in nanoseconds, is
* added to {@code totalLoadTime}.
* <li>Cache lookups that encounter a missing cache entry that is still loading will wait
* for loading to complete (whether successful or not) and then increment {@code
* missCount}.
* </ul>
* <li>When an entry is evicted from the cache, {@code evictionCount} is incremented.
* <li>No stats are modified when a cache entry is invalidated or manually removed.
* <li>No stats are modified by operations invoked on the {@linkplain Cache#asMap asMap} view of
* the cache.
* </ul>
*
* <p>A lookup is specifically defined as an invocation of one of the methods {@link
* LoadingCache#get(Object)}, {@link LoadingCache#getUnchecked(Object)}, {@link Cache#get(Object,
* Callable)}, or {@link LoadingCache#getAll(Iterable)}.
*
* @author Charles Fry
* @since 10.0
*/
@GwtCompatible
public final class CacheStats {
private final long hitCount;
private final long missCount;
private final long loadSuccessCount;
private final long loadExceptionCount;
@SuppressWarnings("GoodTime") // should be a java.time.Duration
private final long totalLoadTime;
private final long evictionCount;
/**
* Constructs a new {@code CacheStats} instance.
*
* <p>Five parameters of the same type in a row is a bad thing, but this class is not constructed
* by end users and is too fine-grained for a builder.
*/
@SuppressWarnings("GoodTime") // should accept a java.time.Duration
public CacheStats(
long hitCount,
long missCount,
long loadSuccessCount,
long loadExceptionCount,
long totalLoadTime,
long evictionCount) {
checkArgument(hitCount >= 0);
checkArgument(missCount >= 0);
checkArgument(loadSuccessCount >= 0);
checkArgument(loadExceptionCount >= 0);
checkArgument(totalLoadTime >= 0);
checkArgument(evictionCount >= 0);
this.hitCount = hitCount;
this.missCount = missCount;
this.loadSuccessCount = loadSuccessCount;
this.loadExceptionCount = loadExceptionCount;
this.totalLoadTime = totalLoadTime;
this.evictionCount = evictionCount;
}
/**
* Returns the number of times {@link Cache} lookup methods have returned either a cached or
* uncached value. This is defined as {@code hitCount + missCount}.
*
* <p><b>Note:</b> the values of the metrics are undefined in case of overflow (though it is
* guaranteed not to throw an exception). If you require specific handling, we recommend
* implementing your own stats collector.
*/
public long requestCount() {
return saturatedAdd(hitCount, missCount);
}
/** Returns the number of times {@link Cache} lookup methods have returned a cached value. */
public long hitCount() {
return hitCount;
}
/**
* Returns the ratio of cache requests which were hits. This is defined as {@code hitCount /
* requestCount}, or {@code 1.0} when {@code requestCount == 0}. Note that {@code hitRate +
* missRate =~ 1.0}.
*/
public double hitRate() {
long requestCount = requestCount();
return (requestCount == 0) ? 1.0 : (double) hitCount / requestCount;
}
/**
* Returns the number of times {@link Cache} lookup methods have returned an uncached (newly
* loaded) value, or null. Multiple concurrent calls to {@link Cache} lookup methods on an absent
* value can result in multiple misses, all returning the results of a single cache load
* operation.
*/
public long missCount() {
return missCount;
}
/**
* Returns the ratio of cache requests which were misses. This is defined as {@code missCount /
* requestCount}, or {@code 0.0} when {@code requestCount == 0}. Note that {@code hitRate +
* missRate =~ 1.0}. Cache misses include all requests which weren't cache hits, including
* requests which resulted in either successful or failed loading attempts, and requests which
* waited for other threads to finish loading. It is thus the case that {@code missCount &gt;=
* loadSuccessCount + loadExceptionCount}. Multiple concurrent misses for the same key will result
* in a single load operation.
*/
public double missRate() {
long requestCount = requestCount();
return (requestCount == 0) ? 0.0 : (double) missCount / requestCount;
}
/**
* Returns the total number of times that {@link Cache} lookup methods attempted to load new
* values. This includes both successful load operations, as well as those that threw exceptions.
* This is defined as {@code loadSuccessCount + loadExceptionCount}.
*
* <p><b>Note:</b> the values of the metrics are undefined in case of overflow (though it is
* guaranteed not to throw an exception). If you require specific handling, we recommend
* implementing your own stats collector.
*/
public long loadCount() {
return saturatedAdd(loadSuccessCount, loadExceptionCount);
}
/**
* Returns the number of times {@link Cache} lookup methods have successfully loaded a new value.
* This is usually incremented in conjunction with {@link #missCount}, though {@code missCount} is
* also incremented when an exception is encountered during cache loading (see {@link
* #loadExceptionCount}). Multiple concurrent misses for the same key will result in a single load
* operation. This may be incremented not in conjunction with {@code missCount} if the load occurs
* as a result of a refresh or if the cache loader returned more items than was requested. {@code
* missCount} may also be incremented not in conjunction with this (nor {@link
* #loadExceptionCount}) on calls to {@code getIfPresent}.
*/
public long loadSuccessCount() {
return loadSuccessCount;
}
/**
* Returns the number of times {@link Cache} lookup methods threw an exception while loading a new
* value. This is usually incremented in conjunction with {@code missCount}, though {@code
* missCount} is also incremented when cache loading completes successfully (see {@link
* #loadSuccessCount}). Multiple concurrent misses for the same key will result in a single load
* operation. This may be incremented not in conjunction with {@code missCount} if the load occurs
* as a result of a refresh or if the cache loader returned more items than was requested. {@code
* missCount} may also be incremented not in conjunction with this (nor {@link #loadSuccessCount})
* on calls to {@code getIfPresent}.
*/
public long loadExceptionCount() {
return loadExceptionCount;
}
/**
* Returns the ratio of cache loading attempts which threw exceptions. This is defined as {@code
* loadExceptionCount / (loadSuccessCount + loadExceptionCount)}, or {@code 0.0} when {@code
* loadSuccessCount + loadExceptionCount == 0}.
*
* <p><b>Note:</b> the values of the metrics are undefined in case of overflow (though it is
* guaranteed not to throw an exception). If you require specific handling, we recommend
* implementing your own stats collector.
*/
public double loadExceptionRate() {
long totalLoadCount = saturatedAdd(loadSuccessCount, loadExceptionCount);
return (totalLoadCount == 0) ? 0.0 : (double) loadExceptionCount / totalLoadCount;
}
/**
* Returns the total number of nanoseconds the cache has spent loading new values. This can be
* used to calculate the miss penalty. This value is increased every time {@code loadSuccessCount}
* or {@code loadExceptionCount} is incremented.
*/
@SuppressWarnings("GoodTime") // should return a java.time.Duration
public long totalLoadTime() {
return totalLoadTime;
}
/**
* Returns the average time spent loading new values. This is defined as {@code totalLoadTime /
* (loadSuccessCount + loadExceptionCount)}.
*
* <p><b>Note:</b> the values of the metrics are undefined in case of overflow (though it is
* guaranteed not to throw an exception). If you require specific handling, we recommend
* implementing your own stats collector.
*/
public double averageLoadPenalty() {
long totalLoadCount = saturatedAdd(loadSuccessCount, loadExceptionCount);
return (totalLoadCount == 0) ? 0.0 : (double) totalLoadTime / totalLoadCount;
}
/**
* Returns the number of times an entry has been evicted. This count does not include manual
* {@linkplain Cache#invalidate invalidations}.
*/
public long evictionCount() {
return evictionCount;
}
/**
* Returns a new {@code CacheStats} representing the difference between this {@code CacheStats}
* and {@code other}. Negative values, which aren't supported by {@code CacheStats} will be
* rounded up to zero.
*/
public CacheStats minus(CacheStats other) {
return new CacheStats(
Math.max(0, saturatedSubtract(hitCount, other.hitCount)),
Math.max(0, saturatedSubtract(missCount, other.missCount)),
Math.max(0, saturatedSubtract(loadSuccessCount, other.loadSuccessCount)),
Math.max(0, saturatedSubtract(loadExceptionCount, other.loadExceptionCount)),
Math.max(0, saturatedSubtract(totalLoadTime, other.totalLoadTime)),
Math.max(0, saturatedSubtract(evictionCount, other.evictionCount)));
}
/**
* Returns a new {@code CacheStats} representing the sum of this {@code CacheStats} and {@code
* other}.
*
* <p><b>Note:</b> the values of the metrics are undefined in case of overflow (though it is
* guaranteed not to throw an exception). If you require specific handling, we recommend
* implementing your own stats collector.
*
* @since 11.0
*/
public CacheStats plus(CacheStats other) {
return new CacheStats(
saturatedAdd(hitCount, other.hitCount),
saturatedAdd(missCount, other.missCount),
saturatedAdd(loadSuccessCount, other.loadSuccessCount),
saturatedAdd(loadExceptionCount, other.loadExceptionCount),
saturatedAdd(totalLoadTime, other.totalLoadTime),
saturatedAdd(evictionCount, other.evictionCount));
}
@Override
public int hashCode() {
return Objects.hashCode(
hitCount, missCount, loadSuccessCount, loadExceptionCount, totalLoadTime, evictionCount);
}
@Override
public boolean equals(Object object) {
if (object instanceof CacheStats) {
CacheStats other = (CacheStats) object;
return hitCount == other.hitCount
&& missCount == other.missCount
&& loadSuccessCount == other.loadSuccessCount
&& loadExceptionCount == other.loadExceptionCount
&& totalLoadTime == other.totalLoadTime
&& evictionCount == other.evictionCount;
}
return false;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("hitCount", hitCount)
.add("missCount", missCount)
.add("loadSuccessCount", loadSuccessCount)
.add("loadExceptionCount", loadExceptionCount)
.add("totalLoadTime", totalLoadTime)
.add("evictionCount", evictionCount)
.toString();
}
}

View file

@ -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.cache;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Preconditions;
import com.google.common.collect.ForwardingObject;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
/**
* A cache which forwards all its method calls to another cache. Subclasses should override one or
* more methods to modify the behavior of the backing cache as desired per the <a
* href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
*
* @author Charles Fry
* @since 10.0
*/
@GwtIncompatible
public abstract class ForwardingCache<K, V> extends ForwardingObject implements Cache<K, V> {
/** Constructor for use by subclasses. */
protected ForwardingCache() {}
@Override
protected abstract Cache<K, V> delegate();
/** @since 11.0 */
@Override
public V getIfPresent(Object key) {
return delegate().getIfPresent(key);
}
/** @since 11.0 */
@Override
public V get(K key, Callable<? extends V> valueLoader) throws ExecutionException {
return delegate().get(key, valueLoader);
}
/** @since 11.0 */
@Override
public ImmutableMap<K, V> getAllPresent(Iterable<?> keys) {
return delegate().getAllPresent(keys);
}
/** @since 11.0 */
@Override
public void put(K key, V value) {
delegate().put(key, value);
}
/** @since 12.0 */
@Override
public void putAll(Map<? extends K, ? extends V> m) {
delegate().putAll(m);
}
@Override
public void invalidate(Object key) {
delegate().invalidate(key);
}
/** @since 11.0 */
@Override
public void invalidateAll(Iterable<?> keys) {
delegate().invalidateAll(keys);
}
@Override
public void invalidateAll() {
delegate().invalidateAll();
}
@Override
public long size() {
return delegate().size();
}
@Override
public CacheStats stats() {
return delegate().stats();
}
@Override
public ConcurrentMap<K, V> asMap() {
return delegate().asMap();
}
@Override
public void cleanUp() {
delegate().cleanUp();
}
/**
* A simplified version of {@link ForwardingCache} where subclasses can pass in an already
* constructed {@link Cache} as the delegate.
*
* @since 10.0
*/
public abstract static class SimpleForwardingCache<K, V> extends ForwardingCache<K, V> {
private final Cache<K, V> delegate;
protected SimpleForwardingCache(Cache<K, V> delegate) {
this.delegate = Preconditions.checkNotNull(delegate);
}
@Override
protected final Cache<K, V> delegate() {
return delegate;
}
}
}

View file

@ -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.cache;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import java.util.concurrent.ExecutionException;
/**
* A cache which forwards all its method calls to another cache. Subclasses should override one or
* more methods to modify the behavior of the backing cache as desired per the <a
* href="http://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>.
*
* <p>Note that {@link #get}, {@link #getUnchecked}, and {@link #apply} all expose the same
* underlying functionality, so should probably be overridden as a group.
*
* @author Charles Fry
* @since 11.0
*/
@GwtIncompatible
public abstract class ForwardingLoadingCache<K, V> extends ForwardingCache<K, V>
implements LoadingCache<K, V> {
/** Constructor for use by subclasses. */
protected ForwardingLoadingCache() {}
@Override
protected abstract LoadingCache<K, V> delegate();
@Override
public V get(K key) throws ExecutionException {
return delegate().get(key);
}
@Override
public V getUnchecked(K key) {
return delegate().getUnchecked(key);
}
@Override
public ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException {
return delegate().getAll(keys);
}
@Override
public V apply(K key) {
return delegate().apply(key);
}
@Override
public void refresh(K key) {
delegate().refresh(key);
}
/**
* A simplified version of {@link ForwardingLoadingCache} where subclasses can pass in an already
* constructed {@link LoadingCache} as the delegate.
*
* @since 10.0
*/
public abstract static class SimpleForwardingLoadingCache<K, V>
extends ForwardingLoadingCache<K, V> {
private final LoadingCache<K, V> delegate;
protected SimpleForwardingLoadingCache(LoadingCache<K, V> delegate) {
this.delegate = Preconditions.checkNotNull(delegate);
}
@Override
protected final LoadingCache<K, V> delegate() {
return delegate;
}
}
}

View file

@ -0,0 +1,160 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ExecutionError;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
/**
* A semi-persistent mapping from keys to values. Values are automatically loaded by the cache, and
* are stored in the cache until either evicted or manually invalidated. The common way to build
* instances is using {@link CacheBuilder}.
*
* <p>Implementations of this interface are expected to be thread-safe, and can be safely accessed
* by multiple concurrent threads.
*
* <p>When evaluated as a {@link Function}, a cache yields the same result as invoking {@link
* #getUnchecked}.
*
* @author Charles Fry
* @since 11.0
*/
@GwtCompatible
public interface LoadingCache<K, V> extends Cache<K, V>, Function<K, V> {
/**
* Returns the value associated with {@code key} in this cache, first loading that value if
* necessary. No observable state associated with this cache is modified until loading completes.
*
* <p>If another call to {@link #get} or {@link #getUnchecked} is currently loading the value for
* {@code key}, simply waits for that thread to finish and returns its loaded value. Note that
* multiple threads can concurrently load values for distinct keys.
*
* <p>Caches loaded by a {@link CacheLoader} will call {@link CacheLoader#load} to load new values
* into the cache. Newly loaded values are added to the cache using {@code
* Cache.asMap().putIfAbsent} after loading has completed; if another value was associated with
* {@code key} while the new value was loading then a removal notification will be sent for the
* new value.
*
* <p>If the cache loader associated with this cache is known not to throw checked exceptions,
* then prefer {@link #getUnchecked} over this method.
*
* @throws ExecutionException if a checked exception was thrown while loading the value. ({@code
* ExecutionException} is thrown <a
* href="https://github.com/google/guava/wiki/CachesExplained#interruption">even if
* computation was interrupted by an {@code InterruptedException}</a>.)
* @throws UncheckedExecutionException if an unchecked exception was thrown while loading the
* value
* @throws ExecutionError if an error was thrown while loading the value
*/
V get(K key) throws ExecutionException;
/**
* Returns the value associated with {@code key} in this cache, first loading that value if
* necessary. No observable state associated with this cache is modified until loading completes.
* Unlike {@link #get}, this method does not throw a checked exception, and thus should only be
* used in situations where checked exceptions are not thrown by the cache loader.
*
* <p>If another call to {@link #get} or {@link #getUnchecked} is currently loading the value for
* {@code key}, simply waits for that thread to finish and returns its loaded value. Note that
* multiple threads can concurrently load values for distinct keys.
*
* <p>Caches loaded by a {@link CacheLoader} will call {@link CacheLoader#load} to load new values
* into the cache. Newly loaded values are added to the cache using {@code
* Cache.asMap().putIfAbsent} after loading has completed; if another value was associated with
* {@code key} while the new value was loading then a removal notification will be sent for the
* new value.
*
* <p><b>Warning:</b> this method silently converts checked exceptions to unchecked exceptions,
* and should not be used with cache loaders which throw checked exceptions. In such cases use
* {@link #get} instead.
*
* @throws UncheckedExecutionException if an exception was thrown while loading the value. (As
* explained in the last paragraph above, this should be an unchecked exception only.)
* @throws ExecutionError if an error was thrown while loading the value
*/
V getUnchecked(K key);
/**
* Returns a map of the values associated with {@code keys}, creating or retrieving those values
* if necessary. The returned map contains entries that were already cached, combined with newly
* loaded entries; it will never contain null keys or values.
*
* <p>Caches loaded by a {@link CacheLoader} will issue a single request to {@link
* CacheLoader#loadAll} for all keys which are not already present in the cache. All entries
* returned by {@link CacheLoader#loadAll} will be stored in the cache, over-writing any
* previously cached values. This method will throw an exception if {@link CacheLoader#loadAll}
* returns {@code null}, returns a map containing null keys or values, or fails to return an entry
* for each requested key.
*
* <p>Note that duplicate elements in {@code keys}, as determined by {@link Object#equals}, will
* be ignored.
*
* @throws ExecutionException if a checked exception was thrown while loading the value. ({@code
* ExecutionException} is thrown <a
* href="https://github.com/google/guava/wiki/CachesExplained#interruption">even if
* computation was interrupted by an {@code InterruptedException}</a>.)
* @throws UncheckedExecutionException if an unchecked exception was thrown while loading the
* values
* @throws ExecutionError if an error was thrown while loading the values
* @since 11.0
*/
ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException;
/**
* @deprecated Provided to satisfy the {@code Function} interface; use {@link #get} or {@link
* #getUnchecked} instead.
* @throws UncheckedExecutionException if an exception was thrown while loading the value. (As
* described in the documentation for {@link #getUnchecked}, {@code LoadingCache} should be
* used as a {@code Function} only with cache loaders that throw only unchecked exceptions.)
*/
@Deprecated
@Override
V apply(K key);
/**
* Loads a new value for key {@code key}, possibly asynchronously. While the new value is loading
* the previous value (if any) will continue to be returned by {@code get(key)} unless it is
* evicted. If the new value is loaded successfully it will replace the previous value in the
* cache; if an exception is thrown while refreshing the previous value will remain, <i>and the
* exception will be logged (using {@link java.util.logging.Logger}) and swallowed</i>.
*
* <p>Caches loaded by a {@link CacheLoader} will call {@link CacheLoader#reload} if the cache
* currently contains a value for {@code key}, and {@link CacheLoader#load} otherwise. Loading is
* asynchronous only if {@link CacheLoader#reload} was overridden with an asynchronous
* implementation.
*
* <p>Returns without doing anything if another thread is currently loading the value for {@code
* key}. If the cache loader associated with this cache performs refresh asynchronously then this
* method may return before refresh completes.
*
* @since 11.0
*/
void refresh(K key);
/**
* {@inheritDoc}
*
* <p><b>Note that although the view <i>is</i> modifiable, no method on the returned map will ever
* cause entries to be automatically loaded.</b>
*/
@Override
ConcurrentMap<K, V> asMap();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2012 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtCompatible;
/**
* Abstract interface for objects that can concurrently add longs.
*
* @author Louis Wasserman
*/
@GwtCompatible
interface LongAddable {
void increment();
void add(long x);
long sum();
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2012 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Supplier;
import java.util.concurrent.atomic.AtomicLong;
/**
* Source of {@link LongAddable} objects that deals with GWT, Unsafe, and all that.
*
* @author Louis Wasserman
*/
@GwtCompatible(emulated = true)
final class LongAddables {
private static final Supplier<LongAddable> SUPPLIER;
static {
SUPPLIER = PureJavaLongAddable::new;
}
public static LongAddable create() {
return SUPPLIER.get();
}
private static final class PureJavaLongAddable extends AtomicLong implements LongAddable {
@Override
public void increment() {
getAndIncrement();
}
@Override
public void add(long x) {
getAndAdd(x);
}
@Override
public long sum() {
return get();
}
}
}

View file

@ -0,0 +1,111 @@
/*
* Copyright (C) 2009 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.cache.LocalCache.ValueReference;
/**
* An entry in a reference map.
*
* <p>Entries in the map can be in the following states:
*
* <p>Valid:
*
* <ul>
* <li>Live: valid key/value are set
* <li>Loading: loading is pending
* </ul>
*
* <p>Invalid:
*
* <ul>
* <li>Expired: time expired (key/value may still be set)
* <li>Collected: key/value was partially collected, but not yet cleaned up
* <li>Unset: marked as unset, awaiting cleanup or reuse
* </ul>
*/
@GwtIncompatible
interface ReferenceEntry<K, V> {
/** Returns the value reference from this entry. */
ValueReference<K, V> getValueReference();
/** Sets the value reference for this entry. */
void setValueReference(ValueReference<K, V> valueReference);
/** Returns the next entry in the chain. */
ReferenceEntry<K, V> getNext();
/** Returns the entry's hash. */
int getHash();
/** Returns the key for this entry. */
K getKey();
/*
* Used by entries that use access order. Access entries are maintained in a doubly-linked list.
* New entries are added at the tail of the list at write time; stale entries are expired from
* the head of the list.
*/
/** Returns the time that this entry was last accessed, in ns. */
@SuppressWarnings("GoodTime")
long getAccessTime();
/** Sets the entry access time in ns. */
@SuppressWarnings("GoodTime") // b/122668874
void setAccessTime(long time);
/** Returns the next entry in the access queue. */
ReferenceEntry<K, V> getNextInAccessQueue();
/** Sets the next entry in the access queue. */
void setNextInAccessQueue(ReferenceEntry<K, V> next);
/** Returns the previous entry in the access queue. */
ReferenceEntry<K, V> getPreviousInAccessQueue();
/** Sets the previous entry in the access queue. */
void setPreviousInAccessQueue(ReferenceEntry<K, V> previous);
/*
* Implemented by entries that use write order. Write entries are maintained in a doubly-linked
* list. New entries are added at the tail of the list at write time and stale entries are
* expired from the head of the list.
*/
@SuppressWarnings("GoodTime")
/** Returns the time that this entry was last written, in ns. */
long getWriteTime();
/** Sets the entry write time in ns. */
@SuppressWarnings("GoodTime") // b/122668874
void setWriteTime(long time);
/** Returns the next entry in the write queue. */
ReferenceEntry<K, V> getNextInWriteQueue();
/** Sets the next entry in the write queue. */
void setNextInWriteQueue(ReferenceEntry<K, V> next);
/** Returns the previous entry in the write queue. */
ReferenceEntry<K, V> getPreviousInWriteQueue();
/** Sets the previous entry in the write queue. */
void setPreviousInWriteQueue(ReferenceEntry<K, V> previous);
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtCompatible;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
/**
* The reason why a cached entry was removed.
*
* @author Charles Fry
* @since 10.0
*/
@GwtCompatible
public enum RemovalCause {
/**
* The entry was manually removed by the user. This can result from the user invoking {@link
* Cache#invalidate}, {@link Cache#invalidateAll(Iterable)}, {@link Cache#invalidateAll()}, {@link
* Map#remove}, {@link ConcurrentMap#remove}, or {@link Iterator#remove}.
*/
EXPLICIT {
@Override
boolean wasEvicted() {
return false;
}
},
/**
* The entry itself was not actually removed, but its value was replaced by the user. This can
* result from the user invoking {@link Cache#put}, {@link LoadingCache#refresh}, {@link Map#put},
* {@link Map#putAll}, {@link ConcurrentMap#replace(Object, Object)}, or {@link
* ConcurrentMap#replace(Object, Object, Object)}.
*/
REPLACED {
@Override
boolean wasEvicted() {
return false;
}
},
/**
* The entry was removed automatically because its key or value was garbage-collected. This can
* occur when using {@link CacheBuilder#weakKeys}, {@link CacheBuilder#weakValues}, or {@link
* CacheBuilder#softValues}.
*/
COLLECTED {
@Override
boolean wasEvicted() {
return true;
}
},
/**
* The entry's expiration timestamp has passed. This can occur when using {@link
* CacheBuilder#expireAfterWrite} or {@link CacheBuilder#expireAfterAccess}.
*/
EXPIRED {
@Override
boolean wasEvicted() {
return true;
}
},
/**
* The entry was evicted due to size constraints. This can occur when using {@link
* CacheBuilder#maximumSize} or {@link CacheBuilder#maximumWeight}.
*/
SIZE {
@Override
boolean wasEvicted() {
return true;
}
};
/**
* Returns {@code true} if there was an automatic removal due to eviction (the cause is neither
* {@link #EXPLICIT} nor {@link #REPLACED}).
*/
abstract boolean wasEvicted();
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtCompatible;
/**
* An object that can receive a notification when an entry is removed from a cache. The removal
* resulting in notification could have occurred to an entry being manually removed or replaced, or
* due to eviction resulting from timed expiration, exceeding a maximum size, or garbage collection.
*
* <p>An instance may be called concurrently by multiple threads to process different entries.
* Implementations of this interface should avoid performing blocking calls or synchronizing on
* shared resources.
*
* @param <K> the most general type of keys this listener can listen for; for example {@code Object}
* if any key is acceptable
* @param <V> the most general type of values this listener can listen for; for example {@code
* Object} if any key is acceptable
* @author Charles Fry
* @since 10.0
*/
@GwtCompatible
@FunctionalInterface
public interface RemovalListener<K, V> {
/**
* Notifies the listener that a removal occurred at some point in the past.
*
* <p>This does not always signify that the key is now absent from the cache, as it may have
* already been re-added.
*/
// Technically should accept RemovalNotification<? extends K, ? extends V>, but because
// RemovalNotification is guaranteed covariant, let's make users' lives simpler.
void onRemoval(RemovalNotification<K, V> notification);
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtIncompatible;
import java.util.concurrent.Executor;
/**
* A collection of common removal listeners.
*
* @author Charles Fry
* @since 10.0
*/
@GwtIncompatible
public final class RemovalListeners {
private RemovalListeners() {}
/**
* Returns a {@code RemovalListener} which processes all eviction notifications using {@code
* executor}.
*
* @param listener the backing listener
* @param executor the executor with which removal notifications are asynchronously executed
*/
public static <K, V> RemovalListener<K, V> asynchronous(
final RemovalListener<K, V> listener, final Executor executor) {
checkNotNull(listener);
checkNotNull(executor);
return new RemovalListener<K, V>() {
@Override
public void onRemoval(final RemovalNotification<K, V> notification) {
executor.execute(
new Runnable() {
@Override
public void run() {
listener.onRemoval(notification);
}
});
}
};
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import java.util.AbstractMap.SimpleImmutableEntry;
/**
* A notification of the removal of a single entry. The key and/or value may be null if they were
* already garbage collected.
*
* <p>Like other {@code Entry} instances associated with {@code CacheBuilder}, this class holds
* strong references to the key and value, regardless of the type of references the cache may be
* using.
*
* @author Charles Fry
* @since 10.0
*/
@GwtCompatible
public final class RemovalNotification<K, V> extends SimpleImmutableEntry<K, V> {
private final RemovalCause cause;
/**
* Creates a new {@code RemovalNotification} for the given {@code key}/{@code value} pair, with
* the given {@code cause} for the removal. The {@code key} and/or {@code value} may be {@code
* null} if they were already garbage collected.
*
* @since 19.0
*/
public static <K, V> RemovalNotification<K, V> create(
K key, V value, RemovalCause cause) {
return new RemovalNotification(key, value, cause);
}
private RemovalNotification(K key, V value, RemovalCause cause) {
super(key, value);
this.cause = checkNotNull(cause);
}
/** Returns the cause for which the entry was removed. */
public RemovalCause getCause() {
return cause;
}
/**
* Returns {@code true} if there was an automatic removal due to eviction (the cause is neither
* {@link RemovalCause#EXPLICIT} nor {@link RemovalCause#REPLACED}).
*/
public boolean wasEvicted() {
return cause.wasEvicted();
}
private static final long serialVersionUID = 0;
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.cache;
import com.google.common.annotations.GwtCompatible;
/**
* Calculates the weights of cache entries.
*
* @author Charles Fry
* @since 11.0
*/
@GwtCompatible
@FunctionalInterface
public interface Weigher<K, V> {
/**
* Returns the weight of a cache entry. There is no unit for entry weights; rather they are simply
* relative to each other.
*
* @return the weight of the entry; must be non-negative
*/
int weigh(K key, V value);
}

View file

@ -0,0 +1,485 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.CollectPreconditions.checkRemove;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Objects;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
/**
* A general-purpose bimap implementation using any two backing {@code Map} instances.
*
* <p>Note that this class contains {@code equals()} calls that keep it from supporting {@code
* IdentityHashMap} backing maps.
*
* @author Kevin Bourrillion
* @author Mike Bostock
*/
@GwtCompatible(emulated = true)
abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
implements BiMap<K, V>, Serializable {
private transient Map<K, V> delegate;
transient AbstractBiMap<V, K> inverse;
/** Package-private constructor for creating a map-backed bimap. */
AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
setDelegates(forward, backward);
}
/** Private constructor for inverse bimap. */
private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) {
delegate = backward;
inverse = forward;
}
@Override
protected Map<K, V> delegate() {
return delegate;
}
/** Returns its input, or throws an exception if this is not a valid key. */
K checkKey(K key) {
return key;
}
/** Returns its input, or throws an exception if this is not a valid value. */
V checkValue(V value) {
return value;
}
/**
* Specifies the delegate maps going in each direction. Called by the constructor and by
* subclasses during deserialization.
*/
void setDelegates(Map<K, V> forward, Map<V, K> backward) {
checkState(delegate == null);
checkState(inverse == null);
checkArgument(forward.isEmpty());
checkArgument(backward.isEmpty());
checkArgument(forward != backward);
delegate = forward;
inverse = makeInverse(backward);
}
AbstractBiMap<V, K> makeInverse(Map<V, K> backward) {
return new Inverse<>(backward, this);
}
void setInverse(AbstractBiMap<V, K> inverse) {
this.inverse = inverse;
}
// Query Operations (optimizations)
@Override
public boolean containsValue(Object value) {
return inverse.containsKey(value);
}
// Modification Operations
@Override
public V put(K key, V value) {
return putInBothMaps(key, value, false);
}
@Override
public V forcePut(K key, V value) {
return putInBothMaps(key, value, true);
}
private V putInBothMaps(K key, V value, boolean force) {
checkKey(key);
checkValue(value);
boolean containedKey = containsKey(key);
if (containedKey && Objects.equal(value, get(key))) {
return value;
}
if (force) {
inverse().remove(value);
} else {
checkArgument(!containsValue(value), "value already present: %s", value);
}
V oldValue = delegate.put(key, value);
updateInverseMap(key, containedKey, oldValue, value);
return oldValue;
}
private void updateInverseMap(K key, boolean containedKey, V oldValue, V newValue) {
if (containedKey) {
removeFromInverseMap(oldValue);
}
inverse.delegate.put(newValue, key);
}
@Override
public V remove(Object key) {
return containsKey(key) ? removeFromBothMaps(key) : null;
}
private V removeFromBothMaps(Object key) {
V oldValue = delegate.remove(key);
removeFromInverseMap(oldValue);
return oldValue;
}
private void removeFromInverseMap(V oldValue) {
inverse.delegate.remove(oldValue);
}
// Bulk Operations
@Override
public void putAll(Map<? extends K, ? extends V> map) {
for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
this.delegate.replaceAll(function);
inverse.delegate.clear();
Entry<K, V> broken = null;
Iterator<Entry<K, V>> itr = this.delegate.entrySet().iterator();
while (itr.hasNext()) {
Entry<K, V> entry = itr.next();
K k = entry.getKey();
V v = entry.getValue();
K conflict = inverse.delegate.putIfAbsent(v, k);
if (conflict != null) {
broken = entry;
// We're definitely going to throw, but we'll try to keep the BiMap in an internally
// consistent state by removing the bad entry.
itr.remove();
}
}
if (broken != null) {
throw new IllegalArgumentException("value already present: " + broken.getValue());
}
}
@Override
public void clear() {
delegate.clear();
inverse.delegate.clear();
}
// Views
@Override
public BiMap<V, K> inverse() {
return inverse;
}
private transient Set<K> keySet;
@Override
public Set<K> keySet() {
Set<K> result = keySet;
return (result == null) ? keySet = new KeySet() : result;
}
private class KeySet extends ForwardingSet<K> {
@Override
protected Set<K> delegate() {
return delegate.keySet();
}
@Override
public void clear() {
AbstractBiMap.this.clear();
}
@Override
public boolean remove(Object key) {
if (!contains(key)) {
return false;
}
removeFromBothMaps(key);
return true;
}
@Override
public boolean removeAll(Collection<?> keysToRemove) {
return standardRemoveAll(keysToRemove);
}
@Override
public boolean retainAll(Collection<?> keysToRetain) {
return standardRetainAll(keysToRetain);
}
@Override
public Iterator<K> iterator() {
return Maps.keyIterator(entrySet().iterator());
}
}
private transient Set<V> valueSet;
@Override
public Set<V> values() {
/*
* We can almost reuse the inverse's keySet, except we have to fix the
* iteration order so that it is consistent with the forward map.
*/
Set<V> result = valueSet;
return (result == null) ? valueSet = new ValueSet() : result;
}
private class ValueSet extends ForwardingSet<V> {
final Set<V> valuesDelegate = inverse.keySet();
@Override
protected Set<V> delegate() {
return valuesDelegate;
}
@Override
public Iterator<V> iterator() {
return Maps.valueIterator(entrySet().iterator());
}
@Override
public Object[] toArray() {
return standardToArray();
}
@Override
public <T> T[] toArray(T[] array) {
return standardToArray(array);
}
@Override
public String toString() {
return standardToString();
}
}
private transient Set<Entry<K, V>> entrySet;
@Override
public Set<Entry<K, V>> entrySet() {
Set<Entry<K, V>> result = entrySet;
return (result == null) ? entrySet = new EntrySet() : result;
}
class BiMapEntry extends ForwardingMapEntry<K, V> {
private final Entry<K, V> delegate;
BiMapEntry(Entry<K, V> delegate) {
this.delegate = delegate;
}
@Override
protected Entry<K, V> delegate() {
return delegate;
}
@Override
public V setValue(V value) {
checkValue(value);
// Preconditions keep the map and inverse consistent.
checkState(entrySet().contains(this), "entry no longer in map");
// similar to putInBothMaps, but set via entry
if (Objects.equal(value, getValue())) {
return value;
}
checkArgument(!containsValue(value), "value already present: %s", value);
V oldValue = delegate.setValue(value);
checkState(Objects.equal(value, get(getKey())), "entry no longer in map");
updateInverseMap(getKey(), true, oldValue, value);
return oldValue;
}
}
Iterator<Entry<K, V>> entrySetIterator() {
final Iterator<Entry<K, V>> iterator = delegate.entrySet().iterator();
return new Iterator<Entry<K, V>>() {
Entry<K, V> entry;
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Entry<K, V> next() {
entry = iterator.next();
return new BiMapEntry(entry);
}
@Override
public void remove() {
checkRemove(entry != null);
V value = entry.getValue();
iterator.remove();
removeFromInverseMap(value);
entry = null;
}
};
}
private class EntrySet extends ForwardingSet<Entry<K, V>> {
final Set<Entry<K, V>> esDelegate = delegate.entrySet();
@Override
protected Set<Entry<K, V>> delegate() {
return esDelegate;
}
@Override
public void clear() {
AbstractBiMap.this.clear();
}
@Override
public boolean remove(Object object) {
if (!esDelegate.contains(object)) {
return false;
}
// safe because esDelegate.contains(object).
Entry<?, ?> entry = (Entry<?, ?>) object;
inverse.delegate.remove(entry.getValue());
/*
* Remove the mapping in inverse before removing from esDelegate because
* if entry is part of esDelegate, entry might be invalidated after the
* mapping is removed from esDelegate.
*/
esDelegate.remove(entry);
return true;
}
@Override
public Iterator<Entry<K, V>> iterator() {
return entrySetIterator();
}
// See java.util.Collections.CheckedEntrySet for details on attacks.
@Override
public Object[] toArray() {
return standardToArray();
}
@Override
public <T> T[] toArray(T[] array) {
return standardToArray(array);
}
@Override
public boolean contains(Object o) {
return Maps.containsEntryImpl(delegate(), o);
}
@Override
public boolean containsAll(Collection<?> c) {
return standardContainsAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return standardRemoveAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return standardRetainAll(c);
}
}
/** The inverse of any other {@code AbstractBiMap} subclass. */
static class Inverse<K, V> extends AbstractBiMap<K, V> {
Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) {
super(backward, forward);
}
/*
* Serialization stores the forward bimap, the inverse of this inverse.
* Deserialization calls inverse() on the forward bimap and returns that
* inverse.
*
* If a bimap and its inverse are serialized together, the deserialized
* instances have inverse() methods that return the other.
*/
@Override
K checkKey(K key) {
return inverse.checkValue(key);
}
@Override
V checkValue(V value) {
return inverse.checkKey(value);
}
/** @serialData the forward bimap */
@GwtIncompatible // java.io.ObjectOutputStream
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
stream.writeObject(inverse());
}
@GwtIncompatible // java.io.ObjectInputStream
@SuppressWarnings("unchecked") // reading data stored by writeObject
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
setInverse((AbstractBiMap<V, K>) stream.readObject());
}
@GwtIncompatible // Not needed in the emulated source.
Object readResolve() {
return inverse().inverse();
}
@GwtIncompatible // Not needed in emulated source.
private static final long serialVersionUID = 0;
}
@GwtIncompatible // Not needed in emulated source.
private static final long serialVersionUID = 0;
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (C) 2009 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkPositionIndex;
import com.google.common.annotations.GwtCompatible;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**
* This class provides a skeletal implementation of the {@link ListIterator} interface across a
* fixed number of elements that may be retrieved by position. It does not support {@link #remove},
* {@link #set}, or {@link #add}.
*
* @author Jared Levy
*/
@GwtCompatible
abstract class AbstractIndexedListIterator<E> extends UnmodifiableListIterator<E> {
private final int size;
private int position;
/** Returns the element with the specified index. This method is called by {@link #next()}. */
protected abstract E get(int index);
/**
* Constructs an iterator across a sequence of the given size whose initial position is 0. That
* is, the first call to {@link #next()} will return the first element (or throw {@link
* NoSuchElementException} if {@code size} is zero).
*
* @throws IllegalArgumentException if {@code size} is negative
*/
protected AbstractIndexedListIterator(int size) {
this(size, 0);
}
/**
* Constructs an iterator across a sequence of the given size with the given initial position.
* That is, the first call to {@link #nextIndex()} will return {@code position}, and the first
* call to {@link #next()} will return the element at that index, if available. Calls to {@link
* #previous()} can retrieve the preceding {@code position} elements.
*
* @throws IndexOutOfBoundsException if {@code position} is negative or is greater than {@code
* size}
* @throws IllegalArgumentException if {@code size} is negative
*/
protected AbstractIndexedListIterator(int size, int position) {
checkPositionIndex(position, size);
this.size = size;
this.position = position;
}
@Override
public final boolean hasNext() {
return position < size;
}
@Override
public final E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return get(position++);
}
@Override
public final int nextIndex() {
return position;
}
@Override
public final boolean hasPrevious() {
return position > 0;
}
@Override
public final E previous() {
if (!hasPrevious()) {
throw new NoSuchElementException();
}
return get(--position);
}
@Override
public final int previousIndex() {
return position - 1;
}
}

View file

@ -0,0 +1,174 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkState;
import com.google.common.annotations.GwtCompatible;
import java.util.NoSuchElementException;
/**
* This class provides a skeletal implementation of the {@code Iterator} interface, to make this
* interface easier to implement for certain types of data sources.
*
* <p>{@code Iterator} requires its implementations to support querying the end-of-data status
* without changing the iterator's state, using the {@link #hasNext} method. But many data sources,
* such as {@link java.io.Reader#read()}, do not expose this information; the only way to discover
* whether there is any data left is by trying to retrieve it. These types of data sources are
* ordinarily difficult to write iterators for. But using this class, one must implement only the
* {@link #computeNext} method, and invoke the {@link #endOfData} method when appropriate.
*
* <p>Another example is an iterator that skips over null elements in a backing iterator. This could
* be implemented as:
*
* <pre>{@code
* public static Iterator<String> skipNulls(final Iterator<String> in) {
* return new AbstractIterator<String>() {
* protected String computeNext() {
* while (in.hasNext()) {
* String s = in.next();
* if (s != null) {
* return s;
* }
* }
* return endOfData();
* }
* };
* }
* }</pre>
*
* <p>This class supports iterators that include null elements.
*
* @author Kevin Bourrillion
* @since 2.0
*/
// When making changes to this class, please also update the copy at
// com.google.common.base.AbstractIterator
@GwtCompatible
public abstract class AbstractIterator<T> extends UnmodifiableIterator<T> {
private State state = State.NOT_READY;
/** Constructor for use by subclasses. */
protected AbstractIterator() {}
private enum State {
/** We have computed the next element and haven't returned it yet. */
READY,
/** We haven't yet computed or have already returned the element. */
NOT_READY,
/** We have reached the end of the data and are finished. */
DONE,
/** We've suffered an exception and are kaput. */
FAILED,
}
private T next;
/**
* Returns the next element. <b>Note:</b> the implementation must call {@link #endOfData()} when
* there are no elements left in the iteration. Failure to do so could result in an infinite loop.
*
* <p>The initial invocation of {@link #hasNext()} or {@link #next()} calls this method, as does
* the first invocation of {@code hasNext} or {@code next} following each successful call to
* {@code next}. Once the implementation either invokes {@code endOfData} or throws an exception,
* {@code computeNext} is guaranteed to never be called again.
*
* <p>If this method throws an exception, it will propagate outward to the {@code hasNext} or
* {@code next} invocation that invoked this method. Any further attempts to use the iterator will
* result in an {@link IllegalStateException}.
*
* <p>The implementation of this method may not invoke the {@code hasNext}, {@code next}, or
* {@link #peek()} methods on this instance; if it does, an {@code IllegalStateException} will
* result.
*
* @return the next element if there was one. If {@code endOfData} was called during execution,
* the return value will be ignored.
* @throws RuntimeException if any unrecoverable error happens. This exception will propagate
* outward to the {@code hasNext()}, {@code next()}, or {@code peek()} invocation that invoked
* this method. Any further attempts to use the iterator will result in an {@link
* IllegalStateException}.
*/
protected abstract T computeNext();
/**
* Implementations of {@link #computeNext} <b>must</b> invoke this method when there are no
* elements left in the iteration.
*
* @return {@code null}; a convenience so your {@code computeNext} implementation can use the
* simple statement {@code return endOfData();}
*/
protected final T endOfData() {
state = State.DONE;
return null;
}
// TODO(kak): Should we remove this? Some people are using it to prefetch?
@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;
}
// TODO(kak): Should we remove this?
@Override
public final T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
state = State.NOT_READY;
T result = next;
next = null;
return result;
}
/**
* Returns the next element in the iteration without advancing the iteration, according to the
* contract of {@link PeekingIterator#peek()}.
*
* <p>Implementations of {@code AbstractIterator} that wish to expose this functionality should
* implement {@code PeekingIterator}.
*/
public final T peek() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return next;
}
}

View file

@ -0,0 +1,141 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Basic implementation of the {@link ListMultimap} interface. It's a wrapper around {@link
* AbstractMapBasedMultimap} that converts the returned collections into {@code Lists}. The {@link
* #createCollection} method must return a {@code List}.
*
* @author Jared Levy
* @since 2.0
*/
@GwtCompatible
abstract class AbstractListMultimap<K, V> extends AbstractMapBasedMultimap<K, V>
implements ListMultimap<K, V> {
/**
* Creates a new multimap that uses the provided map.
*
* @param map place to store the mapping from each key to its corresponding values
*/
protected AbstractListMultimap(Map<K, Collection<V>> map) {
super(map);
}
@Override
abstract List<V> createCollection();
@Override
List<V> createUnmodifiableEmptyCollection() {
return Collections.emptyList();
}
@Override
<E> Collection<E> unmodifiableCollectionSubclass(Collection<E> collection) {
return Collections.unmodifiableList((List<E>) collection);
}
@Override
Collection<V> wrapCollection(K key, Collection<V> collection) {
return wrapList(key, (List<V>) collection, null);
}
// Following Javadoc copied from ListMultimap.
/**
* {@inheritDoc}
*
* <p>Because the values for a given key may have duplicates and follow the insertion ordering,
* this method returns a {@link List}, instead of the {@link Collection} specified in the {@link
* Multimap} interface.
*/
@Override
public List<V> get(K key) {
return (List<V>) super.get(key);
}
/**
* {@inheritDoc}
*
* <p>Because the values for a given key may have duplicates and follow the insertion ordering,
* this method returns a {@link List}, instead of the {@link Collection} specified in the {@link
* Multimap} interface.
*/
@Override
public List<V> removeAll(Object key) {
return (List<V>) super.removeAll(key);
}
/**
* {@inheritDoc}
*
* <p>Because the values for a given key may have duplicates and follow the insertion ordering,
* this method returns a {@link List}, instead of the {@link Collection} specified in the {@link
* Multimap} interface.
*/
@Override
public List<V> replaceValues(K key, Iterable<? extends V> values) {
return (List<V>) super.replaceValues(key, values);
}
/**
* Stores a key-value pair in the multimap.
*
* @param key key to store in the multimap
* @param value value to store in the multimap
* @return {@code true} always
*/
@Override
public boolean put(K key, V value) {
return super.put(key, value);
}
/**
* {@inheritDoc}
*
* <p>Though the method signature doesn't say so explicitly, the returned map has {@link List}
* values.
*/
@Override
public Map<K, Collection<V>> asMap() {
return super.asMap();
}
/**
* Compares the specified object to this multimap for equality.
*
* <p>Two {@code ListMultimap} instances are equal if, for each key, they contain the same values
* in the same order. If the value orderings disagree, the multimaps will not be considered equal.
*/
@Override
public boolean equals(Object object) {
return super.equals(object);
}
private static final long serialVersionUID = 6588350623831699109L;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,338 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
import static com.google.common.collect.CollectPreconditions.checkRemove;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.primitives.Ints;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.ObjIntConsumer;
/**
* Basic implementation of {@code Multiset<E>} backed by an instance of {@code Map<E, Count>}.
*
* <p>For serialization to work, the subclass must specify explicit {@code readObject} and {@code
* writeObject} methods.
*
* @author Kevin Bourrillion
*/
@GwtCompatible(emulated = true)
abstract class AbstractMapBasedMultiset<E> extends AbstractMultiset<E> implements Serializable {
// TODO(lowasser): consider overhauling this back to Map<E, Integer>
private transient Map<E, Count> backingMap;
/*
* Cache the size for efficiency. Using a long lets us avoid the need for
* overflow checking and ensures that size() will function correctly even if
* the multiset had once been larger than Integer.MAX_VALUE.
*/
private transient long size;
/** Standard constructor. */
protected AbstractMapBasedMultiset(Map<E, Count> backingMap) {
checkArgument(backingMap.isEmpty());
this.backingMap = backingMap;
}
/** Used during deserialization only. The backing map must be empty. */
void setBackingMap(Map<E, Count> backingMap) {
this.backingMap = backingMap;
}
// Required Implementations
/**
* {@inheritDoc}
*
* <p>Invoking {@link Multiset.Entry#getCount} on an entry in the returned set always returns the
* current count of that element in the multiset, as opposed to the count at the time the entry
* was retrieved.
*/
@Override
public Set<Multiset.Entry<E>> entrySet() {
return super.entrySet();
}
@Override
Iterator<E> elementIterator() {
final Iterator<Map.Entry<E, Count>> backingEntries = backingMap.entrySet().iterator();
return new Iterator<E>() {
Map.Entry<E, Count> toRemove;
@Override
public boolean hasNext() {
return backingEntries.hasNext();
}
@Override
public E next() {
final Map.Entry<E, Count> mapEntry = backingEntries.next();
toRemove = mapEntry;
return mapEntry.getKey();
}
@Override
public void remove() {
checkRemove(toRemove != null);
size -= toRemove.getValue().getAndSet(0);
backingEntries.remove();
toRemove = null;
}
};
}
@Override
Iterator<Entry<E>> entryIterator() {
final Iterator<Map.Entry<E, Count>> backingEntries = backingMap.entrySet().iterator();
return new Iterator<Multiset.Entry<E>>() {
Map.Entry<E, Count> toRemove;
@Override
public boolean hasNext() {
return backingEntries.hasNext();
}
@Override
public Multiset.Entry<E> next() {
final Map.Entry<E, Count> mapEntry = backingEntries.next();
toRemove = mapEntry;
return new Multisets.AbstractEntry<E>() {
@Override
public E getElement() {
return mapEntry.getKey();
}
@Override
public int getCount() {
Count count = mapEntry.getValue();
if (count == null || count.get() == 0) {
Count frequency = backingMap.get(getElement());
if (frequency != null) {
return frequency.get();
}
}
return (count == null) ? 0 : count.get();
}
};
}
@Override
public void remove() {
checkRemove(toRemove != null);
size -= toRemove.getValue().getAndSet(0);
backingEntries.remove();
toRemove = null;
}
};
}
@Override
public void forEachEntry(ObjIntConsumer<? super E> action) {
checkNotNull(action);
backingMap.forEach((element, count) -> action.accept(element, count.get()));
}
@Override
public void clear() {
for (Count frequency : backingMap.values()) {
frequency.set(0);
}
backingMap.clear();
size = 0L;
}
@Override
int distinctElements() {
return backingMap.size();
}
// Optimizations - Query Operations
@Override
public int size() {
return Ints.saturatedCast(size);
}
@Override
public Iterator<E> iterator() {
return new MapBasedMultisetIterator();
}
/*
* Not subclassing AbstractMultiset$MultisetIterator because next() needs to
* retrieve the Map.Entry<E, Count> entry, which can then be used for
* a more efficient remove() call.
*/
private class MapBasedMultisetIterator implements Iterator<E> {
final Iterator<Map.Entry<E, Count>> entryIterator;
Map.Entry<E, Count> currentEntry;
int occurrencesLeft;
boolean canRemove;
MapBasedMultisetIterator() {
this.entryIterator = backingMap.entrySet().iterator();
}
@Override
public boolean hasNext() {
return occurrencesLeft > 0 || entryIterator.hasNext();
}
@Override
public E next() {
if (occurrencesLeft == 0) {
currentEntry = entryIterator.next();
occurrencesLeft = currentEntry.getValue().get();
}
occurrencesLeft--;
canRemove = true;
return currentEntry.getKey();
}
@Override
public void remove() {
checkRemove(canRemove);
int frequency = currentEntry.getValue().get();
if (frequency <= 0) {
throw new ConcurrentModificationException();
}
if (currentEntry.getValue().addAndGet(-1) == 0) {
entryIterator.remove();
}
size--;
canRemove = false;
}
}
@Override
public int count(Object element) {
Count frequency = Maps.safeGet(backingMap, element);
return (frequency == null) ? 0 : frequency.get();
}
// Optional Operations - Modification Operations
/**
* {@inheritDoc}
*
* @throws IllegalArgumentException if the call would result in more than {@link
* Integer#MAX_VALUE} occurrences of {@code element} in this multiset.
*/
@Override
public int add(E element, int occurrences) {
if (occurrences == 0) {
return count(element);
}
checkArgument(occurrences > 0, "occurrences cannot be negative: %s", occurrences);
Count frequency = backingMap.get(element);
int oldCount;
if (frequency == null) {
oldCount = 0;
backingMap.put(element, new Count(occurrences));
} else {
oldCount = frequency.get();
long newCount = (long) oldCount + (long) occurrences;
checkArgument(newCount <= Integer.MAX_VALUE, "too many occurrences: %s", newCount);
frequency.add(occurrences);
}
size += occurrences;
return oldCount;
}
@Override
public int remove(Object element, int occurrences) {
if (occurrences == 0) {
return count(element);
}
checkArgument(occurrences > 0, "occurrences cannot be negative: %s", occurrences);
Count frequency = backingMap.get(element);
if (frequency == null) {
return 0;
}
int oldCount = frequency.get();
int numberRemoved;
if (oldCount > occurrences) {
numberRemoved = occurrences;
} else {
numberRemoved = oldCount;
backingMap.remove(element);
}
frequency.add(-numberRemoved);
size -= numberRemoved;
return oldCount;
}
// Roughly a 33% performance improvement over AbstractMultiset.setCount().
@Override
public int setCount(E element, int count) {
checkNonnegative(count, "count");
Count existingCounter;
int oldCount;
if (count == 0) {
existingCounter = backingMap.remove(element);
oldCount = getAndSet(existingCounter, count);
} else {
existingCounter = backingMap.get(element);
oldCount = getAndSet(existingCounter, count);
if (existingCounter == null) {
backingMap.put(element, new Count(count));
}
}
size += (count - oldCount);
return oldCount;
}
private static int getAndSet(Count i, int count) {
if (i == null) {
return 0;
}
return i.getAndSet(count);
}
// Don't allow default serialization.
@GwtIncompatible // java.io.ObjectStreamException
private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("Stream data required");
}
@GwtIncompatible // not needed in emulated source.
private static final long serialVersionUID = -2250766705698539974L;
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Objects;
import java.util.Map.Entry;
/**
* Implementation of the {@code equals}, {@code hashCode}, and {@code toString} methods of {@code
* Entry}.
*
* @author Jared Levy
*/
@GwtCompatible
abstract class AbstractMapEntry<K, V> implements Entry<K, V> {
@Override
public abstract K getKey();
@Override
public abstract V getValue();
@Override
public V setValue(V value) {
throw new UnsupportedOperationException();
}
@Override
public boolean equals(Object object) {
if (object instanceof Entry) {
Entry<?, ?> that = (Entry<?, ?>) object;
return Objects.equal(this.getKey(), that.getKey())
&& Objects.equal(this.getValue(), that.getValue());
}
return false;
}
@Override
public int hashCode() {
K k = getKey();
V v = getValue();
return ((k == null) ? 0 : k.hashCode()) ^ ((v == null) ? 0 : v.hashCode());
}
/** Returns a string representation of the form {@code {key}={value}}. */
@Override
public String toString() {
return getKey() + "=" + getValue();
}
}

View file

@ -0,0 +1,265 @@
/*
* Copyright (C) 2012 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
/**
* A skeleton {@code Multimap} implementation, not necessarily in terms of a {@code Map}.
*
* @author Louis Wasserman
*/
@GwtCompatible
abstract class AbstractMultimap<K, V> implements Multimap<K, V> {
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public boolean containsValue(Object value) {
for (Collection<V> collection : asMap().values()) {
if (collection.contains(value)) {
return true;
}
}
return false;
}
@Override
public boolean containsEntry(Object key, Object value) {
Collection<V> collection = asMap().get(key);
return collection != null && collection.contains(value);
}
@Override
public boolean remove(Object key, Object value) {
Collection<V> collection = asMap().get(key);
return collection != null && collection.remove(value);
}
@Override
public boolean put(K key, V value) {
return get(key).add(value);
}
@Override
public boolean putAll(K key, Iterable<? extends V> values) {
checkNotNull(values);
// make sure we only call values.iterator() once
// and we only call get(key) if values is nonempty
if (values instanceof Collection) {
Collection<? extends V> valueCollection = (Collection<? extends V>) values;
return !valueCollection.isEmpty() && get(key).addAll(valueCollection);
} else {
Iterator<? extends V> valueItr = values.iterator();
return valueItr.hasNext() && Iterators.addAll(get(key), valueItr);
}
}
@Override
public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
boolean changed = false;
for (Entry<? extends K, ? extends V> entry : multimap.entries()) {
changed |= put(entry.getKey(), entry.getValue());
}
return changed;
}
@Override
public Collection<V> replaceValues(K key, Iterable<? extends V> values) {
checkNotNull(values);
Collection<V> result = removeAll(key);
putAll(key, values);
return result;
}
private transient Collection<Entry<K, V>> entries;
@Override
public Collection<Entry<K, V>> entries() {
Collection<Entry<K, V>> result = entries;
return (result == null) ? entries = createEntries() : result;
}
abstract Collection<Entry<K, V>> createEntries();
class Entries extends Multimaps.Entries<K, V> {
@Override
Multimap<K, V> multimap() {
return AbstractMultimap.this;
}
@Override
public Iterator<Entry<K, V>> iterator() {
return entryIterator();
}
@Override
public Spliterator<Entry<K, V>> spliterator() {
return entrySpliterator();
}
}
class EntrySet extends Entries implements Set<Entry<K, V>> {
@Override
public int hashCode() {
return Sets.hashCodeImpl(this);
}
@Override
public boolean equals(Object obj) {
return Sets.equalsImpl(this, obj);
}
}
abstract Iterator<Entry<K, V>> entryIterator();
Spliterator<Entry<K, V>> entrySpliterator() {
return Spliterators.spliterator(
entryIterator(), size(), (this instanceof SetMultimap) ? Spliterator.DISTINCT : 0);
}
private transient Set<K> keySet;
@Override
public Set<K> keySet() {
Set<K> result = keySet;
return (result == null) ? keySet = createKeySet() : result;
}
abstract Set<K> createKeySet();
private transient Multiset<K> keys;
@Override
public Multiset<K> keys() {
Multiset<K> result = keys;
return (result == null) ? keys = createKeys() : result;
}
abstract Multiset<K> createKeys();
private transient Collection<V> values;
@Override
public Collection<V> values() {
Collection<V> result = values;
return (result == null) ? values = createValues() : result;
}
abstract Collection<V> createValues();
class Values extends AbstractCollection<V> {
@Override
public Iterator<V> iterator() {
return valueIterator();
}
@Override
public Spliterator<V> spliterator() {
return valueSpliterator();
}
@Override
public int size() {
return AbstractMultimap.this.size();
}
@Override
public boolean contains(Object o) {
return AbstractMultimap.this.containsValue(o);
}
@Override
public void clear() {
AbstractMultimap.this.clear();
}
}
Iterator<V> valueIterator() {
return Maps.valueIterator(entries().iterator());
}
Spliterator<V> valueSpliterator() {
return Spliterators.spliterator(valueIterator(), size(), 0);
}
private transient Map<K, Collection<V>> asMap;
@Override
public Map<K, Collection<V>> asMap() {
Map<K, Collection<V>> result = asMap;
return (result == null) ? asMap = createAsMap() : result;
}
abstract Map<K, Collection<V>> createAsMap();
// Comparison and hashing
@Override
public boolean equals(Object object) {
return Multimaps.equalsImpl(this, object);
}
/**
* Returns the hash code for this multimap.
*
* <p>The hash code of a multimap is defined as the hash code of the map view, as returned by
* {@link Multimap#asMap}.
*
* @see Map#hashCode
*/
@Override
public int hashCode() {
return asMap().hashCode();
}
/**
* Returns a string representation of the multimap, generated by calling {@code toString} on the
* map returned by {@link Multimap#asMap}.
*
* @return a string representation of the multimap
*/
@Override
public String toString() {
return asMap().toString();
}
}

View file

@ -0,0 +1,232 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import static com.google.common.collect.Multisets.setCountImpl;
import com.google.common.annotations.GwtCompatible;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
/**
* This class provides a skeletal implementation of the {@link Multiset} interface. A new multiset
* implementation can be created easily by extending this class and implementing the {@link
* Multiset#entrySet()} method, plus optionally overriding {@link #add(Object, int)} and {@link
* #remove(Object, int)} to enable modifications to the multiset.
*
* <p>The {@link #count} and {@link #size} implementations all iterate across the set returned by
* {@link Multiset#entrySet()}, as do many methods acting on the set returned by {@link
* #elementSet()}. Override those methods for better performance.
*
* @author Kevin Bourrillion
* @author Louis Wasserman
*/
@GwtCompatible
abstract class AbstractMultiset<E> extends AbstractCollection<E> implements Multiset<E> {
// Query Operations
@Override
public boolean isEmpty() {
return entrySet().isEmpty();
}
@Override
public boolean contains(Object element) {
return count(element) > 0;
}
// Modification Operations
@Override
public final boolean add(E element) {
add(element, 1);
return true;
}
@Override
public int add(E element, int occurrences) {
throw new UnsupportedOperationException();
}
@Override
public final boolean remove(Object element) {
return remove(element, 1) > 0;
}
@Override
public int remove(Object element, int occurrences) {
throw new UnsupportedOperationException();
}
@Override
public int setCount(E element, int count) {
return setCountImpl(this, element, count);
}
@Override
public boolean setCount(E element, int oldCount, int newCount) {
return setCountImpl(this, element, oldCount, newCount);
}
// Bulk Operations
/**
* {@inheritDoc}
*
* <p>This implementation is highly efficient when {@code elementsToAdd} is itself a {@link
* Multiset}.
*/
@Override
public final boolean addAll(Collection<? extends E> elementsToAdd) {
return Multisets.addAllImpl(this, elementsToAdd);
}
@Override
public final boolean removeAll(Collection<?> elementsToRemove) {
return Multisets.removeAllImpl(this, elementsToRemove);
}
@Override
public final boolean retainAll(Collection<?> elementsToRetain) {
return Multisets.retainAllImpl(this, elementsToRetain);
}
@Override
public abstract void clear();
// Views
private transient Set<E> elementSet;
@Override
public Set<E> elementSet() {
Set<E> result = elementSet;
if (result == null) {
elementSet = result = createElementSet();
}
return result;
}
/**
* Creates a new instance of this multiset's element set, which will be returned by {@link
* #elementSet()}.
*/
Set<E> createElementSet() {
return new ElementSet();
}
class ElementSet extends Multisets.ElementSet<E> {
@Override
Multiset<E> multiset() {
return AbstractMultiset.this;
}
@Override
public Iterator<E> iterator() {
return elementIterator();
}
}
abstract Iterator<E> elementIterator();
private transient Set<Entry<E>> entrySet;
@Override
public Set<Entry<E>> entrySet() {
Set<Entry<E>> result = entrySet;
if (result == null) {
entrySet = result = createEntrySet();
}
return result;
}
class EntrySet extends Multisets.EntrySet<E> {
@Override
Multiset<E> multiset() {
return AbstractMultiset.this;
}
@Override
public Iterator<Entry<E>> iterator() {
return entryIterator();
}
@Override
public int size() {
return distinctElements();
}
}
Set<Entry<E>> createEntrySet() {
return new EntrySet();
}
abstract Iterator<Entry<E>> entryIterator();
abstract int distinctElements();
// Object methods
/**
* {@inheritDoc}
*
* <p>This implementation returns {@code true} if {@code object} is a multiset of the same size
* and if, for each element, the two multisets have the same count.
*/
@Override
public final boolean equals(Object object) {
return Multisets.equalsImpl(this, object);
}
/**
* {@inheritDoc}
*
* <p>This implementation returns the hash code of {@link Multiset#entrySet()}.
*/
@Override
public final int hashCode() {
return entrySet().hashCode();
}
/**
* {@inheritDoc}
*
* <p>This implementation returns the result of invoking {@code toString} on {@link
* Multiset#entrySet()}.
*/
@Override
public final String toString() {
return entrySet().toString();
}
}

View file

@ -0,0 +1,169 @@
/*
* Copyright (C) 2012 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.Maps.IteratorBasedAbstractMap;
import java.util.Iterator;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
/**
* Skeletal implementation of {@link NavigableMap}.
*
* @author Louis Wasserman
*/
@GwtIncompatible
abstract class AbstractNavigableMap<K, V> extends IteratorBasedAbstractMap<K, V>
implements NavigableMap<K, V> {
@Override
public abstract V get(Object key);
@Override
public Entry<K, V> firstEntry() {
return Iterators.getNext(entryIterator(), null);
}
@Override
public Entry<K, V> lastEntry() {
return Iterators.getNext(descendingEntryIterator(), null);
}
@Override
public Entry<K, V> pollFirstEntry() {
return Iterators.pollNext(entryIterator());
}
@Override
public Entry<K, V> pollLastEntry() {
return Iterators.pollNext(descendingEntryIterator());
}
@Override
public K firstKey() {
Entry<K, V> entry = firstEntry();
if (entry == null) {
throw new NoSuchElementException();
} else {
return entry.getKey();
}
}
@Override
public K lastKey() {
Entry<K, V> entry = lastEntry();
if (entry == null) {
throw new NoSuchElementException();
} else {
return entry.getKey();
}
}
@Override
public Entry<K, V> lowerEntry(K key) {
return headMap(key, false).lastEntry();
}
@Override
public Entry<K, V> floorEntry(K key) {
return headMap(key, true).lastEntry();
}
@Override
public Entry<K, V> ceilingEntry(K key) {
return tailMap(key, true).firstEntry();
}
@Override
public Entry<K, V> higherEntry(K key) {
return tailMap(key, false).firstEntry();
}
@Override
public K lowerKey(K key) {
return Maps.keyOrNull(lowerEntry(key));
}
@Override
public K floorKey(K key) {
return Maps.keyOrNull(floorEntry(key));
}
@Override
public K ceilingKey(K key) {
return Maps.keyOrNull(ceilingEntry(key));
}
@Override
public K higherKey(K key) {
return Maps.keyOrNull(higherEntry(key));
}
abstract Iterator<Entry<K, V>> descendingEntryIterator();
@Override
public SortedMap<K, V> subMap(K fromKey, K toKey) {
return subMap(fromKey, true, toKey, false);
}
@Override
public SortedMap<K, V> headMap(K toKey) {
return headMap(toKey, false);
}
@Override
public SortedMap<K, V> tailMap(K fromKey) {
return tailMap(fromKey, true);
}
@Override
public NavigableSet<K> navigableKeySet() {
return new Maps.NavigableKeySet<>(this);
}
@Override
public Set<K> keySet() {
return navigableKeySet();
}
@Override
public NavigableSet<K> descendingKeySet() {
return descendingMap().navigableKeySet();
}
@Override
public NavigableMap<K, V> descendingMap() {
return new DescendingMap();
}
private final class DescendingMap extends Maps.DescendingMap<K, V> {
@Override
NavigableMap<K, V> forward() {
return AbstractNavigableMap.this;
}
@Override
Iterator<Entry<K, V>> entryIterator() {
return descendingEntryIterator();
}
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtIncompatible;
/**
* A skeletal implementation of {@code RangeSet}.
*
* @author Louis Wasserman
*/
@GwtIncompatible
abstract class AbstractRangeSet<C extends Comparable> implements RangeSet<C> {
AbstractRangeSet() {}
@Override
public boolean contains(C value) {
return rangeContaining(value) != null;
}
@Override
public abstract Range<C> rangeContaining(C value);
@Override
public boolean isEmpty() {
return asRanges().isEmpty();
}
@Override
public void add(Range<C> range) {
throw new UnsupportedOperationException();
}
@Override
public void remove(Range<C> range) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
remove(Range.<C>all());
}
@Override
public boolean enclosesAll(RangeSet<C> other) {
return enclosesAll(other.asRanges());
}
@Override
public void addAll(RangeSet<C> other) {
addAll(other.asRanges());
}
@Override
public void removeAll(RangeSet<C> other) {
removeAll(other.asRanges());
}
@Override
public boolean intersects(Range<C> otherRange) {
return !subRangeSet(otherRange).isEmpty();
}
@Override
public abstract boolean encloses(Range<C> otherRange);
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof RangeSet) {
RangeSet<?> other = (RangeSet<?>) obj;
return this.asRanges().equals(other.asRanges());
}
return false;
}
@Override
public final int hashCode() {
return asRanges().hashCode();
}
@Override
public final String toString() {
return asRanges().toString();
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2010 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.util.NoSuchElementException;
/**
* This class provides a skeletal implementation of the {@code Iterator} interface for sequences
* whose next element can always be derived from the previous element. Null elements are not
* supported, nor is the {@link #remove()} method.
*
* <p>Example:
*
* <pre>{@code
* Iterator<Integer> powersOfTwo =
* new AbstractSequentialIterator<Integer>(1) {
* protected Integer computeNext(Integer previous) {
* return (previous == 1 << 30) ? null : previous * 2;
* }
* };
* }</pre>
*
* @author Chris Povirk
* @since 12.0 (in Guava as {@code AbstractLinkedIterator} since 8.0)
*/
@GwtCompatible
public abstract class AbstractSequentialIterator<T> extends UnmodifiableIterator<T> {
private T nextOrNull;
/**
* Creates a new iterator with the given first element, or, if {@code firstOrNull} is null,
* creates a new empty iterator.
*/
protected AbstractSequentialIterator(T firstOrNull) {
this.nextOrNull = firstOrNull;
}
/**
* Returns the element that follows {@code previous}, or returns {@code null} if no elements
* remain. This method is invoked during each call to {@link #next()} in order to compute the
* result of a <i>future</i> call to {@code next()}.
*/
protected abstract T computeNext(T previous);
@Override
public final boolean hasNext() {
return nextOrNull != null;
}
@Override
public final T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
try {
return nextOrNull;
} finally {
nextOrNull = computeNext(nextOrNull);
}
}
}

View file

@ -0,0 +1,152 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Basic implementation of the {@link SetMultimap} interface. It's a wrapper around {@link
* AbstractMapBasedMultimap} that converts the returned collections into {@code Sets}. The {@link
* #createCollection} method must return a {@code Set}.
*
* @author Jared Levy
*/
@GwtCompatible
abstract class AbstractSetMultimap<K, V> extends AbstractMapBasedMultimap<K, V>
implements SetMultimap<K, V> {
/**
* Creates a new multimap that uses the provided map.
*
* @param map place to store the mapping from each key to its corresponding values
*/
protected AbstractSetMultimap(Map<K, Collection<V>> map) {
super(map);
}
@Override
abstract Set<V> createCollection();
@Override
Set<V> createUnmodifiableEmptyCollection() {
return Collections.emptySet();
}
@Override
<E> Collection<E> unmodifiableCollectionSubclass(Collection<E> collection) {
return Collections.unmodifiableSet((Set<E>) collection);
}
@Override
Collection<V> wrapCollection(K key, Collection<V> collection) {
return new WrappedSet(key, (Set<V>) collection);
}
// Following Javadoc copied from SetMultimap.
/**
* {@inheritDoc}
*
* <p>Because a {@code SetMultimap} has unique values for a given key, this method returns a
* {@link Set}, instead of the {@link Collection} specified in the {@link Multimap} interface.
*/
@Override
public Set<V> get(K key) {
return (Set<V>) super.get(key);
}
/**
* {@inheritDoc}
*
* <p>Because a {@code SetMultimap} has unique values for a given key, this method returns a
* {@link Set}, instead of the {@link Collection} specified in the {@link Multimap} interface.
*/
@Override
public Set<Entry<K, V>> entries() {
return (Set<Entry<K, V>>) super.entries();
}
/**
* {@inheritDoc}
*
* <p>Because a {@code SetMultimap} has unique values for a given key, this method returns a
* {@link Set}, instead of the {@link Collection} specified in the {@link Multimap} interface.
*/
@Override
public Set<V> removeAll(Object key) {
return (Set<V>) super.removeAll(key);
}
/**
* {@inheritDoc}
*
* <p>Because a {@code SetMultimap} has unique values for a given key, this method returns a
* {@link Set}, instead of the {@link Collection} specified in the {@link Multimap} interface.
*
* <p>Any duplicates in {@code values} will be stored in the multimap once.
*/
@Override
public Set<V> replaceValues(K key, Iterable<? extends V> values) {
return (Set<V>) super.replaceValues(key, values);
}
/**
* {@inheritDoc}
*
* <p>Though the method signature doesn't say so explicitly, the returned map has {@link Set}
* values.
*/
@Override
public Map<K, Collection<V>> asMap() {
return super.asMap();
}
/**
* Stores a key-value pair in the multimap.
*
* @param key key to store in the multimap
* @param value value to store in the multimap
* @return {@code true} if the method increased the size of the multimap, or {@code false} if the
* multimap already contained the key-value pair
*/
@Override
public boolean put(K key, V value) {
return super.put(key, value);
}
/**
* Compares the specified object to this multimap for equality.
*
* <p>Two {@code SetMultimap} instances are equal if, for each key, they contain the same values.
* Equality does not depend on the ordering of keys or values.
*/
@Override
public boolean equals(Object object) {
return super.equals(object);
}
private static final long serialVersionUID = 7431625294878419160L;
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (C) 2012 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
/**
* Basic implementation of a {@link SortedSetMultimap} with a sorted key set.
*
* <p>This superclass allows {@code TreeMultimap} to override methods to return navigable set and
* map types in non-GWT only, while GWT code will inherit the SortedMap/SortedSet overrides.
*
* @author Louis Wasserman
*/
@GwtCompatible
abstract class AbstractSortedKeySortedSetMultimap<K, V> extends AbstractSortedSetMultimap<K, V> {
AbstractSortedKeySortedSetMultimap(SortedMap<K, Collection<V>> map) {
super(map);
}
@Override
public SortedMap<K, Collection<V>> asMap() {
return (SortedMap<K, Collection<V>>) super.asMap();
}
@Override
SortedMap<K, Collection<V>> backingMap() {
return (SortedMap<K, Collection<V>>) super.backingMap();
}
@Override
public SortedSet<K> keySet() {
return (SortedSet<K>) super.keySet();
}
@Override
Set<K> createKeySet() {
return createMaybeNavigableKeySet();
}
}

View file

@ -0,0 +1,147 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.collect;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.annotations.GwtCompatible;
import java.util.Comparator;
import java.util.Iterator;
import java.util.NavigableSet;
/**
* This class provides a skeletal implementation of the {@link SortedMultiset} interface.
*
* <p>The {@link #count} and {@link #size} implementations all iterate across the set returned by
* {@link Multiset#entrySet()}, as do many methods acting on the set returned by {@link
* #elementSet()}. Override those methods for better performance.
*
* @author Louis Wasserman
*/
@GwtCompatible(emulated = true)
abstract class AbstractSortedMultiset<E> extends AbstractMultiset<E> implements SortedMultiset<E> {
@GwtTransient final Comparator<? super E> comparator;
// needed for serialization
@SuppressWarnings("unchecked")
AbstractSortedMultiset() {
this((Comparator) Ordering.natural());
}
AbstractSortedMultiset(Comparator<? super E> comparator) {
this.comparator = checkNotNull(comparator);
}
@Override
public NavigableSet<E> elementSet() {
return (NavigableSet<E>) super.elementSet();
}
@Override
NavigableSet<E> createElementSet() {
return new SortedMultisets.NavigableElementSet<E>(this);
}
@Override
public Comparator<? super E> comparator() {
return comparator;
}
@Override
public Entry<E> firstEntry() {
Iterator<Entry<E>> entryIterator = entryIterator();
return entryIterator.hasNext() ? entryIterator.next() : null;
}
@Override
public Entry<E> lastEntry() {
Iterator<Entry<E>> entryIterator = descendingEntryIterator();
return entryIterator.hasNext() ? entryIterator.next() : null;
}
@Override
public Entry<E> pollFirstEntry() {
Iterator<Entry<E>> entryIterator = entryIterator();
if (entryIterator.hasNext()) {
Entry<E> result = entryIterator.next();
result = Multisets.immutableEntry(result.getElement(), result.getCount());
entryIterator.remove();
return result;
}
return null;
}
@Override
public Entry<E> pollLastEntry() {
Iterator<Entry<E>> entryIterator = descendingEntryIterator();
if (entryIterator.hasNext()) {
Entry<E> result = entryIterator.next();
result = Multisets.immutableEntry(result.getElement(), result.getCount());
entryIterator.remove();
return result;
}
return null;
}
@Override
public SortedMultiset<E> subMultiset(
E fromElement,
BoundType fromBoundType,
E toElement,
BoundType toBoundType) {
// These are checked elsewhere, but NullPointerTester wants them checked eagerly.
checkNotNull(fromBoundType);
checkNotNull(toBoundType);
return tailMultiset(fromElement, fromBoundType).headMultiset(toElement, toBoundType);
}
abstract Iterator<Entry<E>> descendingEntryIterator();
Iterator<E> descendingIterator() {
return Multisets.iteratorImpl(descendingMultiset());
}
private transient SortedMultiset<E> descendingMultiset;
@Override
public SortedMultiset<E> descendingMultiset() {
SortedMultiset<E> result = descendingMultiset;
return (result == null) ? descendingMultiset = createDescendingMultiset() : result;
}
SortedMultiset<E> createDescendingMultiset() {
class DescendingMultisetImpl extends DescendingMultiset<E> {
@Override
SortedMultiset<E> forwardMultiset() {
return AbstractSortedMultiset.this;
}
@Override
Iterator<Entry<E>> entryIterator() {
return descendingEntryIterator();
}
@Override
public Iterator<E> iterator() {
return descendingIterator();
}
}
return new DescendingMultisetImpl();
}
}

View file

@ -0,0 +1,148 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.NavigableSet;
import java.util.SortedSet;
/**
* Basic implementation of the {@link SortedSetMultimap} interface. It's a wrapper around {@link
* AbstractMapBasedMultimap} that converts the returned collections into sorted sets. The {@link
* #createCollection} method must return a {@code SortedSet}.
*
* @author Jared Levy
*/
@GwtCompatible
abstract class AbstractSortedSetMultimap<K, V> extends AbstractSetMultimap<K, V>
implements SortedSetMultimap<K, V> {
/**
* Creates a new multimap that uses the provided map.
*
* @param map place to store the mapping from each key to its corresponding values
*/
protected AbstractSortedSetMultimap(Map<K, Collection<V>> map) {
super(map);
}
@Override
abstract SortedSet<V> createCollection();
@Override
SortedSet<V> createUnmodifiableEmptyCollection() {
return unmodifiableCollectionSubclass(createCollection());
}
@Override
<E> SortedSet<E> unmodifiableCollectionSubclass(Collection<E> collection) {
if (collection instanceof NavigableSet) {
return Sets.unmodifiableNavigableSet((NavigableSet<E>) collection);
} else {
return Collections.unmodifiableSortedSet((SortedSet<E>) collection);
}
}
@Override
Collection<V> wrapCollection(K key, Collection<V> collection) {
if (collection instanceof NavigableSet) {
return new WrappedNavigableSet(key, (NavigableSet<V>) collection, null);
} else {
return new WrappedSortedSet(key, (SortedSet<V>) collection, null);
}
}
// Following Javadoc copied from Multimap and SortedSetMultimap.
/**
* Returns a collection view of all values associated with a key. If no mappings in the multimap
* have the provided key, an empty collection is returned.
*
* <p>Changes to the returned collection will update the underlying multimap, and vice versa.
*
* <p>Because a {@code SortedSetMultimap} has unique sorted values for a given key, this method
* returns a {@link SortedSet}, instead of the {@link Collection} specified in the {@link
* Multimap} interface.
*/
@Override
public SortedSet<V> get(K key) {
return (SortedSet<V>) super.get(key);
}
/**
* Removes all values associated with a given key. The returned collection is immutable.
*
* <p>Because a {@code SortedSetMultimap} has unique sorted values for a given key, this method
* returns a {@link SortedSet}, instead of the {@link Collection} specified in the {@link
* Multimap} interface.
*/
@Override
public SortedSet<V> removeAll(Object key) {
return (SortedSet<V>) super.removeAll(key);
}
/**
* Stores a collection of values with the same key, replacing any existing values for that key.
* The returned collection is immutable.
*
* <p>Because a {@code SortedSetMultimap} has unique sorted values for a given key, this method
* returns a {@link SortedSet}, instead of the {@link Collection} specified in the {@link
* Multimap} interface.
*
* <p>Any duplicates in {@code values} will be stored in the multimap once.
*/
@Override
public SortedSet<V> replaceValues(K key, Iterable<? extends V> values) {
return (SortedSet<V>) super.replaceValues(key, values);
}
/**
* Returns a map view that associates each key with the corresponding values in the multimap.
* Changes to the returned map, such as element removal, will update the underlying multimap. The
* map does not support {@code setValue} on its entries, {@code put}, or {@code putAll}.
*
* <p>When passed a key that is present in the map, {@code asMap().get(Object)} has the same
* behavior as {@link #get}, returning a live collection. When passed a key that is not present,
* however, {@code asMap().get(Object)} returns {@code null} instead of an empty collection.
*
* <p>Though the method signature doesn't say so explicitly, the returned map has {@link
* SortedSet} values.
*/
@Override
public Map<K, Collection<V>> asMap() {
return super.asMap();
}
/**
* {@inheritDoc}
*
* <p>Consequently, the values do not follow their natural ordering or the ordering of the value
* comparator.
*/
@Override
public Collection<V> values() {
return super.values();
}
private static final long serialVersionUID = 430848587173315748L;
}

View file

@ -0,0 +1,241 @@
/*
* Copyright (C) 2013 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
/**
* Skeletal, implementation-agnostic implementation of the {@link Table} interface.
*
* @author Louis Wasserman
*/
@GwtCompatible
abstract class AbstractTable<R, C, V> implements Table<R, C, V> {
@Override
public boolean containsRow(Object rowKey) {
return Maps.safeContainsKey(rowMap(), rowKey);
}
@Override
public boolean containsColumn(Object columnKey) {
return Maps.safeContainsKey(columnMap(), columnKey);
}
@Override
public Set<R> rowKeySet() {
return rowMap().keySet();
}
@Override
public Set<C> columnKeySet() {
return columnMap().keySet();
}
@Override
public boolean containsValue(Object value) {
for (Map<C, V> row : rowMap().values()) {
if (row.containsValue(value)) {
return true;
}
}
return false;
}
@Override
public boolean contains(Object rowKey, Object columnKey) {
Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
return row != null && Maps.safeContainsKey(row, columnKey);
}
@Override
public V get(Object rowKey, Object columnKey) {
Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
return (row == null) ? null : Maps.safeGet(row, columnKey);
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public void clear() {
Iterators.clear(cellSet().iterator());
}
@Override
public V remove(Object rowKey, Object columnKey) {
Map<C, V> row = Maps.safeGet(rowMap(), rowKey);
return (row == null) ? null : Maps.safeRemove(row, columnKey);
}
@Override
public V put(R rowKey, C columnKey, V value) {
return row(rowKey).put(columnKey, value);
}
@Override
public void putAll(Table<? extends R, ? extends C, ? extends V> table) {
for (Table.Cell<? extends R, ? extends C, ? extends V> cell : table.cellSet()) {
put(cell.getRowKey(), cell.getColumnKey(), cell.getValue());
}
}
private transient Set<Cell<R, C, V>> cellSet;
@Override
public Set<Cell<R, C, V>> cellSet() {
Set<Cell<R, C, V>> result = cellSet;
return (result == null) ? cellSet = createCellSet() : result;
}
Set<Cell<R, C, V>> createCellSet() {
return new CellSet();
}
abstract Iterator<Table.Cell<R, C, V>> cellIterator();
abstract Spliterator<Table.Cell<R, C, V>> cellSpliterator();
class CellSet extends AbstractSet<Cell<R, C, V>> {
@Override
public boolean contains(Object o) {
if (o instanceof Cell) {
Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o;
Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey());
return row != null
&& Collections2.safeContains(
row.entrySet(), Maps.immutableEntry(cell.getColumnKey(), cell.getValue()));
}
return false;
}
@Override
public boolean remove(Object o) {
if (o instanceof Cell) {
Cell<?, ?, ?> cell = (Cell<?, ?, ?>) o;
Map<C, V> row = Maps.safeGet(rowMap(), cell.getRowKey());
return row != null
&& Collections2.safeRemove(
row.entrySet(), Maps.immutableEntry(cell.getColumnKey(), cell.getValue()));
}
return false;
}
@Override
public void clear() {
AbstractTable.this.clear();
}
@Override
public Iterator<Table.Cell<R, C, V>> iterator() {
return cellIterator();
}
@Override
public Spliterator<Cell<R, C, V>> spliterator() {
return cellSpliterator();
}
@Override
public int size() {
return AbstractTable.this.size();
}
}
private transient Collection<V> values;
@Override
public Collection<V> values() {
Collection<V> result = values;
return (result == null) ? values = createValues() : result;
}
Collection<V> createValues() {
return new Values();
}
Iterator<V> valuesIterator() {
return new TransformedIterator<Cell<R, C, V>, V>(cellSet().iterator()) {
@Override
V transform(Cell<R, C, V> cell) {
return cell.getValue();
}
};
}
Spliterator<V> valuesSpliterator() {
return CollectSpliterators.map(cellSpliterator(), Table.Cell::getValue);
}
class Values extends AbstractCollection<V> {
@Override
public Iterator<V> iterator() {
return valuesIterator();
}
@Override
public Spliterator<V> spliterator() {
return valuesSpliterator();
}
@Override
public boolean contains(Object o) {
return containsValue(o);
}
@Override
public void clear() {
AbstractTable.this.clear();
}
@Override
public int size() {
return AbstractTable.this.size();
}
}
@Override
public boolean equals(Object obj) {
return Tables.equalsImpl(this, obj);
}
@Override
public int hashCode() {
return cellSet().hashCode();
}
/** Returns the string representation {@code rowMap().toString()}. */
@Override
public String toString() {
return rowMap().toString();
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (C) 2012 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.io.Serializable;
import java.util.List;
/**
* An ordering that treats all references as equals, even nulls.
*
* @author Emily Soldal
*/
@GwtCompatible(serializable = true)
final class AllEqualOrdering extends Ordering<Object> implements Serializable {
static final AllEqualOrdering INSTANCE = new AllEqualOrdering();
@Override
public int compare(Object left, Object right) {
return 0;
}
@Override
public <E> List<E> sortedCopy(Iterable<E> iterable) {
return Lists.newArrayList(iterable);
}
@Override
public <E> ImmutableList<E> immutableSortedCopy(Iterable<E> iterable) {
return ImmutableList.copyOf(iterable);
}
@SuppressWarnings("unchecked")
@Override
public <S> Ordering<S> reverse() {
return (Ordering<S>) this;
}
private Object readResolve() {
return INSTANCE;
}
@Override
public String toString() {
return "Ordering.allEqual()";
}
private static final long serialVersionUID = 0;
}

Some files were not shown because too many files have changed in this diff Show more