Coverage Summary for Class: Interners (com.google.common.collect)
| Class | Method, % | Line, % |
|---|---|---|
| Interners | 0% (0/5) | 0% (0/5) |
| Interners$InternerBuilder | 0% (0/6) | 0% (0/12) |
| Interners$InternerFunction | 0% (0/4) | 0% (0/8) |
| Interners$InternerImpl | 0% (0/3) | 0% (0/13) |
| Total | 0% (0/18) | 0% (0/38) |
1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.collect; 16 17 import static com.google.common.base.Preconditions.checkNotNull; 18 19 import com.google.common.annotations.Beta; 20 import com.google.common.annotations.GwtIncompatible; 21 import com.google.common.annotations.VisibleForTesting; 22 import com.google.common.base.Equivalence; 23 import com.google.common.base.Function; 24 import com.google.common.collect.MapMaker.Dummy; 25 import com.google.common.collect.MapMakerInternalMap.InternalEntry; 26 27 /** 28 * Contains static methods pertaining to instances of {@link Interner}. 29 * 30 * @author Kevin Bourrillion 31 * @since 3.0 32 */ 33 @Beta 34 @GwtIncompatible 35 public final class Interners { 36 private Interners() {} 37 38 /** 39 * Builder for {@link Interner} instances. 40 * 41 * @since 21.0 42 */ 43 public static class InternerBuilder { 44 private final MapMaker mapMaker = new MapMaker(); 45 private boolean strong = true; 46 47 private InternerBuilder() {} 48 49 /** 50 * Instructs the {@link InternerBuilder} to build a strong interner. 51 * 52 * @see Interners#newStrongInterner() 53 */ 54 public InternerBuilder strong() { 55 this.strong = true; 56 return this; 57 } 58 59 /** 60 * Instructs the {@link InternerBuilder} to build a weak interner. 61 * 62 * @see Interners#newWeakInterner() 63 */ 64 @GwtIncompatible("java.lang.ref.WeakReference") 65 public InternerBuilder weak() { 66 this.strong = false; 67 return this; 68 } 69 70 /** 71 * Sets the concurrency level that will be used by the to-be-built {@link Interner}. 72 * 73 * @see MapMaker#concurrencyLevel(int) 74 */ 75 public InternerBuilder concurrencyLevel(int concurrencyLevel) { 76 this.mapMaker.concurrencyLevel(concurrencyLevel); 77 return this; 78 } 79 80 public <E> Interner<E> build() { 81 if (!strong) { 82 mapMaker.weakKeys(); 83 } 84 return new InternerImpl<E>(mapMaker); 85 } 86 } 87 88 /** Returns a fresh {@link InternerBuilder} instance. */ 89 public static InternerBuilder newBuilder() { 90 return new InternerBuilder(); 91 } 92 93 /** 94 * Returns a new thread-safe interner which retains a strong reference to each instance it has 95 * interned, thus preventing these instances from being garbage-collected. If this retention is 96 * acceptable, this implementation may perform better than {@link #newWeakInterner}. 97 */ 98 public static <E> Interner<E> newStrongInterner() { 99 return newBuilder().strong().build(); 100 } 101 102 /** 103 * Returns a new thread-safe interner which retains a weak reference to each instance it has 104 * interned, and so does not prevent these instances from being garbage-collected. This most 105 * likely does not perform as well as {@link #newStrongInterner}, but is the best alternative when 106 * the memory usage of that implementation is unacceptable. 107 */ 108 @GwtIncompatible("java.lang.ref.WeakReference") 109 public static <E> Interner<E> newWeakInterner() { 110 return newBuilder().weak().build(); 111 } 112 113 @VisibleForTesting 114 static final class InternerImpl<E> implements Interner<E> { 115 // MapMaker is our friend, we know about this type 116 @VisibleForTesting final MapMakerInternalMap<E, Dummy, ?, ?> map; 117 118 private InternerImpl(MapMaker mapMaker) { 119 this.map = 120 MapMakerInternalMap.createWithDummyValues(mapMaker.keyEquivalence(Equivalence.equals())); 121 } 122 123 @Override 124 public E intern(E sample) { 125 while (true) { 126 // trying to read the canonical... 127 InternalEntry<E, Dummy, ?> entry = map.getEntry(sample); 128 if (entry != null) { 129 E canonical = entry.getKey(); 130 if (canonical != null) { // only matters if weak/soft keys are used 131 return canonical; 132 } 133 } 134 135 // didn't see it, trying to put it instead... 136 Dummy sneaky = map.putIfAbsent(sample, Dummy.VALUE); 137 if (sneaky == null) { 138 return sample; 139 } else { 140 /* Someone beat us to it! Trying again... 141 * 142 * Technically this loop not guaranteed to terminate, so theoretically (extremely 143 * unlikely) this thread might starve, but even then, there is always going to be another 144 * thread doing progress here. 145 */ 146 } 147 } 148 } 149 } 150 151 /** 152 * Returns a function that delegates to the {@link Interner#intern} method of the given interner. 153 * 154 * @since 8.0 155 */ 156 public static <E> Function<E, E> asFunction(Interner<E> interner) { 157 return new InternerFunction<E>(checkNotNull(interner)); 158 } 159 160 private static class InternerFunction<E> implements Function<E, E> { 161 162 private final Interner<E> interner; 163 164 public InternerFunction(Interner<E> interner) { 165 this.interner = interner; 166 } 167 168 @Override 169 public E apply(E input) { 170 return interner.intern(input); 171 } 172 173 @Override 174 public int hashCode() { 175 return interner.hashCode(); 176 } 177 178 @Override 179 public boolean equals(Object other) { 180 if (other instanceof InternerFunction) { 181 InternerFunction<?> that = (InternerFunction<?>) other; 182 return interner.equals(that.interner); 183 } 184 185 return false; 186 } 187 } 188 }