All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.collections.DefaultMapBag Maven / Gradle / Ivy

/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.apache.commons.collections;

import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.set.UnmodifiableSet;

/**
 * A skeletal implementation of the {@link Bag}
 * interface to minimize the effort required for target implementations.
 * Subclasses need only to call setMap(Map) in their constructor 
 * (or invoke the Map constructor) specifying a map instance that will be used
 * to store the contents of the bag.
 * 

* The map will be used to map bag elements to a number; the number represents * the number of occurrences of that element in the bag. * * @deprecated Moved to bag subpackage as AbstractMapBag. Due to be removed in v4.0. * @since Commons Collections 2.0 * @version $Revision: 646777 $ $Date: 2008-04-10 14:33:15 +0200 (Thu, 10 Apr 2008) $ * * @author Chuck Burdick * @author Michael A. Smith * @author Stephen Colebourne * @author Janek Bogucki */ public abstract class DefaultMapBag implements Bag { private Map _map = null; private int _total = 0; private int _mods = 0; /** * No-argument constructor. * Subclasses should invoke setMap(Map) in * their constructors. */ public DefaultMapBag() { } /** * Constructor that assigns the specified Map as the backing store. * The map must be empty. * * @param map the map to assign */ protected DefaultMapBag(Map map) { setMap(map); } /** * Adds a new element to the bag by incrementing its count in the * underlying map. * * @param object the object to add * @return true if the object was not already in the uniqueSet */ public boolean add(Object object) { return add(object, 1); } /** * Adds a new element to the bag by incrementing its count in the map. * * @param object the object to search for * @param nCopies the number of copies to add * @return true if the object was not already in the uniqueSet */ public boolean add(Object object, int nCopies) { _mods++; if (nCopies > 0) { int count = (nCopies + getCount(object)); _map.put(object, new Integer(count)); _total += nCopies; return (count == nCopies); } else { return false; } } /** * Invokes {@link #add(Object)} for each element in the given collection. * * @param coll the collection to add * @return true if this call changed the bag */ public boolean addAll(Collection coll) { boolean changed = false; Iterator i = coll.iterator(); while (i.hasNext()) { boolean added = add(i.next()); changed = changed || added; } return changed; } /** * Clears the bag by clearing the underlying map. */ public void clear() { _mods++; _map.clear(); _total = 0; } /** * Determines if the bag contains the given element by checking if the * underlying map contains the element as a key. * * @param object the object to search for * @return true if the bag contains the given element */ public boolean contains(Object object) { return _map.containsKey(object); } /** * Determines if the bag contains the given elements. * * @param coll the collection to check against * @return true if the Bag contains all the collection */ public boolean containsAll(Collection coll) { return containsAll(new HashBag(coll)); } /** * Returns true if the bag contains all elements in * the given collection, respecting cardinality. * * @param other the bag to check against * @return true if the Bag contains all the collection */ public boolean containsAll(Bag other) { boolean result = true; Iterator i = other.uniqueSet().iterator(); while (i.hasNext()) { Object current = i.next(); boolean contains = getCount(current) >= other.getCount(current); result = result && contains; } return result; } /** * Returns true if the given object is not null, has the precise type * of this bag, and contains the same number of occurrences of all the * same elements. * * @param object the object to test for equality * @return true if that object equals this bag */ public boolean equals(Object object) { if (object == this) { return true; } if (object instanceof Bag == false) { return false; } Bag other = (Bag) object; if (other.size() != size()) { return false; } for (Iterator it = _map.keySet().iterator(); it.hasNext();) { Object element = it.next(); if (other.getCount(element) != getCount(element)) { return false; } } return true; } /** * Returns the hash code of the underlying map. * * @return the hash code of the underlying map */ public int hashCode() { return _map.hashCode(); } /** * Returns true if the underlying map is empty. * * @return true if there are no elements in this bag */ public boolean isEmpty() { return _map.isEmpty(); } public Iterator iterator() { return new BagIterator(this, extractList().iterator()); } static class BagIterator implements Iterator { private DefaultMapBag _parent = null; private Iterator _support = null; private Object _current = null; private int _mods = 0; public BagIterator(DefaultMapBag parent, Iterator support) { _parent = parent; _support = support; _current = null; _mods = parent.modCount(); } public boolean hasNext() { return _support.hasNext(); } public Object next() { if (_parent.modCount() != _mods) { throw new ConcurrentModificationException(); } _current = _support.next(); return _current; } public void remove() { if (_parent.modCount() != _mods) { throw new ConcurrentModificationException(); } _support.remove(); _parent.remove(_current, 1); _mods++; } } public boolean remove(Object object) { return remove(object, getCount(object)); } public boolean remove(Object object, int nCopies) { _mods++; boolean result = false; int count = getCount(object); if (nCopies <= 0) { result = false; } else if (count > nCopies) { _map.put(object, new Integer(count - nCopies)); result = true; _total -= nCopies; } else { // count > 0 && count <= i // need to remove all result = (_map.remove(object) != null); _total -= count; } return result; } public boolean removeAll(Collection coll) { boolean result = false; if (coll != null) { Iterator i = coll.iterator(); while (i.hasNext()) { boolean changed = remove(i.next(), 1); result = result || changed; } } return result; } /** * Remove any members of the bag that are not in the given * bag, respecting cardinality. * * @param coll the collection to retain * @return true if this call changed the collection */ public boolean retainAll(Collection coll) { return retainAll(new HashBag(coll)); } /** * Remove any members of the bag that are not in the given * bag, respecting cardinality. * @see #retainAll(Collection) * * @param other the bag to retain * @return true if this call changed the collection */ public boolean retainAll(Bag other) { boolean result = false; Bag excess = new HashBag(); Iterator i = uniqueSet().iterator(); while (i.hasNext()) { Object current = i.next(); int myCount = getCount(current); int otherCount = other.getCount(current); if (1 <= otherCount && otherCount <= myCount) { excess.add(current, myCount - otherCount); } else { excess.add(current, myCount); } } if (!excess.isEmpty()) { result = removeAll(excess); } return result; } /** * Returns an array of all of this bag's elements. * * @return an array of all of this bag's elements */ public Object[] toArray() { return extractList().toArray(); } /** * Returns an array of all of this bag's elements. * * @param array the array to populate * @return an array of all of this bag's elements */ public Object[] toArray(Object[] array) { return extractList().toArray(array); } /** * Returns the number of occurrence of the given element in this bag * by looking up its count in the underlying map. * * @param object the object to search for * @return the number of occurrences of the object, zero if not found */ public int getCount(Object object) { int result = 0; Integer count = MapUtils.getInteger(_map, object); if (count != null) { result = count.intValue(); } return result; } /** * Returns an unmodifiable view of the underlying map's key set. * * @return the set of unique elements in this bag */ public Set uniqueSet() { return UnmodifiableSet.decorate(_map.keySet()); } /** * Returns the number of elements in this bag. * * @return the number of elements in this bag */ public int size() { return _total; } /** * Actually walks the bag to make sure the count is correct and * resets the running total * * @return the current total size */ protected int calcTotalSize() { _total = extractList().size(); return _total; } /** * Utility method for implementations to set the map that backs * this bag. Not intended for interactive use outside of * subclasses. */ protected void setMap(Map map) { if (map == null || map.isEmpty() == false) { throw new IllegalArgumentException("The map must be non-null and empty"); } _map = map; } /** * Utility method for implementations to access the map that backs * this bag. Not intended for interactive use outside of * subclasses. */ protected Map getMap() { return _map; } /** * Create a list for use in iteration, etc. */ private List extractList() { List result = new ArrayList(); Iterator i = uniqueSet().iterator(); while (i.hasNext()) { Object current = i.next(); for (int index = getCount(current); index > 0; index--) { result.add(current); } } return result; } /** * Return number of modifications for iterator. * * @return the modification count */ private int modCount() { return _mods; } /** * Implement a toString() method suitable for debugging. * * @return a debugging toString */ public String toString() { StringBuffer buf = new StringBuffer(); buf.append("["); Iterator i = uniqueSet().iterator(); while (i.hasNext()) { Object current = i.next(); int count = getCount(current); buf.append(count); buf.append(":"); buf.append(current); if (i.hasNext()) { buf.append(","); } } buf.append("]"); return buf.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy