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