1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import static com.google.common.collect.Multisets.setCountImpl; 20 21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.base.Objects; 23 24 import java.util.AbstractCollection; 25 import java.util.Collection; 26 import java.util.Iterator; 27 import java.util.Set; 28 29 import javax.annotation.Nullable; 30 31 /** 32 * This class provides a skeletal implementation of the {@link Multiset} 33 * interface. A new multiset implementation can be created easily by extending 34 * this class and implementing the {@link Multiset#entrySet()} method, plus 35 * optionally overriding {@link #add(Object, int)} and 36 * {@link #remove(Object, int)} to enable modifications to the multiset. 37 * 38 * <p>The {@link #count} and {@link #size} implementations all iterate across 39 * the set returned by {@link Multiset#entrySet()}, as do many methods acting on 40 * the set returned by {@link #elementSet()}. Override those methods for better 41 * performance. 42 * 43 * @author Kevin Bourrillion 44 * @author Louis Wasserman 45 */ 46 @GwtCompatible 47 abstract class AbstractMultiset<E> extends AbstractCollection<E> 48 implements Multiset<E> { 49 // Query Operations 50 size()51 @Override public int size() { 52 return Multisets.sizeImpl(this); 53 } 54 isEmpty()55 @Override public boolean isEmpty() { 56 return entrySet().isEmpty(); 57 } 58 contains(@ullable Object element)59 @Override public boolean contains(@Nullable Object element) { 60 return count(element) > 0; 61 } 62 iterator()63 @Override public Iterator<E> iterator() { 64 return Multisets.iteratorImpl(this); 65 } 66 67 @Override count(Object element)68 public int count(Object element) { 69 for (Entry<E> entry : entrySet()) { 70 if (Objects.equal(entry.getElement(), element)) { 71 return entry.getCount(); 72 } 73 } 74 return 0; 75 } 76 77 // Modification Operations 78 add(@ullable E element)79 @Override public boolean add(@Nullable E element) { 80 add(element, 1); 81 return true; 82 } 83 84 @Override add(E element, int occurrences)85 public int add(E element, int occurrences) { 86 throw new UnsupportedOperationException(); 87 } 88 remove(Object element)89 @Override public boolean remove(Object element) { 90 return remove(element, 1) > 0; 91 } 92 93 @Override remove(Object element, int occurrences)94 public int remove(Object element, int occurrences) { 95 throw new UnsupportedOperationException(); 96 } 97 98 @Override setCount(E element, int count)99 public int setCount(E element, int count) { 100 return setCountImpl(this, element, count); 101 } 102 103 @Override setCount(E element, int oldCount, int newCount)104 public boolean setCount(E element, int oldCount, int newCount) { 105 return setCountImpl(this, element, oldCount, newCount); 106 } 107 108 // Bulk Operations 109 110 /** 111 * {@inheritDoc} 112 * 113 * <p>This implementation is highly efficient when {@code elementsToAdd} 114 * is itself a {@link Multiset}. 115 */ addAll(Collection<? extends E> elementsToAdd)116 @Override public boolean addAll(Collection<? extends E> elementsToAdd) { 117 return Multisets.addAllImpl(this, elementsToAdd); 118 } 119 removeAll(Collection<?> elementsToRemove)120 @Override public boolean removeAll(Collection<?> elementsToRemove) { 121 return Multisets.removeAllImpl(this, elementsToRemove); 122 } 123 retainAll(Collection<?> elementsToRetain)124 @Override public boolean retainAll(Collection<?> elementsToRetain) { 125 return Multisets.retainAllImpl(this, elementsToRetain); 126 } 127 clear()128 @Override public void clear() { 129 Iterators.clear(entryIterator()); 130 } 131 132 // Views 133 134 private transient Set<E> elementSet; 135 136 @Override elementSet()137 public Set<E> elementSet() { 138 Set<E> result = elementSet; 139 if (result == null) { 140 elementSet = result = createElementSet(); 141 } 142 return result; 143 } 144 145 /** 146 * Creates a new instance of this multiset's element set, which will be 147 * returned by {@link #elementSet()}. 148 */ createElementSet()149 Set<E> createElementSet() { 150 return new ElementSet(); 151 } 152 153 class ElementSet extends Multisets.ElementSet<E> { 154 @Override multiset()155 Multiset<E> multiset() { 156 return AbstractMultiset.this; 157 } 158 } 159 entryIterator()160 abstract Iterator<Entry<E>> entryIterator(); 161 distinctElements()162 abstract int distinctElements(); 163 164 private transient Set<Entry<E>> entrySet; 165 entrySet()166 @Override public Set<Entry<E>> entrySet() { 167 Set<Entry<E>> result = entrySet; 168 return (result == null) ? entrySet = createEntrySet() : result; 169 } 170 171 class EntrySet extends Multisets.EntrySet<E> { multiset()172 @Override Multiset<E> multiset() { 173 return AbstractMultiset.this; 174 } 175 iterator()176 @Override public Iterator<Entry<E>> iterator() { 177 return entryIterator(); 178 } 179 size()180 @Override public int size() { 181 return distinctElements(); 182 } 183 } 184 createEntrySet()185 Set<Entry<E>> createEntrySet() { 186 return new EntrySet(); 187 } 188 189 // Object methods 190 191 /** 192 * {@inheritDoc} 193 * 194 * <p>This implementation returns {@code true} if {@code object} is a multiset 195 * of the same size and if, for each element, the two multisets have the same 196 * count. 197 */ equals(@ullable Object object)198 @Override public boolean equals(@Nullable Object object) { 199 return Multisets.equalsImpl(this, object); 200 } 201 202 /** 203 * {@inheritDoc} 204 * 205 * <p>This implementation returns the hash code of {@link 206 * Multiset#entrySet()}. 207 */ hashCode()208 @Override public int hashCode() { 209 return entrySet().hashCode(); 210 } 211 212 /** 213 * {@inheritDoc} 214 * 215 * <p>This implementation returns the result of invoking {@code toString} on 216 * {@link Multiset#entrySet()}. 217 */ toString()218 @Override public String toString() { 219 return entrySet().toString(); 220 } 221 } 222