001    /*
002     * Copyright (C) 2007 The Guava Authors
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package com.google.common.collect;
018    
019    import static com.google.common.base.Preconditions.checkNotNull;
020    
021    import com.google.common.annotations.Beta;
022    import com.google.common.base.FinalizableReferenceQueue;
023    import com.google.common.base.FinalizableWeakReference;
024    import com.google.common.base.Function;
025    
026    import java.util.concurrent.ConcurrentMap;
027    
028    /**
029     * Contains static methods pertaining to instances of {@link Interner}.
030     *
031     * @author Kevin Bourrillion
032     * @since 3
033     */
034    @Beta
035    public final class Interners {
036      private Interners() {}
037    
038      /**
039       * Returns a new thread-safe interner which retains a strong reference to each
040       * instance it has interned, thus preventing these instances from being
041       * garbage-collected. If this retention is acceptable, this implementation may
042       * perform better than {@link #newWeakInterner}. Note that unlike {@link
043       * String#intern}, using this interner does not consume memory in the
044       * permanent generation.
045       */
046      public static <E> Interner<E> newStrongInterner() {
047        final ConcurrentMap<E, E> map = new MapMaker().makeMap();
048        return new Interner<E>() {
049          @Override
050          public E intern(E sample) {
051            E canonical = map.putIfAbsent(checkNotNull(sample), sample);
052            return (canonical == null) ? sample : canonical;
053          }
054        };
055      }
056    
057      /**
058       * Returns a new thread-safe interner which retains a weak reference to each
059       * instance it has interned, and so does not prevent these instances from
060       * being garbage-collected. This most likely does not perform as well as
061       * {@link #newStrongInterner}, but is the best alternative when the memory
062       * usage of that implementation is unacceptable. Note that unlike {@link
063       * String#intern}, using this interner does not consume memory in the
064       * permanent generation.
065       */
066      public static <E> Interner<E> newWeakInterner() {
067        return new WeakInterner<E>();
068      }
069    
070      private static class WeakInterner<E> implements Interner<E> {
071        private final ConcurrentMap<InternReference, InternReference> map
072            = new MapMaker().makeMap();
073    
074        @Override
075        public E intern(final E sample) {
076          final int hashCode = sample.hashCode();
077    
078          // TODO(kevinb): stop using the dummy instance; use custom Equivalence?
079          Object fakeReference = new Object() {
080            @Override public int hashCode() {
081              return hashCode;
082            }
083            @Override public boolean equals(Object object) {
084              if (object.hashCode() != hashCode) {
085                return false;
086              }
087              /*
088               * Implicitly an unchecked cast to WeakInterner<?>.InternReference,
089               * though until OpenJDK 7, the compiler doesn't recognize this. If we
090               * could explicitly cast to the wildcard type
091               * WeakInterner<?>.InternReference, that would be sufficient for our
092               * purposes. The compiler, however, rejects such casts (or rather, it
093               * does until OpenJDK 7).
094               *
095               * See Sun bug 6665356.
096               */
097              @SuppressWarnings("unchecked")
098              InternReference that = (InternReference) object;
099              return sample.equals(that.get());
100            }
101          };
102    
103          // Fast-path; avoid creating the reference if possible
104          InternReference existingRef = map.get(fakeReference);
105          if (existingRef != null) {
106            E canonical = existingRef.get();
107            if (canonical != null) {
108              return canonical;
109            }
110          }
111    
112          InternReference newRef = new InternReference(sample, hashCode);
113          while (true) {
114            InternReference sneakyRef = map.putIfAbsent(newRef, newRef);
115            if (sneakyRef == null) {
116              return sample;
117            } else {
118              E canonical = sneakyRef.get();
119              if (canonical != null) {
120                return canonical;
121              }
122            }
123          }
124        }
125    
126        private static final FinalizableReferenceQueue frq
127            = new FinalizableReferenceQueue();
128    
129        class InternReference extends FinalizableWeakReference<E> {
130          final int hashCode;
131    
132          InternReference(E key, int hash) {
133            super(key, frq);
134            hashCode = hash;
135          }
136          @Override
137          public void finalizeReferent() {
138            map.remove(this);
139          }
140          @Override public E get() {
141            E referent = super.get();
142            if (referent == null) {
143              finalizeReferent();
144            }
145            return referent;
146          }
147          @Override public int hashCode() {
148            return hashCode;
149          }
150          @Override public boolean equals(Object object) {
151            if (object == this) {
152              return true;
153            }
154            if (object instanceof WeakInterner.InternReference) {
155              /*
156               * On the following line, Eclipse wants a type parameter, producing
157               * WeakInterner<?>.InternReference. The problem is that javac rejects
158               * that form. Omitting WeakInterner satisfies both, though this seems
159               * odd, since we are inside a WeakInterner<E> and thus the
160               * WeakInterner<E> is implied, yet there is no reason to believe that
161               * the other object's WeakInterner has type E. That's right -- we've
162               * found a way to perform an unchecked cast without receiving a
163               * warning from either Eclipse or javac. Taking advantage of that
164               * seems questionable, even though we don't depend upon the type of
165               * that.get(), so we'll just suppress the warning.
166               */
167              @SuppressWarnings("unchecked")
168              WeakInterner.InternReference that =
169                  (WeakInterner.InternReference) object;
170              if (that.hashCode != hashCode) {
171                return false;
172              }
173              E referent = super.get();
174              return referent != null && referent.equals(that.get());
175            }
176            return object.equals(this);
177          }
178        }
179      }
180    
181      /**
182       * Returns a function that delegates to the {@link Interner#intern} method of
183       * the given interner.
184       *
185       * @since 8
186       */
187      public static <E> Function<E, E> asFunction(Interner<E> interner) {
188        return new InternerFunction<E>(checkNotNull(interner));
189      }
190    
191      private static class InternerFunction<E> implements Function<E, E> {
192    
193        private final Interner<E> interner;
194    
195        public InternerFunction(Interner<E> interner) {
196          this.interner = interner;
197        }
198    
199        @Override public E apply(E input) {
200          return interner.intern(input);
201        }
202    
203        @Override public int hashCode() {
204          return interner.hashCode();
205        }
206    
207        @Override public boolean equals(Object other) {
208          if (other instanceof InternerFunction<?>) {
209            InternerFunction<?> that = (InternerFunction<?>) other;
210            return interner.equals(that.interner);
211          }
212    
213          return false;
214        }
215      }
216    }