• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.base.Equivalence;
22 import com.google.common.base.Function;
23 import com.google.common.collect.MapMakerInternalMap.ReferenceEntry;
24 
25 import java.util.concurrent.ConcurrentMap;
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 public final class Interners {
Interners()35   private Interners() {}
36 
37   /**
38    * Returns a new thread-safe interner which retains a strong reference to each instance it has
39    * interned, thus preventing these instances from being garbage-collected. If this retention is
40    * acceptable, this implementation may perform better than {@link #newWeakInterner}. Note that
41    * unlike {@link String#intern}, using this interner does not consume memory in the permanent
42    * generation.
43    */
newStrongInterner()44   public static <E> Interner<E> newStrongInterner() {
45     final ConcurrentMap<E, E> map = new MapMaker().makeMap();
46     return new Interner<E>() {
47       @Override public E intern(E sample) {
48         E canonical = map.putIfAbsent(checkNotNull(sample), sample);
49         return (canonical == null) ? sample : canonical;
50       }
51     };
52   }
53 
54   /**
55    * Returns a new thread-safe interner which retains a weak reference to each instance it has
56    * interned, and so does not prevent these instances from being garbage-collected. This most
57    * likely does not perform as well as {@link #newStrongInterner}, but is the best alternative
58    * when the memory usage of that implementation is unacceptable. Note that unlike {@link
59    * String#intern}, using this interner does not consume memory in the permanent generation.
60    */
61   @GwtIncompatible("java.lang.ref.WeakReference")
62   public static <E> Interner<E> newWeakInterner() {
63     return new WeakInterner<E>();
64   }
65 
66   private static class WeakInterner<E> implements Interner<E> {
67     // MapMaker is our friend, we know about this type
68     private final MapMakerInternalMap<E, Dummy> map = new MapMaker()
69           .weakKeys()
70           .keyEquivalence(Equivalence.equals())
71           .makeCustomMap();
72 
73     @Override public E intern(E sample) {
74       while (true) {
75         // trying to read the canonical...
76         ReferenceEntry<E, Dummy> entry = map.getEntry(sample);
77         if (entry != null) {
78           E canonical = entry.getKey();
79           if (canonical != null) { // only matters if weak/soft keys are used
80             return canonical;
81           }
82         }
83 
84         // didn't see it, trying to put it instead...
85         Dummy sneaky = map.putIfAbsent(sample, Dummy.VALUE);
86         if (sneaky == null) {
87           return sample;
88         } else {
89           /* Someone beat us to it! Trying again...
90            *
91            * Technically this loop not guaranteed to terminate, so theoretically (extremely
92            * unlikely) this thread might starve, but even then, there is always going to be another
93            * thread doing progress here.
94            */
95         }
96       }
97     }
98 
99     private enum Dummy { VALUE }
100   }
101 
102   /**
103    * Returns a function that delegates to the {@link Interner#intern} method of the given interner.
104    *
105    * @since 8.0
106    */
107   public static <E> Function<E, E> asFunction(Interner<E> interner) {
108     return new InternerFunction<E>(checkNotNull(interner));
109   }
110 
111   private static class InternerFunction<E> implements Function<E, E> {
112 
113     private final Interner<E> interner;
114 
115     public InternerFunction(Interner<E> interner) {
116       this.interner = interner;
117     }
118 
119     @Override public E apply(E input) {
120       return interner.intern(input);
121     }
122 
123     @Override public int hashCode() {
124       return interner.hashCode();
125     }
126 
127     @Override public boolean equals(Object other) {
128       if (other instanceof InternerFunction) {
129         InternerFunction<?> that = (InternerFunction<?>) other;
130         return interner.equals(that.interner);
131       }
132 
133       return false;
134     }
135   }
136 }
137