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     *
043     * @param <E>  the element type
044     */
045    interface Entry<E> {
046
047        /**
048         * Compares the specified object with this entry for equality.
049         * Returns true if the given object is also a multiset entry
050         * and the two entries represent the same element with the same
051         * number of occurrences.
052         * <p>
053         * More formally, two entries {@code e1} and {@code e2} represent
054         * the same mapping if
055         * <pre>
056         *     (e1.getElement()==null ? e2.getElement()==null
057         *                            : e1.getElement().equals(e2.getElement())) &amp;&amp;
058         *     (e1.getCount()==e2.getCount())
059         * </pre>
060         *
061         * @param o object to be compared for equality with this multiset entry
062         * @return true if the specified object is equal to this multiset entry
063         */
064        @Override
065        boolean equals(Object o);
066
067        /**
068         * Returns the number of occurrences for the element of this entry.
069         *
070         * @return the number of occurrences of the element
071         */
072        int getCount();
073
074        /**
075         * Returns the element corresponding to this entry.
076         *
077         * @return the element corresponding to this entry
078         */
079        E getElement();
080
081        /**
082         * Returns the hash code value for this multiset entry.
083         * <p>
084         * The hash code of a multiset entry {@code e} is defined to be:
085         * <pre>
086         *      (e==null ? 0 : e.hashCode()) ^ noOccurrences)
087         * </pre>
088         *
089         * @return the hash code value for this multiset entry
090         */
091        @Override
092        int hashCode();
093    }
094
095    /**
096     * Adds one copy of the specified object to the MultiSet.
097     * <p>
098     * If the object is already in the {@link #uniqueSet()} then increment its
099     * count as reported by {@link #getCount(Object)}. Otherwise, add it to the
100     * {@link #uniqueSet()} and report its count as 1.
101     *
102     * @param object  the object to add
103     * @return {@code true} always, as the size of the MultiSet is increased
104     *   in any case
105     */
106    @Override
107    boolean add(E object);
108
109    /**
110     * Adds a number of occurrences of the specified object to the MultiSet.
111     * <p>
112     * If the object is already in the {@link #uniqueSet()} then increment its
113     * count as reported by {@link #getCount(Object)}. Otherwise, add it to the
114     * {@link #uniqueSet()} and report its count as {@code occurrences}.
115     *
116     * @param object  the object to add
117     * @param occurrences  the number of occurrences to add, may be zero,
118     *   in which case no change is made to the multiset
119     * @return the number of occurrences of the object in the multiset before
120     *   this operation; possibly zero
121     * @throws IllegalArgumentException if occurrences is negative
122     */
123    int add(E object, int occurrences);
124
125    /**
126     * Returns {@code true} if the MultiSet contains at least one
127     * occurrence for each element contained in the given collection.
128     *
129     * @param coll  the collection to check against
130     * @return {@code true} if the MultiSet contains all the collection
131     */
132    @Override
133    boolean containsAll(Collection<?> coll);
134
135    /**
136     * Returns a {@link Set} of all entries contained in the MultiSet.
137     * <p>
138     * The returned set is backed by this multiset, so any change to either
139     * is immediately reflected in the other.
140     *
141     * @return the Set of MultiSet entries
142     */
143    Set<Entry<E>> entrySet();
144
145    /**
146     * Compares this MultiSet to another object.
147     * <p>
148     * This MultiSet equals another object if it is also a MultiSet
149     * that contains the same number of occurrences of the same elements.
150     *
151     * @param obj  the object to compare to
152     * @return true if equal
153     */
154    @Override
155    boolean equals(Object obj);
156
157    /**
158     * Returns the number of occurrences of the given object currently
159     * in the MultiSet. If the object does not exist in the multiset,
160     * return 0.
161     *
162     * @param object  the object to search for
163     * @return the number of occurrences of the object, zero if not found
164     */
165    int getCount(Object object);
166
167    /**
168     * Gets a hash code for the MultiSet compatible with the definition of equals.
169     * The hash code is defined as the sum total of a hash code for each element.
170     * The per element hash code is defined as
171     * {@code (e==null ? 0 : e.hashCode()) ^ noOccurrences)}.
172     *
173     * @return the hash code of the MultiSet
174     */
175    @Override
176    int hashCode();
177
178    /**
179     * Returns an {@link Iterator} over the entire set of members,
180     * including copies due to cardinality. This iterator is fail-fast
181     * and will not tolerate concurrent modifications.
182     *
183     * @return iterator over all elements in the MultiSet
184     */
185    @Override
186    Iterator<E> iterator();
187
188    /**
189     * Removes one occurrence of the given object from the MultiSet.
190     * <p>
191     * If the number of occurrences after this operation is reduced
192     * to zero, the object will be removed from the {@link #uniqueSet()}.
193     *
194     * @param object  the object to remove
195     * @return {@code true} if this call changed the collection
196     */
197    @Override
198    boolean remove(Object object);
199
200    /**
201     * Removes a number of occurrences of the specified object from the MultiSet.
202     * <p>
203     * If the number of occurrences to remove is greater than the actual number of
204     * occurrences in the multiset, the object will be removed from the multiset.
205     *
206     * @param object  the object to remove
207     * @param occurrences  the number of occurrences to remove, may be zero,
208     *   in which case no change is made to the multiset
209     * @return the number of occurrences of the object in the multiset
210     *   before the operation; possibly zero
211     * @throws IllegalArgumentException if occurrences is negative
212     */
213    int remove(Object object, int occurrences);
214
215    /**
216     * Remove all occurrences of all elements from this MultiSet represented
217     * in the given collection.
218     *
219     * @param coll  the collection of elements to remove
220     * @return {@code true} if this call changed the multiset
221     */
222    @Override
223    boolean removeAll(Collection<?> coll);
224
225    /**
226     * Remove any elements of this MultiSet that are not contained in the
227     * given collection.
228     *
229     * @param coll  the collection of elements to retain
230     * @return {@code true} if this call changed the multiset
231     */
232    @Override
233    boolean retainAll(Collection<?> coll);
234
235    /**
236     * Sets the number of occurrences of the specified object in the MultiSet
237     * to the given count.
238     * <p>
239     * If the provided count is zero, the object will be removed from the
240     * {@link #uniqueSet()}.
241     *
242     * @param object  the object to update
243     * @param count  the number of occurrences of the object
244     * @return the number of occurrences of the object before this operation, zero
245     *   if the object was not contained in the multiset
246     * @throws IllegalArgumentException if count is negative
247     */
248    int setCount(E object, int count);
249
250    /**
251     * Returns the total number of items in the MultiSet.
252     *
253     * @return the total size of the multiset
254     */
255    @Override
256    int size();
257
258    /**
259     * Returns a {@link Set} of unique elements in the MultiSet.
260     * <p>
261     * Uniqueness constraints are the same as those in {@link java.util.Set}.
262     * <p>
263     * The returned set is backed by this multiset, so any change to either
264     * is immediately reflected in the other. Only removal operations are
265     * supported, in which case all occurrences of the element are removed
266     * from the backing multiset.
267     *
268     * @return the Set of unique MultiSet elements
269     */
270    Set<E> uniqueSet();
271
272}