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.errorprone.annotations.CanIgnoreReturnValue; 23 import com.google.errorprone.annotations.concurrent.LazyInit; 24 import com.google.j2objc.annotations.WeakOuter; 25 import java.util.AbstractCollection; 26 import java.util.Collection; 27 import java.util.Iterator; 28 import java.util.Set; 29 import org.checkerframework.checker.nullness.qual.Nullable; 30 31 /** 32 * This class provides a skeletal implementation of the {@link Multiset} interface. A new multiset 33 * implementation can be created easily by extending this class and implementing the {@link 34 * Multiset#entrySet()} method, plus optionally overriding {@link #add(Object, int)} and {@link 35 * #remove(Object, int)} to enable modifications to the multiset. 36 * 37 * <p>The {@link #count} and {@link #size} implementations all iterate across the set returned by 38 * {@link Multiset#entrySet()}, as do many methods acting on the set returned by {@link 39 * #elementSet()}. Override those methods for better performance. 40 * 41 * @author Kevin Bourrillion 42 * @author Louis Wasserman 43 */ 44 @GwtCompatible 45 abstract class AbstractMultiset<E> extends AbstractCollection<E> implements Multiset<E> { 46 // Query Operations 47 48 @Override isEmpty()49 public boolean isEmpty() { 50 return entrySet().isEmpty(); 51 } 52 53 @Override contains(@ullable Object element)54 public boolean contains(@Nullable Object element) { 55 return count(element) > 0; 56 } 57 58 // Modification Operations 59 @CanIgnoreReturnValue 60 @Override add(@ullable E element)61 public final boolean add(@Nullable E element) { 62 add(element, 1); 63 return true; 64 } 65 66 @CanIgnoreReturnValue 67 @Override add(@ullable E element, int occurrences)68 public int add(@Nullable E element, int occurrences) { 69 throw new UnsupportedOperationException(); 70 } 71 72 @CanIgnoreReturnValue 73 @Override remove(@ullable Object element)74 public final boolean remove(@Nullable Object element) { 75 return remove(element, 1) > 0; 76 } 77 78 @CanIgnoreReturnValue 79 @Override remove(@ullable Object element, int occurrences)80 public int remove(@Nullable Object element, int occurrences) { 81 throw new UnsupportedOperationException(); 82 } 83 84 @CanIgnoreReturnValue 85 @Override setCount(@ullable E element, int count)86 public int setCount(@Nullable E element, int count) { 87 return setCountImpl(this, element, count); 88 } 89 90 @CanIgnoreReturnValue 91 @Override setCount(@ullable E element, int oldCount, int newCount)92 public boolean setCount(@Nullable E element, int oldCount, int newCount) { 93 return setCountImpl(this, element, oldCount, newCount); 94 } 95 96 // Bulk Operations 97 98 /** 99 * {@inheritDoc} 100 * 101 * <p>This implementation is highly efficient when {@code elementsToAdd} is itself a {@link 102 * Multiset}. 103 */ 104 @CanIgnoreReturnValue 105 @Override addAll(Collection<? extends E> elementsToAdd)106 public final boolean addAll(Collection<? extends E> elementsToAdd) { 107 return Multisets.addAllImpl(this, elementsToAdd); 108 } 109 110 @CanIgnoreReturnValue 111 @Override removeAll(Collection<?> elementsToRemove)112 public final boolean removeAll(Collection<?> elementsToRemove) { 113 return Multisets.removeAllImpl(this, elementsToRemove); 114 } 115 116 @CanIgnoreReturnValue 117 @Override retainAll(Collection<?> elementsToRetain)118 public final boolean retainAll(Collection<?> elementsToRetain) { 119 return Multisets.retainAllImpl(this, elementsToRetain); 120 } 121 122 @Override clear()123 public abstract void clear(); 124 125 // Views 126 127 @LazyInit private transient @Nullable Set<E> elementSet; 128 129 @Override elementSet()130 public Set<E> elementSet() { 131 Set<E> result = elementSet; 132 if (result == null) { 133 elementSet = result = createElementSet(); 134 } 135 return result; 136 } 137 138 /** 139 * Creates a new instance of this multiset's element set, which will be returned by {@link 140 * #elementSet()}. 141 */ createElementSet()142 Set<E> createElementSet() { 143 return new ElementSet(); 144 } 145 146 @WeakOuter 147 class ElementSet extends Multisets.ElementSet<E> { 148 @Override multiset()149 Multiset<E> multiset() { 150 return AbstractMultiset.this; 151 } 152 153 @Override iterator()154 public Iterator<E> iterator() { 155 return elementIterator(); 156 } 157 } 158 elementIterator()159 abstract Iterator<E> elementIterator(); 160 161 @LazyInit private transient @Nullable Set<Entry<E>> entrySet; 162 163 @Override entrySet()164 public Set<Entry<E>> entrySet() { 165 Set<Entry<E>> result = entrySet; 166 if (result == null) { 167 entrySet = result = createEntrySet(); 168 } 169 return result; 170 } 171 172 @WeakOuter 173 class EntrySet extends Multisets.EntrySet<E> { 174 @Override multiset()175 Multiset<E> multiset() { 176 return AbstractMultiset.this; 177 } 178 179 @Override iterator()180 public Iterator<Entry<E>> iterator() { 181 return entryIterator(); 182 } 183 184 @Override size()185 public int size() { 186 return distinctElements(); 187 } 188 } 189 createEntrySet()190 Set<Entry<E>> createEntrySet() { 191 return new EntrySet(); 192 } 193 entryIterator()194 abstract Iterator<Entry<E>> entryIterator(); 195 distinctElements()196 abstract int distinctElements(); 197 198 // Object methods 199 200 /** 201 * {@inheritDoc} 202 * 203 * <p>This implementation returns {@code true} if {@code object} is a multiset of the same size 204 * and if, for each element, the two multisets have the same count. 205 */ 206 @Override equals(@ullable Object object)207 public final boolean equals(@Nullable Object object) { 208 return Multisets.equalsImpl(this, object); 209 } 210 211 /** 212 * {@inheritDoc} 213 * 214 * <p>This implementation returns the hash code of {@link Multiset#entrySet()}. 215 */ 216 @Override hashCode()217 public final int hashCode() { 218 return entrySet().hashCode(); 219 } 220 221 /** 222 * {@inheritDoc} 223 * 224 * <p>This implementation returns the result of invoking {@code toString} on {@link 225 * Multiset#entrySet()}. 226 */ 227 @Override toString()228 public final String toString() { 229 return entrySet().toString(); 230 } 231 } 232