    001    /*
    002     * Copyright (C) 2009 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.Objects.firstNonNull;
    018    import static com.google.common.base.Preconditions.checkArgument;
    019    import static com.google.common.base.Preconditions.checkNotNull;
    020    import static com.google.common.base.Preconditions.checkState;
    021
    022    import com.google.common.annotations.GwtCompatible;
    023    import com.google.common.annotations.GwtIncompatible;
    024    import com.google.common.base.Ascii;
    025    import com.google.common.base.Equivalence;
    026    import com.google.common.base.Function;
    027    import com.google.common.base.Objects;
    028    import com.google.common.base.Ticker;
    029    import com.google.common.collect.ComputingConcurrentHashMap.ComputingMapAdapter;
    030    import com.google.common.collect.MapMakerInternalMap.Strength;
    031
    032    import java.io.Serializable;
    033    import java.lang.ref.SoftReference;
    034    import java.lang.ref.WeakReference;
    035    import java.util.AbstractMap;
    036    import java.util.Collections;
    037    import java.util.ConcurrentModificationException;
    038    import java.util.Map;
    039    import java.util.Set;
    040    import java.util.concurrent.ConcurrentHashMap;
    041    import java.util.concurrent.ConcurrentMap;
    042    import java.util.concurrent.TimeUnit;
    043
    044    import javax.annotation.Nullable;
    045
    046    /**
    047     * <p>A builder of {@link ConcurrentMap} instances having any combination of the following features:
    048     *
    049     * <ul>
    050     * <li>keys or values automatically wrapped in {@linkplain WeakReference weak} or {@linkplain
    051     *     SoftReference soft} references
    052     * <li>notification of evicted (or otherwise removed) entries
    053     * <li>on-demand computation of values for keys not already present
    054     * </ul>
    055     *
    056     * <p>Usage example: <pre>   {@code
    057     *
    058     *   ConcurrentMap<Key, Graph> graphs = new MapMaker()
    059     *       .concurrencyLevel(4)
    060     *       .weakKeys()
    061     *       .makeComputingMap(
    062     *           new Function<Key, Graph>() {
    063     *             public Graph apply(Key key) {
    064     *               return createExpensiveGraph(key);
    065     *             }
    066     *           });}</pre>
    067     *
    068     * These features are all optional; {@code new MapMaker().makeMap()} returns a valid concurrent map
    069     * that behaves similarly to a {@link ConcurrentHashMap}.
    070     *
    071     * <p>The returned map is implemented as a hash table with similar performance characteristics to
    072     * {@link ConcurrentHashMap}. It supports all optional operations of the {@code ConcurrentMap}
    073     * interface. It does not permit null keys or values.
    074     *
    075     * <p><b>Note:</b> by default, the returned map uses equality comparisons (the {@link Object#equals
    076     * equals} method) to determine equality for keys or values. However, if {@link #weakKeys} or {@link
    077     * #softKeys} was specified, the map uses identity ({@code ==}) comparisons instead for keys.
    078     * Likewise, if {@link #weakValues} or {@link #softValues} was specified, the map uses identity
    079     * comparisons for values.
    080     *
    081     * <p>The view collections of the returned map have <i>weakly consistent iterators</i>. This means
    082     * that they are safe for concurrent use, but if other threads modify the map after the iterator is
    083     * created, it is undefined which of these changes, if any, are reflected in that iterator. These
    084     * iterators never throw {@link ConcurrentModificationException}.
    085     *
    086     * <p>If soft or weak references were requested, it is possible for a key or value present in the
    087     * the map to be reclaimed by the garbage collector. If this happens, the entry automatically
    088     * disappears from the map. A partially-reclaimed entry is never exposed to the user. Any {@link
    089     * java.util.Map.Entry} instance retrieved from the map's {@linkplain Map#entrySet entry set} is a
    090     * snapshot of that entry's state at the time of retrieval; such entries do, however, support {@link
    091     * java.util.Map.Entry#setValue}, which simply calls {@link Map#put} on the entry's key.
    092     *
    093     * <p>The maps produced by {@code MapMaker} are serializable, and the deserialized maps retain all
    094     * the configuration properties of the original map. During deserialization, if the original map had
    095     * used soft or weak references, the entries are reconstructed as they were, but it's not unlikely
    096     * they'll be quickly garbage-collected before they are ever accessed.
    097     *
    098     * <p>{@code new MapMaker().weakKeys().makeMap()} is a recommended replacement for {@link
    099     * java.util.WeakHashMap}, but note that it compares keys using object identity whereas {@code
    100     * WeakHashMap} uses {@link Object#equals}.
    101     *
    102     * @author Bob Lee
    103     * @author Charles Fry
    104     * @author Kevin Bourrillion
    105     * @since 2.0 (imported from Google Collections Library)
    106     */
    107    @GwtCompatible(emulated = true)
    108    public final class MapMaker extends GenericMapMaker<Object, Object> {
    109      private static final int DEFAULT_INITIAL_CAPACITY = 16;
    110      private static final int DEFAULT_CONCURRENCY_LEVEL = 4;
    111      private static final int DEFAULT_EXPIRATION_NANOS = 0;
    112
    113      static final int UNSET_INT = -1;
    114
    115      // TODO(kevinb): dispense with this after benchmarking
    116      boolean useCustomMap;
    117
    118      int initialCapacity = UNSET_INT;
    119      int concurrencyLevel = UNSET_INT;
    120      int maximumSize = UNSET_INT;
    121
    122      Strength keyStrength;
    123      Strength valueStrength;
    124
    125      long expireAfterWriteNanos = UNSET_INT;
    126      long expireAfterAccessNanos = UNSET_INT;
    127
    128      RemovalCause nullRemovalCause;
    129
    130      Equivalence<Object> keyEquivalence;
    131
    132      Ticker ticker;
    133
    134      /**
    135       * Constructs a new {@code MapMaker} instance with default settings, including strong keys, strong
    136       * values, and no automatic eviction of any kind.
    137       */
    138      public MapMaker() {}
    139
    140      /**
    141       * Sets a custom {@code Equivalence} strategy for comparing keys.
    142       *
    143       * <p>By default, the map uses {@link Equivalence#identity} to determine key equality when
    144       * {@link #weakKeys} or {@link #softKeys} is specified, and {@link Equivalence#equals()}
    145       * otherwise. The only place this is used is in {@link Interners.WeakInterner}.
    146       */
    147      @GwtIncompatible("To be supported")
    148      @Override
    149      MapMaker keyEquivalence(Equivalence<Object> equivalence) {
    150        checkState(keyEquivalence == null, "key equivalence was already set to %s", keyEquivalence);
    151        keyEquivalence = checkNotNull(equivalence);
    152        this.useCustomMap = true;
    153        return this;
    154      }
    155
    156      Equivalence<Object> getKeyEquivalence() {
    157        return firstNonNull(keyEquivalence, getKeyStrength().defaultEquivalence());
    158      }
    159
    160      /**
    161       * Sets the minimum total size for the internal hash tables. For example, if the initial capacity
    162       * is {@code 60}, and the concurrency level is {@code 8}, then eight segments are created, each
    163       * having a hash table of size eight. Providing a large enough estimate at construction time
    164       * avoids the need for expensive resizing operations later, but setting this value unnecessarily
    165       * high wastes memory.
    166       *
    167       * @throws IllegalArgumentException if {@code initialCapacity} is negative
    168       * @throws IllegalStateException if an initial capacity was already set
    169       */
    170      @Override
    171      public MapMaker initialCapacity(int initialCapacity) {
    172        checkState(this.initialCapacity == UNSET_INT, "initial capacity was already set to %s",
    173            this.initialCapacity);
    174        checkArgument(initialCapacity >= 0);
    175        this.initialCapacity = initialCapacity;
    176        return this;
    177      }
    178
    179      int getInitialCapacity() {
    180        return (initialCapacity == UNSET_INT) ? DEFAULT_INITIAL_CAPACITY : initialCapacity;
    181      }
    182
    183      /**
    184       * Specifies the maximum number of entries the map may contain. Note that the map <b>may evict an
    185       * entry before this limit is exceeded</b>. As the map size grows close to the maximum, the map
    186       * evicts entries that are less likely to be used again. For example, the map may evict an entry
    187       * because it hasn't been used recently or very often.
    188       *
    189       * <p>When {@code size} is zero, elements can be successfully added to the map, but are evicted
    190       * immediately. This has the same effect as invoking {@link #expireAfterWrite
    191       * expireAfterWrite}{@code (0, unit)} or {@link #expireAfterAccess expireAfterAccess}{@code (0,
    192       * unit)}. It can be useful in testing, or to disable caching temporarily without a code change.
    193       *
    194       * <p>Caching functionality in {@code MapMaker} is being moved to
    195       * {@link com.google.common.cache.CacheBuilder}.
    196       *
    197       * @param size the maximum size of the map
    198       * @throws IllegalArgumentException if {@code size} is negative
    199       * @throws IllegalStateException if a maximum size was already set
    200       * @deprecated Caching functionality in {@code MapMaker} is being moved to
    201       *     {@link com.google.common.cache.CacheBuilder}, with {@link #maximumSize} being
    202       *     replaced by {@link com.google.common.cache.CacheBuilder#maximumSize}. Note that {@code
    203       *     CacheBuilder} is simply an enhanced API for an implementation which was branched from
    204       *     {@code MapMaker}.
    205       */
    206      @Deprecated
    207      @Override
    208      MapMaker maximumSize(int size) {
    209        checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
    210            this.maximumSize);
    211        checkArgument(size >= 0, "maximum size must not be negative");
    212        this.maximumSize = size;
    213        this.useCustomMap = true;
    214        if (maximumSize == 0) {
    215          // SIZE trumps EXPIRED
    216          this.nullRemovalCause = RemovalCause.SIZE;
    217        }
    218        return this;
    219      }
    220
    221      /**
    222       * Guides the allowed concurrency among update operations. Used as a hint for internal sizing. The
    223       * table is internally partitioned to try to permit the indicated number of concurrent updates
    224       * without contention. Because assignment of entries to these partitions is not necessarily
    225       * uniform, the actual concurrency observed may vary. Ideally, you should choose a value to
    226       * accommodate as many threads as will ever concurrently modify the table. Using a significantly
    227       * higher value than you need can waste space and time, and a significantly lower value can lead
    228       * to thread contention. But overestimates and underestimates within an order of magnitude do not
    229       * usually have much noticeable impact. A value of one permits only one thread to modify the map
    230       * at a time, but since read operations can proceed concurrently, this still yields higher
    231       * concurrency than full synchronization. Defaults to 4.
    232       *
    233       * <p><b>Note:</b> Prior to Guava release 9.0, the default was 16. It is possible the default will
    234       * change again in the future. If you care about this value, you should always choose it
    235       * explicitly.
    236       *
    237       * @throws IllegalArgumentException if {@code concurrencyLevel} is nonpositive
    238       * @throws IllegalStateException if a concurrency level was already set
    239       */
    240      @Override
    241      public MapMaker concurrencyLevel(int concurrencyLevel) {
    242        checkState(this.concurrencyLevel == UNSET_INT, "concurrency level was already set to %s",
    243            this.concurrencyLevel);
    244        checkArgument(concurrencyLevel > 0);
    245        this.concurrencyLevel = concurrencyLevel;
    246        return this;
    247      }
    248
    249      int getConcurrencyLevel() {
    250        return (concurrencyLevel == UNSET_INT) ? DEFAULT_CONCURRENCY_LEVEL : concurrencyLevel;
    251      }
    252
    253      /**
    254       * Specifies that each key (not value) stored in the map should be wrapped in a {@link
    255       * WeakReference} (by default, strong references are used).
    256       *
    257       * <p><b>Warning:</b> when this method is used, the resulting map will use identity ({@code ==})
    258       * comparison to determine equality of keys, which is a technical violation of the {@link Map}
    259       * specification, and may not be what you expect.
    260       *
    261       * @throws IllegalStateException if the key strength was already set
    262       * @see WeakReference
    263       */
    264      @GwtIncompatible("java.lang.ref.WeakReference")
    265      @Override
    266      public MapMaker weakKeys() {
    267        return setKeyStrength(Strength.WEAK);
    268      }
    269
    270      /**
    271       * <b>This method is broken.</b> Maps with soft keys offer no functional advantage over maps with
    272       * weak keys, and they waste memory by keeping unreachable elements in the map. If your goal is to
    273       * create a memory-sensitive map, then consider using soft values instead.
    274       *
    275       * <p>Specifies that each key (not value) stored in the map should be wrapped in a
    276       * {@link SoftReference} (by default, strong references are used). Softly-referenced objects will
    277       * be garbage-collected in a <i>globally</i> least-recently-used manner, in response to memory
    278       * demand.
    279       *
    280       * <p><b>Warning:</b> when this method is used, the resulting map will use identity ({@code ==})
    281       * comparison to determine equality of keys, which is a technical violation of the {@link Map}
    282       * specification, and may not be what you expect.
    283       *
    284       * @throws IllegalStateException if the key strength was already set
    285       * @see SoftReference
    286       * @deprecated use {@link #softValues} to create a memory-sensitive map, or {@link #weakKeys} to
    287       *     create a map that doesn't hold strong references to the keys.
    288       *     <b>This method is scheduled for deletion in January 2013.</b>
    289       */
    290      @Deprecated
    291      @GwtIncompatible("java.lang.ref.SoftReference")
    292      @Override
    293      public MapMaker softKeys() {
    294        return setKeyStrength(Strength.SOFT);
    295      }
    296
    297      MapMaker setKeyStrength(Strength strength) {
    298        checkState(keyStrength == null, "Key strength was already set to %s", keyStrength);
    299        keyStrength = checkNotNull(strength);
    300        if (strength != Strength.STRONG) {
    301          // STRONG could be used during deserialization.
    302          useCustomMap = true;
    303        }
    304        return this;
    305      }
    306
    307      Strength getKeyStrength() {
    308        return firstNonNull(keyStrength, Strength.STRONG);
    309      }
    310
    311      /**
    312       * Specifies that each value (not key) stored in the map should be wrapped in a
    313       * {@link WeakReference} (by default, strong references are used).
    314       *
    315       * <p>Weak values will be garbage collected once they are weakly reachable. This makes them a poor
    316       * candidate for caching; consider {@link #softValues} instead.
    317       *
    318       * <p><b>Warning:</b> when this method is used, the resulting map will use identity ({@code ==})
    319       * comparison to determine equality of values. This technically violates the specifications of
    320       * the methods {@link Map#containsValue containsValue},
    321       * {@link ConcurrentMap#remove(Object, Object) remove(Object, Object)} and
    322       * {@link ConcurrentMap#replace(Object, Object, Object) replace(K, V, V)}, and may not be what you
    323       * expect.
    324       *
    325       * @throws IllegalStateException if the value strength was already set
    326       * @see WeakReference
    327       */
    328      @GwtIncompatible("java.lang.ref.WeakReference")
    329      @Override
    330      public MapMaker weakValues() {
    331        return setValueStrength(Strength.WEAK);
    332      }
    333
    334      /**
    335       * Specifies that each value (not key) stored in the map should be wrapped in a
    336       * {@link SoftReference} (by default, strong references are used). Softly-referenced objects will
    337       * be garbage-collected in a <i>globally</i> least-recently-used manner, in response to memory
    338       * demand.
    339       *
    340       * <p><b>Warning:</b> in most circumstances it is better to set a per-cache {@linkplain
    341       * #maximumSize maximum size} instead of using soft references. You should only use this method if
    342       * you are well familiar with the practical consequences of soft references.
    343       *
    344       * <p><b>Warning:</b> when this method is used, the resulting map will use identity ({@code ==})
    345       * comparison to determine equality of values. This technically violates the specifications of
    346       * the methods {@link Map#containsValue containsValue},
    347       * {@link ConcurrentMap#remove(Object, Object) remove(Object, Object)} and
    348       * {@link ConcurrentMap#replace(Object, Object, Object) replace(K, V, V)}, and may not be what you
    349       * expect.
    350       *
    351       * @throws IllegalStateException if the value strength was already set
    352       * @see SoftReference
    353       */
    354      @GwtIncompatible("java.lang.ref.SoftReference")
    355      @Override
    356      public MapMaker softValues() {
    357        return setValueStrength(Strength.SOFT);
    358      }
    359
    360      MapMaker setValueStrength(Strength strength) {
    361        checkState(valueStrength == null, "Value strength was already set to %s", valueStrength);
    362        valueStrength = checkNotNull(strength);
    363        if (strength != Strength.STRONG) {
    364          // STRONG could be used during deserialization.
    365          useCustomMap = true;
    366        }
    367        return this;
    368      }
    369
    370      Strength getValueStrength() {
    371        return firstNonNull(valueStrength, Strength.STRONG);
    372      }
    373
    374      /**
    375       * Specifies that each entry should be automatically removed from the map once a fixed duration
    376       * has elapsed after the entry's creation, or the most recent replacement of its value.
    377       *
    378       * <p>When {@code duration} is zero, elements can be successfully added to the map, but are
    379       * evicted immediately. This has a very similar effect to invoking {@link #maximumSize
    380       * maximumSize}{@code (0)}. It can be useful in testing, or to disable caching temporarily without
    381       * a code change.
    382       *
    383       * <p>Expired entries may be counted by {@link Map#size}, but will never be visible to read or
    384       * write operations. Expired entries are currently cleaned up during write operations, or during
    385       * occasional read operations in the absense of writes; though this behavior may change in the
    386       * future.
    387       *
    388       * @param duration the length of time after an entry is created that it should be automatically
    389       *     removed
    390       * @param unit the unit that {@code duration} is expressed in
    391       * @throws IllegalArgumentException if {@code duration} is negative
    392       * @throws IllegalStateException if the time to live or time to idle was already set
    393       * @deprecated Caching functionality in {@code MapMaker} is being moved to
    394       *     {@link com.google.common.cache.CacheBuilder}, with {@link #expireAfterWrite} being
    395       *     replaced by {@link com.google.common.cache.CacheBuilder#expireAfterWrite}. Note that {@code
    396       *     CacheBuilder} is simply an enhanced API for an implementation which was branched from
    397       *     {@code MapMaker}.
    398       */
    399      @Deprecated
    400      @Override
    401      MapMaker expireAfterWrite(long duration, TimeUnit unit) {
    402        checkExpiration(duration, unit);
    403        this.expireAfterWriteNanos = unit.toNanos(duration);
    404        if (duration == 0 && this.nullRemovalCause == null) {
    405          // SIZE trumps EXPIRED
    406          this.nullRemovalCause = RemovalCause.EXPIRED;
    407        }
    408        useCustomMap = true;
    409        return this;
    410      }
    411
    412      private void checkExpiration(long duration, TimeUnit unit) {
    413        checkState(expireAfterWriteNanos == UNSET_INT, "expireAfterWrite was already set to %s ns",
    414            expireAfterWriteNanos);
    415        checkState(expireAfterAccessNanos == UNSET_INT, "expireAfterAccess was already set to %s ns",
    416            expireAfterAccessNanos);
    417        checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
    418      }
    419
    420      long getExpireAfterWriteNanos() {
    421        return (expireAfterWriteNanos == UNSET_INT) ? DEFAULT_EXPIRATION_NANOS : expireAfterWriteNanos;
    422      }
    423
    424      /**
    425       * Specifies that each entry should be automatically removed from the map once a fixed duration
    426       * has elapsed after the entry's last read or write access.
    427       *
    428       * <p>When {@code duration} is zero, elements can be successfully added to the map, but are
    429       * evicted immediately. This has a very similar effect to invoking {@link #maximumSize
    430       * maximumSize}{@code (0)}. It can be useful in testing, or to disable caching temporarily without
    431       * a code change.
    432       *
    433       * <p>Expired entries may be counted by {@link Map#size}, but will never be visible to read or
    434       * write operations. Expired entries are currently cleaned up during write operations, or during
    435       * occasional read operations in the absense of writes; though this behavior may change in the
    436       * future.
    437       *
    438       * @param duration the length of time after an entry is last accessed that it should be
    439       *     automatically removed
    440       * @param unit the unit that {@code duration} is expressed in
    441       * @throws IllegalArgumentException if {@code duration} is negative
    442       * @throws IllegalStateException if the time to idle or time to live was already set
    443       * @deprecated Caching functionality in {@code MapMaker} is being moved to
    444       *     {@link com.google.common.cache.CacheBuilder}, with {@link #expireAfterAccess} being
    445       *     replaced by {@link com.google.common.cache.CacheBuilder#expireAfterAccess}. Note that
    446       *     {@code CacheBuilder} is simply an enhanced API for an implementation which was branched
    447       *     from {@code MapMaker}.
    448       */
    449      @Deprecated
    450      @GwtIncompatible("To be supported")
    451      @Override
    452      MapMaker expireAfterAccess(long duration, TimeUnit unit) {
    453        checkExpiration(duration, unit);
    454        this.expireAfterAccessNanos = unit.toNanos(duration);
    455        if (duration == 0 && this.nullRemovalCause == null) {
    456          // SIZE trumps EXPIRED
    457          this.nullRemovalCause = RemovalCause.EXPIRED;
    458        }
    459        useCustomMap = true;
    460        return this;
    461      }
    462
    463      long getExpireAfterAccessNanos() {
    464        return (expireAfterAccessNanos == UNSET_INT)
    465            ? DEFAULT_EXPIRATION_NANOS : expireAfterAccessNanos;
    466      }
    467
    468      Ticker getTicker() {
    469        return firstNonNull(ticker, Ticker.systemTicker());
    470      }
    471
    472      /**
    473       * Specifies a listener instance, which all maps built using this {@code MapMaker} will notify
    474       * each time an entry is removed from the map by any means.
    475       *
    476       * <p>Each map built by this map maker after this method is called invokes the supplied listener
    477       * after removing an element for any reason (see removal causes in {@link RemovalCause}). It will
    478       * invoke the listener during invocations of any of that map's public methods (even read-only
    479       * methods).
    480       *
    481       * <p><b>Important note:</b> Instead of returning <i>this</i> as a {@code MapMaker} instance,
    482       * this method returns {@code GenericMapMaker<K, V>}. From this point on, either the original
    483       * reference or the returned reference may be used to complete configuration and build the map,
    484       * but only the "generic" one is type-safe. That is, it will properly prevent you from building
    485       * maps whose key or value types are incompatible with the types accepted by the listener already
    486       * provided; the {@code MapMaker} type cannot do this. For best results, simply use the standard
    487       * method-chaining idiom, as illustrated in the documentation at top, configuring a {@code
    488       * MapMaker} and building your {@link Map} all in a single statement.
    489       *
    490       * <p><b>Warning:</b> if you ignore the above advice, and use this {@code MapMaker} to build a map
    491       * or cache whose key or value type is incompatible with the listener, you will likely experience
    492       * a {@link ClassCastException} at some <i>undefined</i> point in the future.
    493       *
    494       * @throws IllegalStateException if a removal listener was already set
    495       * @deprecated Caching functionality in {@code MapMaker} is being moved to
    496       *     {@link com.google.common.cache.CacheBuilder}, with {@link #removalListener} being
    497       *     replaced by {@link com.google.common.cache.CacheBuilder#removalListener}. Note that {@code
    498       *     CacheBuilder} is simply an enhanced API for an implementation which was branched from
    499       *     {@code MapMaker}.
    500       */
    501      @Deprecated
    502      @GwtIncompatible("To be supported")
    503      <K, V> GenericMapMaker<K, V> removalListener(RemovalListener<K, V> listener) {
    504        checkState(this.removalListener == null);
    505
    506        // safely limiting the kinds of maps this can produce
    507        @SuppressWarnings("unchecked")
    508        GenericMapMaker<K, V> me = (GenericMapMaker<K, V>) this;
    509        me.removalListener = checkNotNull(listener);
    510        useCustomMap = true;
    511        return me;
    512      }
    513
    514      /**
    515       * Builds a thread-safe map, without on-demand computation of values. This method does not alter
    516       * the state of this {@code MapMaker} instance, so it can be invoked again to create multiple
    517       * independent maps.
    518       *
    519       * <p>The bulk operations {@code putAll}, {@code equals}, and {@code clear} are not guaranteed to
    520       * be performed atomically on the returned map. Additionally, {@code size} and {@code
    521       * containsValue} are implemented as bulk read operations, and thus may fail to observe concurrent
    522       * writes.
    523       *
    524       * @return a serializable concurrent map having the requested features
    525       */
    526      @Override
    527      public <K, V> ConcurrentMap<K, V> makeMap() {
    528        if (!useCustomMap) {
    529          return new ConcurrentHashMap<K, V>(getInitialCapacity(), 0.75f, getConcurrencyLevel());
    530        }
    531        return (nullRemovalCause == null)
    532            ? new MapMakerInternalMap<K, V>(this)
    533            : new NullConcurrentMap<K, V>(this);
    534      }
    535
    536      /**
    537       * Returns a MapMakerInternalMap for the benefit of internal callers that use features of
    538       * that class not exposed through ConcurrentMap.
    539       */
    540      @Override
    541      @GwtIncompatible("MapMakerInternalMap")
    542      <K, V> MapMakerInternalMap<K, V> makeCustomMap() {
    543        return new MapMakerInternalMap<K, V>(this);
    544      }
    545
    546      /**
    547       * Builds a map that supports atomic, on-demand computation of values. {@link Map#get} either
    548       * returns an already-computed value for the given key, atomically computes it using the supplied
    549       * function, or, if another thread is currently computing the value for this key, simply waits for
    550       * that thread to finish and returns its computed value. Note that the function may be executed
    551       * concurrently by multiple threads, but only for distinct keys.
    552       *
    553       * <p>New code should use {@link com.google.common.cache.CacheBuilder}, which supports
    554       * {@linkplain com.google.common.cache.CacheStats statistics} collection, introduces the
    555       * {@link com.google.common.cache.CacheLoader} interface for loading entries into the cache
    556       * (allowing checked exceptions to be thrown in the process), and more cleanly separates
    557       * computation from the cache's {@code Map} view.
    558       *
    559       * <p>If an entry's value has not finished computing yet, query methods besides {@code get} return
    560       * immediately as if an entry doesn't exist. In other words, an entry isn't externally visible
    561       * until the value's computation completes.
    562       *
    563       * <p>{@link Map#get} on the returned map will never return {@code null}. It may throw:
    564       *
    565       * <ul>
    566       * <li>{@link NullPointerException} if the key is null or the computing function returns a null
    567       *     result
    568       * <li>{@link ComputationException} if an exception was thrown by the computing function. If that
    569       * exception is already of type {@link ComputationException} it is propagated directly; otherwise
    570       * it is wrapped.
    571       * </ul>
    572       *
    573       * <p><b>Note:</b> Callers of {@code get} <i>must</i> ensure that the key argument is of type
    574       * {@code K}. The {@code get} method accepts {@code Object}, so the key type is not checked at
    575       * compile time. Passing an object of a type other than {@code K} can result in that object being
    576       * unsafely passed to the computing function as type {@code K}, and unsafely stored in the map.
    577       *
    578       * <p>If {@link Map#put} is called before a computation completes, other threads waiting on the
    579       * computation will wake up and return the stored value.
    580       *
    581       * <p>This method does not alter the state of this {@code MapMaker} instance, so it can be invoked
    582       * again to create multiple independent maps.
    583       *
    584       * <p>Insertion, removal, update, and access operations on the returned map safely execute
    585       * concurrently by multiple threads. Iterators on the returned map are weakly consistent,
    586       * returning elements reflecting the state of the map at some point at or since the creation of
    587       * the iterator. They do not throw {@link ConcurrentModificationException}, and may proceed
    588       * concurrently with other operations.
    589       *
    590       * <p>The bulk operations {@code putAll}, {@code equals}, and {@code clear} are not guaranteed to
    591       * be performed atomically on the returned map. Additionally, {@code size} and {@code
    592       * containsValue} are implemented as bulk read operations, and thus may fail to observe concurrent
    593       * writes.
    594       *
    595       * @param computingFunction the function used to compute new values
    596       * @return a serializable concurrent map having the requested features
    597       * @deprecated Caching functionality in {@code MapMaker} is being moved to
    598       *     {@link com.google.common.cache.CacheBuilder}, with {@link #makeComputingMap} being replaced
    599       *     by {@link com.google.common.cache.CacheBuilder#build}. See the
    600       *     <a href="http://code.google.com/p/guava-libraries/wiki/MapMakerMigration">MapMaker
    601       *     Migration Guide</a> for more details.
    602       *     <b>This method is scheduled for deletion in February 2013.</b>
    603       */
    604      @Deprecated
    605      @Override
    606      public <K, V> ConcurrentMap<K, V> makeComputingMap(
    607          Function<? super K, ? extends V> computingFunction) {
    608        return (nullRemovalCause == null)
    609            ? new ComputingMapAdapter<K, V>(this, computingFunction)
    610            : new NullComputingConcurrentMap<K, V>(this, computingFunction);
    611      }
    612
    613      /**
    614       * Returns a string representation for this MapMaker instance. The exact form of the returned
    615       * string is not specificed.
    616       */
    617      @Override
    618      public String toString() {
    619        Objects.ToStringHelper s = Objects.toStringHelper(this);
    620        if (initialCapacity != UNSET_INT) {
    621          s.add("initialCapacity", initialCapacity);
    622        }
    623        if (concurrencyLevel != UNSET_INT) {
    624          s.add("concurrencyLevel", concurrencyLevel);
    625        }
    626        if (maximumSize != UNSET_INT) {
    627          s.add("maximumSize", maximumSize);
    628        }
    629        if (expireAfterWriteNanos != UNSET_INT) {
    630          s.add("expireAfterWrite", expireAfterWriteNanos + "ns");
    631        }
    632        if (expireAfterAccessNanos != UNSET_INT) {
    633          s.add("expireAfterAccess", expireAfterAccessNanos + "ns");
    634        }
    635        if (keyStrength != null) {
    636          s.add("keyStrength", Ascii.toLowerCase(keyStrength.toString()));
    637        }
    638        if (valueStrength != null) {
    639          s.add("valueStrength", Ascii.toLowerCase(valueStrength.toString()));
    640        }
    641        if (keyEquivalence != null) {
    642          s.addValue("keyEquivalence");
    643        }
    644        if (removalListener != null) {
    645          s.addValue("removalListener");
    646        }
    647        return s.toString();
    648      }
    649
    650      /**
    651       * An object that can receive a notification when an entry is removed from a map. The removal
    652       * resulting in notification could have occured to an entry being manually removed or replaced, or
    653       * due to eviction resulting from timed expiration, exceeding a maximum size, or garbage
    654       * collection.
    655       *
    656       * <p>An instance may be called concurrently by multiple threads to process different entries.
    657       * Implementations of this interface should avoid performing blocking calls or synchronizing on
    658       * shared resources.
    659       *
    660       * @param <K> the most general type of keys this listener can listen for; for
    661       *     example {@code Object} if any key is acceptable
    662       * @param <V> the most general type of values this listener can listen for; for
    663       *     example {@code Object} if any key is acceptable
    664       */
    665      interface RemovalListener<K, V> {
    666        /**
    667         * Notifies the listener that a removal occurred at some point in the past.
    668         */
    669        void onRemoval(RemovalNotification<K, V> notification);
    670      }
    671
    672      /**
    673       * A notification of the removal of a single entry. The key or value may be null if it was already
    674       * garbage collected.
    675       *
    676       * <p>Like other {@code Map.Entry} instances associated with MapMaker, this class holds strong
    677       * references to the key and value, regardless of the type of references the map may be using.
    678       */
    679      static final class RemovalNotification<K, V> extends ImmutableEntry<K, V> {
    680        private static final long serialVersionUID = 0;
    681
    682        private final RemovalCause cause;
    683
    684        RemovalNotification(@Nullable K key, @Nullable V value, RemovalCause cause) {
    685          super(key, value);
    686          this.cause = cause;
    687        }
    688
    689        /**
    690         * Returns the cause for which the entry was removed.
    691         */
    692        public RemovalCause getCause() {
    693          return cause;
    694        }
    695
    696        /**
    697         * Returns {@code true} if there was an automatic removal due to eviction (the cause is neither
    698         * {@link RemovalCause#EXPLICIT} nor {@link RemovalCause#REPLACED}).
    699         */
    700        public boolean wasEvicted() {
    701          return cause.wasEvicted();
    702        }
    703      }
    704
    705      /**
    706       * The reason why an entry was removed.
    707       */
    708      enum RemovalCause {
    709        /**
    710         * The entry was manually removed by the user. This can result from the user invoking
    711         * {@link Map#remove}, {@link ConcurrentMap#remove}, or {@link java.util.Iterator#remove}.
    712         */
    713        EXPLICIT {
    714          @Override
    715          boolean wasEvicted() {
    716            return false;
    717          }
    718        },
    719
    720        /**
    721         * The entry itself was not actually removed, but its value was replaced by the user. This can
    722         * result from the user invoking {@link Map#put}, {@link Map#putAll},
    723         * {@link ConcurrentMap#replace(Object, Object)}, or
    724         * {@link ConcurrentMap#replace(Object, Object, Object)}.
    725         */
    726        REPLACED {
    727          @Override
    728          boolean wasEvicted() {
    729            return false;
    730          }
    731        },
    732
    733        /**
    734         * The entry was removed automatically because its key or value was garbage-collected. This
    735         * can occur when using {@link #softKeys}, {@link #softValues}, {@link #weakKeys}, or {@link
    736         * #weakValues}.
    737         */
    738        COLLECTED {
    739          @Override
    740          boolean wasEvicted() {
    741            return true;
    742          }
    743        },
    744
    745        /**
    746         * The entry's expiration timestamp has passed. This can occur when using {@link
    747         * #expireAfterWrite} or {@link #expireAfterAccess}.
    748         */
    749        EXPIRED {
    750          @Override
    751          boolean wasEvicted() {
    752            return true;
    753          }
    754        },
    755
    756        /**
    757         * The entry was evicted due to size constraints. This can occur when using {@link
    758         * #maximumSize}.
    759         */
    760        SIZE {
    761          @Override
    762          boolean wasEvicted() {
    763            return true;
    764          }
    765        };
    766
    767        /**
    768         * Returns {@code true} if there was an automatic removal due to eviction (the cause is neither
    769         * {@link #EXPLICIT} nor {@link #REPLACED}).
    770         */
    771        abstract boolean wasEvicted();
    772      }
    773
    774      /** A map that is always empty and evicts on insertion. */
    775      static class NullConcurrentMap<K, V> extends AbstractMap<K, V>
    776          implements ConcurrentMap<K, V>, Serializable {
    777        private static final long serialVersionUID = 0;
    778
    779        private final RemovalListener<K, V> removalListener;
    780        private final RemovalCause removalCause;
    781
    782        NullConcurrentMap(MapMaker mapMaker) {
    783          removalListener = mapMaker.getRemovalListener();
    784          removalCause = mapMaker.nullRemovalCause;
    785        }
    786
    787        // implements ConcurrentMap
    788
    789        @Override
    790        public boolean containsKey(@Nullable Object key) {
    791          return false;
    792        }
    793
    794        @Override
    795        public boolean containsValue(@Nullable Object value) {
    796          return false;
    797        }
    798
    799        @Override
    800        public V get(@Nullable Object key) {
    801          return null;
    802        }
    803
    804        void notifyRemoval(K key, V value) {
    805          RemovalNotification<K, V> notification =
    806              new RemovalNotification<K, V>(key, value, removalCause);
    807          removalListener.onRemoval(notification);
    808        }
    809
    810        @Override
    811        public V put(K key, V value) {
    812          checkNotNull(key);
    813          checkNotNull(value);
    814          notifyRemoval(key, value);
    815          return null;
    816        }
    817
    818        @Override
    819        public V putIfAbsent(K key, V value) {
    820          return put(key, value);
    821        }
    822
    823        @Override
    824        public V remove(@Nullable Object key) {
    825          return null;
    826        }
    827
    828        @Override
    829        public boolean remove(@Nullable Object key, @Nullable Object value) {
    830          return false;
    831        }
    832
    833        @Override
    834        public V replace(K key, V value) {
    835          checkNotNull(key);
    836          checkNotNull(value);
    837          return null;
    838        }
    839
    840        @Override
    841        public boolean replace(K key, @Nullable V oldValue, V newValue) {
    842          checkNotNull(key);
    843          checkNotNull(newValue);
    844          return false;
    845        }
    846
    847        @Override
    848        public Set<Entry<K, V>> entrySet() {
    849          return Collections.emptySet();
    850        }
    851      }
    852
    853      /** Computes on retrieval and evicts the result. */
    854      static final class NullComputingConcurrentMap<K, V> extends NullConcurrentMap<K, V> {
    855        private static final long serialVersionUID = 0;
    856
    857        final Function<? super K, ? extends V> computingFunction;
    858
    859        NullComputingConcurrentMap(
    860            MapMaker mapMaker, Function<? super K, ? extends V> computingFunction) {
    861          super(mapMaker);
    862          this.computingFunction = checkNotNull(computingFunction);
    863        }
    864
    865        @SuppressWarnings("unchecked") // unsafe, which is why Cache is preferred
    866        @Override
    867        public V get(Object k) {
    868          K key = (K) k;
    869          V value = compute(key);
    870          checkNotNull(value, computingFunction + " returned null for key " + key + ".");
    871          notifyRemoval(key, value);
    872          return value;
    873        }
    874
    875        private V compute(K key) {
    876          checkNotNull(key);
    877          try {
    878            return computingFunction.apply(key);
    879          } catch (ComputationException e) {
    880            throw e;
    881          } catch (Throwable t) {
    882            throw new ComputationException(t);
    883          }
    884        }
    885      }
    886
    887    }