diff --git a/src/java/org/apache/commons/math/linear/SparseRealMatrix.java b/src/java/org/apache/commons/math/linear/SparseRealMatrix.java index baed5da1f..47915d1c1 100644 --- a/src/java/org/apache/commons/math/linear/SparseRealMatrix.java +++ b/src/java/org/apache/commons/math/linear/SparseRealMatrix.java @@ -104,10 +104,10 @@ public class SparseRealMatrix extends AbstractRealMatrix { final RealMatrix out = new SparseRealMatrix(this); for (OpenIntToDoubleHashMap.Iterator iterator = m.entries.iterator(); iterator.hasNext();) { - final OpenIntToDoubleHashMap.Entry entry = iterator.next(); - final int row = entry.key() / columnDimension; - final int col = entry.key() - row * columnDimension; - out.setEntry(row, col, getEntry(row, col) + entry.value()); + iterator.advance(); + final int row = iterator.key() / columnDimension; + final int col = iterator.key() - row * columnDimension; + out.setEntry(row, col, getEntry(row, col) + iterator.value()); } return out; @@ -138,10 +138,10 @@ public class SparseRealMatrix extends AbstractRealMatrix { final RealMatrix out = new SparseRealMatrix(this); for (OpenIntToDoubleHashMap.Iterator iterator = m.entries.iterator(); iterator.hasNext();) { - final OpenIntToDoubleHashMap.Entry entry = iterator.next(); - final int row = entry.key() / columnDimension; - final int col = entry.key() - row * columnDimension; - out.setEntry(row, col, getEntry(row, col) - entry.value()); + iterator.advance(); + final int row = iterator.key() / columnDimension; + final int col = iterator.key() - row * columnDimension; + out.setEntry(row, col, getEntry(row, col) - iterator.value()); } return out; diff --git a/src/java/org/apache/commons/math/util/OpenIntToDoubleHashMap.java b/src/java/org/apache/commons/math/util/OpenIntToDoubleHashMap.java index fe0fe0a0a..af1eeb263 100644 --- a/src/java/org/apache/commons/math/util/OpenIntToDoubleHashMap.java +++ b/src/java/org/apache/commons/math/util/OpenIntToDoubleHashMap.java @@ -456,16 +456,28 @@ public class OpenIntToDoubleHashMap implements Serializable { /** Reference modification count. */ final int referenceCount; + /** Index of curent element. */ + private int current; + /** Index of next element. */ - private int index; + private int next; /** * Simple constructor. */ private Iterator() { + + // preserve the modification count of the map to detect concurrent modifications later referenceCount = count; - index = -1; - goToNext(); + + // initialize current index + next = -1; + try { + advance(); + } catch (NoSuchElementException nsee) { + // ignored + } + } /** @@ -473,81 +485,73 @@ public class OpenIntToDoubleHashMap implements Serializable { * @return true if there is a next element */ public boolean hasNext() { - return index >= 0; + return next >= 0; } /** - * Get the next entry. - * @return next entry + * Get the key of current entry. + * @return key of current entry * @exception ConcurrentModificationException if the map is modified during iteration * @exception NoSuchElementException if there is no element left in the map */ - public Entry next() + public int key() throws ConcurrentModificationException, NoSuchElementException { if (referenceCount != count) { throw MathRuntimeException.createConcurrentModificationException("map has been modified while iterating", null); } - if (index < 0) { + if (current < 0) { throw MathRuntimeException.createNoSuchElementException("iterator exhausted", null); } - final Entry entry = new Entry(keys[index], values[index]); - goToNext(); - return entry; + return keys[current]; } /** - * Find next index. + * Get the value of current entry. + * @return value of current entry + * @exception ConcurrentModificationException if the map is modified during iteration + * @exception NoSuchElementException if there is no element left in the map */ - private void goToNext() { + public double value() + throws ConcurrentModificationException, NoSuchElementException { + if (referenceCount != count) { + throw MathRuntimeException.createConcurrentModificationException("map has been modified while iterating", + null); + } + if (current < 0) { + throw MathRuntimeException.createNoSuchElementException("iterator exhausted", null); + } + return values[current]; + } + + /** + * Advance iterator one step further. + * @exception ConcurrentModificationException if the map is modified during iteration + * @exception NoSuchElementException if there is no element left in the map + */ + public void advance() + throws ConcurrentModificationException, NoSuchElementException { + + if (referenceCount != count) { + throw MathRuntimeException.createConcurrentModificationException("map has been modified while iterating", + null); + } + + // advance on step + current = next; + + // prepare next step try { - while (states[++index] != FULL) { + while (states[++next] != FULL) { // nothing to do } } catch (ArrayIndexOutOfBoundsException e) { - index = -1; + next = -2; + if (current < 0) { + throw MathRuntimeException.createNoSuchElementException("iterator exhausted", null); + } } - } - } - - /** Entry class for the map. - *
Entry elements are built on the fly only during iteration, - * copying values. So changes in the map are not - * reflected on already built entries.
- */ - public static class Entry { - - /** Key. */ - private final int key; - - /** Value. */ - private final double value; - - /** - * Simple constructor. - * @param key entry key - * @param value entry value - */ - private Entry(final int key, final double value) { - this.key = key; - this.value = value; - } - - /** - * Get the key. - * @return entry key - */ - public int key() { - return key; - } - - /** - * Get the value. - * @return entry value - */ - public double value() { - return value; } } diff --git a/src/test/org/apache/commons/math/util/OpenIntToDoubleHashMapTest.java b/src/test/org/apache/commons/math/util/OpenIntToDoubleHashMapTest.java index 3a3d23c62..09fb61e5c 100644 --- a/src/test/org/apache/commons/math/util/OpenIntToDoubleHashMapTest.java +++ b/src/test/org/apache/commons/math/util/OpenIntToDoubleHashMapTest.java @@ -228,15 +228,17 @@ public class OpenIntToDoubleHashMapTest extends TestCase { OpenIntToDoubleHashMap.Iterator iterator = map.iterator(); for (int i = 0; i < map.size(); ++i) { assertTrue(iterator.hasNext()); - OpenIntToDoubleHashMap.Entry entry = iterator.next(); - int key = entry.key(); + iterator.advance(); + int key = iterator.key(); assertTrue(map.containsKey(key)); assertEquals(javaMap.get(key), map.get(key), 0); + assertEquals(javaMap.get(key), iterator.value(), 0); assertTrue(javaMap.containsKey(key)); } assertFalse(iterator.hasNext()); try { - iterator.next(); + iterator.advance(); + fail("an exception should have been thrown"); } catch (NoSuchElementException nsee) { // expected } @@ -247,7 +249,8 @@ public class OpenIntToDoubleHashMapTest extends TestCase { OpenIntToDoubleHashMap.Iterator iterator = map.iterator(); map.put(3, 3); try { - iterator.next(); + iterator.advance(); + fail("an exception should have been thrown"); } catch (ConcurrentModificationException cme) { // expected }