You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tn...@apache.org on 2015/11/21 21:13:35 UTC
svn commit: r1715563 - in
/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset:
AbstractMapMultiSet.java AbstractMultiSet.java HashMultiSet.java
Author: tn
Date: Sat Nov 21 20:13:35 2015
New Revision: 1715563
URL: http://svn.apache.org/viewvc?rev=1715563&view=rev
Log:
Add abstract class to simplify creation of MultiSet implementations, needed for MultiValuedMap; additional cleanup.
Added:
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMultiSet.java (with props)
Modified:
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/HashMultiSet.java
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java?rev=1715563&r1=1715562&r2=1715563&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java Sat Nov 21 20:13:35 2015
@@ -20,16 +20,11 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
-import java.util.AbstractCollection;
-import java.util.AbstractSet;
-import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
-import java.util.Set;
import org.apache.commons.collections4.MultiSet;
-import org.apache.commons.collections4.collection.AbstractCollectionDecorator;
import org.apache.commons.collections4.iterators.AbstractIteratorDecorator;
/**
@@ -43,7 +38,7 @@ import org.apache.commons.collections4.i
* @since 4.1
* @version $Id$
*/
-public abstract class AbstractMapMultiSet<E> extends AbstractCollection<E> implements MultiSet<E> {
+public abstract class AbstractMapMultiSet<E> extends AbstractMultiSet<E> {
/** The map to use to store the data */
private transient Map<E, MutableInteger> map;
@@ -51,10 +46,6 @@ public abstract class AbstractMapMultiSe
private transient int size;
/** The modification count for fail fast iterators */
private transient int modCount;
- /** View of the elements */
- private transient Set<E> uniqueSet;
- /** View of the entries */
- private transient Set<Entry<E>> entrySet;
/**
* Constructor needed for subclass serialisation.
@@ -78,12 +69,23 @@ public abstract class AbstractMapMultiSe
* Utility method for implementations to access the map that backs this multiset.
* Not intended for interactive use outside of subclasses.
*
- * @return the map being used by the Bag
+ * @return the map being used by the MultiSet
*/
protected Map<E, MutableInteger> getMap() {
return map;
}
+ /**
+ * Sets the map being wrapped.
+ * <p>
+ * <b>NOTE:</b> this method should only be used during deserialization
+ *
+ * @param map the map to wrap
+ */
+ protected void setMap(Map<E, MutableInteger> map) {
+ this.map = map;
+ }
+
//-----------------------------------------------------------------------
/**
* Returns the number of elements in this multiset.
@@ -121,21 +123,6 @@ public abstract class AbstractMapMultiSe
return 0;
}
- @Override
- public int setCount(final E object, final int count) {
- if (count < 0) {
- throw new IllegalArgumentException("Count must not be negative.");
- }
-
- int oldCount = getCount(object);
- if (oldCount < count) {
- add(object, count - oldCount);
- } else {
- remove(object, oldCount - count);
- }
- return oldCount;
- }
-
//-----------------------------------------------------------------------
/**
* Determines if the multiset contains the given element by checking if the
@@ -158,13 +145,13 @@ public abstract class AbstractMapMultiSe
*/
@Override
public Iterator<E> iterator() {
- return new MultiSetIterator<E>(this);
+ return new MapBasedMultiSetIterator<E>(this);
}
/**
* Inner class iterator for the MultiSet.
*/
- static class MultiSetIterator<E> implements Iterator<E> {
+ private static class MapBasedMultiSetIterator<E> implements Iterator<E> {
private final AbstractMapMultiSet<E> parent;
private final Iterator<Map.Entry<E, MutableInteger>> entryIterator;
private Map.Entry<E, MutableInteger> current;
@@ -177,7 +164,7 @@ public abstract class AbstractMapMultiSe
*
* @param parent the parent multiset
*/
- public MultiSetIterator(final AbstractMapMultiSet<E> parent) {
+ public MapBasedMultiSetIterator(final AbstractMapMultiSet<E> parent) {
this.parent = parent;
this.entryIterator = parent.map.entrySet().iterator();
this.current = null;
@@ -228,12 +215,6 @@ public abstract class AbstractMapMultiSe
//-----------------------------------------------------------------------
@Override
- public boolean add(final E object) {
- add(object, 1);
- return true;
- }
-
- @Override
public int add(final E object, final int occurrences) {
if (occurrences < 0) {
throw new IllegalArgumentException("Occurrences must not be negative.");
@@ -266,11 +247,6 @@ public abstract class AbstractMapMultiSe
}
@Override
- public boolean remove(final Object object) {
- return remove(object, 1) != 0;
- }
-
- @Override
public int remove(final Object object, final int occurrences) {
if (occurrences < 0) {
throw new IllegalArgumentException("Occurrences must not be negative.");
@@ -294,18 +270,6 @@ public abstract class AbstractMapMultiSe
return oldCount;
}
- @Override
- public boolean removeAll(final Collection<?> coll) {
- boolean result = false;
- final Iterator<?> i = coll.iterator();
- while (i.hasNext()) {
- final Object obj = i.next();
- final boolean changed = remove(obj, getCount(obj)) != 0;
- result = result || changed;
- }
- return result;
- }
-
//-----------------------------------------------------------------------
/**
* Mutable integer class for storing the data.
@@ -337,165 +301,23 @@ public abstract class AbstractMapMultiSe
}
//-----------------------------------------------------------------------
- /**
- * Returns an array of all of this multiset's elements.
- *
- * @return an array of all of this multiset's elements
- */
- @Override
- public Object[] toArray() {
- final Object[] result = new Object[size()];
- int i = 0;
- final Iterator<E> it = map.keySet().iterator();
- while (it.hasNext()) {
- final E current = it.next();
- for (int index = getCount(current); index > 0; index--) {
- result[i++] = current;
- }
- }
- return result;
- }
-
- /**
- * Returns an array of all of this multiset's elements.
- * If the input array has more elements than are in the multiset,
- * trailing elements will be set to null.
- *
- * @param <T> the type of the array elements
- * @param array the array to populate
- * @return an array of all of this multiset's elements
- * @throws ArrayStoreException if the runtime type of the specified array is not
- * a supertype of the runtime type of the elements in this list
- * @throws NullPointerException if the specified array is null
- */
@Override
- public <T> T[] toArray(T[] array) {
- final int size = size();
- if (array.length < size) {
- @SuppressWarnings("unchecked") // safe as both are of type T
- final T[] unchecked = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
- array = unchecked;
- }
-
- int i = 0;
- final Iterator<E> it = map.keySet().iterator();
- while (it.hasNext()) {
- final E current = it.next();
- for (int index = getCount(current); index > 0; index--) {
- // unsafe, will throw ArrayStoreException if types are not compatible, see javadoc
- @SuppressWarnings("unchecked")
- final T unchecked = (T) current;
- array[i++] = unchecked;
- }
- }
- while (i < array.length) {
- array[i++] = null;
- }
- return array;
+ protected Iterator<E> createUniqueSetIterator() {
+ return new UniqueSetIterator<E>(getMap().keySet().iterator(), this);
}
- /**
- * Returns a view of the underlying map's key set.
- *
- * @return the set of unique elements in this multiset
- */
@Override
- public Set<E> uniqueSet() {
- if (uniqueSet == null) {
- uniqueSet = new UniqueSet<E>(this);
- }
- return uniqueSet;
- }
-
- /**
- * Creates a unique set iterator.
- * Subclasses can override this to return iterators with different properties.
- *
- * @param iterator the iterator to decorate
- * @return the uniqueSet iterator
- */
- protected Iterator<E> createUniqueSetIterator(final Iterator<E> iterator) {
- return new UniqueSetIterator<E>(iterator, this);
+ protected int uniqueElements() {
+ return map.size();
}
- /**
- * Returns an unmodifiable view of the underlying map's key set.
- *
- * @return the set of unique elements in this multiset
- */
@Override
- public Set<Entry<E>> entrySet() {
- if (entrySet == null) {
- entrySet = new EntrySet<E>(this);
- }
- return entrySet;
- }
-
- /**
- * Creates an entry set iterator.
- * Subclasses can override this to return iterators with different properties.
- *
- * @param iterator the iterator to decorate
- * @return the entrySet iterator
- */
- protected Iterator<Entry<E>> createEntrySetIterator(final Iterator<Map.Entry<E, MutableInteger>> iterator) {
- return new EntrySetIterator<E>(iterator, this);
+ protected Iterator<Entry<E>> createEntrySetIterator() {
+ return new EntrySetIterator<E>(map.entrySet().iterator(), this);
}
//-----------------------------------------------------------------------
/**
- * Inner class UniqueSet.
- */
- protected static class UniqueSet<E> extends AbstractCollectionDecorator<E> implements Set<E> {
-
- /** Serialization version */
- private static final long serialVersionUID = 20150610L;
-
- /** The parent multiset */
- protected final AbstractMapMultiSet<E> parent;
-
- /**
- * Constructs a new unique element view of the MultiSet.
- *
- * @param parent the parent MultiSet
- */
- protected UniqueSet(final AbstractMapMultiSet<E> parent) {
- super(parent.map.keySet());
- this.parent = parent;
- }
-
- @Override
- public Iterator<E> iterator() {
- return parent.createUniqueSetIterator(super.iterator());
- }
-
- @Override
- public boolean contains(final Object key) {
- return parent.contains(key);
- }
-
- @Override
- public boolean remove(final Object key) {
- return parent.remove(key, parent.getCount(key)) != 0;
- }
-
- @Override
- public boolean equals(final Object object) {
- return object == this || decorated().equals(object);
- }
-
- @Override
- public int hashCode() {
- return decorated().hashCode();
- }
-
- @Override
- public void clear() {
- parent.clear();
- }
- }
-
- /**
* Inner class UniqueSetIterator.
*/
protected static class UniqueSetIterator<E> extends AbstractIteratorDecorator<E> {
@@ -539,61 +361,6 @@ public abstract class AbstractMapMultiSe
}
}
- //-----------------------------------------------------------------------
- /**
- * Inner class EntrySet.
- */
- protected static class EntrySet<E> extends AbstractSet<Entry<E>> {
-
- private final AbstractMapMultiSet<E> parent;
-
- /**
- * Constructs a new view of the MultiSet.
- *
- * @param parent the parent MultiSet
- */
- protected EntrySet(final AbstractMapMultiSet<E> parent) {
- this.parent = parent;
- }
-
- @Override
- public int size() {
- return parent.map.entrySet().size();
- }
-
- @Override
- public Iterator<Entry<E>> iterator() {
- return parent.createEntrySetIterator(parent.map.entrySet().iterator());
- }
-
- @Override
- public boolean contains(final Object obj) {
- if (obj instanceof Entry<?> == false) {
- return false;
- }
- final Entry<?> entry = (Entry<?>) obj;
- final Object element = entry.getElement();
- return parent.getCount(element) == entry.getCount();
- }
-
- @Override
- public boolean remove(final Object obj) {
- if (obj instanceof Entry<?> == false) {
- return false;
- }
- final Entry<?> entry = (Entry<?>) obj;
- final Object element = entry.getElement();
- if (parent.contains(element)) {
- final int count = parent.getCount(element);
- if (entry.getCount() == count) {
- parent.remove(element, count);
- return true;
- }
- }
- return false;
- }
- }
-
/**
* Inner class EntrySetIterator.
*/
@@ -647,7 +414,7 @@ public abstract class AbstractMapMultiSe
/**
* Inner class MultiSetEntry.
*/
- protected static class MultiSetEntry<E> implements Entry<E> {
+ protected static class MultiSetEntry<E> extends AbstractEntry<E> {
protected final Map.Entry<E, MutableInteger> parentEntry;
@@ -668,20 +435,15 @@ public abstract class AbstractMapMultiSe
public int getCount() {
return parentEntry.getValue().value;
}
-
- @Override
- public String toString() {
- return String.format("%s:%d", getElement(), getCount());
- }
-
}
//-----------------------------------------------------------------------
/**
- * Write the map out using a custom routine.
+ * Write the multiset out using a custom routine.
* @param out the output stream
* @throws IOException any of the usual I/O related exceptions
*/
+ @Override
protected void doWriteObject(final ObjectOutputStream out) throws IOException {
out.writeInt(map.size());
for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
@@ -691,16 +453,15 @@ public abstract class AbstractMapMultiSe
}
/**
- * Read the map in using a custom routine.
- * @param map the map to use
+ * Read the multiset in using a custom routine.
* @param in the input stream
* @throws IOException any of the usual I/O related exceptions
* @throws ClassNotFoundException if the stream contains an object which class can not be loaded
* @throws ClassCastException if the stream does not contain the correct objects
*/
- protected void doReadObject(final Map<E, MutableInteger> map, final ObjectInputStream in)
+ @Override
+ protected void doReadObject(final ObjectInputStream in)
throws IOException, ClassNotFoundException {
- this.map = map;
final int entrySize = in.readInt();
for (int i = 0; i < entrySize; i++) {
@SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect
@@ -712,6 +473,64 @@ public abstract class AbstractMapMultiSe
}
//-----------------------------------------------------------------------
+ /**
+ * Returns an array of all of this multiset's elements.
+ *
+ * @return an array of all of this multiset's elements
+ */
+ @Override
+ public Object[] toArray() {
+ final Object[] result = new Object[size()];
+ int i = 0;
+ for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
+ final E current = entry.getKey();
+ final MutableInteger count = entry.getValue();
+ for (int index = count.value; index > 0; index--) {
+ result[i++] = current;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns an array of all of this multiset's elements.
+ * If the input array has more elements than are in the multiset,
+ * trailing elements will be set to null.
+ *
+ * @param <T> the type of the array elements
+ * @param array the array to populate
+ * @return an array of all of this multiset's elements
+ * @throws ArrayStoreException if the runtime type of the specified array is not
+ * a supertype of the runtime type of the elements in this list
+ * @throws NullPointerException if the specified array is null
+ */
+ @Override
+ public <T> T[] toArray(T[] array) {
+ final int size = size();
+ if (array.length < size) {
+ @SuppressWarnings("unchecked") // safe as both are of type T
+ final T[] unchecked = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
+ array = unchecked;
+ }
+
+ int i = 0;
+ for (final Map.Entry<E, MutableInteger> entry : map.entrySet()) {
+ final E current = entry.getKey();
+ final MutableInteger count = entry.getValue();
+ for (int index = count.value; index > 0; index--) {
+ // unsafe, will throw ArrayStoreException if types are not compatible, see javadoc
+ @SuppressWarnings("unchecked")
+ final T unchecked = (T) current;
+ array[i++] = unchecked;
+ }
+ }
+ while (i < array.length) {
+ array[i++] = null;
+ }
+ return array;
+ }
+
+ //-----------------------------------------------------------------------
@Override
public boolean equals(final Object object) {
if (object == this) {
@@ -742,32 +561,4 @@ public abstract class AbstractMapMultiSe
}
return total;
}
-
- /**
- * Implement a toString() method suitable for debugging.
- *
- * @return a debugging toString
- */
- @Override
- public String toString() {
- if (size() == 0) {
- return "[]";
- }
- final StringBuilder buf = new StringBuilder();
- buf.append('[');
- final Iterator<E> it = uniqueSet().iterator();
- while (it.hasNext()) {
- final Object current = it.next();
- final int count = getCount(current);
- buf.append(current);
- buf.append(':');
- buf.append(count);
- if (it.hasNext()) {
- buf.append(", ");
- }
- }
- buf.append(']');
- return buf.toString();
- }
-
}
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMultiSet.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMultiSet.java?rev=1715563&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMultiSet.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMultiSet.java Sat Nov 21 20:13:35 2015
@@ -0,0 +1,509 @@
+/*
+ * 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.collections4.multiset;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.AbstractCollection;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.collections4.IteratorUtils;
+import org.apache.commons.collections4.MultiSet;
+import org.apache.commons.collections4.Transformer;
+
+/**
+ * Abstract implementation of the {@link MultiSet} interface to simplify the
+ * creation of subclass implementations.
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public abstract class AbstractMultiSet<E> extends AbstractCollection<E> implements MultiSet<E> {
+
+ /** View of the elements */
+ private transient Set<E> uniqueSet;
+ /** View of the entries */
+ private transient Set<Entry<E>> entrySet;
+
+ /**
+ * Constructor needed for subclass serialisation.
+ */
+ protected AbstractMultiSet() {
+ super();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns the number of elements in this multiset.
+ *
+ * @return current size of the multiset
+ */
+ @Override
+ public int size() {
+ int totalSize = 0;
+ for (Entry<E> entry : entrySet()) {
+ totalSize += entry.getCount();
+ }
+ return totalSize;
+ }
+
+ /**
+ * Returns the number of occurrence of the given element in this multiset by
+ * iterating over its entrySet.
+ *
+ * @param object the object to search for
+ * @return the number of occurrences of the object, zero if not found
+ */
+ @Override
+ public int getCount(final Object object) {
+ for (Entry<E> entry : entrySet()) {
+ final E element = entry.getElement();
+ if (element == object ||
+ element != null && element.equals(object)) {
+ return entry.getCount();
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int setCount(final E object, final int count) {
+ if (count < 0) {
+ throw new IllegalArgumentException("Count must not be negative.");
+ }
+
+ int oldCount = getCount(object);
+ if (oldCount < count) {
+ add(object, count - oldCount);
+ } else {
+ remove(object, oldCount - count);
+ }
+ return oldCount;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Determines if the multiset contains the given element.
+ *
+ * @param object the object to search for
+ * @return true if the multiset contains the given element
+ */
+ @Override
+ public boolean contains(final Object object) {
+ return getCount(object) > 0;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets an iterator over the multiset elements. Elements present in the
+ * MultiSet more than once will be returned repeatedly.
+ *
+ * @return the iterator
+ */
+ @Override
+ public Iterator<E> iterator() {
+ return new MultiSetIterator<E>(this);
+ }
+
+ /**
+ * Inner class iterator for the MultiSet.
+ */
+ private static class MultiSetIterator<E> implements Iterator<E> {
+ private final AbstractMultiSet<E> parent;
+ private final Iterator<Entry<E>> entryIterator;
+ private Entry<E> current;
+ private int itemCount;
+ private boolean canRemove;
+
+ /**
+ * Constructor.
+ *
+ * @param parent the parent multiset
+ */
+ public MultiSetIterator(final AbstractMultiSet<E> parent) {
+ this.parent = parent;
+ this.entryIterator = parent.entrySet().iterator();
+ this.current = null;
+ this.canRemove = false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean hasNext() {
+ return itemCount > 0 || entryIterator.hasNext();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public E next() {
+ if (itemCount == 0) {
+ current = entryIterator.next();
+ itemCount = current.getCount();
+ }
+ canRemove = true;
+ itemCount--;
+ return current.getElement();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void remove() {
+ if (canRemove == false) {
+ throw new IllegalStateException();
+ }
+ final int count = current.getCount();
+ if (count > 1) {
+ parent.remove(current.getElement());
+ } else {
+ entryIterator.remove();
+ }
+ canRemove = false;
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public boolean add(final E object) {
+ add(object, 1);
+ return true;
+ }
+
+ @Override
+ public int add(final E object, final int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Clears the multiset removing all elements from the entrySet.
+ */
+ @Override
+ public void clear() {
+ Iterator<Entry<E>> it = entrySet().iterator();
+ while (it.hasNext()) {
+ it.next();
+ it.remove();
+ }
+ }
+
+ @Override
+ public boolean remove(final Object object) {
+ return remove(object, 1) != 0;
+ }
+
+ @Override
+ public int remove(final Object object, final int occurrences) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean removeAll(final Collection<?> coll) {
+ boolean result = false;
+ final Iterator<?> i = coll.iterator();
+ while (i.hasNext()) {
+ final Object obj = i.next();
+ final boolean changed = remove(obj, getCount(obj)) != 0;
+ result = result || changed;
+ }
+ return result;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Returns a view of the unique elements of this multiset.
+ *
+ * @return the set of unique elements in this multiset
+ */
+ @Override
+ public Set<E> uniqueSet() {
+ if (uniqueSet == null) {
+ uniqueSet = createUniqueSet();
+ }
+ return uniqueSet;
+ }
+
+ /**
+ * Create a new view for the set of unique elements in this multiset.
+ *
+ * @return a view of the set of unique elements
+ */
+ protected Set<E> createUniqueSet() {
+ return new UniqueSet<E>(this);
+ }
+
+ /**
+ * Creates a unique set iterator.
+ * Subclasses can override this to return iterators with different properties.
+ *
+ * @return the uniqueSet iterator
+ */
+ protected Iterator<E> createUniqueSetIterator() {
+ final Transformer<Entry<E>, E> transformer = new Transformer<Entry<E>, E>() {
+ @Override
+ public E transform(Entry<E> entry) {
+ return entry.getElement();
+ }
+ };
+ return IteratorUtils.transformedIterator(entrySet().iterator(), transformer);
+ }
+
+ /**
+ * Returns an unmodifiable view of the entries of this multiset.
+ *
+ * @return the set of entries in this multiset
+ */
+ @Override
+ public Set<Entry<E>> entrySet() {
+ if (entrySet == null) {
+ entrySet = createEntrySet();
+ }
+ return entrySet;
+ }
+
+ /**
+ * Create a new view for the set of entries in this multiset.
+ *
+ * @return a view of the set of entries
+ */
+ protected Set<Entry<E>> createEntrySet() {
+ return new EntrySet<E>(this);
+ }
+
+ /**
+ * Returns the number of unique elements in this multiset.
+ *
+ * @return the number of unique elements
+ */
+ protected abstract int uniqueElements();
+
+ /**
+ * Creates an entry set iterator.
+ * Subclasses can override this to return iterators with different properties.
+ *
+ * @return the entrySet iterator
+ */
+ protected abstract Iterator<Entry<E>> createEntrySetIterator();
+
+ //-----------------------------------------------------------------------
+ /**
+ * Inner class UniqueSet.
+ */
+ protected static class UniqueSet<E> extends AbstractSet<E> {
+
+ /** The parent multiset */
+ protected final AbstractMultiSet<E> parent;
+
+ /**
+ * Constructs a new unique element view of the MultiSet.
+ *
+ * @param parent the parent MultiSet
+ */
+ protected UniqueSet(final AbstractMultiSet<E> parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return parent.createUniqueSetIterator();
+ }
+
+ @Override
+ public boolean contains(final Object key) {
+ return parent.contains(key);
+ }
+
+ @Override
+ public boolean containsAll(final Collection<?> coll) {
+ return parent.containsAll(coll);
+ }
+
+ @Override
+ public boolean remove(final Object key) {
+ return parent.remove(key, parent.getCount(key)) != 0;
+ }
+
+ @Override
+ public int size() {
+ return parent.uniqueElements();
+ }
+
+ @Override
+ public void clear() {
+ parent.clear();
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Inner class EntrySet.
+ */
+ protected static class EntrySet<E> extends AbstractSet<Entry<E>> {
+
+ private final AbstractMultiSet<E> parent;
+
+ /**
+ * Constructs a new view of the MultiSet.
+ *
+ * @param parent the parent MultiSet
+ */
+ protected EntrySet(final AbstractMultiSet<E> parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public int size() {
+ return parent.uniqueElements();
+ }
+
+ @Override
+ public Iterator<Entry<E>> iterator() {
+ return parent.createEntrySetIterator();
+ }
+
+ @Override
+ public boolean contains(final Object obj) {
+ if (obj instanceof Entry<?> == false) {
+ return false;
+ }
+ final Entry<?> entry = (Entry<?>) obj;
+ final Object element = entry.getElement();
+ return parent.getCount(element) == entry.getCount();
+ }
+
+ @Override
+ public boolean remove(final Object obj) {
+ if (obj instanceof Entry<?> == false) {
+ return false;
+ }
+ final Entry<?> entry = (Entry<?>) obj;
+ final Object element = entry.getElement();
+ if (parent.contains(element)) {
+ final int count = parent.getCount(element);
+ if (entry.getCount() == count) {
+ parent.remove(element, count);
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Inner class AbstractEntry.
+ */
+ protected static abstract class AbstractEntry<E> implements Entry<E> {
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof Entry) {
+ final Entry<?> other = (Entry<?>) object;
+ final E element = this.getElement();
+ final Object otherElement = other.getElement();
+
+ return this.getCount() == other.getCount() &&
+ (element == otherElement ||
+ element != null && element.equals(otherElement));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ final E element = getElement();
+ return ((element == null) ? 0 : element.hashCode()) ^ getCount();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s:%d", getElement(), getCount());
+ }
+
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Write the multiset out using a custom routine.
+ * @param out the output stream
+ * @throws IOException any of the usual I/O related exceptions
+ */
+ protected void doWriteObject(final ObjectOutputStream out) throws IOException {
+ out.writeInt(entrySet().size());
+ for (final Entry<E> entry : entrySet()) {
+ out.writeObject(entry.getElement());
+ out.writeInt(entry.getCount());
+ }
+ }
+
+ /**
+ * Read the multiset in using a custom routine.
+ * @param in the input stream
+ * @throws IOException any of the usual I/O related exceptions
+ * @throws ClassNotFoundException if the stream contains an object which class can not be loaded
+ * @throws ClassCastException if the stream does not contain the correct objects
+ */
+ protected void doReadObject(final ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ final int entrySize = in.readInt();
+ for (int i = 0; i < entrySize; i++) {
+ @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect
+ final E obj = (E) in.readObject();
+ final int count = in.readInt();
+ setCount(obj, count);
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ @Override
+ public boolean equals(final Object object) {
+ if (object == this) {
+ return true;
+ }
+ if (object instanceof MultiSet == false) {
+ return false;
+ }
+ final MultiSet<?> other = (MultiSet<?>) object;
+ if (other.size() != size()) {
+ return false;
+ }
+ for (final Entry<E> entry : entrySet()) {
+ if (other.getCount(entry.getElement()) != getCount(entry.getElement())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return entrySet().hashCode();
+ }
+
+ /**
+ * Implement a toString() method suitable for debugging.
+ *
+ * @return a debugging toString
+ */
+ @Override
+ public String toString() {
+ return entrySet().toString();
+ }
+
+}
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMultiSet.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMultiSet.java
------------------------------------------------------------------------------
svn:keywords = Id Revision HeadURL
Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/AbstractMultiSet.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/HashMultiSet.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/HashMultiSet.java?rev=1715563&r1=1715562&r2=1715563&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/HashMultiSet.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/multiset/HashMultiSet.java Sat Nov 21 20:13:35 2015
@@ -70,7 +70,8 @@ public class HashMultiSet<E> extends Abs
*/
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
- super.doReadObject(new HashMap<E, MutableInteger>(), in);
+ setMap(new HashMap<E, MutableInteger>());
+ super.doReadObject(in);
}
}