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 17package com.google.common.collect; 18 19import static com.google.common.collect.Multisets.setCountImpl; 20 21import com.google.common.annotations.GwtCompatible; 22import com.google.common.base.Objects; 23 24import java.util.AbstractCollection; 25import java.util.Collection; 26import java.util.Iterator; 27import java.util.Set; 28 29import 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 47abstract class AbstractMultiset<E> extends AbstractCollection<E> 48 implements Multiset<E> { 49 // Query Operations 50 51 @Override public int size() { 52 return Multisets.sizeImpl(this); 53 } 54 55 @Override public boolean isEmpty() { 56 return entrySet().isEmpty(); 57 } 58 59 @Override public boolean contains(@Nullable Object element) { 60 return count(element) > 0; 61 } 62 63 @Override public Iterator<E> iterator() { 64 return Multisets.iteratorImpl(this); 65 } 66 67 @Override 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 79 @Override public boolean add(@Nullable E element) { 80 add(element, 1); 81 return true; 82 } 83 84 @Override 85 public int add(E element, int occurrences) { 86 throw new UnsupportedOperationException(); 87 } 88 89 @Override public boolean remove(Object element) { 90 return remove(element, 1) > 0; 91 } 92 93 @Override 94 public int remove(Object element, int occurrences) { 95 throw new UnsupportedOperationException(); 96 } 97 98 @Override 99 public int setCount(E element, int count) { 100 return setCountImpl(this, element, count); 101 } 102 103 @Override 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 */ 116 @Override public boolean addAll(Collection<? extends E> elementsToAdd) { 117 return Multisets.addAllImpl(this, elementsToAdd); 118 } 119 120 @Override public boolean removeAll(Collection<?> elementsToRemove) { 121 return Multisets.removeAllImpl(this, elementsToRemove); 122 } 123 124 @Override public boolean retainAll(Collection<?> elementsToRetain) { 125 return Multisets.retainAllImpl(this, elementsToRetain); 126 } 127 128 @Override public void clear() { 129 Iterators.clear(entryIterator()); 130 } 131 132 // Views 133 134 private transient Set<E> elementSet; 135 136 @Override 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 */ 149 Set<E> createElementSet() { 150 return new ElementSet(); 151 } 152 153 class ElementSet extends Multisets.ElementSet<E> { 154 @Override 155 Multiset<E> multiset() { 156 return AbstractMultiset.this; 157 } 158 } 159 160 abstract Iterator<Entry<E>> entryIterator(); 161 162 abstract int distinctElements(); 163 164 private transient Set<Entry<E>> entrySet; 165 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> { 172 @Override Multiset<E> multiset() { 173 return AbstractMultiset.this; 174 } 175 176 @Override public Iterator<Entry<E>> iterator() { 177 return entryIterator(); 178 } 179 180 @Override public int size() { 181 return distinctElements(); 182 } 183 } 184 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 */ 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 */ 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 */ 218 @Override public String toString() { 219 return entrySet().toString(); 220 } 221} 222