001 /*
002 * Copyright (C) 2007 The Guava Authors
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 @Override
050 public E intern(E sample) {
051 E canonical = map.putIfAbsent(checkNotNull(sample), sample);
052 return (canonical == null) ? sample : canonical;
053 }
054 };
055 }
056
057 /**
058 * Returns a new thread-safe interner which retains a weak reference to each
059 * instance it has interned, and so does not prevent these instances from
060 * being garbage-collected. This most likely does not perform as well as
061 * {@link #newStrongInterner}, but is the best alternative when the memory
062 * usage of that implementation is unacceptable. Note that unlike {@link
063 * String#intern}, using this interner does not consume memory in the
064 * permanent generation.
065 */
066 public static <E> Interner<E> newWeakInterner() {
067 return new WeakInterner<E>();
068 }
069
070 private static class WeakInterner<E> implements Interner<E> {
071 private final ConcurrentMap<InternReference, InternReference> map
072 = new MapMaker().makeMap();
073
074 @Override
075 public E intern(final E sample) {
076 final int hashCode = sample.hashCode();
077
078 // TODO(kevinb): stop using the dummy instance; use custom Equivalence?
079 Object fakeReference = new Object() {
080 @Override public int hashCode() {
081 return hashCode;
082 }
083 @Override public boolean equals(Object object) {
084 if (object.hashCode() != hashCode) {
085 return false;
086 }
087 /*
088 * Implicitly an unchecked cast to WeakInterner<?>.InternReference,
089 * though until OpenJDK 7, the compiler doesn't recognize this. If we
090 * could explicitly cast to the wildcard type
091 * WeakInterner<?>.InternReference, that would be sufficient for our
092 * purposes. The compiler, however, rejects such casts (or rather, it
093 * does until OpenJDK 7).
094 *
095 * See Sun bug 6665356.
096 */
097 @SuppressWarnings("unchecked")
098 InternReference that = (InternReference) object;
099 return sample.equals(that.get());
100 }
101 };
102
103 // Fast-path; avoid creating the reference if possible
104 InternReference existingRef = map.get(fakeReference);
105 if (existingRef != null) {
106 E canonical = existingRef.get();
107 if (canonical != null) {
108 return canonical;
109 }
110 }
111
112 InternReference newRef = new InternReference(sample, hashCode);
113 while (true) {
114 InternReference sneakyRef = map.putIfAbsent(newRef, newRef);
115 if (sneakyRef == null) {
116 return sample;
117 } else {
118 E canonical = sneakyRef.get();
119 if (canonical != null) {
120 return canonical;
121 }
122 }
123 }
124 }
125
126 private static final FinalizableReferenceQueue frq
127 = new FinalizableReferenceQueue();
128
129 class InternReference extends FinalizableWeakReference<E> {
130 final int hashCode;
131
132 InternReference(E key, int hash) {
133 super(key, frq);
134 hashCode = hash;
135 }
136 @Override
137 public void finalizeReferent() {
138 map.remove(this);
139 }
140 @Override public E get() {
141 E referent = super.get();
142 if (referent == null) {
143 finalizeReferent();
144 }
145 return referent;
146 }
147 @Override public int hashCode() {
148 return hashCode;
149 }
150 @Override public boolean equals(Object object) {
151 if (object == this) {
152 return true;
153 }
154 if (object instanceof WeakInterner.InternReference) {
155 /*
156 * On the following line, Eclipse wants a type parameter, producing
157 * WeakInterner<?>.InternReference. The problem is that javac rejects
158 * that form. Omitting WeakInterner satisfies both, though this seems
159 * odd, since we are inside a WeakInterner<E> and thus the
160 * WeakInterner<E> is implied, yet there is no reason to believe that
161 * the other object's WeakInterner has type E. That's right -- we've
162 * found a way to perform an unchecked cast without receiving a
163 * warning from either Eclipse or javac. Taking advantage of that
164 * seems questionable, even though we don't depend upon the type of
165 * that.get(), so we'll just suppress the warning.
166 */
167 @SuppressWarnings("unchecked")
168 WeakInterner.InternReference that =
169 (WeakInterner.InternReference) object;
170 if (that.hashCode != hashCode) {
171 return false;
172 }
173 E referent = super.get();
174 return referent != null && referent.equals(that.get());
175 }
176 return object.equals(this);
177 }
178 }
179 }
180
181 /**
182 * Returns a function that delegates to the {@link Interner#intern} method of
183 * the given interner.
184 *
185 * @since 8
186 */
187 public static <E> Function<E, E> asFunction(Interner<E> interner) {
188 return new InternerFunction<E>(checkNotNull(interner));
189 }
190
191 private static class InternerFunction<E> implements Function<E, E> {
192
193 private final Interner<E> interner;
194
195 public InternerFunction(Interner<E> interner) {
196 this.interner = interner;
197 }
198
199 @Override public E apply(E input) {
200 return interner.intern(input);
201 }
202
203 @Override public int hashCode() {
204 return interner.hashCode();
205 }
206
207 @Override public boolean equals(Object other) {
208 if (other instanceof InternerFunction<?>) {
209 InternerFunction<?> that = (InternerFunction<?>) other;
210 return interner.equals(that.interner);
211 }
212
213 return false;
214 }
215 }
216 }