removed overhead of Entry object allocation during OpenIntToDoubleHashMap iteration

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@726490 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2008-12-14 16:31:58 +00:00
parent 11d8f0ec5f
commit da40b8373a
3 changed files with 74 additions and 67 deletions

View File

@ -104,10 +104,10 @@ public class SparseRealMatrix extends AbstractRealMatrix {
final RealMatrix out = new SparseRealMatrix(this); final RealMatrix out = new SparseRealMatrix(this);
for (OpenIntToDoubleHashMap.Iterator iterator = m.entries.iterator(); iterator.hasNext();) { for (OpenIntToDoubleHashMap.Iterator iterator = m.entries.iterator(); iterator.hasNext();) {
final OpenIntToDoubleHashMap.Entry entry = iterator.next(); iterator.advance();
final int row = entry.key() / columnDimension; final int row = iterator.key() / columnDimension;
final int col = entry.key() - row * columnDimension; final int col = iterator.key() - row * columnDimension;
out.setEntry(row, col, getEntry(row, col) + entry.value()); out.setEntry(row, col, getEntry(row, col) + iterator.value());
} }
return out; return out;
@ -138,10 +138,10 @@ public class SparseRealMatrix extends AbstractRealMatrix {
final RealMatrix out = new SparseRealMatrix(this); final RealMatrix out = new SparseRealMatrix(this);
for (OpenIntToDoubleHashMap.Iterator iterator = m.entries.iterator(); iterator.hasNext();) { for (OpenIntToDoubleHashMap.Iterator iterator = m.entries.iterator(); iterator.hasNext();) {
final OpenIntToDoubleHashMap.Entry entry = iterator.next(); iterator.advance();
final int row = entry.key() / columnDimension; final int row = iterator.key() / columnDimension;
final int col = entry.key() - row * columnDimension; final int col = iterator.key() - row * columnDimension;
out.setEntry(row, col, getEntry(row, col) - entry.value()); out.setEntry(row, col, getEntry(row, col) - iterator.value());
} }
return out; return out;

View File

@ -456,16 +456,28 @@ public class OpenIntToDoubleHashMap implements Serializable {
/** Reference modification count. */ /** Reference modification count. */
final int referenceCount; final int referenceCount;
/** Index of curent element. */
private int current;
/** Index of next element. */ /** Index of next element. */
private int index; private int next;
/** /**
* Simple constructor. * Simple constructor.
*/ */
private Iterator() { private Iterator() {
// preserve the modification count of the map to detect concurrent modifications later
referenceCount = count; 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 * @return true if there is a next element
*/ */
public boolean hasNext() { public boolean hasNext() {
return index >= 0; return next >= 0;
} }
/** /**
* Get the next entry. * Get the key of current entry.
* @return next entry * @return key of current entry
* @exception ConcurrentModificationException if the map is modified during iteration * @exception ConcurrentModificationException if the map is modified during iteration
* @exception NoSuchElementException if there is no element left in the map * @exception NoSuchElementException if there is no element left in the map
*/ */
public Entry next() public int key()
throws ConcurrentModificationException, NoSuchElementException { throws ConcurrentModificationException, NoSuchElementException {
if (referenceCount != count) { if (referenceCount != count) {
throw MathRuntimeException.createConcurrentModificationException("map has been modified while iterating", throw MathRuntimeException.createConcurrentModificationException("map has been modified while iterating",
null); null);
} }
if (index < 0) { if (current < 0) {
throw MathRuntimeException.createNoSuchElementException("iterator exhausted", null); throw MathRuntimeException.createNoSuchElementException("iterator exhausted", null);
} }
final Entry entry = new Entry(keys[index], values[index]); return keys[current];
goToNext();
return entry;
} }
/** /**
* 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 { try {
while (states[++index] != FULL) { while (states[++next] != FULL) {
// nothing to do // nothing to do
} }
} catch (ArrayIndexOutOfBoundsException e) { } catch (ArrayIndexOutOfBoundsException e) {
index = -1; next = -2;
if (current < 0) {
throw MathRuntimeException.createNoSuchElementException("iterator exhausted", null);
}
} }
}
}
/** Entry class for the map.
* <p>Entry elements are built on the fly only during iteration,
* copying values. So changes in the map are <strong>not</strong>
* reflected on already built entries.</p>
*/
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;
} }
} }

View File

@ -228,15 +228,17 @@ public class OpenIntToDoubleHashMapTest extends TestCase {
OpenIntToDoubleHashMap.Iterator iterator = map.iterator(); OpenIntToDoubleHashMap.Iterator iterator = map.iterator();
for (int i = 0; i < map.size(); ++i) { for (int i = 0; i < map.size(); ++i) {
assertTrue(iterator.hasNext()); assertTrue(iterator.hasNext());
OpenIntToDoubleHashMap.Entry entry = iterator.next(); iterator.advance();
int key = entry.key(); int key = iterator.key();
assertTrue(map.containsKey(key)); assertTrue(map.containsKey(key));
assertEquals(javaMap.get(key), map.get(key), 0); assertEquals(javaMap.get(key), map.get(key), 0);
assertEquals(javaMap.get(key), iterator.value(), 0);
assertTrue(javaMap.containsKey(key)); assertTrue(javaMap.containsKey(key));
} }
assertFalse(iterator.hasNext()); assertFalse(iterator.hasNext());
try { try {
iterator.next(); iterator.advance();
fail("an exception should have been thrown");
} catch (NoSuchElementException nsee) { } catch (NoSuchElementException nsee) {
// expected // expected
} }
@ -247,7 +249,8 @@ public class OpenIntToDoubleHashMapTest extends TestCase {
OpenIntToDoubleHashMap.Iterator iterator = map.iterator(); OpenIntToDoubleHashMap.Iterator iterator = map.iterator();
map.put(3, 3); map.put(3, 3);
try { try {
iterator.next(); iterator.advance();
fail("an exception should have been thrown");
} catch (ConcurrentModificationException cme) { } catch (ConcurrentModificationException cme) {
// expected // expected
} }