Auto-generating primitive collections for int and char keys.
Motivation: Currently we have IntObjectMap/HashMap, but it will be useful to support other primitive-based maps. Modifications: Moved the code int the current maps to template files and run Groovy code from common/pom.xml to apply the templates. Result: Autogeneration of int and char-based hash maps.
This commit is contained in:
parent
6928a2d79f
commit
386fd89597
@ -28,6 +28,13 @@
|
|||||||
|
|
||||||
<name>Netty/Common</name>
|
<name>Netty/Common</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<collection.template.dir>${project.basedir}/src/main/templates</collection.template.dir>
|
||||||
|
<collection.template.test.dir>${project.basedir}/src/test/templates</collection.template.test.dir>
|
||||||
|
<collection.src.dir>${project.build.directory}/generated-sources/collections/java</collection.src.dir>
|
||||||
|
<collection.testsrc.dir>${project.build.directory}/generated-test-sources/collections/java</collection.testsrc.dir>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- Byte code generator - completely optional -->
|
<!-- Byte code generator - completely optional -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -54,5 +61,73 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<!-- Add generated collection sources. -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
|
<version>1.9.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>add-source</id>
|
||||||
|
<phase>generate-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>add-source</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<sources>
|
||||||
|
<source>${collection.src.dir}</source>
|
||||||
|
</sources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>add-test-source</id>
|
||||||
|
<phase>generate-test-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>add-test-source</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<sources>
|
||||||
|
<source>${collection.testsrc.dir}</source>
|
||||||
|
</sources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!-- Generate the primitive collections from the template files. -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.gmaven</groupId>
|
||||||
|
<artifactId>groovy-maven-plugin</artifactId>
|
||||||
|
<version>2.0</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.groovy</groupId>
|
||||||
|
<artifactId>groovy-all</artifactId>
|
||||||
|
<version>2.4.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ant</groupId>
|
||||||
|
<artifactId>ant-optional</artifactId>
|
||||||
|
<version>1.5.3-1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>generate-collections</id>
|
||||||
|
<phase>generate-sources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>execute</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<source>${project.basedir}/src/main/script/codegen.groovy</source>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|
||||||
|
39
common/src/main/script/codegen.groovy
Normal file
39
common/src/main/script/codegen.groovy
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
String[] templateDirs = [properties["collection.template.dir"],
|
||||||
|
properties["collection.template.test.dir"]]
|
||||||
|
String[] outputDirs = [properties["collection.src.dir"],
|
||||||
|
properties["collection.testsrc.dir"]]
|
||||||
|
|
||||||
|
templateDirs.eachWithIndex { templateDir, i ->
|
||||||
|
convertSources templateDir, outputDirs[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
void convertSources(String templateDir, String outputDir) {
|
||||||
|
String[] keyPrimitives = ["byte", "char", "short", "int", "long"]
|
||||||
|
String[] keyObjects = ["Byte", "Character", "Short", "Integer", "Long"];
|
||||||
|
|
||||||
|
keyPrimitives.eachWithIndex { keyPrimitive, i ->
|
||||||
|
convertTemplates templateDir, outputDir, keyPrimitive, keyObjects[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void convertTemplates(String templateDir,
|
||||||
|
String outputDir,
|
||||||
|
String keyPrimitive,
|
||||||
|
String keyObject) {
|
||||||
|
def keyName = keyPrimitive.capitalize()
|
||||||
|
def replaceFrom = "(^.*)K([^.]+)\\.template\$"
|
||||||
|
def replaceTo = "\\1" + keyName + "\\2.java"
|
||||||
|
def hashCodeFn = keyPrimitive.equals("long") ? "(int)(key ^ (key >>> 32))" : "(int) key"
|
||||||
|
ant.copy(todir: outputDir) {
|
||||||
|
fileset(dir: templateDir) {
|
||||||
|
include(name: "**/*.template")
|
||||||
|
}
|
||||||
|
filterset() {
|
||||||
|
filter(token: "K", value: keyName)
|
||||||
|
filter(token: "k", value: keyPrimitive)
|
||||||
|
filter(token: "O", value: keyObject)
|
||||||
|
filter(token: "HASH_CODE", value: hashCodeFn)
|
||||||
|
}
|
||||||
|
regexpmapper(from: replaceFrom, to: replaceTo)
|
||||||
|
}
|
||||||
|
}
|
@ -23,14 +23,14 @@ import java.util.Iterator;
|
|||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hash map implementation of {@link IntObjectMap} that uses open addressing for keys.
|
* A hash map implementation of {@link @K@ObjectMap} that uses open addressing for keys.
|
||||||
* To minimize the memory footprint, this class uses open addressing rather than chaining.
|
* To minimize the memory footprint, this class uses open addressing rather than chaining.
|
||||||
* Collisions are resolved using linear probing. Deletions implement compaction, so cost of
|
* Collisions are resolved using linear probing. Deletions implement compaction, so cost of
|
||||||
* remove can approach O(N) for full maps, which makes a small loadFactor recommended.
|
* remove can approach O(N) for full maps, which makes a small loadFactor recommended.
|
||||||
*
|
*
|
||||||
* @param <V> The value type stored in the map.
|
* @param <V> The value type stored in the map.
|
||||||
*/
|
*/
|
||||||
public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectMap.Entry<V>> {
|
public class @K@ObjectHashMap<V> implements @K@ObjectMap<V>, Iterable<@K@ObjectMap.Entry<V>> {
|
||||||
|
|
||||||
/** Default initial capacity. Used if not specified in the constructor */
|
/** Default initial capacity. Used if not specified in the constructor */
|
||||||
public static final int DEFAULT_CAPACITY = 11;
|
public static final int DEFAULT_CAPACITY = 11;
|
||||||
@ -50,20 +50,20 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
/** The load factor for the map. Used to calculate {@link #maxSize}. */
|
/** The load factor for the map. Used to calculate {@link #maxSize}. */
|
||||||
private final float loadFactor;
|
private final float loadFactor;
|
||||||
|
|
||||||
private int[] keys;
|
private @k@[] keys;
|
||||||
private V[] values;
|
private V[] values;
|
||||||
private Collection<V> valueCollection;
|
private Collection<V> valueCollection;
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
public IntObjectHashMap() {
|
public @K@ObjectHashMap() {
|
||||||
this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
|
this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntObjectHashMap(int initialCapacity) {
|
public @K@ObjectHashMap(int initialCapacity) {
|
||||||
this(initialCapacity, DEFAULT_LOAD_FACTOR);
|
this(initialCapacity, DEFAULT_LOAD_FACTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntObjectHashMap(int initialCapacity, float loadFactor) {
|
public @K@ObjectHashMap(int initialCapacity, float loadFactor) {
|
||||||
if (initialCapacity < 1) {
|
if (initialCapacity < 1) {
|
||||||
throw new IllegalArgumentException("initialCapacity must be >= 1");
|
throw new IllegalArgumentException("initialCapacity must be >= 1");
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
int capacity = adjustCapacity(initialCapacity);
|
int capacity = adjustCapacity(initialCapacity);
|
||||||
|
|
||||||
// Allocate the arrays.
|
// Allocate the arrays.
|
||||||
keys = new int[capacity];
|
keys = new @k@[capacity];
|
||||||
@SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })
|
@SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })
|
||||||
V[] temp = (V[]) new Object[capacity];
|
V[] temp = (V[]) new Object[capacity];
|
||||||
values = temp;
|
values = temp;
|
||||||
@ -98,13 +98,13 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public V get(int key) {
|
public V get(@k@ key) {
|
||||||
int index = indexOf(key);
|
int index = indexOf(key);
|
||||||
return index == -1 ? null : toExternal(values[index]);
|
return index == -1 ? null : toExternal(values[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public V put(int key, V value) {
|
public V put(@k@ key, V value) {
|
||||||
int startIndex = hashIndex(key);
|
int startIndex = hashIndex(key);
|
||||||
int index = startIndex;
|
int index = startIndex;
|
||||||
|
|
||||||
@ -136,10 +136,10 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putAll(IntObjectMap<V> sourceMap) {
|
public void putAll(@K@ObjectMap<V> sourceMap) {
|
||||||
if (sourceMap instanceof IntObjectHashMap) {
|
if (sourceMap instanceof IntObjectHashMap) {
|
||||||
// Optimization - iterate through the arrays.
|
// Optimization - iterate through the arrays.
|
||||||
IntObjectHashMap<V> source = (IntObjectHashMap<V>) sourceMap;
|
@K@ObjectHashMap<V> source = (@K@ObjectHashMap<V>) sourceMap;
|
||||||
for (int i = 0; i < source.values.length; ++i) {
|
for (int i = 0; i < source.values.length; ++i) {
|
||||||
V sourceValue = source.values[i];
|
V sourceValue = source.values[i];
|
||||||
if (sourceValue != null) {
|
if (sourceValue != null) {
|
||||||
@ -156,7 +156,7 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public V remove(int key) {
|
public V remove(@k@ key) {
|
||||||
int index = indexOf(key);
|
int index = indexOf(key);
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return null;
|
return null;
|
||||||
@ -179,13 +179,13 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
Arrays.fill(keys, 0);
|
Arrays.fill(keys, (@k@) 0);
|
||||||
Arrays.fill(values, null);
|
Arrays.fill(values, null);
|
||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean containsKey(int key) {
|
public boolean containsKey(@k@ key) {
|
||||||
return indexOf(key) >= 0;
|
return indexOf(key) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,8 +212,8 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] keys() {
|
public @k@[] keys() {
|
||||||
int[] outKeys = new int[size()];
|
@k@[] outKeys = new @k@[size()];
|
||||||
int targetIx = 0;
|
int targetIx = 0;
|
||||||
for (int i = 0; i < values.length; ++i) {
|
for (int i = 0; i < values.length; ++i) {
|
||||||
if (values[i] != null) {
|
if (values[i] != null) {
|
||||||
@ -244,7 +244,7 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
@Override
|
@Override
|
||||||
public Iterator<V> iterator() {
|
public Iterator<V> iterator() {
|
||||||
return new Iterator<V>() {
|
return new Iterator<V>() {
|
||||||
final Iterator<Entry<V>> iter = IntObjectHashMap.this.iterator();
|
final Iterator<Entry<V>> iter = @K@ObjectHashMap.this.iterator();
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return iter.hasNext();
|
return iter.hasNext();
|
||||||
@ -278,7 +278,7 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
// array, which may have different lengths for two maps of same size(), so the
|
// array, which may have different lengths for two maps of same size(), so the
|
||||||
// capacity cannot be used as input for hashing but the size can.
|
// capacity cannot be used as input for hashing but the size can.
|
||||||
int hash = size;
|
int hash = size;
|
||||||
for (int key : keys) {
|
for (@k@ key : keys) {
|
||||||
// 0 can be a valid key or unused slot, but won't impact the hashcode in either case.
|
// 0 can be a valid key or unused slot, but won't impact the hashcode in either case.
|
||||||
// This way we can use a cheap loop without conditionals, or hard-to-unroll operations,
|
// This way we can use a cheap loop without conditionals, or hard-to-unroll operations,
|
||||||
// or the devastatingly bad memory locality of visiting value objects.
|
// or the devastatingly bad memory locality of visiting value objects.
|
||||||
@ -286,7 +286,7 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
// of terms, only their values; since the map is an unordered collection and
|
// of terms, only their values; since the map is an unordered collection and
|
||||||
// entries can end up in different positions in different maps that have the same
|
// entries can end up in different positions in different maps that have the same
|
||||||
// elements, but with different history of puts/removes, due to conflicts.
|
// elements, but with different history of puts/removes, due to conflicts.
|
||||||
hash ^= key;
|
hash ^= hashCode(key);
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
@ -296,18 +296,18 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!(obj instanceof IntObjectMap)) {
|
if (!(obj instanceof @K@ObjectMap)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
IntObjectMap other = (IntObjectMap) obj;
|
@K@ObjectMap other = (@K@ObjectMap) obj;
|
||||||
if (size != other.size()) {
|
if (size != other.size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < values.length; ++i) {
|
for (int i = 0; i < values.length; ++i) {
|
||||||
V value = values[i];
|
V value = values[i];
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
int key = keys[i];
|
@k@ key = keys[i];
|
||||||
Object otherValue = other.get(key);
|
Object otherValue = other.get(key);
|
||||||
if (value == NULL_VALUE) {
|
if (value == NULL_VALUE) {
|
||||||
if (otherValue != null) {
|
if (otherValue != null) {
|
||||||
@ -327,7 +327,7 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
* @param key the key for an entry in the map.
|
* @param key the key for an entry in the map.
|
||||||
* @return the index where the key was found, or {@code -1} if no entry is found for that key.
|
* @return the index where the key was found, or {@code -1} if no entry is found for that key.
|
||||||
*/
|
*/
|
||||||
private int indexOf(int key) {
|
private int indexOf(@k@ key) {
|
||||||
int startIndex = hashIndex(key);
|
int startIndex = hashIndex(key);
|
||||||
int index = startIndex;
|
int index = startIndex;
|
||||||
|
|
||||||
@ -350,9 +350,16 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
/**
|
/**
|
||||||
* Returns the hashed index for the given key.
|
* Returns the hashed index for the given key.
|
||||||
*/
|
*/
|
||||||
private int hashIndex(int key) {
|
private int hashIndex(@k@ key) {
|
||||||
// Allowing for negative keys by adding the length after the first mod operation.
|
// Allowing for negative keys by adding the length after the first mod operation.
|
||||||
return (key % keys.length + keys.length) % keys.length;
|
return (hashCode(key) % keys.length + keys.length) % keys.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hash code for the key.
|
||||||
|
*/
|
||||||
|
private static int hashCode(@k@ key) {
|
||||||
|
return @HASH_CODE@;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -428,10 +435,10 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
* @param newCapacity the new capacity for the map.
|
* @param newCapacity the new capacity for the map.
|
||||||
*/
|
*/
|
||||||
private void rehash(int newCapacity) {
|
private void rehash(int newCapacity) {
|
||||||
int[] oldKeys = keys;
|
@k@[] oldKeys = keys;
|
||||||
V[] oldVals = values;
|
V[] oldVals = values;
|
||||||
|
|
||||||
keys = new int[newCapacity];
|
keys = new @k@[newCapacity];
|
||||||
@SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })
|
@SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })
|
||||||
V[] temp = (V[]) new Object[newCapacity];
|
V[] temp = (V[]) new Object[newCapacity];
|
||||||
values = temp;
|
values = temp;
|
||||||
@ -444,7 +451,7 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
if (oldVal != null) {
|
if (oldVal != null) {
|
||||||
// Inlined put(), but much simpler: we don't need to worry about
|
// Inlined put(), but much simpler: we don't need to worry about
|
||||||
// duplicated keys, growing/rehashing, or failing to insert.
|
// duplicated keys, growing/rehashing, or failing to insert.
|
||||||
int oldKey = oldKeys[i];
|
@k@ oldKey = oldKeys[i];
|
||||||
int index = hashIndex(oldKey);
|
int index = hashIndex(oldKey);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -512,7 +519,7 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
// into the Iterator object (potentially making loop optimization much easier).
|
// into the Iterator object (potentially making loop optimization much easier).
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int key() {
|
public @k@ key() {
|
||||||
return keys[entryIndex];
|
return keys[entryIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,7 +553,7 @@ public class IntObjectHashMap<V> implements IntObjectMap<V>, Iterable<IntObjectM
|
|||||||
/**
|
/**
|
||||||
* Helper method called by {@link #toString()} in order to convert a single map key into a string.
|
* Helper method called by {@link #toString()} in order to convert a single map key into a string.
|
||||||
*/
|
*/
|
||||||
protected String keyToString(int key) {
|
protected String keyToString(@k@ key) {
|
||||||
return Integer.toString(key);
|
return @O@.toString(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,11 +17,11 @@ package io.netty.util.collection;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for a primitive map that uses {@code int}s as keys.
|
* Interface for a primitive map that uses {@code @k@}s as keys.
|
||||||
*
|
*
|
||||||
* @param <V> the value type stored in the map.
|
* @param <V> the value type stored in the map.
|
||||||
*/
|
*/
|
||||||
public interface IntObjectMap<V> {
|
public interface @K@ObjectMap<V> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Entry in the map.
|
* An Entry in the map.
|
||||||
@ -32,7 +32,7 @@ public interface IntObjectMap<V> {
|
|||||||
/**
|
/**
|
||||||
* Gets the key for this entry.
|
* Gets the key for this entry.
|
||||||
*/
|
*/
|
||||||
int key();
|
@k@ key();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value for this entry.
|
* Gets the value for this entry.
|
||||||
@ -51,7 +51,7 @@ public interface IntObjectMap<V> {
|
|||||||
* @param key the key whose associated value is to be returned.
|
* @param key the key whose associated value is to be returned.
|
||||||
* @return the value or {@code null} if the key was not found in the map.
|
* @return the value or {@code null} if the key was not found in the map.
|
||||||
*/
|
*/
|
||||||
V get(int key);
|
V get(@k@ key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the given entry into the map.
|
* Puts the given entry into the map.
|
||||||
@ -60,12 +60,12 @@ public interface IntObjectMap<V> {
|
|||||||
* @param value the value of the entry.
|
* @param value the value of the entry.
|
||||||
* @return the previous value for this key or {@code null} if there was no previous mapping.
|
* @return the previous value for this key or {@code null} if there was no previous mapping.
|
||||||
*/
|
*/
|
||||||
V put(int key, V value);
|
V put(@k@ key, V value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts all of the entries from the given map into this map.
|
* Puts all of the entries from the given map into this map.
|
||||||
*/
|
*/
|
||||||
void putAll(IntObjectMap<V> sourceMap);
|
void putAll(@K@ObjectMap<V> sourceMap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the entry with the specified key.
|
* Removes the entry with the specified key.
|
||||||
@ -73,7 +73,7 @@ public interface IntObjectMap<V> {
|
|||||||
* @param key the key for the entry to be removed from this map.
|
* @param key the key for the entry to be removed from this map.
|
||||||
* @return the previous value for the key, or {@code null} if there was no mapping.
|
* @return the previous value for the key, or {@code null} if there was no mapping.
|
||||||
*/
|
*/
|
||||||
V remove(int key);
|
V remove(@k@ key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of entries contained in this map.
|
* Returns the number of entries contained in this map.
|
||||||
@ -94,7 +94,7 @@ public interface IntObjectMap<V> {
|
|||||||
/**
|
/**
|
||||||
* Indicates whether or not this map contains a value for the specified key.
|
* Indicates whether or not this map contains a value for the specified key.
|
||||||
*/
|
*/
|
||||||
boolean containsKey(int key);
|
boolean containsKey(@k@ key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether or not the map contains the specified value.
|
* Indicates whether or not the map contains the specified value.
|
||||||
@ -109,7 +109,7 @@ public interface IntObjectMap<V> {
|
|||||||
/**
|
/**
|
||||||
* Gets the keys contained in this map.
|
* Gets the keys contained in this map.
|
||||||
*/
|
*/
|
||||||
int[] keys();
|
@k@[] keys();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the values contained in this map.
|
* Gets the values contained in this map.
|
@ -27,9 +27,9 @@ import java.util.Set;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link IntObjectHashMap}.
|
* Tests for {@link @K@ObjectHashMap}.
|
||||||
*/
|
*/
|
||||||
public class IntObjectHashMapTest {
|
public class @K@ObjectHashMapTest {
|
||||||
|
|
||||||
private static class Value {
|
private static class Value {
|
||||||
private final String name;
|
private final String name;
|
||||||
@ -69,69 +69,72 @@ public class IntObjectHashMapTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntObjectHashMap<Value> map;
|
private @K@ObjectHashMap<Value> map;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
map = new IntObjectHashMap<Value>();
|
map = new @K@ObjectHashMap<Value>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void putNewMappingShouldSucceed() {
|
public void putNewMappingShouldSucceed() {
|
||||||
Value v = new Value("v");
|
Value v = new Value("v");
|
||||||
assertNull(map.put(1, v));
|
@k@ key = 1;
|
||||||
|
assertNull(map.put(key, v));
|
||||||
assertEquals(1, map.size());
|
assertEquals(1, map.size());
|
||||||
assertTrue(map.containsKey(1));
|
assertTrue(map.containsKey(key));
|
||||||
assertTrue(map.containsValue(v));
|
assertTrue(map.containsValue(v));
|
||||||
assertEquals(v, map.get(1));
|
assertEquals(v, map.get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void putShouldReplaceValue() {
|
public void putShouldReplaceValue() {
|
||||||
Value v1 = new Value("v1");
|
Value v1 = new Value("v1");
|
||||||
assertNull(map.put(1, v1));
|
@k@ key = 1;
|
||||||
|
assertNull(map.put(key, v1));
|
||||||
|
|
||||||
// Replace the value.
|
// Replace the value.
|
||||||
Value v2 = new Value("v2");
|
Value v2 = new Value("v2");
|
||||||
assertSame(v1, map.put(1, v2));
|
assertSame(v1, map.put(key, v2));
|
||||||
|
|
||||||
assertEquals(1, map.size());
|
assertEquals(1, map.size());
|
||||||
assertTrue(map.containsKey(1));
|
assertTrue(map.containsKey(key));
|
||||||
assertTrue(map.containsValue(v2));
|
assertTrue(map.containsValue(v2));
|
||||||
assertEquals(v2, map.get(1));
|
assertEquals(v2, map.get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void putShouldGrowMap() {
|
public void putShouldGrowMap() {
|
||||||
for (int i = 0; i < 10000; ++i) {
|
for (@k@ key = 0; key < (@k@) 255; ++key) {
|
||||||
Value v = new Value(Integer.toString(i));
|
Value v = new Value(@O@.toString(key));
|
||||||
assertNull(map.put(i, v));
|
assertNull(map.put(key, v));
|
||||||
assertEquals(i + 1, map.size());
|
assertEquals(key + 1, map.size());
|
||||||
assertTrue(map.containsKey(i));
|
assertTrue(map.containsKey(key));
|
||||||
assertTrue(map.containsValue(v));
|
assertTrue(map.containsValue(v));
|
||||||
assertEquals(v, map.get(i));
|
assertEquals(v, map.get(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void negativeKeyShouldSucceed() {
|
public void negativeKeyShouldSucceed() {
|
||||||
Value v = new Value("v");
|
Value v = new Value("v");
|
||||||
map.put(-3, v);
|
map.put((@k@) -3, v);
|
||||||
assertEquals(1, map.size());
|
assertEquals(1, map.size());
|
||||||
assertEquals(v, map.get(-3));
|
assertEquals(v, map.get((@k@) -3));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void removeMissingValueShouldReturnNull() {
|
public void removeMissingValueShouldReturnNull() {
|
||||||
assertNull(map.remove(1));
|
assertNull(map.remove((@k@) 1));
|
||||||
assertEquals(0, map.size());
|
assertEquals(0, map.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void removeShouldReturnPreviousValue() {
|
public void removeShouldReturnPreviousValue() {
|
||||||
Value v = new Value("v");
|
Value v = new Value("v");
|
||||||
map.put(1, v);
|
@k@ key = 1;
|
||||||
assertSame(v, map.remove(1));
|
map.put(key, v);
|
||||||
|
assertSame(v, map.remove(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,8 +145,8 @@ public class IntObjectHashMapTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void noFreeSlotsShouldRehash() {
|
public void noFreeSlotsShouldRehash() {
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (@k@ i = 0; i < 10; ++i) {
|
||||||
map.put(i, new Value(Integer.toString(i)));
|
map.put(i, new Value(@O@.toString(i)));
|
||||||
// Now mark it as REMOVED so that size won't cause the rehash.
|
// Now mark it as REMOVED so that size won't cause the rehash.
|
||||||
map.remove(i);
|
map.remove(i);
|
||||||
assertEquals(0, map.size());
|
assertEquals(0, map.size());
|
||||||
@ -151,26 +154,30 @@ public class IntObjectHashMapTest {
|
|||||||
|
|
||||||
// Now add an entry to force the rehash since no FREE slots are available in the map.
|
// Now add an entry to force the rehash since no FREE slots are available in the map.
|
||||||
Value v = new Value("v");
|
Value v = new Value("v");
|
||||||
map.put(1, v);
|
@k@ key = 1;
|
||||||
|
map.put(key, v);
|
||||||
assertEquals(1, map.size());
|
assertEquals(1, map.size());
|
||||||
assertSame(v, map.get(1));
|
assertSame(v, map.get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void putAllShouldSucceed() {
|
public void putAllShouldSucceed() {
|
||||||
|
@k@ k1 = 1;
|
||||||
|
@k@ k2 = 2;
|
||||||
|
@k@ k3 = 3;
|
||||||
Value v1 = new Value("v1");
|
Value v1 = new Value("v1");
|
||||||
Value v2 = new Value("v2");
|
Value v2 = new Value("v2");
|
||||||
Value v3 = new Value("v3");
|
Value v3 = new Value("v3");
|
||||||
map.put(1, v1);
|
map.put(k1, v1);
|
||||||
map.put(2, v2);
|
map.put(k2, v2);
|
||||||
map.put(3, v3);
|
map.put(k3, v3);
|
||||||
|
|
||||||
IntObjectHashMap<Value> map2 = new IntObjectHashMap<Value>();
|
@K@ObjectHashMap<Value> map2 = new @K@ObjectHashMap<Value>();
|
||||||
map2.putAll(map);
|
map2.putAll(map);
|
||||||
assertEquals(3, map2.size());
|
assertEquals(3, map2.size());
|
||||||
assertSame(v1, map2.get(1));
|
assertSame(v1, map2.get(k1));
|
||||||
assertSame(v2, map2.get(2));
|
assertSame(v2, map2.get(k2));
|
||||||
assertSame(v3, map2.get(3));
|
assertSame(v3, map2.get(k3));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -178,9 +185,9 @@ public class IntObjectHashMapTest {
|
|||||||
Value v1 = new Value("v1");
|
Value v1 = new Value("v1");
|
||||||
Value v2 = new Value("v2");
|
Value v2 = new Value("v2");
|
||||||
Value v3 = new Value("v3");
|
Value v3 = new Value("v3");
|
||||||
map.put(1, v1);
|
map.put((@k@) 1, v1);
|
||||||
map.put(2, v2);
|
map.put((@k@) 2, v2);
|
||||||
map.put(3, v3);
|
map.put((@k@) 3, v3);
|
||||||
map.clear();
|
map.clear();
|
||||||
assertEquals(0, map.size());
|
assertEquals(0, map.size());
|
||||||
assertTrue(map.isEmpty());
|
assertTrue(map.isEmpty());
|
||||||
@ -188,77 +195,85 @@ public class IntObjectHashMapTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void containsValueShouldFindNull() {
|
public void containsValueShouldFindNull() {
|
||||||
map.put(1, new Value("v1"));
|
map.put((@k@) 1, new Value("v1"));
|
||||||
map.put(2, null);
|
map.put((@k@) 2, null);
|
||||||
map.put(3, new Value("v2"));
|
map.put((@k@) 3, new Value("v2"));
|
||||||
assertTrue(map.containsValue(null));
|
assertTrue(map.containsValue(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void containsValueShouldFindInstance() {
|
public void containsValueShouldFindInstance() {
|
||||||
Value v = new Value("v1");
|
Value v = new Value("v1");
|
||||||
map.put(1, new Value("v2"));
|
map.put((@k@) 1, new Value("v2"));
|
||||||
map.put(2, new Value("v3"));
|
map.put((@k@) 2, new Value("v3"));
|
||||||
map.put(3, v);
|
map.put((@k@) 3, v);
|
||||||
assertTrue(map.containsValue(v));
|
assertTrue(map.containsValue(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void containsValueShouldFindEquivalentValue() {
|
public void containsValueShouldFindEquivalentValue() {
|
||||||
map.put(1, new Value("v1"));
|
map.put((@k@) 1, new Value("v1"));
|
||||||
map.put(2, new Value("v2"));
|
map.put((@k@) 2, new Value("v2"));
|
||||||
map.put(3, new Value("v3"));
|
map.put((@k@) 3, new Value("v3"));
|
||||||
assertTrue(map.containsValue(new Value("v2")));
|
assertTrue(map.containsValue(new Value("v2")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void containsValueNotFindMissingValue() {
|
public void containsValueNotFindMissingValue() {
|
||||||
map.put(1, new Value("v1"));
|
map.put((@k@) 1, new Value("v1"));
|
||||||
map.put(2, new Value("v2"));
|
map.put((@k@) 2, new Value("v2"));
|
||||||
map.put(3, new Value("v3"));
|
map.put((@k@) 3, new Value("v3"));
|
||||||
assertFalse(map.containsValue(new Value("v4")));
|
assertFalse(map.containsValue(new Value("v4")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void iteratorShouldTraverseEntries() {
|
public void iteratorShouldTraverseEntries() {
|
||||||
map.put(1, new Value("v1"));
|
@k@ k1 = 1;
|
||||||
map.put(2, new Value("v2"));
|
@k@ k2 = 2;
|
||||||
map.put(3, new Value("v3"));
|
@k@ k3 = 3;
|
||||||
|
@k@ k4 = 4;
|
||||||
|
map.put(k1, new Value("v1"));
|
||||||
|
map.put(k2, new Value("v2"));
|
||||||
|
map.put(k3, new Value("v3"));
|
||||||
|
|
||||||
// Add and then immediately remove another entry.
|
// Add and then immediately remove another entry.
|
||||||
map.put(4, new Value("v4"));
|
map.put(k4, new Value("v4"));
|
||||||
map.remove(4);
|
map.remove(k4);
|
||||||
|
|
||||||
Set<Integer> found = new HashSet<Integer>();
|
Set<@O@> found = new HashSet<@O@>();
|
||||||
for (IntObjectMap.Entry<Value> entry : map.entries()) {
|
for (@K@ObjectMap.Entry<Value> entry : map.entries()) {
|
||||||
assertTrue(found.add(entry.key()));
|
assertTrue(found.add(entry.key()));
|
||||||
}
|
}
|
||||||
assertEquals(3, found.size());
|
assertEquals(3, found.size());
|
||||||
assertTrue(found.contains(1));
|
assertTrue(found.contains(k1));
|
||||||
assertTrue(found.contains(2));
|
assertTrue(found.contains(k2));
|
||||||
assertTrue(found.contains(3));
|
assertTrue(found.contains(k3));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void keysShouldBeReturned() {
|
public void keysShouldBeReturned() {
|
||||||
map.put(1, new Value("v1"));
|
@k@ k1 = 1;
|
||||||
map.put(2, new Value("v2"));
|
@k@ k2 = 2;
|
||||||
map.put(3, new Value("v3"));
|
@k@ k3 = 3;
|
||||||
|
@k@ k4 = 4;
|
||||||
|
map.put(k1, new Value("v1"));
|
||||||
|
map.put(k2, new Value("v2"));
|
||||||
|
map.put(k3, new Value("v3"));
|
||||||
|
|
||||||
// Add and then immediately remove another entry.
|
// Add and then immediately remove another entry.
|
||||||
map.put(4, new Value("v4"));
|
map.put(k4, new Value("v4"));
|
||||||
map.remove(4);
|
map.remove(k4);
|
||||||
|
|
||||||
int[] keys = map.keys();
|
@k@[] keys = map.keys();
|
||||||
assertEquals(3, keys.length);
|
assertEquals(3, keys.length);
|
||||||
|
|
||||||
Set<Integer> expected = new HashSet<Integer>();
|
Set<@O@> expected = new HashSet<@O@>();
|
||||||
expected.add(1);
|
expected.add(k1);
|
||||||
expected.add(2);
|
expected.add(k2);
|
||||||
expected.add(3);
|
expected.add(k3);
|
||||||
|
|
||||||
Set<Integer> found = new HashSet<Integer>();
|
Set<@O@> found = new HashSet<@O@>();
|
||||||
for (int key : keys) {
|
for (@k@ key : keys) {
|
||||||
assertTrue(found.add(key));
|
assertTrue(found.add(key));
|
||||||
}
|
}
|
||||||
assertEquals(expected, found);
|
assertEquals(expected, found);
|
||||||
@ -266,16 +281,20 @@ public class IntObjectHashMapTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void valuesShouldBeReturned() {
|
public void valuesShouldBeReturned() {
|
||||||
|
@k@ k1 = 1;
|
||||||
|
@k@ k2 = 2;
|
||||||
|
@k@ k3 = 3;
|
||||||
|
@k@ k4 = 4;
|
||||||
Value v1 = new Value("v1");
|
Value v1 = new Value("v1");
|
||||||
Value v2 = new Value("v2");
|
Value v2 = new Value("v2");
|
||||||
Value v3 = new Value("v3");
|
Value v3 = new Value("v3");
|
||||||
map.put(1, v1);
|
map.put(k1, v1);
|
||||||
map.put(2, v2);
|
map.put(k2, v2);
|
||||||
map.put(3, v3);
|
map.put(k3, v3);
|
||||||
|
|
||||||
// Add and then immediately remove another entry.
|
// Add and then immediately remove another entry.
|
||||||
map.put(4, new Value("v4"));
|
map.put(k4, new Value("v4"));
|
||||||
map.remove(4);
|
map.remove(k4);
|
||||||
|
|
||||||
// Ensure values() return all values.
|
// Ensure values() return all values.
|
||||||
Set<Value> expected = new HashSet<Value>();
|
Set<Value> expected = new HashSet<Value>();
|
||||||
@ -305,9 +324,9 @@ public class IntObjectHashMapTest {
|
|||||||
public void mapShouldSupportHashingConflicts() {
|
public void mapShouldSupportHashingConflicts() {
|
||||||
for (int mod = 0; mod < 10; ++mod) {
|
for (int mod = 0; mod < 10; ++mod) {
|
||||||
for (int sz = 1; sz <= 101; sz += 2) {
|
for (int sz = 1; sz <= 101; sz += 2) {
|
||||||
IntObjectHashMap<String> map = new IntObjectHashMap<String>(sz);
|
@K@ObjectHashMap<String> map = new @K@ObjectHashMap<String>(sz);
|
||||||
for (int i = 0; i < 100; ++i) {
|
for (int i = 0; i < 100; ++i) {
|
||||||
map.put(i * mod, "");
|
map.put((@k@)(i * mod), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,34 +334,34 @@ public class IntObjectHashMapTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void hashcodeEqualsTest() {
|
public void hashcodeEqualsTest() {
|
||||||
IntObjectHashMap<Integer> map1 = new IntObjectHashMap<Integer>();
|
@K@ObjectHashMap<@O@> map1 = new @K@ObjectHashMap<@O@>();
|
||||||
IntObjectHashMap<Integer> map2 = new IntObjectHashMap<Integer>();
|
@K@ObjectHashMap<@O@> map2 = new @K@ObjectHashMap<@O@>();
|
||||||
Random rnd = new Random(0);
|
Random rnd = new Random(0);
|
||||||
while (map1.size() < 100) {
|
while (map1.size() < 100) {
|
||||||
int key = rnd.nextInt(100);
|
@k@ key = (@k@) rnd.nextInt(100);
|
||||||
map1.put(key, key);
|
map1.put(key, @O@.valueOf(key));
|
||||||
map2.put(key, key);
|
map2.put(key, @O@.valueOf(key));
|
||||||
}
|
}
|
||||||
assertEquals(map1.hashCode(), map2.hashCode());
|
assertEquals(map1.hashCode(), map2.hashCode());
|
||||||
assertEquals(map1, map2);
|
assertEquals(map1, map2);
|
||||||
// Remove one "middle" element, maps should now be non-equals.
|
// Remove one "middle" element, maps should now be non-equals.
|
||||||
int[] keys = map1.keys();
|
@k@[] keys = map1.keys();
|
||||||
map2.remove(keys[50]);
|
map2.remove(keys[50]);
|
||||||
assertFalse(map1.equals(map2));
|
assertFalse(map1.equals(map2));
|
||||||
// Put it back; will likely be in a different position, but maps will be equal again.
|
// Put it back; will likely be in a different position, but maps will be equal again.
|
||||||
map2.put(keys[50], map1.keys()[50]);
|
map2.put(keys[50], @O@.valueOf(map1.keys()[50]));
|
||||||
assertEquals(map1, map2);
|
assertEquals(map1, map2);
|
||||||
assertEquals(map1.hashCode(), map2.hashCode());
|
assertEquals(map1.hashCode(), map2.hashCode());
|
||||||
// Make map2 have one extra element, will be non-equal.
|
// Make map2 have one extra element, will be non-equal.
|
||||||
map2.put(1000, 1000);
|
map2.put((@k@) 100, (@k@) 100);
|
||||||
assertFalse(map1.equals(map2));
|
assertFalse(map1.equals(map2));
|
||||||
// Rebuild map2 with elements in a different order, again the maps should be equal.
|
// 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
|
// (These tests with same elements in different order also show that the hashCode
|
||||||
// function does not depend on the internal ordering of entries.)
|
// function does not depend on the internal ordering of entries.)
|
||||||
map2.clear();
|
map2.clear();
|
||||||
Arrays.sort(keys);
|
Arrays.sort(keys);
|
||||||
for (int key : keys) {
|
for (@k@ key : keys) {
|
||||||
map2.put(key, key);
|
map2.put(key, @O@.valueOf(key));
|
||||||
}
|
}
|
||||||
assertEquals(map1.hashCode(), map2.hashCode());
|
assertEquals(map1.hashCode(), map2.hashCode());
|
||||||
assertEquals(map1, map2);
|
assertEquals(map1, map2);
|
||||||
@ -365,25 +384,25 @@ public class IntObjectHashMapTest {
|
|||||||
// This size is also chosen so after the single rehash, the map will be densely
|
// This size is also chosen so after the single rehash, the map will be densely
|
||||||
// populated, getting close to a second rehash but not triggering it.
|
// populated, getting close to a second rehash but not triggering it.
|
||||||
int startTableSize = 1105;
|
int startTableSize = 1105;
|
||||||
IntObjectHashMap<Integer> map = new IntObjectHashMap<Integer>(startTableSize);
|
@K@ObjectHashMap<@O@> map = new @K@ObjectHashMap<@O@>(startTableSize);
|
||||||
// Reference map which implementation we trust to be correct, will mirror all operations.
|
// Reference map which implementation we trust to be correct, will mirror all operations.
|
||||||
HashMap<Integer, Integer> goodMap = new HashMap<Integer, Integer>();
|
HashMap<@O@, @O@> goodMap = new HashMap<@O@, @O@>();
|
||||||
|
|
||||||
// Add initial population.
|
// Add initial population.
|
||||||
for (int i = 0; i < baseSize / 4; ++i) {
|
for (int i = 0; i < baseSize / 4; ++i) {
|
||||||
int key = rnd.nextInt(baseSize);
|
@k@ key = (@k@) rnd.nextInt(baseSize);
|
||||||
assertEquals(goodMap.put(key, key), map.put(key, key));
|
assertEquals(goodMap.put(key, @O@.valueOf(key)), map.put(key, @O@.valueOf(key)));
|
||||||
// 50% elements are multiple of a divisor of startTableSize => more conflicts.
|
// 50% elements are multiple of a divisor of startTableSize => more conflicts.
|
||||||
key = rnd.nextInt(baseSize) * 17;
|
key = (@k@) (rnd.nextInt(baseSize) * 17);
|
||||||
assertEquals(goodMap.put(key, key), map.put(key, key));
|
assertEquals(goodMap.put(key, @O@.valueOf(key)), map.put(key, @O@.valueOf(key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now do some mixed adds and removes for further fuzzing
|
// Now do some mixed adds and removes for further fuzzing
|
||||||
// Rehash will happen here, but only once, and the final size will be closer to max.
|
// Rehash will happen here, but only once, and the final size will be closer to max.
|
||||||
for (int i = 0; i < baseSize * 1000; ++i) {
|
for (int i = 0; i < baseSize * 1000; ++i) {
|
||||||
int key = rnd.nextInt(baseSize);
|
@k@ key = (@k@) rnd.nextInt(baseSize);
|
||||||
if (rnd.nextDouble() >= 0.2) {
|
if (rnd.nextDouble() >= 0.2) {
|
||||||
assertEquals(goodMap.put(key, key), map.put(key, key));
|
assertEquals(goodMap.put(key, @O@.valueOf(key)), map.put(key, @O@.valueOf(key)));
|
||||||
} else {
|
} else {
|
||||||
assertEquals(goodMap.remove(key), map.remove(key));
|
assertEquals(goodMap.remove(key), map.remove(key));
|
||||||
}
|
}
|
||||||
@ -392,7 +411,7 @@ public class IntObjectHashMapTest {
|
|||||||
// Final batch of fuzzing, only searches and removes.
|
// Final batch of fuzzing, only searches and removes.
|
||||||
int removeSize = map.size() / 2;
|
int removeSize = map.size() / 2;
|
||||||
while (removeSize > 0) {
|
while (removeSize > 0) {
|
||||||
int key = rnd.nextInt(baseSize);
|
@k@ key = (@k@) rnd.nextInt(baseSize);
|
||||||
boolean found = goodMap.containsKey(key);
|
boolean found = goodMap.containsKey(key);
|
||||||
assertEquals(found, map.containsKey(key));
|
assertEquals(found, map.containsKey(key));
|
||||||
assertEquals(goodMap.remove(key), map.remove(key));
|
assertEquals(goodMap.remove(key), map.remove(key));
|
||||||
@ -403,16 +422,16 @@ public class IntObjectHashMapTest {
|
|||||||
|
|
||||||
// Now gotta write some code to compare the final maps, as equals() won't work.
|
// Now gotta write some code to compare the final maps, as equals() won't work.
|
||||||
assertEquals(goodMap.size(), map.size());
|
assertEquals(goodMap.size(), map.size());
|
||||||
Integer[] goodKeys = goodMap.keySet().toArray(new Integer[goodMap.size()]);
|
@O@[] goodKeys = goodMap.keySet().toArray(new @O@[goodMap.size()]);
|
||||||
Arrays.sort(goodKeys);
|
Arrays.sort(goodKeys);
|
||||||
int [] keys = map.keys();
|
@k@ [] keys = map.keys();
|
||||||
Arrays.sort(keys);
|
Arrays.sort(keys);
|
||||||
for (int i = 0; i < goodKeys.length; ++i) {
|
for (int i = 0; i < goodKeys.length; ++i) {
|
||||||
assertEquals((int) goodKeys[i], keys[i]);
|
assertEquals((@k@) goodKeys[i], keys[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally drain the map.
|
// Finally drain the map.
|
||||||
for (int key : map.keys()) {
|
for (@k@ key : map.keys()) {
|
||||||
assertEquals(goodMap.remove(key), map.remove(key));
|
assertEquals(goodMap.remove(key), map.remove(key));
|
||||||
}
|
}
|
||||||
assertTrue(map.isEmpty());
|
assertTrue(map.isEmpty());
|
Loading…
Reference in New Issue
Block a user