17dd252788645e940eada959bdde927426e2531c9Paul Duffin/*
27dd252788645e940eada959bdde927426e2531c9Paul Duffin * Copyright (C) 2011 The Guava Authors
37dd252788645e940eada959bdde927426e2531c9Paul Duffin *
47dd252788645e940eada959bdde927426e2531c9Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License");
57dd252788645e940eada959bdde927426e2531c9Paul Duffin * you may not use this file except in compliance with the License.
67dd252788645e940eada959bdde927426e2531c9Paul Duffin * You may obtain a copy of the License at
77dd252788645e940eada959bdde927426e2531c9Paul Duffin *
87dd252788645e940eada959bdde927426e2531c9Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0
97dd252788645e940eada959bdde927426e2531c9Paul Duffin *
107dd252788645e940eada959bdde927426e2531c9Paul Duffin * Unless required by applicable law or agreed to in writing, software
117dd252788645e940eada959bdde927426e2531c9Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS,
127dd252788645e940eada959bdde927426e2531c9Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137dd252788645e940eada959bdde927426e2531c9Paul Duffin * See the License for the specific language governing permissions and
147dd252788645e940eada959bdde927426e2531c9Paul Duffin * limitations under the License.
157dd252788645e940eada959bdde927426e2531c9Paul Duffin */
167dd252788645e940eada959bdde927426e2531c9Paul Duffin
177dd252788645e940eada959bdde927426e2531c9Paul Duffinpackage com.google.common.collect;
187dd252788645e940eada959bdde927426e2531c9Paul Duffin
197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport static com.google.common.base.Preconditions.checkArgument;
200888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport static com.google.common.collect.CollectPreconditions.checkNonnegative;
217dd252788645e940eada959bdde927426e2531c9Paul Duffin
220888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.caliper.BeforeExperiment;
230888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport com.google.caliper.Benchmark;
247dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.caliper.Param;
257dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.annotations.VisibleForTesting;
267dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.primitives.Ints;
277dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.util.concurrent.ThreadFactoryBuilder;
287dd252788645e940eada959bdde927426e2531c9Paul Duffin
297dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.Iterator;
307dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.List;
317dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.Map;
327dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.Random;
337dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.Set;
347dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.Callable;
357dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.ConcurrentHashMap;
367dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.ConcurrentMap;
377dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.ExecutionException;
387dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.ExecutorService;
397dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.Executors;
407dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.concurrent.Future;
417dd252788645e940eada959bdde927426e2531c9Paul Duffin
427dd252788645e940eada959bdde927426e2531c9Paul Duffinimport javax.annotation.Nullable;
437dd252788645e940eada959bdde927426e2531c9Paul Duffin
447dd252788645e940eada959bdde927426e2531c9Paul Duffin/**
457dd252788645e940eada959bdde927426e2531c9Paul Duffin * Benchmarks for {@link ConcurrentHashMultiset}.
467dd252788645e940eada959bdde927426e2531c9Paul Duffin *
477dd252788645e940eada959bdde927426e2531c9Paul Duffin * @author mike nonemacher
487dd252788645e940eada959bdde927426e2531c9Paul Duffin */
490888a09821a98ac0680fad765217302858e70fa4Paul Duffinpublic class ConcurrentHashMultisetBenchmark {
507dd252788645e940eada959bdde927426e2531c9Paul Duffin  @Param({"1", "2", "4", "8"}) int threads;
517dd252788645e940eada959bdde927426e2531c9Paul Duffin  @Param({"3", "30", "300"}) int size;
527dd252788645e940eada959bdde927426e2531c9Paul Duffin  @Param MultisetSupplier implSupplier;
537dd252788645e940eada959bdde927426e2531c9Paul Duffin
547dd252788645e940eada959bdde927426e2531c9Paul Duffin  private Multiset<Integer> multiset;
557dd252788645e940eada959bdde927426e2531c9Paul Duffin  private ImmutableList<Integer> keys;
567dd252788645e940eada959bdde927426e2531c9Paul Duffin  private ExecutorService threadPool;
577dd252788645e940eada959bdde927426e2531c9Paul Duffin
580888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @BeforeExperiment void setUp() throws Exception {
597dd252788645e940eada959bdde927426e2531c9Paul Duffin    multiset = implSupplier.get();
607dd252788645e940eada959bdde927426e2531c9Paul Duffin    ImmutableList.Builder<Integer> builder = ImmutableList.builder();
617dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (int i = 0; i < size; i++) {
627dd252788645e940eada959bdde927426e2531c9Paul Duffin      builder.add(i);
637dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
647dd252788645e940eada959bdde927426e2531c9Paul Duffin    keys = builder.build();
657dd252788645e940eada959bdde927426e2531c9Paul Duffin    threadPool =
667dd252788645e940eada959bdde927426e2531c9Paul Duffin        Executors.newFixedThreadPool(threads, new ThreadFactoryBuilder().setDaemon(true).build());
677dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
687dd252788645e940eada959bdde927426e2531c9Paul Duffin
690888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @Benchmark long add(final int reps) throws ExecutionException, InterruptedException {
707dd252788645e940eada959bdde927426e2531c9Paul Duffin    return doMultithreadedLoop(
717dd252788645e940eada959bdde927426e2531c9Paul Duffin        new Callable<Long>() {
727dd252788645e940eada959bdde927426e2531c9Paul Duffin          @Override public Long call() {
737dd252788645e940eada959bdde927426e2531c9Paul Duffin            return runAddSingleThread(reps);
747dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
757dd252788645e940eada959bdde927426e2531c9Paul Duffin        });
767dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
777dd252788645e940eada959bdde927426e2531c9Paul Duffin
780888a09821a98ac0680fad765217302858e70fa4Paul Duffin  @Benchmark long addRemove(final int reps) throws ExecutionException, InterruptedException {
797dd252788645e940eada959bdde927426e2531c9Paul Duffin    return doMultithreadedLoop(
807dd252788645e940eada959bdde927426e2531c9Paul Duffin        new Callable<Long>() {
817dd252788645e940eada959bdde927426e2531c9Paul Duffin          @Override public Long call() {
827dd252788645e940eada959bdde927426e2531c9Paul Duffin            return runAddRemoveSingleThread(reps);
837dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
847dd252788645e940eada959bdde927426e2531c9Paul Duffin        });
857dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
867dd252788645e940eada959bdde927426e2531c9Paul Duffin
877dd252788645e940eada959bdde927426e2531c9Paul Duffin  private long doMultithreadedLoop(Callable<Long> task)
887dd252788645e940eada959bdde927426e2531c9Paul Duffin      throws InterruptedException, ExecutionException {
897dd252788645e940eada959bdde927426e2531c9Paul Duffin
907dd252788645e940eada959bdde927426e2531c9Paul Duffin    List<Future<Long>> futures = Lists.newArrayListWithCapacity(threads);
917dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (int i = 0; i < threads; i++) {
927dd252788645e940eada959bdde927426e2531c9Paul Duffin      futures.add(threadPool.submit(task));
937dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
947dd252788645e940eada959bdde927426e2531c9Paul Duffin    long total = 0;
957dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (Future<Long> future : futures) {
967dd252788645e940eada959bdde927426e2531c9Paul Duffin      total += future.get();
977dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
987dd252788645e940eada959bdde927426e2531c9Paul Duffin    return total;
997dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1007dd252788645e940eada959bdde927426e2531c9Paul Duffin
1017dd252788645e940eada959bdde927426e2531c9Paul Duffin  private long runAddSingleThread(int reps) {
1027dd252788645e940eada959bdde927426e2531c9Paul Duffin    Random random = new Random();
1037dd252788645e940eada959bdde927426e2531c9Paul Duffin    int nKeys = keys.size();
1047dd252788645e940eada959bdde927426e2531c9Paul Duffin    long blah = 0;
1057dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (int i = 0; i < reps; i++) {
1067dd252788645e940eada959bdde927426e2531c9Paul Duffin      Integer key = keys.get(random.nextInt(nKeys));
1077dd252788645e940eada959bdde927426e2531c9Paul Duffin      int delta = random.nextInt(5);
1087dd252788645e940eada959bdde927426e2531c9Paul Duffin      blah += delta;
1097dd252788645e940eada959bdde927426e2531c9Paul Duffin      multiset.add(key, delta);
1107dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1117dd252788645e940eada959bdde927426e2531c9Paul Duffin    return blah;
1127dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1137dd252788645e940eada959bdde927426e2531c9Paul Duffin
1147dd252788645e940eada959bdde927426e2531c9Paul Duffin  private long runAddRemoveSingleThread(int reps) {
1157dd252788645e940eada959bdde927426e2531c9Paul Duffin    Random random = new Random();
1167dd252788645e940eada959bdde927426e2531c9Paul Duffin    int nKeys = keys.size();
1177dd252788645e940eada959bdde927426e2531c9Paul Duffin    long blah = 0;
1187dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (int i = 0; i < reps; i++) {
1197dd252788645e940eada959bdde927426e2531c9Paul Duffin      Integer key = keys.get(random.nextInt(nKeys));
1207dd252788645e940eada959bdde927426e2531c9Paul Duffin      // This range is [-5, 4] - slight negative bias so we often hit zero, which brings the
1217dd252788645e940eada959bdde927426e2531c9Paul Duffin      // auto-removal of zeroes into play.
1227dd252788645e940eada959bdde927426e2531c9Paul Duffin      int delta = random.nextInt(10) - 5;
1237dd252788645e940eada959bdde927426e2531c9Paul Duffin      blah += delta;
1247dd252788645e940eada959bdde927426e2531c9Paul Duffin      if (delta >= 0) {
1257dd252788645e940eada959bdde927426e2531c9Paul Duffin        multiset.add(key, delta);
1267dd252788645e940eada959bdde927426e2531c9Paul Duffin      } else {
1277dd252788645e940eada959bdde927426e2531c9Paul Duffin        multiset.remove(key, -delta);
1287dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
1297dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1307dd252788645e940eada959bdde927426e2531c9Paul Duffin    return blah;
1317dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1327dd252788645e940eada959bdde927426e2531c9Paul Duffin
1337dd252788645e940eada959bdde927426e2531c9Paul Duffin  private enum MultisetSupplier {
1347dd252788645e940eada959bdde927426e2531c9Paul Duffin    CONCURRENT_HASH_MULTISET() {
1357dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override Multiset<Integer> get() {
1367dd252788645e940eada959bdde927426e2531c9Paul Duffin        return ConcurrentHashMultiset.create();
1377dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
1387dd252788645e940eada959bdde927426e2531c9Paul Duffin    },
1397dd252788645e940eada959bdde927426e2531c9Paul Duffin    BOXED_ATOMIC_REPLACE() {
1407dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override Multiset<Integer> get() {
1417dd252788645e940eada959bdde927426e2531c9Paul Duffin        return OldConcurrentHashMultiset.create();
1427dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
1437dd252788645e940eada959bdde927426e2531c9Paul Duffin    },
1447dd252788645e940eada959bdde927426e2531c9Paul Duffin    SYNCHRONIZED_MULTISET() {
1457dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override Multiset<Integer> get() {
1467dd252788645e940eada959bdde927426e2531c9Paul Duffin        return Synchronized.multiset(HashMultiset.<Integer>create(), null);
1477dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
1487dd252788645e940eada959bdde927426e2531c9Paul Duffin    },
1497dd252788645e940eada959bdde927426e2531c9Paul Duffin    ;
1507dd252788645e940eada959bdde927426e2531c9Paul Duffin
1517dd252788645e940eada959bdde927426e2531c9Paul Duffin    abstract Multiset<Integer> get();
1527dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1537dd252788645e940eada959bdde927426e2531c9Paul Duffin
1547dd252788645e940eada959bdde927426e2531c9Paul Duffin  /**
1557dd252788645e940eada959bdde927426e2531c9Paul Duffin   * Duplication of the old version of ConcurrentHashMultiset (with some unused stuff removed, like
1567dd252788645e940eada959bdde927426e2531c9Paul Duffin   * serialization code) which used a map with boxed integers for the values.
1577dd252788645e940eada959bdde927426e2531c9Paul Duffin   */
1587dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static final class OldConcurrentHashMultiset<E> extends AbstractMultiset<E> {
1597dd252788645e940eada959bdde927426e2531c9Paul Duffin    /** The number of occurrences of each element. */
1607dd252788645e940eada959bdde927426e2531c9Paul Duffin    private final transient ConcurrentMap<E, Integer> countMap;
1617dd252788645e940eada959bdde927426e2531c9Paul Duffin
1627dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
1637dd252788645e940eada959bdde927426e2531c9Paul Duffin     * Creates a new, empty {@code OldConcurrentHashMultiset} using the default
1647dd252788645e940eada959bdde927426e2531c9Paul Duffin     * initial capacity, load factor, and concurrency settings.
1657dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
1667dd252788645e940eada959bdde927426e2531c9Paul Duffin    public static <E> OldConcurrentHashMultiset<E> create() {
1677dd252788645e940eada959bdde927426e2531c9Paul Duffin      return new OldConcurrentHashMultiset<E>(new ConcurrentHashMap<E, Integer>());
1687dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1697dd252788645e940eada959bdde927426e2531c9Paul Duffin
1707dd252788645e940eada959bdde927426e2531c9Paul Duffin    @VisibleForTesting OldConcurrentHashMultiset(ConcurrentMap<E, Integer> countMap) {
1717dd252788645e940eada959bdde927426e2531c9Paul Duffin      checkArgument(countMap.isEmpty());
1727dd252788645e940eada959bdde927426e2531c9Paul Duffin      this.countMap = countMap;
1737dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1747dd252788645e940eada959bdde927426e2531c9Paul Duffin
1757dd252788645e940eada959bdde927426e2531c9Paul Duffin    // Query Operations
1767dd252788645e940eada959bdde927426e2531c9Paul Duffin
1777dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
1787dd252788645e940eada959bdde927426e2531c9Paul Duffin     * Returns the number of occurrences of {@code element} in this multiset.
1797dd252788645e940eada959bdde927426e2531c9Paul Duffin     *
1807dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @param element the element to look for
1817dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @return the nonnegative number of occurrences of the element
1827dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
1837dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public int count(@Nullable Object element) {
1847dd252788645e940eada959bdde927426e2531c9Paul Duffin      try {
1857dd252788645e940eada959bdde927426e2531c9Paul Duffin        return unbox(countMap.get(element));
1867dd252788645e940eada959bdde927426e2531c9Paul Duffin      } catch (NullPointerException e) {
1877dd252788645e940eada959bdde927426e2531c9Paul Duffin        return 0;
1887dd252788645e940eada959bdde927426e2531c9Paul Duffin      } catch (ClassCastException e) {
1897dd252788645e940eada959bdde927426e2531c9Paul Duffin        return 0;
1907dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
1917dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
1927dd252788645e940eada959bdde927426e2531c9Paul Duffin
1937dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
1947dd252788645e940eada959bdde927426e2531c9Paul Duffin     * {@inheritDoc}
1957dd252788645e940eada959bdde927426e2531c9Paul Duffin     *
1967dd252788645e940eada959bdde927426e2531c9Paul Duffin     * <p>If the data in the multiset is modified by any other threads during this
1977dd252788645e940eada959bdde927426e2531c9Paul Duffin     * method, it is undefined which (if any) of these modifications will be
1987dd252788645e940eada959bdde927426e2531c9Paul Duffin     * reflected in the result.
1997dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
2007dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public int size() {
2017dd252788645e940eada959bdde927426e2531c9Paul Duffin      long sum = 0L;
2027dd252788645e940eada959bdde927426e2531c9Paul Duffin      for (Integer value : countMap.values()) {
2037dd252788645e940eada959bdde927426e2531c9Paul Duffin        sum += value;
2047dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
2057dd252788645e940eada959bdde927426e2531c9Paul Duffin      return Ints.saturatedCast(sum);
2067dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2077dd252788645e940eada959bdde927426e2531c9Paul Duffin
2087dd252788645e940eada959bdde927426e2531c9Paul Duffin    /*
2097dd252788645e940eada959bdde927426e2531c9Paul Duffin    * Note: the superclass toArray() methods assume that size() gives a correct
2107dd252788645e940eada959bdde927426e2531c9Paul Duffin    * answer, which ours does not.
2117dd252788645e940eada959bdde927426e2531c9Paul Duffin    */
2127dd252788645e940eada959bdde927426e2531c9Paul Duffin
2137dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public Object[] toArray() {
2147dd252788645e940eada959bdde927426e2531c9Paul Duffin      return snapshot().toArray();
2157dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2167dd252788645e940eada959bdde927426e2531c9Paul Duffin
2177dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public <T> T[] toArray(T[] array) {
2187dd252788645e940eada959bdde927426e2531c9Paul Duffin      return snapshot().toArray(array);
2197dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2207dd252788645e940eada959bdde927426e2531c9Paul Duffin
2217dd252788645e940eada959bdde927426e2531c9Paul Duffin    /*
2227dd252788645e940eada959bdde927426e2531c9Paul Duffin    * We'd love to use 'new ArrayList(this)' or 'list.addAll(this)', but
2237dd252788645e940eada959bdde927426e2531c9Paul Duffin    * either of these would recurse back to us again!
2247dd252788645e940eada959bdde927426e2531c9Paul Duffin    */
2257dd252788645e940eada959bdde927426e2531c9Paul Duffin    private List<E> snapshot() {
2267dd252788645e940eada959bdde927426e2531c9Paul Duffin      List<E> list = Lists.newArrayListWithExpectedSize(size());
2277dd252788645e940eada959bdde927426e2531c9Paul Duffin      for (Multiset.Entry<E> entry : entrySet()) {
2287dd252788645e940eada959bdde927426e2531c9Paul Duffin        E element = entry.getElement();
2297dd252788645e940eada959bdde927426e2531c9Paul Duffin        for (int i = entry.getCount(); i > 0; i--) {
2307dd252788645e940eada959bdde927426e2531c9Paul Duffin          list.add(element);
2317dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
2327dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
2337dd252788645e940eada959bdde927426e2531c9Paul Duffin      return list;
2347dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2357dd252788645e940eada959bdde927426e2531c9Paul Duffin
2367dd252788645e940eada959bdde927426e2531c9Paul Duffin    // Modification Operations
2377dd252788645e940eada959bdde927426e2531c9Paul Duffin
2387dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
2397dd252788645e940eada959bdde927426e2531c9Paul Duffin     * Adds a number of occurrences of the specified element to this multiset.
2407dd252788645e940eada959bdde927426e2531c9Paul Duffin     *
2417dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @param element the element to add
2427dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @param occurrences the number of occurrences to add
2437dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @return the previous count of the element before the operation; possibly
2447dd252788645e940eada959bdde927426e2531c9Paul Duffin     *     zero
2457dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @throws IllegalArgumentException if {@code occurrences} is negative, or if
2467dd252788645e940eada959bdde927426e2531c9Paul Duffin     *     the resulting amount would exceed {@link Integer#MAX_VALUE}
2477dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
2487dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public int add(E element, int occurrences) {
2497dd252788645e940eada959bdde927426e2531c9Paul Duffin      if (occurrences == 0) {
2507dd252788645e940eada959bdde927426e2531c9Paul Duffin        return count(element);
2517dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
2527dd252788645e940eada959bdde927426e2531c9Paul Duffin      checkArgument(occurrences > 0, "Invalid occurrences: %s", occurrences);
2537dd252788645e940eada959bdde927426e2531c9Paul Duffin
2547dd252788645e940eada959bdde927426e2531c9Paul Duffin      while (true) {
2557dd252788645e940eada959bdde927426e2531c9Paul Duffin        int current = count(element);
2567dd252788645e940eada959bdde927426e2531c9Paul Duffin        if (current == 0) {
2577dd252788645e940eada959bdde927426e2531c9Paul Duffin          if (countMap.putIfAbsent(element, occurrences) == null) {
2587dd252788645e940eada959bdde927426e2531c9Paul Duffin            return 0;
2597dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
2607dd252788645e940eada959bdde927426e2531c9Paul Duffin        } else {
2617dd252788645e940eada959bdde927426e2531c9Paul Duffin          checkArgument(occurrences <= Integer.MAX_VALUE - current,
2627dd252788645e940eada959bdde927426e2531c9Paul Duffin              "Overflow adding %s occurrences to a count of %s",
2637dd252788645e940eada959bdde927426e2531c9Paul Duffin              occurrences, current);
2647dd252788645e940eada959bdde927426e2531c9Paul Duffin          int next = current + occurrences;
2657dd252788645e940eada959bdde927426e2531c9Paul Duffin          if (countMap.replace(element, current, next)) {
2667dd252788645e940eada959bdde927426e2531c9Paul Duffin            return current;
2677dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
2687dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
2697dd252788645e940eada959bdde927426e2531c9Paul Duffin        // If we're still here, there was a race, so just try again.
2707dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
2717dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
2727dd252788645e940eada959bdde927426e2531c9Paul Duffin
2737dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
2747dd252788645e940eada959bdde927426e2531c9Paul Duffin     * Removes a number of occurrences of the specified element from this
2757dd252788645e940eada959bdde927426e2531c9Paul Duffin     * multiset. If the multiset contains fewer than this number of occurrences to
2767dd252788645e940eada959bdde927426e2531c9Paul Duffin     * begin with, all occurrences will be removed.
2777dd252788645e940eada959bdde927426e2531c9Paul Duffin     *
2787dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @param element the element whose occurrences should be removed
2797dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @param occurrences the number of occurrences of the element to remove
2807dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @return the count of the element before the operation; possibly zero
2817dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @throws IllegalArgumentException if {@code occurrences} is negative
2827dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
2837dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public int remove(@Nullable Object element, int occurrences) {
2847dd252788645e940eada959bdde927426e2531c9Paul Duffin      if (occurrences == 0) {
2857dd252788645e940eada959bdde927426e2531c9Paul Duffin        return count(element);
2867dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
2877dd252788645e940eada959bdde927426e2531c9Paul Duffin      checkArgument(occurrences > 0, "Invalid occurrences: %s", occurrences);
2887dd252788645e940eada959bdde927426e2531c9Paul Duffin
2897dd252788645e940eada959bdde927426e2531c9Paul Duffin      while (true) {
2907dd252788645e940eada959bdde927426e2531c9Paul Duffin        int current = count(element);
2917dd252788645e940eada959bdde927426e2531c9Paul Duffin        if (current == 0) {
2927dd252788645e940eada959bdde927426e2531c9Paul Duffin          return 0;
2937dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
2947dd252788645e940eada959bdde927426e2531c9Paul Duffin        if (occurrences >= current) {
2957dd252788645e940eada959bdde927426e2531c9Paul Duffin          if (countMap.remove(element, current)) {
2967dd252788645e940eada959bdde927426e2531c9Paul Duffin            return current;
2977dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
2987dd252788645e940eada959bdde927426e2531c9Paul Duffin        } else {
2997dd252788645e940eada959bdde927426e2531c9Paul Duffin          // We know it's an "E" because it already exists in the map.
3007dd252788645e940eada959bdde927426e2531c9Paul Duffin          @SuppressWarnings("unchecked")
3017dd252788645e940eada959bdde927426e2531c9Paul Duffin          E casted = (E) element;
3027dd252788645e940eada959bdde927426e2531c9Paul Duffin
3037dd252788645e940eada959bdde927426e2531c9Paul Duffin          if (countMap.replace(casted, current, current - occurrences)) {
3047dd252788645e940eada959bdde927426e2531c9Paul Duffin            return current;
3057dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
3067dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
3077dd252788645e940eada959bdde927426e2531c9Paul Duffin        // If we're still here, there was a race, so just try again.
3087dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
3097dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
3107dd252788645e940eada959bdde927426e2531c9Paul Duffin
3117dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
3127dd252788645e940eada959bdde927426e2531c9Paul Duffin     * Removes <b>all</b> occurrences of the specified element from this multiset.
3137dd252788645e940eada959bdde927426e2531c9Paul Duffin     * This method complements {@link Multiset#remove(Object)}, which removes only
3147dd252788645e940eada959bdde927426e2531c9Paul Duffin     * one occurrence at a time.
3157dd252788645e940eada959bdde927426e2531c9Paul Duffin     *
3167dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @param element the element whose occurrences should all be removed
3177dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @return the number of occurrences successfully removed, possibly zero
3187dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
3197dd252788645e940eada959bdde927426e2531c9Paul Duffin    private int removeAllOccurrences(@Nullable Object element) {
3207dd252788645e940eada959bdde927426e2531c9Paul Duffin      try {
3217dd252788645e940eada959bdde927426e2531c9Paul Duffin        return unbox(countMap.remove(element));
3227dd252788645e940eada959bdde927426e2531c9Paul Duffin      } catch (NullPointerException e) {
3237dd252788645e940eada959bdde927426e2531c9Paul Duffin        return 0;
3247dd252788645e940eada959bdde927426e2531c9Paul Duffin      } catch (ClassCastException e) {
3257dd252788645e940eada959bdde927426e2531c9Paul Duffin        return 0;
3267dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
3277dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
3287dd252788645e940eada959bdde927426e2531c9Paul Duffin
3297dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
3307dd252788645e940eada959bdde927426e2531c9Paul Duffin     * Removes exactly the specified number of occurrences of {@code element}, or
3317dd252788645e940eada959bdde927426e2531c9Paul Duffin     * makes no change if this is not possible.
3327dd252788645e940eada959bdde927426e2531c9Paul Duffin     *
3337dd252788645e940eada959bdde927426e2531c9Paul Duffin     * <p>This method, in contrast to {@link #remove(Object, int)}, has no effect
3347dd252788645e940eada959bdde927426e2531c9Paul Duffin     * when the element count is smaller than {@code occurrences}.
3357dd252788645e940eada959bdde927426e2531c9Paul Duffin     *
3367dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @param element the element to remove
3377dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @param occurrences the number of occurrences of {@code element} to remove
3387dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @return {@code true} if the removal was possible (including if {@code
3397dd252788645e940eada959bdde927426e2531c9Paul Duffin     *     occurrences} is zero)
3407dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
3417dd252788645e940eada959bdde927426e2531c9Paul Duffin    public boolean removeExactly(@Nullable Object element, int occurrences) {
3427dd252788645e940eada959bdde927426e2531c9Paul Duffin      if (occurrences == 0) {
3437dd252788645e940eada959bdde927426e2531c9Paul Duffin        return true;
3447dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
3457dd252788645e940eada959bdde927426e2531c9Paul Duffin      checkArgument(occurrences > 0, "Invalid occurrences: %s", occurrences);
3467dd252788645e940eada959bdde927426e2531c9Paul Duffin
3477dd252788645e940eada959bdde927426e2531c9Paul Duffin      while (true) {
3487dd252788645e940eada959bdde927426e2531c9Paul Duffin        int current = count(element);
3497dd252788645e940eada959bdde927426e2531c9Paul Duffin        if (occurrences > current) {
3507dd252788645e940eada959bdde927426e2531c9Paul Duffin          return false;
3517dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
3527dd252788645e940eada959bdde927426e2531c9Paul Duffin        if (occurrences == current) {
3537dd252788645e940eada959bdde927426e2531c9Paul Duffin          if (countMap.remove(element, occurrences)) {
3547dd252788645e940eada959bdde927426e2531c9Paul Duffin            return true;
3557dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
3567dd252788645e940eada959bdde927426e2531c9Paul Duffin        } else {
3577dd252788645e940eada959bdde927426e2531c9Paul Duffin          @SuppressWarnings("unchecked") // it's in the map, must be an "E"
3587dd252788645e940eada959bdde927426e2531c9Paul Duffin              E casted = (E) element;
3597dd252788645e940eada959bdde927426e2531c9Paul Duffin          if (countMap.replace(casted, current, current - occurrences)) {
3607dd252788645e940eada959bdde927426e2531c9Paul Duffin            return true;
3617dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
3627dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
3637dd252788645e940eada959bdde927426e2531c9Paul Duffin        // If we're still here, there was a race, so just try again.
3647dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
3657dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
3667dd252788645e940eada959bdde927426e2531c9Paul Duffin
3677dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
3687dd252788645e940eada959bdde927426e2531c9Paul Duffin     * Adds or removes occurrences of {@code element} such that the {@link #count}
3697dd252788645e940eada959bdde927426e2531c9Paul Duffin     * of the element becomes {@code count}.
3707dd252788645e940eada959bdde927426e2531c9Paul Duffin     *
3717dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @return the count of {@code element} in the multiset before this call
3727dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @throws IllegalArgumentException if {@code count} is negative
3737dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
3747dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public int setCount(E element, int count) {
3757dd252788645e940eada959bdde927426e2531c9Paul Duffin      checkNonnegative(count, "count");
3767dd252788645e940eada959bdde927426e2531c9Paul Duffin      return (count == 0)
3777dd252788645e940eada959bdde927426e2531c9Paul Duffin          ? removeAllOccurrences(element)
3787dd252788645e940eada959bdde927426e2531c9Paul Duffin          : unbox(countMap.put(element, count));
3797dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
3807dd252788645e940eada959bdde927426e2531c9Paul Duffin
3817dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
3827dd252788645e940eada959bdde927426e2531c9Paul Duffin     * Sets the number of occurrences of {@code element} to {@code newCount}, but
3837dd252788645e940eada959bdde927426e2531c9Paul Duffin     * only if the count is currently {@code oldCount}. If {@code element} does
3847dd252788645e940eada959bdde927426e2531c9Paul Duffin     * not appear in the multiset exactly {@code oldCount} times, no changes will
3857dd252788645e940eada959bdde927426e2531c9Paul Duffin     * be made.
3867dd252788645e940eada959bdde927426e2531c9Paul Duffin     *
3877dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @return {@code true} if the change was successful. This usually indicates
3887dd252788645e940eada959bdde927426e2531c9Paul Duffin     *     that the multiset has been modified, but not always: in the case that
3897dd252788645e940eada959bdde927426e2531c9Paul Duffin     *     {@code oldCount == newCount}, the method will return {@code true} if
3907dd252788645e940eada959bdde927426e2531c9Paul Duffin     *     the condition was met.
3917dd252788645e940eada959bdde927426e2531c9Paul Duffin     * @throws IllegalArgumentException if {@code oldCount} or {@code newCount} is
3927dd252788645e940eada959bdde927426e2531c9Paul Duffin     *     negative
3937dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
3947dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public boolean setCount(E element, int oldCount, int newCount) {
3957dd252788645e940eada959bdde927426e2531c9Paul Duffin      checkNonnegative(oldCount, "oldCount");
3967dd252788645e940eada959bdde927426e2531c9Paul Duffin      checkNonnegative(newCount, "newCount");
3977dd252788645e940eada959bdde927426e2531c9Paul Duffin      if (newCount == 0) {
3987dd252788645e940eada959bdde927426e2531c9Paul Duffin        if (oldCount == 0) {
3997dd252788645e940eada959bdde927426e2531c9Paul Duffin          // No change to make, but must return true if the element is not present
4007dd252788645e940eada959bdde927426e2531c9Paul Duffin          return !countMap.containsKey(element);
4017dd252788645e940eada959bdde927426e2531c9Paul Duffin        } else {
4027dd252788645e940eada959bdde927426e2531c9Paul Duffin          return countMap.remove(element, oldCount);
4037dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
4047dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
4057dd252788645e940eada959bdde927426e2531c9Paul Duffin      if (oldCount == 0) {
4067dd252788645e940eada959bdde927426e2531c9Paul Duffin        return countMap.putIfAbsent(element, newCount) == null;
4077dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
4087dd252788645e940eada959bdde927426e2531c9Paul Duffin      return countMap.replace(element, oldCount, newCount);
4097dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
4107dd252788645e940eada959bdde927426e2531c9Paul Duffin
4117dd252788645e940eada959bdde927426e2531c9Paul Duffin    // Views
4127dd252788645e940eada959bdde927426e2531c9Paul Duffin
4137dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override Set<E> createElementSet() {
4147dd252788645e940eada959bdde927426e2531c9Paul Duffin      final Set<E> delegate = countMap.keySet();
4157dd252788645e940eada959bdde927426e2531c9Paul Duffin      return new ForwardingSet<E>() {
4167dd252788645e940eada959bdde927426e2531c9Paul Duffin        @Override protected Set<E> delegate() {
4177dd252788645e940eada959bdde927426e2531c9Paul Duffin          return delegate;
4187dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
4197dd252788645e940eada959bdde927426e2531c9Paul Duffin        @Override public boolean remove(Object object) {
4207dd252788645e940eada959bdde927426e2531c9Paul Duffin          try {
4217dd252788645e940eada959bdde927426e2531c9Paul Duffin            return delegate.remove(object);
4227dd252788645e940eada959bdde927426e2531c9Paul Duffin          } catch (NullPointerException e) {
4237dd252788645e940eada959bdde927426e2531c9Paul Duffin            return false;
4247dd252788645e940eada959bdde927426e2531c9Paul Duffin          } catch (ClassCastException e) {
4257dd252788645e940eada959bdde927426e2531c9Paul Duffin            return false;
4267dd252788645e940eada959bdde927426e2531c9Paul Duffin          }
4277dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
4287dd252788645e940eada959bdde927426e2531c9Paul Duffin      };
4297dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
4307dd252788645e940eada959bdde927426e2531c9Paul Duffin
4317dd252788645e940eada959bdde927426e2531c9Paul Duffin    private transient EntrySet entrySet;
4327dd252788645e940eada959bdde927426e2531c9Paul Duffin
4337dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public Set<Multiset.Entry<E>> entrySet() {
4347dd252788645e940eada959bdde927426e2531c9Paul Duffin      EntrySet result = entrySet;
4357dd252788645e940eada959bdde927426e2531c9Paul Duffin      if (result == null) {
4367dd252788645e940eada959bdde927426e2531c9Paul Duffin        entrySet = result = new EntrySet();
4377dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
4387dd252788645e940eada959bdde927426e2531c9Paul Duffin      return result;
4397dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
4407dd252788645e940eada959bdde927426e2531c9Paul Duffin
4417dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override int distinctElements() {
4427dd252788645e940eada959bdde927426e2531c9Paul Duffin      return countMap.size();
4437dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
4447dd252788645e940eada959bdde927426e2531c9Paul Duffin
4457dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public boolean isEmpty() {
4467dd252788645e940eada959bdde927426e2531c9Paul Duffin      return countMap.isEmpty();
4477dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
4487dd252788645e940eada959bdde927426e2531c9Paul Duffin
4497dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override Iterator<Entry<E>> entryIterator() {
4507dd252788645e940eada959bdde927426e2531c9Paul Duffin      final Iterator<Map.Entry<E, Integer>> backingIterator =
4517dd252788645e940eada959bdde927426e2531c9Paul Duffin          countMap.entrySet().iterator();
4527dd252788645e940eada959bdde927426e2531c9Paul Duffin      return new Iterator<Entry<E>>() {
4537dd252788645e940eada959bdde927426e2531c9Paul Duffin        @Override public boolean hasNext() {
4547dd252788645e940eada959bdde927426e2531c9Paul Duffin          return backingIterator.hasNext();
4557dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
4567dd252788645e940eada959bdde927426e2531c9Paul Duffin
4577dd252788645e940eada959bdde927426e2531c9Paul Duffin        @Override public Multiset.Entry<E> next() {
4587dd252788645e940eada959bdde927426e2531c9Paul Duffin          Map.Entry<E, Integer> backingEntry = backingIterator.next();
4597dd252788645e940eada959bdde927426e2531c9Paul Duffin          return Multisets.immutableEntry(backingEntry.getKey(),
4607dd252788645e940eada959bdde927426e2531c9Paul Duffin              backingEntry.getValue());
4617dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
4627dd252788645e940eada959bdde927426e2531c9Paul Duffin
4637dd252788645e940eada959bdde927426e2531c9Paul Duffin        @Override public void remove() {
4647dd252788645e940eada959bdde927426e2531c9Paul Duffin          backingIterator.remove();
4657dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
4667dd252788645e940eada959bdde927426e2531c9Paul Duffin      };
4677dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
4687dd252788645e940eada959bdde927426e2531c9Paul Duffin
4697dd252788645e940eada959bdde927426e2531c9Paul Duffin    @Override public void clear() {
4707dd252788645e940eada959bdde927426e2531c9Paul Duffin      countMap.clear();
4717dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
4727dd252788645e940eada959bdde927426e2531c9Paul Duffin
4737dd252788645e940eada959bdde927426e2531c9Paul Duffin    private class EntrySet extends AbstractMultiset<E>.EntrySet {
4747dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override Multiset<E> multiset() {
4757dd252788645e940eada959bdde927426e2531c9Paul Duffin        return OldConcurrentHashMultiset.this;
4767dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
4777dd252788645e940eada959bdde927426e2531c9Paul Duffin
4787dd252788645e940eada959bdde927426e2531c9Paul Duffin      /*
4797dd252788645e940eada959bdde927426e2531c9Paul Duffin      * Note: the superclass toArray() methods assume that size() gives a correct
4807dd252788645e940eada959bdde927426e2531c9Paul Duffin      * answer, which ours does not.
4817dd252788645e940eada959bdde927426e2531c9Paul Duffin      */
4827dd252788645e940eada959bdde927426e2531c9Paul Duffin
4837dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override public Object[] toArray() {
4847dd252788645e940eada959bdde927426e2531c9Paul Duffin        return snapshot().toArray();
4857dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
4867dd252788645e940eada959bdde927426e2531c9Paul Duffin
4877dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override public <T> T[] toArray(T[] array) {
4887dd252788645e940eada959bdde927426e2531c9Paul Duffin        return snapshot().toArray(array);
4897dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
4907dd252788645e940eada959bdde927426e2531c9Paul Duffin
4917dd252788645e940eada959bdde927426e2531c9Paul Duffin      private List<Multiset.Entry<E>> snapshot() {
4927dd252788645e940eada959bdde927426e2531c9Paul Duffin        List<Multiset.Entry<E>> list = Lists.newArrayListWithExpectedSize(size());
4937dd252788645e940eada959bdde927426e2531c9Paul Duffin        // not Iterables.addAll(list, this), because that'll forward back here
4947dd252788645e940eada959bdde927426e2531c9Paul Duffin        Iterators.addAll(list, iterator());
4957dd252788645e940eada959bdde927426e2531c9Paul Duffin        return list;
4967dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
4977dd252788645e940eada959bdde927426e2531c9Paul Duffin
4987dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override public boolean remove(Object object) {
4997dd252788645e940eada959bdde927426e2531c9Paul Duffin        if (object instanceof Multiset.Entry) {
5007dd252788645e940eada959bdde927426e2531c9Paul Duffin          Multiset.Entry<?> entry = (Multiset.Entry<?>) object;
5017dd252788645e940eada959bdde927426e2531c9Paul Duffin          Object element = entry.getElement();
5027dd252788645e940eada959bdde927426e2531c9Paul Duffin          int entryCount = entry.getCount();
5037dd252788645e940eada959bdde927426e2531c9Paul Duffin          return countMap.remove(element, entryCount);
5047dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
5057dd252788645e940eada959bdde927426e2531c9Paul Duffin        return false;
5067dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
5077dd252788645e940eada959bdde927426e2531c9Paul Duffin
5087dd252788645e940eada959bdde927426e2531c9Paul Duffin      /**
5097dd252788645e940eada959bdde927426e2531c9Paul Duffin       * The hash code is the same as countMap's, though the objects aren't equal.
5107dd252788645e940eada959bdde927426e2531c9Paul Duffin       */
5117dd252788645e940eada959bdde927426e2531c9Paul Duffin      @Override public int hashCode() {
5127dd252788645e940eada959bdde927426e2531c9Paul Duffin        return countMap.hashCode();
5137dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
5147dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
5157dd252788645e940eada959bdde927426e2531c9Paul Duffin
5167dd252788645e940eada959bdde927426e2531c9Paul Duffin    /**
5177dd252788645e940eada959bdde927426e2531c9Paul Duffin     * We use a special form of unboxing that treats null as zero.
5187dd252788645e940eada959bdde927426e2531c9Paul Duffin     */
5197dd252788645e940eada959bdde927426e2531c9Paul Duffin    private static int unbox(@Nullable Integer i) {
5207dd252788645e940eada959bdde927426e2531c9Paul Duffin      return (i == null) ? 0 : i;
5217dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
5227dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
5237dd252788645e940eada959bdde927426e2531c9Paul Duffin}
524