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 Bag 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 * <i>NOTE: This interface violates the {@link Collection} contract.</i>
032 * The behavior specified in many of these methods is <i>not</i> the same
033 * as the behavior specified by <code>Collection</code>.
034 * The noncompliant methods are clearly marked with "(Violation)".
035 * Exercise caution when using a bag as a <code>Collection</code>.
036 * <p>
037 * This violation resulted from the original specification of this interface.
038 * In an ideal world, the interface would be changed to fix the problems, however
039 * it has been decided to maintain backwards compatibility instead.
040 *
041 * @param <E> the type held in the bag
042 * @since 2.0
043 * @version $Id: Bag.html 972421 2015-11-14 20:00:04Z tn $
044 */
045public interface Bag<E> extends Collection<E> {
046
047    /**
048     * Returns the number of occurrences (cardinality) of the given
049     * object currently in the bag. If the object does not exist in the
050     * bag, return 0.
051     *
052     * @param object  the object to search for
053     * @return the number of occurrences of the object, zero if not found
054     */
055    int getCount(Object object);
056
057    /**
058     * <i>(Violation)</i>
059     * Adds one copy of the specified object to the Bag.
060     * <p>
061     * If the object is already in the {@link #uniqueSet()} then increment its
062     * count as reported by {@link #getCount(Object)}. Otherwise add it to the
063     * {@link #uniqueSet()} and report its count as 1.
064     * <p>
065     * Since this method always increases the size of the bag,
066     * according to the {@link Collection#add(Object)} contract, it
067     * should always return <code>true</code>.  Since it sometimes returns
068     * <code>false</code>, this method violates the contract.
069     *
070     * @param object  the object to add
071     * @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
072     */
073    boolean add(E object);
074
075    /**
076     * Adds <code>nCopies</code> copies of the specified object to the Bag.
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>nCopies</code>.
081     *
082     * @param object  the object to add
083     * @param nCopies  the number of copies to add
084     * @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
085     */
086    boolean add(E object, int nCopies);
087
088    /**
089     * <i>(Violation)</i>
090     * Removes all occurrences of the given object from the bag.
091     * <p>
092     * This will also remove the object from the {@link #uniqueSet()}.
093     * <p>
094     * According to the {@link Collection#remove(Object)} method,
095     * this method should only remove the <i>first</i> occurrence of the
096     * given object, not <i>all</i> occurrences.
097     *
098     * @param object  the object to remove
099     * @return <code>true</code> if this call changed the collection
100     */
101    boolean remove(Object object);
102
103    /**
104     * Removes <code>nCopies</code> copies of the specified object from the Bag.
105     * <p>
106     * If the number of copies to remove is greater than the actual number of
107     * copies in the Bag, no error is thrown.
108     *
109     * @param object  the object to remove
110     * @param nCopies  the number of copies to remove
111     * @return <code>true</code> if this call changed the collection
112     */
113    boolean remove(Object object, int nCopies);
114
115    /**
116     * Returns a {@link Set} of unique elements in the Bag.
117     * <p>
118     * Uniqueness constraints are the same as those in {@link java.util.Set}.
119     *
120     * @return the Set of unique Bag elements
121     */
122    Set<E> uniqueSet();
123
124    /**
125     * Returns the total number of items in the bag across all types.
126     *
127     * @return the total size of the Bag
128     */
129    int size();
130
131    /**
132     * <i>(Violation)</i>
133     * Returns <code>true</code> if the bag contains all elements in
134     * the given collection, respecting cardinality.  That is, if the
135     * given collection <code>coll</code> contains <code>n</code> copies
136     * of a given object, calling {@link #getCount(Object)} on that object must
137     * be <code>&gt;= n</code> for all <code>n</code> in <code>coll</code>.
138     * <p>
139     * The {@link Collection#containsAll(Collection)} method specifies
140     * that cardinality should <i>not</i> be respected; this method should
141     * return true if the bag contains at least one of every object contained
142     * in the given collection.
143     *
144     * @param coll  the collection to check against
145     * @return <code>true</code> if the Bag contains all the collection
146     */
147    boolean containsAll(Collection<?> coll);
148
149    /**
150     * <i>(Violation)</i>
151     * Remove all elements represented in the given collection,
152     * respecting cardinality.  That is, if the given collection
153     * <code>coll</code> contains <code>n</code> copies of a given object,
154     * the bag will have <code>n</code> fewer copies, assuming the bag
155     * had at least <code>n</code> copies to begin with.
156     *
157     * <p>The {@link Collection#removeAll(Collection)} method specifies
158     * that cardinality should <i>not</i> be respected; this method should
159     * remove <i>all</i> occurrences of every object contained in the
160     * given collection.
161     *
162     * @param coll  the collection to remove
163     * @return <code>true</code> if this call changed the collection
164     */
165    boolean removeAll(Collection<?> coll);
166
167    /**
168     * <i>(Violation)</i>
169     * Remove any members of the bag that are not in the given
170     * collection, respecting cardinality.  That is, if the given
171     * collection <code>coll</code> contains <code>n</code> copies of a
172     * given object and the bag has <code>m &gt; n</code> copies, then
173     * delete <code>m - n</code> copies from the bag.  In addition, if
174     * <code>e</code> is an object in the bag but
175     * <code>!coll.contains(e)</code>, then remove <code>e</code> and any
176     * of its copies.
177     *
178     * <p>The {@link Collection#retainAll(Collection)} method specifies
179     * that cardinality should <i>not</i> be respected; this method should
180     * keep <i>all</i> occurrences of every object contained in the
181     * given collection.
182     *
183     * @param coll  the collection to retain
184     * @return <code>true</code> if this call changed the collection
185     */
186    boolean retainAll(Collection<?> coll);
187
188    /**
189     * Returns an {@link Iterator} over the entire set of members,
190     * including copies due to cardinality. This iterator is fail-fast
191     * and will not tolerate concurrent modifications.
192     *
193     * @return iterator over all elements in the Bag
194     */
195    Iterator<E> iterator();
196
197    // The following is not part of the formal Bag interface, however where possible
198    // Bag implementations should follow these comments.
199//    /**
200//     * Compares this Bag to another.
201//     * This Bag equals another Bag if it contains the same number of occurrences of
202//     * the same elements.
203//     * This equals definition is compatible with the Set interface.
204//     *
205//     * @param obj  the Bag to compare to
206//     * @return true if equal
207//     */
208//    boolean equals(Object obj);
209//
210//    /**
211//     * Gets a hash code for the Bag compatible with the definition of equals.
212//     * The hash code is defined as the sum total of a hash code for each element.
213//     * The per element hash code is defined as
214//     * <code>(e==null ? 0 : e.hashCode()) ^ noOccurances)</code>.
215//     * This hash code definition is compatible with the Set interface.
216//     *
217//     * @return the hash code of the Bag
218//     */
219//    int hashCode();
220
221}