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