11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2010 The Guava Authors
31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * in compliance with the License. You may obtain a copy of the License at
61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0
81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software distributed under the License
101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * or implied. See the License for the specific language governing permissions and limitations under
121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the License.
131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.collect;
161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.base.Preconditions.checkNotNull;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport static com.google.common.base.Preconditions.checkState;
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Equivalence;
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Function;
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.base.Throwables;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.MapMaker.RemovalCause;
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.MapMaker.RemovalListener;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.IOException;
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.ObjectInputStream;
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.ObjectOutputStream;
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.Serializable;
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.lang.ref.ReferenceQueue;
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ConcurrentMap;
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.ExecutionException;
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicReferenceArray;
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport javax.annotation.Nullable;
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport javax.annotation.concurrent.GuardedBy;
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Adds computing functionality to {@link MapMakerInternalMap}.
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Bob Lee
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Charles Fry
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertclass ComputingConcurrentHashMap<K, V> extends MapMakerInternalMap<K, V> {
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  final Function<? super K, ? extends V> computingFunction;
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Creates a new, empty map with the specified strategy, initial capacity, load factor and
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * concurrency level.
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  ComputingConcurrentHashMap(MapMaker builder,
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Function<? super K, ? extends V> computingFunction) {
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    super(builder);
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    this.computingFunction = checkNotNull(computingFunction);
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Segment<K, V> createSegment(int initialCapacity, int maxSegmentSize) {
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new ComputingSegment<K, V>(this, initialCapacity, maxSegmentSize);
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  ComputingSegment<K, V> segmentFor(int hash) {
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return (ComputingSegment<K, V>) super.segmentFor(hash);
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  V getOrCompute(K key) throws ExecutionException {
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int hash = hash(checkNotNull(key));
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return segmentFor(hash).getOrCompute(key, hash, computingFunction);
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @SuppressWarnings("serial") // This class is never serialized.
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static final class ComputingSegment<K, V> extends Segment<K, V> {
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ComputingSegment(MapMakerInternalMap<K, V> map, int initialCapacity, int maxSegmentSize) {
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super(map, initialCapacity, maxSegmentSize);
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    V getOrCompute(K key, int hash, Function<? super K, ? extends V> computingFunction)
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throws ExecutionException {
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        outer: while (true) {
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // don't call getLiveEntry, which would ignore computing values
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          ReferenceEntry<K, V> e = getEntry(key, hash);
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          if (e != null) {
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            V value = getLiveValue(e);
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            if (value != null) {
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              recordRead(e);
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              return value;
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // at this point e is either null, computing, or expired;
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // avoid locking if it's already computing
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          if (e == null || !e.getValueReference().isComputingReference()) {
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            boolean createNewEntry = true;
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            ComputingValueReference<K, V> computingValueReference = null;
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            lock();
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            try {
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              preWriteCleanup();
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              int newCount = this.count - 1;
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              AtomicReferenceArray<ReferenceEntry<K, V>> table = this.table;
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              int index = hash & (table.length() - 1);
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              ReferenceEntry<K, V> first = table.get(index);
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              for (e = first; e != null; e = e.getNext()) {
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                K entryKey = e.getKey();
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                if (e.getHash() == hash && entryKey != null
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    && map.keyEquivalence.equivalent(key, entryKey)) {
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                  ValueReference<K, V> valueReference = e.getValueReference();
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                  if (valueReference.isComputingReference()) {
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    createNewEntry = false;
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                  } else {
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    V value = e.getValueReference().get();
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    if (value == null) {
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                      enqueueNotification(entryKey, hash, value, RemovalCause.COLLECTED);
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    } else if (map.expires() && map.isExpired(e)) {
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                      // This is a duplicate check, as preWriteCleanup already purged expired
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                      // entries, but let's accomodate an incorrect expiration queue.
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                      enqueueNotification(entryKey, hash, value, RemovalCause.EXPIRED);
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    } else {
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                      recordLockedRead(e);
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                      return value;
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    }
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    // immediately reuse invalid entries
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    evictionQueue.remove(e);
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    expirationQueue.remove(e);
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                    this.count = newCount; // write-volatile
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                  }
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                  break;
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                }
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              }
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              if (createNewEntry) {
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                computingValueReference = new ComputingValueReference<K, V>(computingFunction);
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                if (e == null) {
1391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                  e = newEntry(key, hash, first);
1401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                  e.setValueReference(computingValueReference);
1411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                  table.set(index, e);
1421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                } else {
1431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                  e.setValueReference(computingValueReference);
1441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                }
1451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              }
1461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            } finally {
1471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              unlock();
1481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              postWriteCleanup();
1491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
1501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            if (createNewEntry) {
1521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              // This thread solely created the entry.
1531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              return compute(key, hash, e, computingValueReference);
1541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
1551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
1561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // The entry already exists. Wait for the computation.
1581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          checkState(!Thread.holdsLock(e), "Recursive computation");
1591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // don't consider expiration as we're concurrent with computation
1601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          V value = e.getValueReference().waitForValue();
1611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          if (value != null) {
1621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            recordRead(e);
1631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            return value;
1641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
1651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // else computing thread will clearValue
1661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          continue outer;
1671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } finally {
1691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        postReadCleanup();
1701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    V compute(K key, int hash, ReferenceEntry<K, V> e,
1741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ComputingValueReference<K, V> computingValueReference)
1751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throws ExecutionException {
1761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      V value = null;
1771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      long start = System.nanoTime();
1781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      long end = 0;
1791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
1801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // Synchronizes on the entry to allow failing fast when a recursive computation is
1811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // detected. This is not fool-proof since the entry may be copied when the segment
1821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        // is written to.
1831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        synchronized (e) {
1841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          value = computingValueReference.compute(key, hash);
1851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          end = System.nanoTime();
1861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (value != null) {
1881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          // putIfAbsent
1891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          V oldValue = put(key, hash, value, true);
1901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          if (oldValue != null) {
1911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            // the computed value was already clobbered
1921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            enqueueNotification(key, hash, value, RemovalCause.REPLACED);
1931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
1941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return value;
1961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } finally {
1971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (end == 0) {
1981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          end = System.nanoTime();
1991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
2001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (value == null) {
2011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          clearValue(key, hash, computingValueReference);
2021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
2031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
2041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
2081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Used to provide computation exceptions to other threads.
2091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
2101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final class ComputationExceptionReference<K, V> implements ValueReference<K, V> {
2111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Throwable t;
2121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ComputationExceptionReference(Throwable t) {
2141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.t = t;
2151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public V get() {
2191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return null;
2201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ReferenceEntry<K, V> getEntry() {
2241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return null;
2251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
2291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
2301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean isComputingReference() {
2341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return false;
2351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public V waitForValue() throws ExecutionException {
2391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      throw new ExecutionException(t);
2401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void clear(ValueReference<K, V> newValue) {}
2441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
2471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Used to provide computation result to other threads.
2481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
2491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final class ComputedReference<K, V> implements ValueReference<K, V> {
2501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final V value;
2511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ComputedReference(@Nullable V value) {
2531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.value = value;
2541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public V get() {
2581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return value;
2591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ReferenceEntry<K, V> getEntry() {
2631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return null;
2641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
2681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
2691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean isComputingReference() {
2731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return false;
2741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public V waitForValue() {
2781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return get();
2791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void clear(ValueReference<K, V> newValue) {}
2831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
2841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final class ComputingValueReference<K, V> implements ValueReference<K, V> {
2861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Function<? super K, ? extends V> computingFunction;
2871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @GuardedBy("ComputingValueReference.this") // writes
2891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    volatile ValueReference<K, V> computedReference = unset();
2901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ComputingValueReference(Function<? super K, ? extends V> computingFunction) {
2921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.computingFunction = computingFunction;
2931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
2941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
2951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
2961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public V get() {
2971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // All computation lookups go through waitForValue. This method thus is
2981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // only used by put, to whom we always want to appear absent.
2991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return null;
3001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
3031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ReferenceEntry<K, V> getEntry() {
3041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return null;
3051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
3081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public ValueReference<K, V> copyFor(ReferenceQueue<V> queue, ReferenceEntry<K, V> entry) {
3091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return this;
3101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
3131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public boolean isComputingReference() {
3141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return true;
3151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    /**
3181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     * Waits for a computation to complete. Returns the result of the computation.
3191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert     */
3201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
3211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public V waitForValue() throws ExecutionException {
3221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (computedReference == UNSET) {
3231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        boolean interrupted = false;
3241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        try {
3251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          synchronized (this) {
3261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            while (computedReference == UNSET) {
3271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              try {
3281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                wait();
3291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              } catch (InterruptedException ie) {
3301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert                interrupted = true;
3311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              }
3321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
3331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
3341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        } finally {
3351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          if (interrupted) {
3361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            Thread.currentThread().interrupt();
3371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          }
3381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
3391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return computedReference.waitForValue();
3411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
3441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public void clear(ValueReference<K, V> newValue) {
3451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // The pending computation was clobbered by a manual write. Unblock all
3461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // pending gets, and have them return the new value.
3471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      setValueReference(newValue);
3481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      // TODO(fry): could also cancel computation if we had a thread handle
3501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    V compute(K key, int hash) throws ExecutionException {
3531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      V value;
3541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
3551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        value = computingFunction.apply(key);
3561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (Throwable t) {
3571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        setValueReference(new ComputationExceptionReference<K, V>(t));
3581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new ExecutionException(t);
3591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      setValueReference(new ComputedReference<K, V>(value));
3621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return value;
3631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    void setValueReference(ValueReference<K, V> valueReference) {
3661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      synchronized (this) {
3671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        if (computedReference == UNSET) {
3681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          computedReference = valueReference;
3691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          notifyAll();
3701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
3711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
3741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  /**
3761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * Overrides get() to compute on demand. Also throws an exception when {@code null} is returned
3771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   * from a computation.
3781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert   */
3791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static final class ComputingMapAdapter<K, V>
3801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      extends ComputingConcurrentHashMap<K, V> implements Serializable {
3811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private static final long serialVersionUID = 0;
3821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ComputingMapAdapter(MapMaker mapMaker,
3841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Function<? super K, ? extends V> computingFunction) {
3851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super(mapMaker, computingFunction);
3861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
3871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
3881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @SuppressWarnings("unchecked") // unsafe, which is one advantage of Cache over Map
3891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
3901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    public V get(Object key) {
3911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      V value;
3921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      try {
3931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        value = getOrCompute((K) key);
3941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } catch (ExecutionException e) {
3951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Throwable cause = e.getCause();
3961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Throwables.propagateIfInstanceOf(cause, ComputationException.class);
3971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new ComputationException(cause);
3981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
3991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (value == null) {
4011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        throw new NullPointerException(computingFunction + " returned null for key " + key + ".");
4021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
4031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return value;
4041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  // Serialization Support
4081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static final long serialVersionUID = 4;
4101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override
4121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  Object writeReplace() {
4131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new ComputingSerializationProxy<K, V>(keyStrength, valueStrength, keyEquivalence,
4141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        valueEquivalence, expireAfterWriteNanos, expireAfterAccessNanos, maximumSize,
4151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        concurrencyLevel, removalListener, this, computingFunction);
4161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  static final class ComputingSerializationProxy<K, V> extends AbstractSerializationProxy<K, V> {
4191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Function<? super K, ? extends V> computingFunction;
4211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ComputingSerializationProxy(Strength keyStrength, Strength valueStrength,
4231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        Equivalence<Object> keyEquivalence, Equivalence<Object> valueEquivalence,
4241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        long expireAfterWriteNanos, long expireAfterAccessNanos, int maximumSize,
4251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        int concurrencyLevel, RemovalListener<? super K, ? super V> removalListener,
4261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        ConcurrentMap<K, V> delegate, Function<? super K, ? extends V> computingFunction) {
4271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      super(keyStrength, valueStrength, keyEquivalence, valueEquivalence, expireAfterWriteNanos,
4281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          expireAfterAccessNanos, maximumSize, concurrencyLevel, removalListener, delegate);
4291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      this.computingFunction = computingFunction;
4301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private void writeObject(ObjectOutputStream out) throws IOException {
4331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      out.defaultWriteObject();
4341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      writeMapTo(out);
4351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @SuppressWarnings("deprecation") // self-use
4381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
4391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      in.defaultReadObject();
4401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      MapMaker mapMaker = readMapMaker(in);
4411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      delegate = mapMaker.makeComputingMap(computingFunction);
4421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      readEntries(in);
4431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Object readResolve() {
4461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return delegate;
4471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
4481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
4491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    private static final long serialVersionUID = 4;
4501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
4511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
452