001/* 002 * Copyright (C) 2007 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.collect; 016 017import static com.google.common.base.Preconditions.checkNotNull; 018 019import com.google.common.annotations.Beta; 020import com.google.common.annotations.GwtIncompatible; 021import com.google.common.annotations.VisibleForTesting; 022import com.google.common.base.Equivalence; 023import com.google.common.base.Function; 024import com.google.common.collect.MapMakerInternalMap.InternalEntry; 025import java.util.concurrent.ConcurrentMap; 026 027/** 028 * Contains static methods pertaining to instances of {@link Interner}. 029 * 030 * @author Kevin Bourrillion 031 * @since 3.0 032 */ 033@Beta 034@GwtIncompatible 035public final class Interners { 036 private Interners() {} 037 038 /** 039 * Builder for {@link Interner} instances. 040 * 041 * @since 21.0 042 */ 043 public static class InternerBuilder { 044 private final MapMaker mapMaker = new MapMaker(); 045 private boolean strong = true; 046 047 private InternerBuilder() { 048 } 049 050 /** 051 * Instructs the {@link InternerBuilder} to build a strong interner. 052 * 053 * @see Interners#newStrongInterner() 054 */ 055 public InternerBuilder strong() { 056 this.strong = true; 057 return this; 058 } 059 060 /** 061 * Instructs the {@link InternerBuilder} to build a weak interner. 062 * 063 * @see Interners#newWeakInterner() 064 */ 065 @GwtIncompatible("java.lang.ref.WeakReference") 066 public InternerBuilder weak() { 067 this.strong = false; 068 return this; 069 } 070 071 /** 072 * Sets the concurrency level that will be used by the to-be-built {@link Interner}. 073 * 074 * @see MapMaker#concurrencyLevel(int) 075 */ 076 public InternerBuilder concurrencyLevel(int concurrencyLevel) { 077 this.mapMaker.concurrencyLevel(concurrencyLevel); 078 return this; 079 } 080 081 public <E> Interner<E> build() { 082 return strong ? new StrongInterner<E>(mapMaker) : new WeakInterner<E>(mapMaker); 083 } 084 } 085 086 /** Returns a fresh {@link InternerBuilder} instance. */ 087 public static InternerBuilder newBuilder() { 088 return new InternerBuilder(); 089 } 090 091 /** 092 * Returns a new thread-safe interner which retains a strong reference to each instance it has 093 * interned, thus preventing these instances from being garbage-collected. If this retention is 094 * acceptable, this implementation may perform better than {@link #newWeakInterner}. 095 */ 096 public static <E> Interner<E> newStrongInterner() { 097 return newBuilder().strong().build(); 098 } 099 100 /** 101 * Returns a new thread-safe interner which retains a weak reference to each instance it has 102 * interned, and so does not prevent these instances from being garbage-collected. This most 103 * likely does not perform as well as {@link #newStrongInterner}, but is the best alternative 104 * when the memory usage of that implementation is unacceptable. 105 */ 106 @GwtIncompatible("java.lang.ref.WeakReference") 107 public static <E> Interner<E> newWeakInterner() { 108 return newBuilder().weak().build(); 109 } 110 111 @VisibleForTesting 112 static final class StrongInterner<E> implements Interner<E> { 113 @VisibleForTesting 114 final ConcurrentMap<E, E> map; 115 116 private StrongInterner(MapMaker mapMaker) { 117 this.map = mapMaker.makeMap(); 118 } 119 120 @Override 121 public E intern(E sample) { 122 E canonical = map.putIfAbsent(checkNotNull(sample), sample); 123 return (canonical == null) ? sample : canonical; 124 } 125 } 126 127 @VisibleForTesting 128 static final class WeakInterner<E> implements Interner<E> { 129 // MapMaker is our friend, we know about this type 130 @VisibleForTesting 131 final MapMakerInternalMap<E, Dummy, ?, ?> map; 132 133 private WeakInterner(MapMaker mapMaker) { 134 this.map = mapMaker.weakKeys().keyEquivalence(Equivalence.equals()).makeCustomMap(); 135 } 136 137 @Override 138 public E intern(E sample) { 139 while (true) { 140 // trying to read the canonical... 141 InternalEntry<E, Dummy, ?> entry = map.getEntry(sample); 142 if (entry != null) { 143 E canonical = entry.getKey(); 144 if (canonical != null) { // only matters if weak/soft keys are used 145 return canonical; 146 } 147 } 148 149 // didn't see it, trying to put it instead... 150 Dummy sneaky = map.putIfAbsent(sample, Dummy.VALUE); 151 if (sneaky == null) { 152 return sample; 153 } else { 154 /* Someone beat us to it! Trying again... 155 * 156 * Technically this loop not guaranteed to terminate, so theoretically (extremely 157 * unlikely) this thread might starve, but even then, there is always going to be another 158 * thread doing progress here. 159 */ 160 } 161 } 162 } 163 164 private enum Dummy { 165 VALUE 166 } 167 } 168 169 /** 170 * Returns a function that delegates to the {@link Interner#intern} method of the given interner. 171 * 172 * @since 8.0 173 */ 174 public static <E> Function<E, E> asFunction(Interner<E> interner) { 175 return new InternerFunction<E>(checkNotNull(interner)); 176 } 177 178 private static class InternerFunction<E> implements Function<E, E> { 179 180 private final Interner<E> interner; 181 182 public InternerFunction(Interner<E> interner) { 183 this.interner = interner; 184 } 185 186 @Override 187 public E apply(E input) { 188 return interner.intern(input); 189 } 190 191 @Override 192 public int hashCode() { 193 return interner.hashCode(); 194 } 195 196 @Override 197 public boolean equals(Object other) { 198 if (other instanceof InternerFunction) { 199 InternerFunction<?> that = (InternerFunction<?>) other; 200 return interner.equals(that.interner); 201 } 202 203 return false; 204 } 205 } 206}