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 }