DefaultHeaders#valueIterator to support removal (#9063)
Motivation: While iterating values it is often desirable to be able to remove individual entries. The existing mechanism to do this involves removal of all entries and conditional re-insertion which is heavy weight in order to remove a single value. Modifications: - DefaultHeaders$ValueIterator supports removal Result: It is possible to remove entries while iterating the values in DefaultHeaders.
This commit is contained in:
parent
9ed41db1d7
commit
1d9090aab2
@ -1012,6 +1012,16 @@ public class DefaultHeaders<K, V, T extends Headers<K, V, T>> implements Headers
|
||||
return value;
|
||||
}
|
||||
|
||||
private void remove0(HeaderEntry<K, V> entry) {
|
||||
int i = index(entry.hash);
|
||||
HeaderEntry<K, V> e = entries[i];
|
||||
if (e == entry) {
|
||||
entries[i] = entry.next;
|
||||
}
|
||||
entry.remove();
|
||||
--size;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private T thisT() {
|
||||
return (T) this;
|
||||
@ -1055,6 +1065,7 @@ public class DefaultHeaders<K, V, T extends Headers<K, V, T>> implements Headers
|
||||
private final class ValueIterator implements Iterator<V> {
|
||||
private final K name;
|
||||
private final int hash;
|
||||
private HeaderEntry<K, V> previous;
|
||||
private HeaderEntry<K, V> next;
|
||||
|
||||
ValueIterator(K name) {
|
||||
@ -1073,14 +1084,18 @@ public class DefaultHeaders<K, V, T extends Headers<K, V, T>> implements Headers
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
HeaderEntry<K, V> current = next;
|
||||
previous = next;
|
||||
calculateNext(next.next);
|
||||
return current.value;
|
||||
return previous.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
if (previous == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
remove0(previous);
|
||||
previous = null;
|
||||
}
|
||||
|
||||
private void calculateNext(HeaderEntry<K, V> entry) {
|
||||
|
@ -121,9 +121,47 @@ public class DefaultHeadersTest {
|
||||
Iterator<CharSequence> itr = headers.valueIterator(of("name"));
|
||||
while (itr.hasNext()) {
|
||||
values.add(itr.next());
|
||||
itr.remove();
|
||||
}
|
||||
assertEquals(3, values.size());
|
||||
assertEquals(0, headers.size());
|
||||
assertTrue(headers.isEmpty());
|
||||
assertTrue(values.containsAll(asList(of("value1"), of("value2"), of("value3"))));
|
||||
itr = headers.valueIterator(of("name"));
|
||||
assertFalse(itr.hasNext());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void valuesItrRemoveThrowsWhenEmpty() {
|
||||
TestDefaultHeaders headers = newInstance();
|
||||
assertEquals(0, headers.size());
|
||||
assertTrue(headers.isEmpty());
|
||||
Iterator<CharSequence> itr = headers.valueIterator(of("name"));
|
||||
itr.remove();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valuesItrRemoveThrowsAfterLastElement() {
|
||||
TestDefaultHeaders headers = newInstance();
|
||||
headers.add(of("name"), of("value1"));
|
||||
assertEquals(1, headers.size());
|
||||
|
||||
List<CharSequence> values = new ArrayList<CharSequence>();
|
||||
Iterator<CharSequence> itr = headers.valueIterator(of("name"));
|
||||
while (itr.hasNext()) {
|
||||
values.add(itr.next());
|
||||
itr.remove();
|
||||
}
|
||||
assertEquals(1, values.size());
|
||||
assertEquals(0, headers.size());
|
||||
assertTrue(headers.isEmpty());
|
||||
assertTrue(values.contains(of("value1")));
|
||||
try {
|
||||
itr.remove();
|
||||
fail();
|
||||
} catch (IllegalStateException ignored) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user