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