001 /*
002 * Copyright (C) 2007 Google Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package com.google.common.collect;
018
019 import static com.google.common.base.Preconditions.checkNotNull;
020
021 import com.google.common.annotations.Beta;
022 import com.google.common.base.FinalizableReferenceQueue;
023 import com.google.common.base.FinalizableWeakReference;
024 import com.google.common.base.Function;
025
026 import java.util.concurrent.ConcurrentMap;
027
028 /**
029 * Contains static methods pertaining to instances of {@link Interner}.
030 *
031 * @author Kevin Bourrillion
032 * @since 3
033 */
034 @Beta
035 public final class Interners {
036 private Interners() {}
037
038 /**
039 * Returns a new thread-safe interner which retains a strong reference to each
040 * instance it has interned, thus preventing these instances from being
041 * garbage-collected. If this retention is acceptable, this implementation may
042 * perform better than {@link #newWeakInterner}. Note that unlike {@link
043 * String#intern}, using this interner does not consume memory in the
044 * permanent generation.
045 */
046 public static <E> Interner<E> newStrongInterner() {
047 final ConcurrentMap<E, E> map = new MapMaker().makeMap();
048 return new Interner<E>() {
049 public E intern(E sample) {
050 E canonical = map.putIfAbsent(checkNotNull(sample), sample);
051 return (canonical == null) ? sample : canonical;
052 }
053 };
054 }
055
056 /**
057 * Returns a new thread-safe interner which retains a weak reference to each
058 * instance it has interned, and so does not prevent these instances from
059 * being garbage-collected. This most likely does not perform as well as
060 * {@link #newStrongInterner}, but is the best alternative when the memory
061 * usage of that implementation is unacceptable. Note that unlike {@link
062 * String#intern}, using this interner does not consume memory in the
063 * permanent generation.
064 */
065 public static <E> Interner<E> newWeakInterner() {
066 return new WeakInterner<E>();
067 }
068
069 private static class WeakInterner<E> implements Interner<E> {
070 private final ConcurrentMap<InternReference, InternReference> map
071 = new MapMaker().makeMap();
072
073 public E intern(final E sample) {
074 final int hashCode = sample.hashCode();
075
076 // TODO(kevinb): stop using the dummy instance; use custom Equivalence?
077 Object fakeReference = new Object() {
078 @Override public int hashCode() {
079 return hashCode;
080 }
081 @Override public boolean equals(Object object) {
082 if (object.hashCode() != hashCode) {
083 return false;
084 }
085 /*
086 * Implicitly an unchecked cast to WeakInterner<?>.InternReference,
087 * though until OpenJDK 7, the compiler doesn't recognize this. If we
088 * could explicitly cast to the wildcard type
089 * WeakInterner<?>.InternReference, that would be sufficient for our
090 * purposes. The compiler, however, rejects such casts (or rather, it
091 * does until OpenJDK 7).
092 *
093 * See Sun bug 6665356.
094 */
095 @SuppressWarnings("unchecked")
096 InternReference that = (InternReference) object;
097 return sample.equals(that.get());
098 }
099 };
100
101 // Fast-path; avoid creating the reference if possible
102 InternReference existingRef = map.get(fakeReference);
103 if (existingRef != null) {
104 E canonical = existingRef.get();
105 if (canonical != null) {
106 return canonical;
107 }
108 }
109
110 InternReference newRef = new InternReference(sample, hashCode);
111 while (true) {
112 InternReference sneakyRef = map.putIfAbsent(newRef, newRef);
113 if (sneakyRef == null) {
114 return sample;
115 } else {
116 E canonical = sneakyRef.get();
117 if (canonical != null) {
118 return canonical;
119 }
120 }
121 }
122 }
123
124 private static final FinalizableReferenceQueue frq
125 = new FinalizableReferenceQueue();
126
127 class InternReference extends FinalizableWeakReference<E> {
128 final int hashCode;
129
130 InternReference(E key, int hash) {
131 super(key, frq);
132 hashCode = hash;
133 }
134 public void finalizeReferent() {
135 map.remove(this);
136 }
137 @Override public E get() {
138 E referent = super.get();
139 if (referent == null) {
140 finalizeReferent();
141 }
142 return referent;
143 }
144 @Override public int hashCode() {
145 return hashCode;
146 }
147 @Override public boolean equals(Object object) {
148 if (object == this) {
149 return true;
150 }
151 if (object instanceof WeakInterner.InternReference) {
152 /*
153 * On the following line, Eclipse wants a type parameter, producing
154 * WeakInterner<?>.InternReference. The problem is that javac rejects
155 * that form. Omitting WeakInterner satisfies both, though this seems
156 * odd, since we are inside a WeakInterner<E> and thus the
157 * WeakInterner<E> is implied, yet there is no reason to believe that
158 * the other object's WeakInterner has type E. That's right -- we've
159 * found a way to perform an unchecked cast without receiving a
160 * warning from either Eclipse or javac. Taking advantage of that
161 * seems questionable, even though we don't depend upon the type of
162 * that.get(), so we'll just suppress the warning.
163 */
164 @SuppressWarnings("unchecked")
165 WeakInterner.InternReference that =
166 (WeakInterner.InternReference) object;
167 if (that.hashCode != hashCode) {
168 return false;
169 }
170 E referent = super.get();
171 return referent != null && referent.equals(that.get());
172 }
173 return object.equals(this);
174 }
175 }
176 }
177
178 /**
179 * Returns a function that delegates to the {@link Interner#intern} method of
180 * the given interner.
181 *
182 * @since 8
183 */
184 public static <E> Function<E, E> asFunction(Interner<E> interner) {
185 return new InternerFunction<E>(checkNotNull(interner));
186 }
187
188 private static class InternerFunction<E> implements Function<E, E> {
189
190 private final Interner<E> interner;
191
192 public InternerFunction(Interner<E> interner) {
193 this.interner = interner;
194 }
195
196 @Override public E apply(E input) {
197 return interner.intern(input);
198 }
199
200 @Override public int hashCode() {
201 return interner.hashCode();
202 }
203
204 @Override public boolean equals(Object other) {
205 if (other instanceof InternerFunction<?>) {
206 InternerFunction<?> that = (InternerFunction<?>) other;
207 return interner.equals(that.interner);
208 }
209
210 return false;
211 }
212 }
213 }