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 }