11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/*
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2007 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.checkArgument;
181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.GwtCompatible;
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.collect.Multiset.Entry;
211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.io.Serializable;
231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Iterator;
241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Map;
251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.concurrent.atomic.AtomicInteger;
261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/**
281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unit test for {@link AbstractMultiset}.
291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert *
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Kevin Bourrillion
311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Louis Wasserman
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */
331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@SuppressWarnings("serial") // No serialization is used in this test
341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@GwtCompatible
351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpublic class SimpleAbstractMultisetTest extends AbstractMultisetTest {
361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  @Override protected <E> Multiset<E> create() {
381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    return new SimpleAbstractMultiset<E>();
391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testFastAddAllMultiset() {
421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final AtomicInteger addCalls = new AtomicInteger();
431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Multiset<String> multiset = new NoRemoveMultiset<String>() {
441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      @Override
451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      public int add(String element, int occurrences) {
461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        addCalls.incrementAndGet();
471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return super.add(element, occurrences);
481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    };
501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    ImmutableMultiset<String> adds =
511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        new ImmutableMultiset.Builder<String>().addCopies("x", 10).build();
521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    multiset.addAll(adds);
531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertEquals(addCalls.get(), 1);
541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  public void testRemoveUnsupported() {
571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Multiset<String> multiset = new NoRemoveMultiset<String>();
581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    multiset.add("a");
591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    try {
601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      multiset.remove("a");
611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      fail();
621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    } catch (UnsupportedOperationException expected) {}
631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    assertTrue(multiset.contains("a"));
641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class NoRemoveMultiset<E> extends AbstractMultiset<E>
671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      implements Serializable {
681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    final Map<E, Integer> backingMap = Maps.newHashMap();
691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public int add(E element, int occurrences) {
711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkArgument(occurrences >= 0);
721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Integer frequency = backingMap.get(element);
731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (frequency == null) {
741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        frequency = 0;
751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (occurrences == 0) {
771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return frequency;
781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkArgument(occurrences <= Integer.MAX_VALUE - frequency);
801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      backingMap.put(element, frequency + occurrences);
811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return frequency;
821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    Iterator<Entry<E>> entryIterator() {
861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      final Iterator<Map.Entry<E, Integer>> backingEntries = backingMap.entrySet().iterator();
871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return new Iterator<Multiset.Entry<E>>() {
881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override
891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        public boolean hasNext() {
901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return backingEntries.hasNext();
911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override
941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        public Multiset.Entry<E> next() {
951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          final Map.Entry<E, Integer> mapEntry = backingEntries.next();
961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          return new Multisets.AbstractEntry<E>() {
971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            @Override
981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            public E getElement() {
991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              return mapEntry.getKey();
1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            @Override
1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            public int getCount() {
1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              Integer frequency = backingMap.get(getElement());
1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert              return (frequency == null) ? 0 : frequency;
1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert            }
1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          };
1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        @Override
1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        public void remove() {
1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert          backingEntries.remove();
1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        }
1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      };
1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override
1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    int distinctElements() {
1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      return backingMap.size();
1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert
1231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  private static class SimpleAbstractMultiset<E> extends NoRemoveMultiset<E> {
1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @SuppressWarnings("unchecked")
1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    @Override public int remove(Object element, int occurrences) {
1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      checkArgument(occurrences >= 0);
1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      Integer count = backingMap.get(element);
1281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      if (count == null) {
1291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return 0;
1301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } else if (count > occurrences) {
1311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        backingMap.put((E) element, count - occurrences);
1321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return count;
1331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      } else {
1341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert        return backingMap.remove(element);
1351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert      }
1361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert    }
1371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  }
1381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert}
139