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