    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         * Gets 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         * Gets 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     * Gets 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}