
com.google.common.collect.Interners Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of guava-collections Show documentation
Show all versions of guava-collections Show documentation
Guava Collections is a collections extension library with
expanded collection types, implementations, and utility
methods for dealing with aggregate data.
The newest version!
/*
* Copyright (C) 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.collect;
import com.google.common.annotations.Beta;
import com.google.common.base.FinalizableReferenceQueue;
import com.google.common.base.FinalizableWeakReference;
import java.util.concurrent.ConcurrentMap;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Contains static methods pertaining to instances of {@link Interner}.
*
* @author Kevin Bourrillion
* @since 3
*/
@Beta
public final class Interners {
private Interners() {}
/**
* Returns a new thread-safe interner which retains a strong reference to
* each instance it has interned, thus preventing these instances from being
* garbage-collected. If this retention is acceptable, this implementation may
* perform better than {@link #newWeakInterner}.
*/
public static Interner newStrongInterner() {
final ConcurrentMap map = new MapMaker().makeMap();
return new Interner() {
public E intern(E sample) {
E canonical = map.putIfAbsent(checkNotNull(sample), sample);
return (canonical == null) ? sample : canonical;
}
};
}
/**
* Returns a new thread-safe interner which retains a weak reference to each
* instance it has interned, and so does not prevent these instances from
* being garbage-collected. This most likely does not perform as well as
* {@link #newStrongInterner}, but is the best alternative when the memory
* usage of that implementation is unacceptable.
*/
public static Interner newWeakInterner() {
return new WeakInterner();
}
private static class WeakInterner implements Interner {
private final ConcurrentMap map
= new MapMaker().makeMap();
public E intern(final E sample) {
final int hashCode = sample.hashCode();
// TODO: once MapMaker supports arbitrary Equivalence, we won't need the
// dummy instance anymore
Object fakeReference = new Object() {
@Override public int hashCode() {
return hashCode;
}
@Override public boolean equals(Object object) {
if (object.hashCode() != hashCode) {
return false;
}
/*
* Implicitly an unchecked cast to WeakInterner>.InternReference,
* though until OpenJDK 7, the compiler doesn't recognize this. If we
* could explicitly cast to the wildcard type
* WeakInterner>.InternReference, that would be sufficient for our
* purposes. The compiler, however, rejects such casts (or rather, it
* does until OpenJDK 7).
*
* See Sun bug 6665356.
*/
@SuppressWarnings("unchecked")
InternReference that = (InternReference) object;
return sample.equals(that.get());
}
};
// Fast-path; avoid creating the reference if possible
InternReference existingRef = map.get(fakeReference);
if (existingRef != null) {
E canonical = existingRef.get();
if (canonical != null) {
return canonical;
}
}
InternReference newRef = new InternReference(sample, hashCode);
while (true) {
InternReference sneakyRef = map.putIfAbsent(newRef, newRef);
if (sneakyRef == null) {
return sample;
} else {
E canonical = sneakyRef.get();
if (canonical != null) {
return canonical;
}
}
}
}
private static final FinalizableReferenceQueue frq
= new FinalizableReferenceQueue();
class InternReference extends FinalizableWeakReference {
final int hashCode;
InternReference(E key, int hash) {
super(key, frq);
hashCode = hash;
}
public void finalizeReferent() {
map.remove(this);
}
@Override public E get() {
E referent = super.get();
if (referent == null) {
finalizeReferent();
}
return referent;
}
@Override public int hashCode() {
return hashCode;
}
@Override public boolean equals(Object object) {
// TODO: should we try to do something to make equals() somewhat more
// normal?
if (object == this) {
return true;
}
if (object instanceof WeakInterner.InternReference) {
/*
* On the following line, Eclipse wants a type parameter, producing
* WeakInterner>.InternReference. The problem is that javac rejects
* that form. Omitting WeakInterner satisfies both, though this seems
* odd, since we are inside a WeakInterner and thus the
* WeakInterner is implied, yet there is no reason to believe that
* the other object's WeakInterner has type E. That's right -- we've
* found a way to perform an unchecked cast without receiving a
* warning from either Eclipse or javac. Taking advantage of that
* seems questionable, even though we don't depend upon the type of
* that.get(), so we'll just suppress the warning.
*/
@SuppressWarnings("unchecked")
WeakInterner.InternReference that =
(WeakInterner.InternReference) object;
if (that.hashCode != hashCode) {
return false;
}
E referent = super.get();
return referent != null && referent.equals(that.get());
}
return object.equals(this);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy