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
015package com.google.common.collect;
016
017import static com.google.common.base.Preconditions.checkNotNull;
018
019import com.google.common.annotations.GwtIncompatible;
020import com.google.common.annotations.J2ktIncompatible;
021import com.google.common.annotations.VisibleForTesting;
022import com.google.common.base.Equivalence;
023import com.google.common.base.Function;
024import com.google.common.collect.MapMaker.Dummy;
025import com.google.common.collect.MapMakerInternalMap.InternalEntry;
026import com.google.errorprone.annotations.CanIgnoreReturnValue;
027import org.jspecify.annotations.Nullable;
028
029/**
030 * Contains static methods pertaining to instances of {@link Interner}.
031 *
032 * @author Kevin Bourrillion
033 * @since 3.0
034 */
035@J2ktIncompatible
036@GwtIncompatible
037public final class Interners {
038  private Interners() {}
039
040  /**
041   * Builder for {@link Interner} instances.
042   *
043   * @since 21.0
044   */
045  public static final class InternerBuilder {
046    private final MapMaker mapMaker = new MapMaker();
047    private boolean strong = true;
048
049    private InternerBuilder() {}
050
051    /**
052     * Instructs the {@link InternerBuilder} to build a strong interner.
053     *
054     * @see Interners#newStrongInterner()
055     */
056    @CanIgnoreReturnValue
057    public InternerBuilder strong() {
058      this.strong = true;
059      return this;
060    }
061
062    /**
063     * Instructs the {@link InternerBuilder} to build a weak interner.
064     *
065     * @see Interners#newWeakInterner()
066     */
067    @CanIgnoreReturnValue
068    public InternerBuilder weak() {
069      this.strong = false;
070      return this;
071    }
072
073    /**
074     * Sets the concurrency level that will be used by the to-be-built {@link Interner}.
075     *
076     * @see MapMaker#concurrencyLevel(int)
077     */
078    @CanIgnoreReturnValue
079    public InternerBuilder concurrencyLevel(int concurrencyLevel) {
080      this.mapMaker.concurrencyLevel(concurrencyLevel);
081      return this;
082    }
083
084    /** Builds and returns a new interner. */
085    public <E> Interner<E> build() {
086      if (!strong) {
087        mapMaker.weakKeys();
088      }
089      return new InternerImpl<>(mapMaker);
090    }
091  }
092
093  /** Returns a fresh {@link InternerBuilder} instance. */
094  public static InternerBuilder newBuilder() {
095    return new InternerBuilder();
096  }
097
098  /**
099   * Returns a new thread-safe interner which retains a strong reference to each instance it has
100   * interned, thus preventing these instances from being garbage-collected. If this retention is
101   * acceptable, this implementation may perform better than {@link #newWeakInterner}.
102   */
103  public static <E> Interner<E> newStrongInterner() {
104    return newBuilder().strong().build();
105  }
106
107  /**
108   * Returns a new thread-safe interner which retains a weak reference to each instance it has
109   * interned, and so does not prevent these instances from being garbage-collected. This most
110   * likely does not perform as well as {@link #newStrongInterner}, but is the best alternative when
111   * the memory usage of that implementation is unacceptable.
112   */
113  public static <E> Interner<E> newWeakInterner() {
114    return newBuilder().weak().build();
115  }
116
117  @VisibleForTesting
118  static final class InternerImpl<E> implements Interner<E> {
119    // MapMaker is our friend, we know about this type
120    @VisibleForTesting final MapMakerInternalMap<E, Dummy, ?, ?> map;
121
122    private InternerImpl(MapMaker mapMaker) {
123      this.map =
124          MapMakerInternalMap.createWithDummyValues(mapMaker.keyEquivalence(Equivalence.equals()));
125    }
126
127    @Override
128    public E intern(E sample) {
129      while (true) {
130        // trying to read the canonical...
131        @SuppressWarnings("rawtypes") // using raw types to avoid a bug in our nullness checker :(
132        InternalEntry entry = map.getEntry(sample);
133        if (entry != null) {
134          Object canonical = entry.getKey();
135          if (canonical != null) { // only matters if weak/soft keys are used
136            // The compiler would know this is safe if not for our use of raw types (see above).
137            @SuppressWarnings("unchecked")
138            E result = (E) canonical;
139            return result;
140          }
141        }
142
143        // didn't see it, trying to put it instead...
144        Dummy sneaky = map.putIfAbsent(sample, Dummy.VALUE);
145        if (sneaky == null) {
146          return sample;
147        } else {
148          /* Someone beat us to it! Trying again...
149           *
150           * Technically this loop not guaranteed to terminate, so theoretically (extremely
151           * unlikely) this thread might starve, but even then, there is always going to be another
152           * thread doing progress here.
153           */
154        }
155      }
156    }
157  }
158
159  /**
160   * Returns a function that delegates to the {@link Interner#intern} method of the given interner.
161   *
162   * @since 8.0
163   */
164  public static <E> Function<E, E> asFunction(Interner<E> interner) {
165    return new InternerFunction<>(checkNotNull(interner));
166  }
167
168  private static final class InternerFunction<E> implements Function<E, E> {
169
170    private final Interner<E> interner;
171
172    InternerFunction(Interner<E> interner) {
173      this.interner = interner;
174    }
175
176    @Override
177    public E apply(E input) {
178      return interner.intern(input);
179    }
180
181    @Override
182    public int hashCode() {
183      return interner.hashCode();
184    }
185
186    @Override
187    public boolean equals(@Nullable Object other) {
188      if (other instanceof InternerFunction) {
189        InternerFunction<?> that = (InternerFunction<?>) other;
190        return interner.equals(that.interner);
191      }
192
193      return false;
194    }
195  }
196}