Question: Be sure you pass the test first. It wont take you more than 15 mins. The class currently uses an Iterator, but one that is
Be sure you pass the test first. It wont take you more than 15 mins.
The class currently uses an Iterator, but one that is prone to errors. Update the ArrayMultiSet class AND/OR its inner-class Iterator so that it has a working fail-fast Iterator.
package edu.buffalo.cse116; import java.util.Arrays; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.NoSuchElementException; /** * Class which implements the concept of a multiset -- an unorganized collection which does not limited the number of * times an instance can be added. * * @author Carl Alphonce * @author Matthew Hertz * @paramType of data contained with the instance. */ public class ArrayMultiSet implements Collection { /** Array in which the elements in this multiset are stored. */ private E[] _store; /** * Array indices below this amount contain the active elements in this collection. */ private int _size; /** * Modification counter used to preserve the fail-fast nature of its iterators. */ private long _modCount; /** * Create a new empty multiset. */ public ArrayMultiSet() { _modCount = 0; clear(); } /** * Remove all of the elements within the instance and invalidate any current iterators. */ @SuppressWarnings("unchecked") @Override public void clear() { _store = (E[]) (new Object[16]); _size = 0; // maintains the class invariant } /** * Update the multiset so that it includes all of the elements from before the call AND the given element. * * @param e Item to be added to this collection. */ @Override public boolean add(E e) { // Check if we do not have enough space in the underlying array to store the // new element if (_size == _store.length) { // We do not have space, so create a new larger space (doubling the size // is the most time efficient) _store = Arrays.copyOf(_store, _store.length * 2); } // Add the element to the store _store[_size] = e; // Finally, we can increase _size, since this change will no longer violate // any class invariants. _size += 1; return true; } /** * Return true if at least one element in the multiset is equal to the given object. When {@code obj} is null, it must * use the {@code ==} operator to perform these checks, but when {@code obj} is not null, the {@link Object#equals} * method is used. * * @param obj Object (or null) for which we will search * @return {@code true} if {@code obj} was found; {@code false} if a match could not be found. */ @Override public boolean contains(Object obj) { // Only scan through _size, since those are the only "real" entries for the // multiset. for (int i = 0; i < _size; i++ ) { // When obj is null, we need to use == if ((obj == null) && (_store[i] == null)) { return true; } // Otherwise, we use .equals() to find a match else if ((obj != null) && obj.equals(_store[i])) { return true; } // No else clause, since the match could be at a higher index! } // Checked all VALID indices, so the result must be: return false; } @Override public int size() { return _size; } /** * Remove the element found at the given index. This method also acts to maintain the class invariants.
* Precondition: {@code i} is a valid index within {@code _store}. * * @param i Index of the element to remove from the multiset. */ private void removeAtIndex(int i) { // We do not need to check i, since we made that a precondition (assumption) // for this method. // Slide elements at highest index down to fill in "hole" we are creating _store[i] = _store[_size - 1]; // Update which is the first unused index in the array _size -= 1; // Finally set the newly unused index to null thus avoiding a space leak _store[_size] = null; } /** * Removes a single instance of the given object, if one can be found in the multiset. The method returns {@code true} * if a match was found (and removed) and {@code false} if no match was found. Normally, this uses * {@link Object#equals} to check if there is a match, but uses {@code ==} when {@code obj} is {@code null}. * * @param obj Object (or null) which we want to remove * @return {@code true} if {@code obj} was found and an instance removed; {@code false} if a match could not be found. */ @Override public boolean remove(Object obj) { for (int i = 0; i < _size; i++ ) { if ((obj == null) && (_store[i] == null)) { removeAtIndex(i); return true; } else if ((obj != null) && obj.equals(_store[i])) { removeAtIndex(i); return true; } // No else clause, since a match may still exist at a higher index! } // Checked all VALID indices, so the result must be: return false; } @Override public boolean isEmpty() { return _size == 0; } @Override public Iteratoriterator() { return new MultiSetIterator(); } /** * Instances of this class are used as the iterators for a multiset. We must keep this as an inner-class, because the * multiset definition does not include any methods to access its elements. * * @author Carl Alphonse * @author Matthew Hertz */ private class MultiSetIterator implements Iterator { /** * The index of the _store entry which will be returned by the next call to next() */ private int _cursor; /** * In keeping with the fail-fast convention, the iterator is only valid while _modCount remains on this version. */ private long _collectionVersion; /** * Create a new instance of this class that will go through the (valid) entries in the store. */ public MultiSetIterator() { _cursor = 0; } public boolean hasNext() { } public E next() { } public void remove() { throw new UnsupportedOperationException(); } } /* * The remaining methods are part of the Collection interface, but are beyond what is necessary for CSE 116. * Students who want a complete Multiset implementation should investigate Google's "Guava" library. */ @Override public Object[] toArray() { throw new UnsupportedOperationException(); } @Override public T[] toArray(T[] a) { throw new UnsupportedOperationException(); } @Override public boolean containsAll(Collection> c) { throw new UnsupportedOperationException(); } @Override public boolean addAll(Collection extends E> c) { throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection> c) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(Collection> c) { throw new UnsupportedOperationException(); } }
----------------------------
test
package edu.buffalo.cse116;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.*;
import java.lang.reflect.Field; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.NoSuchElementException;
import org.junit.Before; import org.junit.Test;
public class ArrayMultiSetIteratorTest {
@Test public void checkIteratorVersioning() throws IllegalAccessException { ArrayMultiSet
collectionVersion = getCollectionVersion(testeeTwo); assertEquals("Iterator constructor should assign _collectionVersion the correct value.", 72, collectionVersion);
}
@Test public void checkHasNextStart() throws IllegalAccessException { ArrayMultiSet
@Test public void checkHasNextMiddle() throws IllegalAccessException { ArrayMultiSet
@Test public void checkHasNextLast() throws IllegalAccessException { ArrayMultiSet
@Test public void checkHasNextAfterLast() throws IllegalAccessException { ArrayMultiSet
@Test public void checkNextStartNotEmpty() throws IllegalAccessException { ArrayMultiSet
@Test public void checkNextMiddle() throws IllegalAccessException { ArrayMultiSet
@Test public void checkNextLast() throws IllegalAccessException { ArrayMultiSet
@Test public void checkNextAfterLast() throws IllegalAccessException { ArrayMultiSet
@Test public void checkNextModWhileInCollectionMiddle() throws IllegalAccessException { ArrayMultiSet
@Test public void checkNextModAfterCollectionEnd() throws IllegalAccessException { ArrayMultiSet
@Test public void checkAddUpdatesModCount() throws IllegalAccessException { ArrayMultiSet
@Test public void checkRemoveSuccessUpdatesModCount() throws IllegalAccessException { ArrayMultiSet
@Test public void checkRemoveFailsModCountUnchanged() throws IllegalAccessException { ArrayMultiSet
private Field cursorField; private Field collectionVersionField; private Field modCountField;
@Before public final void checkFieldsUnchanged() { ArrayMultiSet> ams = new ArrayMultiSet<>(); Class> amsClass = ams.getClass(); try { modCountField = amsClass.getDeclaredField("_modCount"); modCountField.setAccessible(true); } catch (Exception e) { fail("Your ArrayMultiSet class should still define a field named \"_modCount\""); } Class> cIterator = ams.iterator().getClass(); Field[] fields = cIterator.getDeclaredFields(); assertEquals("You should not add any fields to the MultiSetIterator class. This class's field count:", 3, fields.length); try { collectionVersionField = cIterator.getDeclaredField("_collectionVersion"); collectionVersionField.setAccessible(true); } catch (Exception e) { fail("Your MultiSetIterator class should still define a field named \"_collectionVersion\""); } try { cursorField = cIterator.getDeclaredField("_cursor"); cursorField.setAccessible(true); } catch (Exception e) { fail("Your MultiSetIterator class should still define a field named \"_cursor\""); } }
private long getModCount(ArrayMultiSet> testee) throws IllegalAccessException { return modCountField.getLong(testee); }
private void setModCount(ArrayMultiSet> testee, long newVersion) throws IllegalAccessException { modCountField.setLong(testee, newVersion); }
private long getCollectionVersion(Iterator> testee) throws IllegalAccessException { return collectionVersionField.getLong(testee); }
private void setCollectionVersion(Iterator> testee, long newVersion) throws IllegalAccessException { collectionVersionField.setLong(testee, newVersion); }
private int getCursor(Iterator> testee) throws IllegalAccessException { return cursorField.getInt(testee); }
private void setCursor(Iterator> testee, int newSize) throws IllegalAccessException { cursorField.setInt(testee, newSize); } }
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
