    001    /*
    002     * Copyright (C) 2007 The Guava Authors
    003     *
    004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
    005     * in compliance with the License. You may obtain a copy of the License at
    006     *
    007     * http://www.apache.org/licenses/LICENSE-2.0
    008     *
    009     * Unless required by applicable law or agreed to in writing, software distributed under the License
    010     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
    011     * or implied. See the License for the specific language governing permissions and limitations under
    012     * the License.
    013     */
    014
    015    package com.google.common.collect;
    016
    017    import static com.google.common.base.Preconditions.checkNotNull;
    018
    019    import com.google.common.annotations.Beta;
    020    import com.google.common.annotations.GwtIncompatible;
    021    import com.google.common.base.Equivalence;
    022    import com.google.common.base.Function;
    023    import com.google.common.collect.MapMakerInternalMap.ReferenceEntry;
    024
    025    import java.util.concurrent.ConcurrentMap;
    026
    027    /**
    028     * Contains static methods pertaining to instances of {@link Interner}.
    029     *
    030     * @author Kevin Bourrillion
    031     * @since 3.0
    032     */
    033    @Beta
    034    public final class Interners {
    035      private Interners() {}
    036
    037      /**
    038       * Returns a new thread-safe interner which retains a strong reference to each instance it has
    039       * interned, thus preventing these instances from being garbage-collected. If this retention is
    040       * acceptable, this implementation may perform better than {@link #newWeakInterner}. Note that
    041       * unlike {@link String#intern}, using this interner does not consume memory in the permanent
    042       * generation.
    043       */
    044      public static <E> Interner<E> newStrongInterner() {
    045        final ConcurrentMap<E, E> map = new MapMaker().makeMap();
    046        return new Interner<E>() {
    047          @Override public E intern(E sample) {
    048            E canonical = map.putIfAbsent(checkNotNull(sample), sample);
    049            return (canonical == null) ? sample : canonical;
    050          }
    051        };
    052      }
    053
    054      /**
    055       * Returns a new thread-safe interner which retains a weak reference to each instance it has
    056       * interned, and so does not prevent these instances from being garbage-collected. This most
    057       * likely does not perform as well as {@link #newStrongInterner}, but is the best alternative
    058       * when the memory usage of that implementation is unacceptable. Note that unlike {@link
    059       * String#intern}, using this interner does not consume memory in the permanent generation.
    060       */
    061      @GwtIncompatible("java.lang.ref.WeakReference")
    062      public static <E> Interner<E> newWeakInterner() {
    063        return new WeakInterner<E>();
    064      }
    065
    066      private static class WeakInterner<E> implements Interner<E> {
    067        // MapMaker is our friend, we know about this type
    068        private final MapMakerInternalMap<E, Dummy> map = new MapMaker()
    069              .weakKeys()
    070              .keyEquivalence(Equivalence.equals())
    071              .makeCustomMap();
    072
    073        @Override public E intern(E sample) {
    074          while (true) {
    075            // trying to read the canonical...
    076            ReferenceEntry<E, Dummy> entry = map.getEntry(sample);
    077            if (entry != null) {
    078              E canonical = entry.getKey();
    079              if (canonical != null) { // only matters if weak/soft keys are used
    080                return canonical;
    081              }
    082            }
    083
    084            // didn't see it, trying to put it instead...
    085            Dummy sneaky = map.putIfAbsent(sample, Dummy.VALUE);
    086            if (sneaky == null) {
    087              return sample;
    088            } else {
    089              /* Someone beat us to it! Trying again...
    090               *
    091               * Technically this loop not guaranteed to terminate, so theoretically (extremely
    092               * unlikely) this thread might starve, but even then, there is always going to be another
    093               * thread doing progress here.
    094               */
    095            }
    096          }
    097        }
    098
    099        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    }