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