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