001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.collections4;
018
019import java.util.Collection;
020import java.util.Iterator;
021import java.util.Set;
022
023/**
024 * Defines a collection that counts the number of times an object appears in
025 * the collection.
026 * <p>
027 * Suppose you have a MultiSet that contains {@code {a, a, b, c}}.
028 * Calling {@link #getCount(Object)} on {@code a} would return 2, while
029 * calling {@link #uniqueSet()} would return {@code {a, b, c}}.
030 * </p>
031 *
032 * @param <E> the type held in the multiset
033 * @since 4.1
034 */
035public interface MultiSet<E> extends Collection<E> {
036
037    /**
038     * An unmodifiable entry for an element and its occurrence as contained in a MultiSet.
039     * <p>
040     * The {@link MultiSet#entrySet()} method returns a view of the multiset whose elements
041     * implement this interface.
042     * </p>
043     *
044     * @param <E>  the element type
045     */
046    interface Entry<E> {
047
048        /**
049         * Compares the specified object with this entry for equality.
050         * Returns true if the given object is also a multiset entry
051         * and the two entries represent the same element with the same
052         * number of occurrences.
053         * <p>
054         * More formally, two entries {@code e1} and {@code e2} represent
055         * the same mapping if
056         * </p>
057         * <pre>
058         *     (e1.getElement()==null ? e2.getElement()==null
059         *                            : e1.getElement().equals(e2.getElement())) &amp;&amp;
060         *     (e1.getCount()==e2.getCount())
061         * </pre>
062         *
063         * @param o object to be compared for equality with this multiset entry
064         * @return true if the specified object is equal to this multiset entry
065         */
066        @Override
067        boolean equals(Object o);
068
069        /**
070         * Returns the number of occurrences for the element of this entry.
071         *
072         * @return the number of occurrences of the element
073         */
074        int getCount();
075
076        /**
077         * Returns the element corresponding to this entry.
078         *
079         * @return the element corresponding to this entry
080         */
081        E getElement();
082
083        /**
084         * Returns the hash code value for this multiset entry.
085         * <p>
086         * The hash code of a multiset entry {@code e} is defined to be:
087         * <pre>
088         *      (e==null ? 0 : e.hashCode()) ^ noOccurrences)
089         * </pre>
090         *
091         * @return the hash code value for this multiset entry
092         */
093        @Override
094        int hashCode();
095    }
096
097    /**
098     * Adds one copy of the specified object to the MultiSet.
099     * <p>
100     * If the object is already in the {@link #uniqueSet()} then increment its
101     * count as reported by {@link #getCount(Object)}. Otherwise, add it to the
102     * {@link #uniqueSet()} and report its count as 1.
103     * </p>
104     *
105     * @param object  the object to add
106     * @return {@code true} always, as the size of the MultiSet is increased
107     *   in any case
108     */
109    @Override
110    boolean add(E object);
111
112    /**
113     * Adds a number of occurrences of the specified object to the MultiSet.
114     * <p>
115     * If the object is already in the {@link #uniqueSet()} then increment its
116     * count as reported by {@link #getCount(Object)}. Otherwise, add it to the
117     * {@link #uniqueSet()} and report its count as {@code occurrences}.
118     * </p>
119     *
120     * @param object  the object to add
121     * @param occurrences  the number of occurrences to add, may be zero,
122     *   in which case no change is made to the multiset
123     * @return the number of occurrences of the object in the multiset before
124     *   this operation; possibly zero
125     * @throws IllegalArgumentException if occurrences is negative
126     */
127    int add(E object, int occurrences);
128
129    /**
130     * Returns {@code true} if the MultiSet contains at least one
131     * occurrence for each element contained in the given collection.
132     *
133     * @param coll  the collection to check against
134     * @return {@code true} if the MultiSet contains all the collection
135     */
136    @Override
137    boolean containsAll(Collection<?> coll);
138
139    /**
140     * Returns a {@link Set} of all entries contained in the MultiSet.
141     * <p>
142     * The returned set is backed by this multiset, so any change to either
143     * is immediately reflected in the other.
144     * </p>
145     *
146     * @return the Set of MultiSet entries
147     */
148    Set<Entry<E>> entrySet();
149
150    /**
151     * Compares this MultiSet to another object.
152     * <p>
153     * This MultiSet equals another object if it is also a MultiSet
154     * that contains the same number of occurrences of the same elements.
155     * </p>
156     *
157     * @param obj  the object to compare to
158     * @return true if equal
159     */
160    @Override
161    boolean equals(Object obj);
162
163    /**
164     * Returns the number of occurrences of the given object currently
165     * in the MultiSet. If the object does not exist in the multiset,
166     * return 0.
167     *
168     * @param object  the object to search for
169     * @return the number of occurrences of the object, zero if not found
170     */
171    int getCount(Object object);
172
173    /**
174     * Gets a hash code for the MultiSet compatible with the definition of equals.
175     * The hash code is defined as the sum total of a hash code for each element.
176     * The per element hash code is defined as
177     * {@code (e==null ? 0 : e.hashCode()) ^ noOccurrences)}.
178     *
179     * @return the hash code of the MultiSet
180     */
181    @Override
182    int hashCode();
183
184    /**
185     * Returns an {@link Iterator} over the entire set of members,
186     * including copies due to cardinality. This iterator is fail-fast
187     * and will not tolerate concurrent modifications.
188     *
189     * @return iterator over all elements in the MultiSet
190     */
191    @Override
192    Iterator<E> iterator();
193
194    /**
195     * Removes one occurrence of the given object from the MultiSet.
196     * <p>
197     * If the number of occurrences after this operation is reduced
198     * to zero, the object will be removed from the {@link #uniqueSet()}.
199     *
200     * @param object  the object to remove
201     * @return {@code true} if this call changed the collection
202     */
203    @Override
204    boolean remove(Object object);
205
206    /**
207     * Removes a number of occurrences of the specified object from the MultiSet.
208     * <p>
209     * If the number of occurrences to remove is greater than the actual number of
210     * occurrences in the multiset, the object will be removed from the multiset.
211     * </p>
212     *
213     * @param object  the object to remove
214     * @param occurrences  the number of occurrences to remove, may be zero,
215     *   in which case no change is made to the multiset
216     * @return the number of occurrences of the object in the multiset
217     *   before the operation; possibly zero
218     * @throws IllegalArgumentException if occurrences is negative
219     */
220    int remove(Object object, int occurrences);
221
222    /**
223     * Remove all occurrences of all elements from this MultiSet represented
224     * in the given collection.
225     *
226     * @param coll  the collection of elements to remove
227     * @return {@code true} if this call changed the multiset
228     */
229    @Override
230    boolean removeAll(Collection<?> coll);
231
232    /**
233     * Remove any elements of this MultiSet that are not contained in the
234     * given collection.
235     *
236     * @param coll  the collection of elements to retain
237     * @return {@code true} if this call changed the multiset
238     */
239    @Override
240    boolean retainAll(Collection<?> coll);
241
242    /**
243     * Sets the number of occurrences of the specified object in the MultiSet
244     * to the given count.
245     * <p>
246     * If the provided count is zero, the object will be removed from the
247     * {@link #uniqueSet()}.
248     * </p>
249     *
250     * @param object  the object to update
251     * @param count  the number of occurrences of the object
252     * @return the number of occurrences of the object before this operation, zero
253     *   if the object was not contained in the multiset
254     * @throws IllegalArgumentException if count is negative
255     */
256    int setCount(E object, int count);
257
258    /**
259     * Returns the total number of items in the MultiSet.
260     *
261     * @return the total size of the multiset
262     */
263    @Override
264    int size();
265
266    /**
267     * Returns a {@link Set} of unique elements in the MultiSet.
268     * <p>
269     * Uniqueness constraints are the same as those in {@link java.util.Set}.
270     * </p>
271     * <p>
272     * The returned set is backed by this multiset, so any change to either
273     * is immediately reflected in the other. Only removal operations are
274     * supported, in which case all occurrences of the element are removed
275     * from the backing multiset.
276     * </p>
277     *
278     * @return the Set of unique MultiSet elements
279     */
280    Set<E> uniqueSet();
281
282}