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
017package com.google.common.collect;
018
019import static com.google.common.base.Preconditions.checkNotNull;
020
021import com.google.common.annotations.Beta;
022import com.google.common.base.FinalizableReferenceQueue;
023import com.google.common.base.FinalizableWeakReference;
024import com.google.common.base.Function;
025
026import 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
035public 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}