• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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