    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}