Make IntObjectHashMap extend Map
Motivation: It would be useful to support the Java `Map` interface in our primitive maps. Modifications: Renamed current methods to "pXXX", where p is short for "primitive". Made the template for all primitive maps extend the appropriate Map interface. Result: Fixes #3970
This commit is contained in:
parent
ecc01da9dd
commit
93fc3c6e45
@ -387,8 +387,7 @@ public class DefaultHttp2Connection implements Http2Connection {
|
||||
|
||||
@Override
|
||||
public Http2Stream forEachChild(Http2StreamVisitor visitor) throws Http2Exception {
|
||||
for (IntObjectHashMap.Entry<DefaultStream> entry : children.entries()) {
|
||||
Http2Stream stream = entry.value();
|
||||
for (DefaultStream stream : children.values()) {
|
||||
if (!visitor.visit(stream)) {
|
||||
return stream;
|
||||
}
|
||||
|
@ -484,7 +484,7 @@ public class DefaultHttp2FrameReader implements Http2FrameReader, Http2FrameSize
|
||||
char id = (char) payload.readUnsignedShort();
|
||||
long value = payload.readUnsignedInt();
|
||||
try {
|
||||
settings.put(id, value);
|
||||
settings.put(id, Long.valueOf(value));
|
||||
} catch (IllegalArgumentException e) {
|
||||
switch(id) {
|
||||
case SETTINGS_MAX_FRAME_SIZE:
|
||||
|
@ -213,7 +213,7 @@ public class DefaultHttp2FrameWriter implements Http2FrameWriter, Http2FrameSize
|
||||
int payloadLength = SETTING_ENTRY_LENGTH * settings.size();
|
||||
ByteBuf buf = ctx.alloc().buffer(FRAME_HEADER_LENGTH + settings.size() * SETTING_ENTRY_LENGTH);
|
||||
writeFrameHeaderInternal(buf, payloadLength, SETTINGS, new Http2Flags(), 0);
|
||||
for (CharObjectMap.Entry<Long> entry : settings.entries()) {
|
||||
for (CharObjectMap.PrimitiveEntry<Long> entry : settings.entries()) {
|
||||
writeUnsignedShort(entry.key(), buf);
|
||||
writeUnsignedInt(entry.value(), buf);
|
||||
}
|
||||
|
@ -14,18 +14,6 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http2;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.base64.Base64;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpClientUpgradeHandler;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.util.collection.CharObjectHashMap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static io.netty.handler.codec.base64.Base64Dialect.URL_SAFE;
|
||||
import static io.netty.handler.codec.http2.Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME;
|
||||
import static io.netty.handler.codec.http2.Http2CodecUtil.HTTP_UPGRADE_SETTINGS_HEADER;
|
||||
@ -36,6 +24,18 @@ import static io.netty.util.CharsetUtil.UTF_8;
|
||||
import static io.netty.util.ReferenceCountUtil.release;
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.base64.Base64;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpClientUpgradeHandler;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.util.collection.CharObjectMap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Client-side cleartext upgrade codec from HTTP to HTTP/2.
|
||||
*/
|
||||
@ -105,7 +105,7 @@ public class Http2ClientUpgradeCodec implements HttpClientUpgradeHandler.Upgrade
|
||||
// Serialize the payload of the SETTINGS frame.
|
||||
int payloadLength = SETTING_ENTRY_LENGTH * settings.size();
|
||||
buf = ctx.alloc().buffer(payloadLength);
|
||||
for (CharObjectHashMap.Entry<Long> entry : settings.entries()) {
|
||||
for (CharObjectMap.PrimitiveEntry<Long> entry : settings.entries()) {
|
||||
writeUnsignedShort(entry.key(), buf);
|
||||
writeUnsignedInt(entry.value(), buf);
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ public final class Http2Settings extends CharObjectHashMap<Long> {
|
||||
* the standard settings will not cause the map capacity to change.
|
||||
*/
|
||||
private static final int DEFAULT_CAPACITY = (int) (NUM_STANDARD_SETTINGS / DEFAULT_LOAD_FACTOR) + 1;
|
||||
private static final Long FALSE = 0L;
|
||||
private static final Long TRUE = 1L;
|
||||
|
||||
public Http2Settings() {
|
||||
this(DEFAULT_CAPACITY);
|
||||
@ -84,7 +86,7 @@ public final class Http2Settings extends CharObjectHashMap<Long> {
|
||||
* @throws IllegalArgumentException if verification of the setting fails.
|
||||
*/
|
||||
public Http2Settings headerTableSize(int value) {
|
||||
put(SETTINGS_HEADER_TABLE_SIZE, (long) value);
|
||||
put(SETTINGS_HEADER_TABLE_SIZE, Long.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -96,14 +98,14 @@ public final class Http2Settings extends CharObjectHashMap<Long> {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value != 0L;
|
||||
return TRUE.equals(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code SETTINGS_ENABLE_PUSH} value.
|
||||
*/
|
||||
public Http2Settings pushEnabled(boolean enabled) {
|
||||
put(SETTINGS_ENABLE_PUSH, enabled ? 1L : 0L);
|
||||
put(SETTINGS_ENABLE_PUSH, enabled ? TRUE : FALSE);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -120,7 +122,7 @@ public final class Http2Settings extends CharObjectHashMap<Long> {
|
||||
* @throws IllegalArgumentException if verification of the setting fails.
|
||||
*/
|
||||
public Http2Settings maxConcurrentStreams(long value) {
|
||||
put(SETTINGS_MAX_CONCURRENT_STREAMS, value);
|
||||
put(SETTINGS_MAX_CONCURRENT_STREAMS, Long.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -137,7 +139,7 @@ public final class Http2Settings extends CharObjectHashMap<Long> {
|
||||
* @throws IllegalArgumentException if verification of the setting fails.
|
||||
*/
|
||||
public Http2Settings initialWindowSize(int value) {
|
||||
put(SETTINGS_INITIAL_WINDOW_SIZE, (long) value);
|
||||
put(SETTINGS_INITIAL_WINDOW_SIZE, Long.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -154,7 +156,7 @@ public final class Http2Settings extends CharObjectHashMap<Long> {
|
||||
* @throws IllegalArgumentException if verification of the setting fails.
|
||||
*/
|
||||
public Http2Settings maxFrameSize(int value) {
|
||||
put(SETTINGS_MAX_FRAME_SIZE, (long) value);
|
||||
put(SETTINGS_MAX_FRAME_SIZE, Long.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -183,7 +185,7 @@ public final class Http2Settings extends CharObjectHashMap<Long> {
|
||||
value = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
put(SETTINGS_MAX_HEADER_LIST_SIZE, (long) value);
|
||||
put(SETTINGS_MAX_HEADER_LIST_SIZE, Long.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@ import io.netty.util.collection.IntObjectMap;
|
||||
import io.netty.util.concurrent.EventExecutor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@ -896,10 +897,10 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
|
||||
// Send a bunch of data on each stream.
|
||||
final IntObjectMap<Integer> streamSizes = new IntObjectHashMap<Integer>(4);
|
||||
streamSizes.put(STREAM_A, 400);
|
||||
streamSizes.put(STREAM_B, 500);
|
||||
streamSizes.put(STREAM_C, 600);
|
||||
streamSizes.put(STREAM_D, 700);
|
||||
streamSizes.put(STREAM_A, (Integer) 400);
|
||||
streamSizes.put(STREAM_B, (Integer) 500);
|
||||
streamSizes.put(STREAM_C, (Integer) 600);
|
||||
streamSizes.put(STREAM_D, (Integer) 700);
|
||||
|
||||
FakeFlowControlled dataA = new FakeFlowControlled(streamSizes.get(STREAM_A));
|
||||
FakeFlowControlled dataB = new FakeFlowControlled(streamSizes.get(STREAM_B));
|
||||
@ -922,11 +923,11 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
streamableBytesForTree(stream0));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_A, STREAM_C, STREAM_D)),
|
||||
streamableBytesForTree(streamA));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_B)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_B)),
|
||||
streamableBytesForTree(streamB));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_C)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_C)),
|
||||
streamableBytesForTree(streamC));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_D)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_D)),
|
||||
streamableBytesForTree(streamD));
|
||||
}
|
||||
|
||||
@ -966,10 +967,10 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
|
||||
// Send a bunch of data on each stream.
|
||||
final IntObjectMap<Integer> streamSizes = new IntObjectHashMap<Integer>(4);
|
||||
streamSizes.put(STREAM_A, 400);
|
||||
streamSizes.put(STREAM_B, 500);
|
||||
streamSizes.put(STREAM_C, 600);
|
||||
streamSizes.put(STREAM_D, 700);
|
||||
streamSizes.put(STREAM_A, (Integer) 400);
|
||||
streamSizes.put(STREAM_B, (Integer) 500);
|
||||
streamSizes.put(STREAM_C, (Integer) 600);
|
||||
streamSizes.put(STREAM_D, (Integer) 700);
|
||||
|
||||
FakeFlowControlled dataA = new FakeFlowControlled(streamSizes.get(STREAM_A));
|
||||
FakeFlowControlled dataB = new FakeFlowControlled(streamSizes.get(STREAM_B));
|
||||
@ -996,9 +997,9 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
streamableBytesForTree(streamA));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_B, STREAM_C, STREAM_D)),
|
||||
streamableBytesForTree(streamB));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_C)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_C)),
|
||||
streamableBytesForTree(streamC));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_D)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_D)),
|
||||
streamableBytesForTree(streamD));
|
||||
}
|
||||
|
||||
@ -1041,11 +1042,11 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
|
||||
// Send a bunch of data on each stream.
|
||||
final IntObjectMap<Integer> streamSizes = new IntObjectHashMap<Integer>(4);
|
||||
streamSizes.put(STREAM_A, 400);
|
||||
streamSizes.put(STREAM_B, 500);
|
||||
streamSizes.put(STREAM_C, 600);
|
||||
streamSizes.put(STREAM_D, 700);
|
||||
streamSizes.put(STREAM_E, 900);
|
||||
streamSizes.put(STREAM_A, (Integer) 400);
|
||||
streamSizes.put(STREAM_B, (Integer) 500);
|
||||
streamSizes.put(STREAM_C, (Integer) 600);
|
||||
streamSizes.put(STREAM_D, (Integer) 700);
|
||||
streamSizes.put(STREAM_E, (Integer) 900);
|
||||
|
||||
FakeFlowControlled dataA = new FakeFlowControlled(streamSizes.get(STREAM_A));
|
||||
FakeFlowControlled dataB = new FakeFlowControlled(streamSizes.get(STREAM_B));
|
||||
@ -1072,11 +1073,11 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
assertEquals(calculateStreamSizeSum(streamSizes,
|
||||
Arrays.asList(STREAM_A, STREAM_E, STREAM_C, STREAM_D)),
|
||||
streamableBytesForTree(streamA));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_B)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_B)),
|
||||
streamableBytesForTree(streamB));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_C)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_C)),
|
||||
streamableBytesForTree(streamC));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_D)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_D)),
|
||||
streamableBytesForTree(streamD));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_E, STREAM_C, STREAM_D)),
|
||||
streamableBytesForTree(streamE));
|
||||
@ -1106,10 +1107,10 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
|
||||
// Send a bunch of data on each stream.
|
||||
final IntObjectMap<Integer> streamSizes = new IntObjectHashMap<Integer>(4);
|
||||
streamSizes.put(STREAM_A, 400);
|
||||
streamSizes.put(STREAM_B, 500);
|
||||
streamSizes.put(STREAM_C, 600);
|
||||
streamSizes.put(STREAM_D, 700);
|
||||
streamSizes.put(STREAM_A, (Integer) 400);
|
||||
streamSizes.put(STREAM_B, (Integer) 500);
|
||||
streamSizes.put(STREAM_C, (Integer) 600);
|
||||
streamSizes.put(STREAM_D, (Integer) 700);
|
||||
|
||||
FakeFlowControlled dataA = new FakeFlowControlled(streamSizes.get(STREAM_A));
|
||||
FakeFlowControlled dataB = new FakeFlowControlled(streamSizes.get(STREAM_B));
|
||||
@ -1133,11 +1134,11 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
streamableBytesForTree(stream0));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_C, STREAM_D)),
|
||||
streamableBytesForTree(streamA));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_B)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_B)),
|
||||
streamableBytesForTree(streamB));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_C)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_C)),
|
||||
streamableBytesForTree(streamC));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_D)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_D)),
|
||||
streamableBytesForTree(streamD));
|
||||
}
|
||||
|
||||
@ -1174,10 +1175,10 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
|
||||
// Send a bunch of data on each stream.
|
||||
final IntObjectMap<Integer> streamSizes = new IntObjectHashMap<Integer>(4);
|
||||
streamSizes.put(STREAM_A, 400);
|
||||
streamSizes.put(STREAM_B, 500);
|
||||
streamSizes.put(STREAM_C, 600);
|
||||
streamSizes.put(STREAM_D, 700);
|
||||
streamSizes.put(STREAM_A, (Integer) 400);
|
||||
streamSizes.put(STREAM_B, (Integer) 500);
|
||||
streamSizes.put(STREAM_C, (Integer) 600);
|
||||
streamSizes.put(STREAM_D, (Integer) 700);
|
||||
|
||||
FakeFlowControlled dataA = new FakeFlowControlled(streamSizes.get(STREAM_A));
|
||||
FakeFlowControlled dataB = new FakeFlowControlled(streamSizes.get(STREAM_B));
|
||||
@ -1201,10 +1202,10 @@ public class DefaultHttp2RemoteFlowControllerTest {
|
||||
streamableBytesForTree(stream0));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_A, STREAM_D)),
|
||||
streamableBytesForTree(streamA));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_B)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_B)),
|
||||
streamableBytesForTree(streamB));
|
||||
assertEquals(0, streamableBytesForTree(streamC));
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Arrays.asList(STREAM_D)),
|
||||
assertEquals(calculateStreamSizeSum(streamSizes, Collections.singletonList(STREAM_D)),
|
||||
streamableBytesForTree(streamD));
|
||||
}
|
||||
|
||||
|
@ -65,14 +65,14 @@ public class Http2SettingsTest {
|
||||
@Test
|
||||
public void nonStandardSettingsShouldBeSet() {
|
||||
char key = 0;
|
||||
settings.put(key, 123L);
|
||||
settings.put(key, (Long) 123L);
|
||||
assertEquals(123L, (long) settings.get(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingsShouldSupportUnsignedShort() {
|
||||
char key = (char) (Short.MAX_VALUE + 1);
|
||||
settings.put(key, 123L);
|
||||
settings.put(key, (Long) 123L);
|
||||
assertEquals(123L, (long) settings.get(key));
|
||||
}
|
||||
|
||||
|
@ -14,12 +14,12 @@
|
||||
*/
|
||||
package io.netty.util.collection;
|
||||
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility methods for primitive collections.
|
||||
@ -61,11 +61,6 @@ public final class PrimitiveCollections {
|
||||
throw new UnsupportedOperationException("put");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(IntObjectMap<Object> sourceMap) {
|
||||
throw new UnsupportedOperationException("putAll");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(int key) {
|
||||
return null;
|
||||
@ -81,11 +76,21 @@ public final class PrimitiveCollections {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> keySet() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(int key) {
|
||||
return false;
|
||||
@ -97,24 +102,39 @@ public final class PrimitiveCollections {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Entry<Object>> entries() {
|
||||
public Iterable<PrimitiveEntry<Object>> entries() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] keys() {
|
||||
return EmptyArrays.EMPTY_INTS;
|
||||
public Object get(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] values(Class<Object> clazz) {
|
||||
return EmptyArrays.EMPTY_OBJECTS;
|
||||
public Object put(Integer key, Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends Integer, ?> m) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<Integer, Object>> entrySet() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,9 +142,12 @@ public final class PrimitiveCollections {
|
||||
*
|
||||
* @param <V> the value type stored in the map.
|
||||
*/
|
||||
private static final class UnmodifiableIntObjectMap<V> implements IntObjectMap<V>,
|
||||
Iterable<IntObjectMap.Entry<V>> {
|
||||
final IntObjectMap<V> map;
|
||||
private static final class UnmodifiableIntObjectMap<V> implements IntObjectMap<V> {
|
||||
private final IntObjectMap<V> map;
|
||||
private Set<Integer> keySet;
|
||||
private Set<Entry<Integer, V>> entrySet;
|
||||
private Collection<V> values;
|
||||
private Iterable<PrimitiveEntry<V>> entries;
|
||||
|
||||
UnmodifiableIntObjectMap(IntObjectMap<V> map) {
|
||||
this.map = map;
|
||||
@ -140,11 +163,6 @@ public final class PrimitiveCollections {
|
||||
throw new UnsupportedOperationException("put");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(IntObjectMap<V> sourceMap) {
|
||||
throw new UnsupportedOperationException("putAll");
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(int key) {
|
||||
throw new UnsupportedOperationException("remove");
|
||||
@ -171,42 +189,80 @@ public final class PrimitiveCollections {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(V value) {
|
||||
public boolean containsValue(Object value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Entry<V>> entries() {
|
||||
return this;
|
||||
public boolean containsKey(Object key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<V>> iterator() {
|
||||
public V get(Object key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(Integer key, V value) {
|
||||
throw new UnsupportedOperationException("put");
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
throw new UnsupportedOperationException("remove");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends Integer, ? extends V> m) {
|
||||
throw new UnsupportedOperationException("putAll");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<PrimitiveEntry<V>> entries() {
|
||||
if (entries == null) {
|
||||
entries = new Iterable<PrimitiveEntry<V>>() {
|
||||
@Override
|
||||
public Iterator<PrimitiveEntry<V>> iterator() {
|
||||
return new IteratorImpl(map.entries().iterator());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] keys() {
|
||||
return map.keys();
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V[] values(Class<V> clazz) {
|
||||
return map.values(clazz);
|
||||
public Set<Integer> keySet() {
|
||||
if (keySet == null) {
|
||||
keySet = Collections.unmodifiableSet(map.keySet());
|
||||
}
|
||||
return keySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<Integer, V>> entrySet() {
|
||||
if (entrySet == null) {
|
||||
entrySet = Collections.unmodifiableSet(map.entrySet());
|
||||
}
|
||||
return entrySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
return map.values();
|
||||
if (values == null) {
|
||||
values = Collections.unmodifiableCollection(map.values());
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmodifiable wrapper for an iterator.
|
||||
*/
|
||||
private class IteratorImpl implements Iterator<Entry<V>> {
|
||||
final Iterator<Entry<V>> iter;
|
||||
private class IteratorImpl implements Iterator<PrimitiveEntry<V>> {
|
||||
final Iterator<PrimitiveEntry<V>> iter;
|
||||
|
||||
IteratorImpl(Iterator<Entry<V>> iter) {
|
||||
IteratorImpl(Iterator<PrimitiveEntry<V>> iter) {
|
||||
this.iter = iter;
|
||||
}
|
||||
|
||||
@ -216,7 +272,7 @@ public final class PrimitiveCollections {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<V> next() {
|
||||
public PrimitiveEntry<V> next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
@ -232,10 +288,10 @@ public final class PrimitiveCollections {
|
||||
/**
|
||||
* Unmodifiable wrapper for an entry.
|
||||
*/
|
||||
private class EntryImpl implements Entry<V> {
|
||||
final Entry<V> entry;
|
||||
private class EntryImpl implements PrimitiveEntry<V> {
|
||||
final PrimitiveEntry<V> entry;
|
||||
|
||||
EntryImpl(Entry<V> entry) {
|
||||
EntryImpl(PrimitiveEntry<V> entry) {
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
|
@ -9,17 +9,19 @@ templateDirs.eachWithIndex { templateDir, i ->
|
||||
|
||||
void convertSources(String templateDir, String outputDir) {
|
||||
String[] keyPrimitives = ["byte", "char", "short", "int", "long"]
|
||||
String[] keyObjects = ["Byte", "Character", "Short", "Integer", "Long"];
|
||||
String[] keyObjects = ["Byte", "Character", "Short", "Integer", "Long"]
|
||||
String[] keyNumberMethod = ["byteValue", "charValue", "shortValue", "intValue", "longValue"]
|
||||
|
||||
keyPrimitives.eachWithIndex { keyPrimitive, i ->
|
||||
convertTemplates templateDir, outputDir, keyPrimitive, keyObjects[i]
|
||||
convertTemplates templateDir, outputDir, keyPrimitive, keyObjects[i], keyNumberMethod[i]
|
||||
}
|
||||
}
|
||||
|
||||
void convertTemplates(String templateDir,
|
||||
String outputDir,
|
||||
String keyPrimitive,
|
||||
String keyObject) {
|
||||
String keyObject,
|
||||
String keyNumberMethod) {
|
||||
def keyName = keyPrimitive.capitalize()
|
||||
def replaceFrom = "(^.*)K([^.]+)\\.template\$"
|
||||
def replaceTo = "\\1" + keyName + "\\2.java"
|
||||
@ -32,6 +34,7 @@ void convertTemplates(String templateDir,
|
||||
filter(token: "K", value: keyName)
|
||||
filter(token: "k", value: keyPrimitive)
|
||||
filter(token: "O", value: keyObject)
|
||||
filter(token: "KEY_NUMBER_METHOD", value: keyNumberMethod)
|
||||
filter(token: "HASH_CODE", value: hashCodeFn)
|
||||
}
|
||||
regexpmapper(from: replaceFrom, to: replaceTo)
|
||||
|
@ -17,12 +17,14 @@ package io.netty.util.collection;
|
||||
|
||||
import static io.netty.util.internal.MathUtil.findNextPositivePowerOfTwo;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A hash map implementation of {@link @K@ObjectMap} that uses open addressing for keys.
|
||||
@ -32,7 +34,7 @@ import java.util.NoSuchElementException;
|
||||
*
|
||||
* @param <V> The value type stored in the map.
|
||||
*/
|
||||
public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectMap.Entry<V>> {
|
||||
public class @K@ObjectHashMap<V> implements @K@ObjectMap<V> {
|
||||
|
||||
/** Default initial capacity. Used if not specified in the constructor */
|
||||
public static final int DEFAULT_CAPACITY = 8;
|
||||
@ -57,6 +59,15 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
private int size;
|
||||
private int mask;
|
||||
|
||||
private final Set<@O@> keySet = new KeySet();
|
||||
private final Set<Entry<@O@, V>> entrySet = new EntrySet();
|
||||
private final Iterable<PrimitiveEntry<V>> entries = new Iterable<PrimitiveEntry<V>>() {
|
||||
@Override
|
||||
public Iterator<PrimitiveEntry<V>> iterator() {
|
||||
return new PrimitiveIterator();
|
||||
}
|
||||
};
|
||||
|
||||
public @K@ObjectHashMap() {
|
||||
this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
|
||||
}
|
||||
@ -139,9 +150,10 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@K@ObjectMap<V> sourceMap) {
|
||||
if (sourceMap instanceof IntObjectHashMap) {
|
||||
public void putAll(Map<? extends @O@, ? extends V> sourceMap) {
|
||||
if (sourceMap instanceof @K@ObjectHashMap) {
|
||||
// Optimization - iterate through the arrays.
|
||||
@SuppressWarnings("unchecked")
|
||||
@K@ObjectHashMap<V> source = (@K@ObjectHashMap<V>) sourceMap;
|
||||
for (int i = 0; i < source.values.length; ++i) {
|
||||
V sourceValue = source.values[i];
|
||||
@ -153,8 +165,8 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
}
|
||||
|
||||
// Otherwise, just add each entry.
|
||||
for (Entry<V> entry : sourceMap.entries()) {
|
||||
put(entry.key(), entry.value());
|
||||
for (Entry<? extends @O@, ? extends V> entry : sourceMap.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,8 +205,9 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(V value) {
|
||||
V v1 = toInternal(value);
|
||||
public boolean containsValue(Object value) {
|
||||
@SuppressWarnings("unchecked")
|
||||
V v1 = toInternal((V) value);
|
||||
for (V v2 : values) {
|
||||
// The map supports null values; this will be matched as NULL_VALUE.equals(NULL_VALUE).
|
||||
if (v2 != null && v2.equals(v1)) {
|
||||
@ -205,38 +218,8 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Entry<V>> entries() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<V>> iterator() {
|
||||
return new IteratorImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @k@[] keys() {
|
||||
@k@[] outKeys = new @k@[size()];
|
||||
int targetIx = 0;
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
if (values[i] != null) {
|
||||
outKeys[targetIx++] = keys[i];
|
||||
}
|
||||
}
|
||||
return outKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V[] values(Class<V> clazz) {
|
||||
@SuppressWarnings("unchecked")
|
||||
V[] outValues = (V[]) Array.newInstance(clazz, size());
|
||||
int targetIx = 0;
|
||||
for (V value : values) {
|
||||
if (value != null) {
|
||||
outValues[targetIx++] = value;
|
||||
}
|
||||
}
|
||||
return outValues;
|
||||
public Iterable<PrimitiveEntry<V>> entries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -245,7 +228,8 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return new Iterator<V>() {
|
||||
final Iterator<Entry<V>> iter = @K@ObjectHashMap.this.iterator();
|
||||
final PrimitiveIterator iter = new PrimitiveIterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iter.hasNext();
|
||||
@ -319,6 +303,40 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return containsKey(objectToKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
return get(objectToKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(@O@ key, V value) {
|
||||
return put(objectToKey(key), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
return remove(objectToKey(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<@O@> keySet() {
|
||||
return keySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<@O@, V>> entrySet() {
|
||||
return entrySet;
|
||||
}
|
||||
|
||||
private @k@ objectToKey(Object key) {
|
||||
return (@k@) ((@O@) key).@KEY_NUMBER_METHOD@();
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the index for the given key. This method probes using double hashing.
|
||||
*
|
||||
@ -447,7 +465,7 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
for (;;) {
|
||||
if (values[index] == null) {
|
||||
keys[index] = oldKey;
|
||||
values[index] = toInternal(oldVal);
|
||||
values[index] = oldVal;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -458,10 +476,115 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isEmpty()) {
|
||||
return "{}";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(4 * size);
|
||||
sb.append('{');
|
||||
boolean first = true;
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
V value = values[i];
|
||||
if (value != null) {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(keyToString(keys[i])).append('=').append(value == this ? "(this Map)" :
|
||||
toExternal(value));
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
return sb.append('}').toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator for traversing the entries in this map.
|
||||
* Helper method called by {@link #toString()} in order to convert a single map key into a string.
|
||||
* This is protected to allow subclasses to override the appearance of a given key.
|
||||
*/
|
||||
private final class IteratorImpl implements Iterator<Entry<V>>, Entry<V> {
|
||||
protected String keyToString(@k@ key) {
|
||||
return @O@.toString(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set implementation for iterating over the entries of the map.
|
||||
*/
|
||||
private final class EntrySet extends AbstractSet<Entry<@O@, V>> {
|
||||
@Override
|
||||
public Iterator<Entry<@O@, V>> iterator() {
|
||||
return new MapIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return @K@ObjectHashMap.this.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set implementation for iterating over the keys.
|
||||
*/
|
||||
private final class KeySet extends AbstractSet<@O@> {
|
||||
@Override
|
||||
public int size() {
|
||||
return @K@ObjectHashMap.this.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return @K@ObjectHashMap.this.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return @K@ObjectHashMap.this.remove(o) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> retainedKeys) {
|
||||
boolean changed = false;
|
||||
for(Iterator<PrimitiveEntry<V>> iter = entries().iterator(); iter.hasNext(); ) {
|
||||
PrimitiveEntry<V> entry = iter.next();
|
||||
if (!retainedKeys.contains(entry.key())) {
|
||||
changed = true;
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
@K@ObjectHashMap.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<@O@> iterator() {
|
||||
return new Iterator<@O@>() {
|
||||
private final Iterator<Entry<@O@, V>> iter = entrySet.iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iter.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @O@ next() {
|
||||
return iter.next().getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
iter.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator over primitive entries. Entry key/values are overwritten by each call to {@link #next()}.
|
||||
*/
|
||||
private final class PrimitiveIterator implements Iterator<PrimitiveEntry<V>>, PrimitiveEntry<V> {
|
||||
private int prevIndex = -1;
|
||||
private int nextIndex = -1;
|
||||
private int entryIndex = -1;
|
||||
@ -483,7 +606,7 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<V> next() {
|
||||
public PrimitiveEntry<V> next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
@ -524,26 +647,68 @@ public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectM
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator used by the {@link Map} interface.
|
||||
*/
|
||||
private final class MapIterator implements Iterator<Entry<@O@, V>> {
|
||||
private final PrimitiveIterator iter = new PrimitiveIterator();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (size == 0) {
|
||||
return "{}";
|
||||
public boolean hasNext() {
|
||||
return iter.hasNext();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(4 * size);
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
V value = values[i];
|
||||
if (value != null) {
|
||||
sb.append(sb.length() == 0 ? "{" : ", ");
|
||||
sb.append(keyToString(keys[i])).append('=').append(value == this ? "(this Map)" : value);
|
||||
|
||||
@Override
|
||||
public Entry<@O@, V> next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
iter.next();
|
||||
|
||||
return new MapEntry(iter.entryIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
iter.remove();
|
||||
}
|
||||
return sb.append('}').toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method called by {@link #toString()} in order to convert a single map key into a string.
|
||||
* A single entry in the map.
|
||||
*/
|
||||
protected String keyToString(@k@ key) {
|
||||
return @O@.toString(key);
|
||||
final class MapEntry implements Entry<@O@, V> {
|
||||
private final int entryIndex;
|
||||
|
||||
MapEntry(int entryIndex) {
|
||||
this.entryIndex = entryIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @O@ getKey() {
|
||||
verifyExists();
|
||||
return keys[entryIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
verifyExists();
|
||||
return toExternal(values[entryIndex]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
verifyExists();
|
||||
V prevValue = toExternal(values[entryIndex]);
|
||||
values[entryIndex] = toInternal(value);
|
||||
return prevValue;
|
||||
}
|
||||
|
||||
private void verifyExists() {
|
||||
if (values[entryIndex] == null) {
|
||||
throw new IllegalStateException("The map entry has been removed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,21 +14,21 @@
|
||||
*/
|
||||
package io.netty.util.collection;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface for a primitive map that uses {@code @k@}s as keys.
|
||||
*
|
||||
* @param <V> the value type stored in the map.
|
||||
*/
|
||||
public interface @K@ObjectMap<V> {
|
||||
public interface @K@ObjectMap<V> extends Map<@O@, V> {
|
||||
|
||||
/**
|
||||
* An Entry in the map.
|
||||
* A primitive entry in the map, provided by the iterator from {@link #entries()}
|
||||
*
|
||||
* @param <V> the value type stored in the map.
|
||||
*/
|
||||
interface Entry<V> {
|
||||
interface PrimitiveEntry<V> {
|
||||
/**
|
||||
* Gets the key for this entry.
|
||||
*/
|
||||
@ -62,11 +62,6 @@ public interface @K@ObjectMap<V> {
|
||||
*/
|
||||
V put(@k@ key, V value);
|
||||
|
||||
/**
|
||||
* Puts all of the entries from the given map into this map.
|
||||
*/
|
||||
void putAll(@K@ObjectMap<V> sourceMap);
|
||||
|
||||
/**
|
||||
* Removes the entry with the specified key.
|
||||
*
|
||||
@ -76,48 +71,14 @@ public interface @K@ObjectMap<V> {
|
||||
V remove(@k@ key);
|
||||
|
||||
/**
|
||||
* Returns the number of entries contained in this map.
|
||||
* Gets an iterable to traverse over the primitive entries contained in this map. As an optimization,
|
||||
* the {@link PrimitiveEntry}s returned by the {@link Iterator} may change as the {@link Iterator}
|
||||
* progresses. The caller should not rely on {@link PrimitiveEntry} key/value stability.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Indicates whether or not this map is empty (i.e {@link #size()} == {@code 0]).
|
||||
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Clears all entries from this map.
|
||||
*/
|
||||
void clear();
|
||||
Iterable<PrimitiveEntry<V>> entries();
|
||||
|
||||
/**
|
||||
* Indicates whether or not this map contains a value for the specified key.
|
||||
*/
|
||||
boolean containsKey(@k@ key);
|
||||
|
||||
/**
|
||||
* Indicates whether or not the map contains the specified value.
|
||||
*/
|
||||
boolean containsValue(V value);
|
||||
|
||||
/**
|
||||
* Gets an iterable collection of the entries contained in this map.
|
||||
*/
|
||||
Iterable<Entry<V>> entries();
|
||||
|
||||
/**
|
||||
* Gets the keys contained in this map.
|
||||
*/
|
||||
@k@[] keys();
|
||||
|
||||
/**
|
||||
* Gets the values contained in this map.
|
||||
*/
|
||||
V[] values(Class<V> clazz);
|
||||
|
||||
/**
|
||||
* Gets the values contatins in this map as a {@link Collection}.
|
||||
*/
|
||||
Collection<V> values();
|
||||
}
|
||||
|
@ -18,9 +18,10 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
@ -87,6 +88,17 @@ public class @K@ObjectHashMapTest {
|
||||
assertEquals(v, map.get(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putNewMappingShouldSucceed_mapApi() {
|
||||
Value v = new Value("v");
|
||||
@O@ key = (@O@)(@k@) 1;
|
||||
assertNull(map.put(key, v));
|
||||
assertEquals(1, map.size());
|
||||
assertTrue(map.containsKey(key));
|
||||
assertTrue(map.containsValue(v));
|
||||
assertEquals(v, map.get(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putShouldReplaceValue() {
|
||||
Value v1 = new Value("v1");
|
||||
@ -103,6 +115,22 @@ public class @K@ObjectHashMapTest {
|
||||
assertEquals(v2, map.get(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putShouldReplaceValue_mapApi() {
|
||||
Value v1 = new Value("v1");
|
||||
@O@ key = (@O@)(@k@) 1;
|
||||
assertNull(map.put(key, v1));
|
||||
|
||||
// Replace the value.
|
||||
Value v2 = new Value("v2");
|
||||
assertSame(v1, map.put(key, v2));
|
||||
|
||||
assertEquals(1, map.size());
|
||||
assertTrue(map.containsKey(key));
|
||||
assertTrue(map.containsValue(v2));
|
||||
assertEquals(v2, map.get(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putShouldGrowMap() {
|
||||
for (@k@ key = 0; key < (@k@) 255; ++key) {
|
||||
@ -115,6 +143,19 @@ public class @K@ObjectHashMapTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putShouldGrowMap_mapApi() {
|
||||
for (@k@ key = 0; key < (@k@) 255; ++key) {
|
||||
@O@ okey = (@O@) key;
|
||||
Value v = new Value(@O@.toString(key));
|
||||
assertNull(map.put(okey, v));
|
||||
assertEquals(key + 1, map.size());
|
||||
assertTrue(map.containsKey(okey));
|
||||
assertTrue(map.containsValue(v));
|
||||
assertEquals(v, map.get(okey));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void negativeKeyShouldSucceed() {
|
||||
Value v = new Value("v");
|
||||
@ -123,12 +164,26 @@ public class @K@ObjectHashMapTest {
|
||||
assertEquals(v, map.get((@k@) -3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void negativeKeyShouldSucceed_mapApi() {
|
||||
Value v = new Value("v");
|
||||
map.put((@O@)(@k@) -3, v);
|
||||
assertEquals(1, map.size());
|
||||
assertEquals(v, map.get((@O@)(@k@) -3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeMissingValueShouldReturnNull() {
|
||||
assertNull(map.remove((@k@) 1));
|
||||
assertEquals(0, map.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeMissingValueShouldReturnNull_mapApi() {
|
||||
assertNull(map.remove((@O@)(@k@) 1));
|
||||
assertEquals(0, map.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeShouldReturnPreviousValue() {
|
||||
Value v = new Value("v");
|
||||
@ -137,6 +192,14 @@ public class @K@ObjectHashMapTest {
|
||||
assertSame(v, map.remove(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeShouldReturnPreviousValue_mapApi() {
|
||||
Value v = new Value("v");
|
||||
@O@ key = (@O@)(@k@) 1;
|
||||
map.put(key, v);
|
||||
assertSame(v, map.remove(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* This test is a bit internal-centric. We're just forcing a rehash to occur based on no longer
|
||||
* having any FREE slots available. We do this by adding and then removing several keys up to
|
||||
@ -160,24 +223,84 @@ public class @K@ObjectHashMapTest {
|
||||
assertSame(v, map.get(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noFreeSlotsShouldRehash_mapApi() {
|
||||
for (@k@ i = 0; i < 10; ++i) {
|
||||
map.put(i, new Value(@O@.toString(i)));
|
||||
// Now mark it as REMOVED so that size won't cause the rehash.
|
||||
map.remove((@O@) i);
|
||||
assertEquals(0, map.size());
|
||||
}
|
||||
|
||||
// Now add an entry to force the rehash since no FREE slots are available in the map.
|
||||
Value v = new Value("v");
|
||||
@O@ key = (@O@)(@k@) 1;
|
||||
map.put(key, v);
|
||||
assertEquals(1, map.size());
|
||||
assertSame(v, map.get(key));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putAllShouldSucceed() {
|
||||
@K@ObjectHashMap<Value> other = new @K@ObjectHashMap<Value>();
|
||||
|
||||
@k@ k1 = 1;
|
||||
@k@ k2 = 2;
|
||||
@k@ k3 = 3;
|
||||
Value v1 = new Value("v1");
|
||||
Value v2 = new Value("v2");
|
||||
Value v3 = new Value("v3");
|
||||
map.put(k1, v1);
|
||||
map.put(k2, v2);
|
||||
map.put(k3, v3);
|
||||
other.put(k1, v1);
|
||||
other.put(k2, v2);
|
||||
other.put(k3, v3);
|
||||
|
||||
@K@ObjectHashMap<Value> map2 = new @K@ObjectHashMap<Value>();
|
||||
map2.putAll(map);
|
||||
assertEquals(3, map2.size());
|
||||
assertSame(v1, map2.get(k1));
|
||||
assertSame(v2, map2.get(k2));
|
||||
assertSame(v3, map2.get(k3));
|
||||
map.putAll(other);
|
||||
assertEquals(3, map.size());
|
||||
assertSame(v1, map.get(k1));
|
||||
assertSame(v2, map.get(k2));
|
||||
assertSame(v3, map.get(k3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putAllShouldSucceed_mapApi() {
|
||||
@K@ObjectHashMap<Value> other = new @K@ObjectHashMap<Value>();
|
||||
|
||||
@O@ k1 = (@O@)(@k@) 1;
|
||||
@O@ k2 = (@O@)(@k@) 2;
|
||||
@O@ k3 = (@O@)(@k@) 3;
|
||||
Value v1 = new Value("v1");
|
||||
Value v2 = new Value("v2");
|
||||
Value v3 = new Value("v3");
|
||||
other.put(k1, v1);
|
||||
other.put(k2, v2);
|
||||
other.put(k3, v3);
|
||||
|
||||
map.putAll(other);
|
||||
assertEquals(3, map.size());
|
||||
assertSame(v1, map.get(k1));
|
||||
assertSame(v2, map.get(k2));
|
||||
assertSame(v3, map.get(k3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putAllWithJavaMapShouldSucceed_mapApi() {
|
||||
Map<@O@, Value> other = new HashMap<@O@, Value>();
|
||||
|
||||
@O@ k1 = (@O@)(@k@) 1;
|
||||
@O@ k2 = (@O@)(@k@) 2;
|
||||
@O@ k3 = (@O@)(@k@) 3;
|
||||
Value v1 = new Value("v1");
|
||||
Value v2 = new Value("v2");
|
||||
Value v3 = new Value("v3");
|
||||
other.put(k1, v1);
|
||||
other.put(k2, v2);
|
||||
other.put(k3, v3);
|
||||
|
||||
map.putAll(other);
|
||||
assertEquals(3, map.size());
|
||||
assertSame(v1, map.get(k1));
|
||||
assertSame(v2, map.get(k2));
|
||||
assertSame(v3, map.get(k3));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -201,6 +324,14 @@ public class @K@ObjectHashMapTest {
|
||||
assertTrue(map.containsValue(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsValueShouldFindNull_mapApi() {
|
||||
map.put((@O@)(@k@) 1, new Value("v1"));
|
||||
map.put((@O@)(@k@) 2, null);
|
||||
map.put((@O@)(@k@) 3, new Value("v2"));
|
||||
assertTrue(map.containsValue(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsValueShouldFindInstance() {
|
||||
Value v = new Value("v1");
|
||||
@ -210,6 +341,15 @@ public class @K@ObjectHashMapTest {
|
||||
assertTrue(map.containsValue(v));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsValueShouldFindInstance_mapApi() {
|
||||
Value v = new Value("v1");
|
||||
map.put((@O@)(@k@) 1, new Value("v2"));
|
||||
map.put((@O@)(@k@) 2, new Value("v3"));
|
||||
map.put((@O@)(@k@) 3, v);
|
||||
assertTrue(map.containsValue(v));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsValueShouldFindEquivalentValue() {
|
||||
map.put((@k@) 1, new Value("v1"));
|
||||
@ -218,6 +358,14 @@ public class @K@ObjectHashMapTest {
|
||||
assertTrue(map.containsValue(new Value("v2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsValueShouldFindEquivalentValue_mapApi() {
|
||||
map.put((@O@)(@k@) 1, new Value("v1"));
|
||||
map.put((@O@)(@k@) 2, new Value("v2"));
|
||||
map.put((@O@)(@k@) 3, new Value("v3"));
|
||||
assertTrue(map.containsValue(new Value("v2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsValueNotFindMissingValue() {
|
||||
map.put((@k@) 1, new Value("v1"));
|
||||
@ -226,6 +374,14 @@ public class @K@ObjectHashMapTest {
|
||||
assertFalse(map.containsValue(new Value("v4")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containsValueNotFindMissingValue_mapApi() {
|
||||
map.put((@O@)(@k@) 1, new Value("v1"));
|
||||
map.put((@O@)(@k@) 2, new Value("v2"));
|
||||
map.put((@O@)(@k@) 3, new Value("v3"));
|
||||
assertFalse(map.containsValue(new Value("v4")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void iteratorShouldTraverseEntries() {
|
||||
@k@ k1 = 1;
|
||||
@ -241,8 +397,8 @@ public class @K@ObjectHashMapTest {
|
||||
map.remove(k4);
|
||||
|
||||
Set<@O@> found = new HashSet<@O@>();
|
||||
for (@K@ObjectMap.Entry<Value> entry : map.entries()) {
|
||||
assertTrue(found.add(entry.key()));
|
||||
for (@K@ObjectMap.Entry<@O@, Value> entry : map.entrySet()) {
|
||||
assertTrue(found.add(entry.getKey()));
|
||||
}
|
||||
assertEquals(3, found.size());
|
||||
assertTrue(found.contains(k1));
|
||||
@ -264,8 +420,8 @@ public class @K@ObjectHashMapTest {
|
||||
map.put(k4, new Value("v4"));
|
||||
map.remove(k4);
|
||||
|
||||
@k@[] keys = map.keys();
|
||||
assertEquals(3, keys.length);
|
||||
Set<@O@> keys = map.keySet();
|
||||
assertEquals(3, keys.size());
|
||||
|
||||
Set<@O@> expected = new HashSet<@O@>();
|
||||
expected.add(k1);
|
||||
@ -298,25 +454,11 @@ public class @K@ObjectHashMapTest {
|
||||
|
||||
// Ensure values() return all values.
|
||||
Set<Value> expected = new HashSet<Value>();
|
||||
Set<Value> actual = new HashSet<Value>();
|
||||
|
||||
expected.add(v1);
|
||||
expected.add(v2);
|
||||
expected.add(v3);
|
||||
|
||||
Value[] valueArray = map.values(Value.class);
|
||||
assertEquals(3, valueArray.length);
|
||||
for (Value value : valueArray) {
|
||||
assertTrue(actual.add(value));
|
||||
}
|
||||
assertEquals(expected, actual);
|
||||
actual.clear();
|
||||
|
||||
Collection<Value> valueCollection = map.values();
|
||||
assertEquals(3, valueCollection.size());
|
||||
for (Value value : valueCollection) {
|
||||
assertTrue(actual.add(value));
|
||||
}
|
||||
Set<Value> actual = new HashSet<Value>(map.values());
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@ -332,6 +474,18 @@ public class @K@ObjectHashMapTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapShouldSupportHashingConflicts_mapApi() {
|
||||
for (int mod = 0; mod < 10; ++mod) {
|
||||
for (int sz = 1; sz <= 101; sz += 2) {
|
||||
@K@ObjectHashMap<String> map = new @K@ObjectHashMap<String>(sz);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
map.put((@O@)(@k@)(i * mod), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashcodeEqualsTest() {
|
||||
@K@ObjectHashMap<@O@> map1 = new @K@ObjectHashMap<@O@>();
|
||||
@ -345,23 +499,27 @@ public class @K@ObjectHashMapTest {
|
||||
assertEquals(map1.hashCode(), map2.hashCode());
|
||||
assertEquals(map1, map2);
|
||||
// Remove one "middle" element, maps should now be non-equals.
|
||||
@k@[] keys = map1.keys();
|
||||
map2.remove(keys[50]);
|
||||
Set<@O@> keys = map1.keySet();
|
||||
@O@ removed = null;
|
||||
Iterator<@O@> iter = keys.iterator();
|
||||
for (int ix = 0; iter.hasNext() && ix < 50; ++ix) {
|
||||
removed = iter.next();
|
||||
}
|
||||
map2.remove(removed);
|
||||
assertFalse(map1.equals(map2));
|
||||
// Put it back; will likely be in a different position, but maps will be equal again.
|
||||
map2.put(keys[50], @O@.valueOf(map1.keys()[50]));
|
||||
map2.put(removed, removed);
|
||||
assertEquals(map1, map2);
|
||||
assertEquals(map1.hashCode(), map2.hashCode());
|
||||
// Make map2 have one extra element, will be non-equal.
|
||||
map2.put((@k@) 100, (@k@) 100);
|
||||
map2.put((@k@) 100, (@O@)(@k@) 100);
|
||||
assertFalse(map1.equals(map2));
|
||||
// Rebuild map2 with elements in a different order, again the maps should be equal.
|
||||
// (These tests with same elements in different order also show that the hashCode
|
||||
// function does not depend on the internal ordering of entries.)
|
||||
map2.clear();
|
||||
Arrays.sort(keys);
|
||||
for (@k@ key : keys) {
|
||||
map2.put(key, @O@.valueOf(key));
|
||||
for (@O@ key : map1.keySet()) {
|
||||
map2.put(key, key);
|
||||
}
|
||||
assertEquals(map1.hashCode(), map2.hashCode());
|
||||
assertEquals(map1, map2);
|
||||
@ -424,14 +582,14 @@ public class @K@ObjectHashMapTest {
|
||||
assertEquals(goodMap.size(), map.size());
|
||||
@O@[] goodKeys = goodMap.keySet().toArray(new @O@[goodMap.size()]);
|
||||
Arrays.sort(goodKeys);
|
||||
@k@ [] keys = map.keys();
|
||||
@O@[] keys = map.keySet().toArray(new @O@[map.size()]);
|
||||
Arrays.sort(keys);
|
||||
for (int i = 0; i < goodKeys.length; ++i) {
|
||||
assertEquals((@k@) goodKeys[i], keys[i]);
|
||||
assertEquals(goodKeys[i], keys[i]);
|
||||
}
|
||||
|
||||
// Finally drain the map.
|
||||
for (@k@ key : map.keys()) {
|
||||
for (@k@ key : keys) {
|
||||
assertEquals(goodMap.remove(key), map.remove(key));
|
||||
}
|
||||
assertTrue(map.isEmpty());
|
||||
|
@ -28,6 +28,7 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||
@ -289,8 +290,8 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
||||
}
|
||||
Collection<AbstractEpollChannel> array = new ArrayList<AbstractEpollChannel>(channels.size());
|
||||
|
||||
for (IntObjectMap.Entry<AbstractEpollChannel> entry: channels.entries()) {
|
||||
array.add(entry.value());
|
||||
for (AbstractEpollChannel channel: channels.values()) {
|
||||
array.add(channel);
|
||||
}
|
||||
|
||||
for (AbstractEpollChannel ch: array) {
|
||||
|
Loading…
Reference in New Issue
Block a user