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 }