    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.Equivalences;
    022    import com.google.common.base.Function;
    023    import com.google.common.collect.CustomConcurrentHashMap.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      private static class CustomInterner<E> implements Interner<E> {
    055        // MapMaker is our friend, we know about this type
    056        private final CustomConcurrentHashMap<E, Dummy> map;
    057
    058        CustomInterner(GenericMapMaker<? super E, Object> mm) {
    059          this.map = mm
    060              .strongValues()
    061              .keyEquivalence(Equivalences.equals())
    062              .makeCustomMap();
    063        }
    064
    065        @Override public E intern(E sample) {
    066          while (true) {
    067            // trying to read the canonical...
    068            ReferenceEntry<E, Dummy> entry = map.getEntry(sample);
    069            if (entry != null) {
    070              E canonical = entry.getKey();
    071              if (canonical != null) { // only matters if weak/soft keys are used
    072                return canonical;
    073              }
    074            }
    075
    076            // didn't see it, trying to put it instead...
    077            Dummy sneaky = map.putIfAbsent(sample, Dummy.VALUE);
    078            if (sneaky == null) {
    079              return sample;
    080            } else {
    081              /* Someone beat us to it! Trying again...
    082               *
    083               * Technically this loop not guaranteed to terminate, so theoretically (extremely
    084               * unlikely) this thread might starve, but even then, there is always going to be another
    085               * thread doing progress here.
    086               */
    087            }
    088          }
    089        }
    090
    091        private enum Dummy { VALUE }
    092      }
    093
    094      /**
    095       * Returns a new thread-safe interner which retains a weak reference to each instance it has
    096       * interned, and so does not prevent these instances from being garbage-collected. This most
    097       * likely does not perform as well as {@link #newStrongInterner}, but is the best alternative
    098       * when the memory usage of that implementation is unacceptable. Note that unlike {@link
    099       * 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    }