Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8186958: Need method to create pre-sized HashMap #7928

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1461683
8186958: Need method to create pre-sized HashMap
XenoAmess Mar 23, 2022
68787ac
fix javadoc's @return
XenoAmess Mar 24, 2022
2b294b3
move the static functions to map classes themselves.
XenoAmess Mar 24, 2022
5457e6c
use jmh Blackhole
XenoAmess Mar 24, 2022
4cf926d
delete a space.
XenoAmess Mar 24, 2022
dadde82
refine javadoc about default load factor
XenoAmess Mar 24, 2022
aea7edf
refine javadoc; refine implement when expectedSize < 0
XenoAmess Mar 24, 2022
e5bc200
update jmh
XenoAmess Mar 24, 2022
7a1f3b0
update codes
XenoAmess Mar 30, 2022
d4147bc
update usages of HashMap
XenoAmess Apr 2, 2022
ec0b08c
update usages of LinkedHashMap
XenoAmess Apr 2, 2022
796975b
revert changes in jdk.compile
XenoAmess Apr 2, 2022
e548cd6
refine javadoc for LinkedHashMap#newLinkedHashMap
XenoAmess Apr 6, 2022
4769b87
drop CalculateHashMapCapacityTestJMH
XenoAmess Apr 6, 2022
b973ee5
use (double) DEFAULT_LOAD_FACTOR instead of 0.75
XenoAmess Apr 6, 2022
bdf47f3
variable nameToReferenceSize rename to moduleCount
XenoAmess Apr 10, 2022
7adc89c
Merge branch 'master' into fix_8186958
XenoAmess Apr 10, 2022
5801dc7
Minor adjustment to test cases of WhiteBoxResizeTest
stuart-marks Apr 13, 2022
2f6f8f4
Add test cases for static factory methods.
stuart-marks Apr 13, 2022
ab8fbb8
Add apiNote to appropriate constructors of HM, LHM, and WHM.
stuart-marks Apr 13, 2022
2f5617b
revert changes in:
XenoAmess Apr 13, 2022
4476c76
Copyright latest year to 2022
XenoAmess Apr 13, 2022
d110ecf
update LastModified
XenoAmess Apr 13, 2022
5603f19
fix usage in XSAttributeChecker
XenoAmess Apr 14, 2022
5b437da
revert changes on ProcessEnvironment
XenoAmess Apr 14, 2022
71b7dba
add `@LastModified: Apr 2022` to DocumentCache
XenoAmess Apr 14, 2022
95e22f2
java.xml.crypto's usage downgrade grammar to 1.8
XenoAmess Apr 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -570,7 +570,7 @@ public Map<String, Integer> getDisplayNames(String calendarType,
String[] names = getCalendarDisplayStrings(locale.toLanguageTag(),
field, style);
if (names != null) {
map = new HashMap<>((int)Math.ceil(names.length / 0.75));
map = HashMap.newHashMap(names.length);
for (int value = 0; value < names.length; value++) {
if (names[value] != null) {
map.put(names[value], value);
Expand Down
5 changes: 2 additions & 3 deletions src/java.base/share/classes/java/lang/Character.java
Expand Up @@ -744,8 +744,7 @@ public static final class UnicodeBlock extends Subset {
* 0.75 - the default load factor of HashMap
*/
private static final int NUM_ENTITIES = 737;
private static Map<String, UnicodeBlock> map =
new HashMap<>((int)(NUM_ENTITIES / 0.75f + 1.0f));
private static Map<String, UnicodeBlock> map = HashMap.newHashMap(NUM_ENTITIES);

/**
* Creates a UnicodeBlock with the given identifier name.
Expand Down Expand Up @@ -8572,7 +8571,7 @@ public static enum UnicodeScript {

private static final HashMap<String, Character.UnicodeScript> aliases;
static {
aliases = new HashMap<>((int)(162 / 0.75f + 1.0f));
aliases = HashMap.newHashMap(162);
XenoAmess marked this conversation as resolved.
Show resolved Hide resolved
aliases.put("ADLM", ADLAM);
aliases.put("AGHB", CAUCASIAN_ALBANIAN);
aliases.put("AHOM", AHOM);
Expand Down
6 changes: 3 additions & 3 deletions src/java.base/share/classes/java/lang/Class.java
Expand Up @@ -3910,7 +3910,7 @@ Map<String, T> enumConstantDirectory() {
if (universe == null)
throw new IllegalArgumentException(
getName() + " is not an enum class");
directory = new HashMap<>((int)(universe.length / 0.75f) + 1);
directory = HashMap.newHashMap(universe.length);
for (T constant : universe) {
directory.put(((Enum<?>)constant).name(), constant);
}
Expand Down Expand Up @@ -4125,10 +4125,10 @@ private AnnotationData createAnnotationData(int classRedefinedCount) {
Class<? extends Annotation> annotationClass = e.getKey();
if (AnnotationType.getInstance(annotationClass).isInherited()) {
if (annotations == null) { // lazy construction
annotations = new LinkedHashMap<>((Math.max(
annotations = LinkedHashMap.newLinkedHashMap(Math.max(
declaredAnnotations.size(),
Math.min(12, declaredAnnotations.size() + superAnnotations.size())
) * 4 + 2) / 3
)
);
}
annotations.put(annotationClass, e.getValue());
Expand Down
5 changes: 2 additions & 3 deletions src/java.base/share/classes/java/lang/Module.java
Expand Up @@ -980,7 +980,7 @@ void implAddOpensToAllUnnamed(Set<String> concealedPkgs, Set<String> exportedPkg
// the packages to all unnamed modules.
Map<String, Set<Module>> openPackages = this.openPackages;
if (openPackages == null) {
openPackages = new HashMap<>((4 * (concealedPkgs.size() + exportedPkgs.size()) / 3) + 1);
openPackages = HashMap.newHashMap(concealedPkgs.size() + exportedPkgs.size());
} else {
openPackages = new HashMap<>(openPackages);
}
Expand Down Expand Up @@ -1133,8 +1133,7 @@ static Map<String, Module> defineModules(Configuration cf,
boolean isBootLayer = (ModuleLayer.boot() == null);

int numModules = cf.modules().size();
int cap = (int)(numModules / 0.75f + 1.0f);
Map<String, Module> nameToModule = new HashMap<>(cap);
Map<String, Module> nameToModule = HashMap.newHashMap(numModules);

// to avoid repeated lookups and reduce iteration overhead, we create
// arrays holding correlated information about each module.
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/lang/Thread.java
Expand Up @@ -1655,7 +1655,7 @@ public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
// Get a snapshot of the list of all threads
Thread[] threads = getThreads();
StackTraceElement[][] traces = dumpThreads(threads);
Map<Thread, StackTraceElement[]> m = new HashMap<>(threads.length);
Map<Thread, StackTraceElement[]> m = HashMap.newHashMap(threads.length);
for (int i = 0; i < threads.length; i++) {
StackTraceElement[] stackTrace = traces[i];
if (stackTrace != null) {
Expand Down
Expand Up @@ -290,7 +290,7 @@ static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType
BoundMethodHandle mh = target.rebind();

// Match each unique conversion to the positions at which it is to be applied
var convSpecMap = new HashMap<Object, int[]>(((4 * convCount) / 3) + 1);
HashMap<Object, int[]> convSpecMap = HashMap.newHashMap(convCount);
for (int i = 0; i < convSpecs.length - MH_RECEIVER_OFFSET; i++) {
Object convSpec = convSpecs[i];
if (convSpec == null) continue;
Expand Down
9 changes: 4 additions & 5 deletions src/java.base/share/classes/java/lang/module/Resolver.java
Expand Up @@ -498,12 +498,11 @@ private void checkHashes() {
*/
private Map<ResolvedModule, Set<ResolvedModule>> makeGraph(Configuration cf) {

// initial capacity of maps to avoid resizing
int capacity = 1 + (4 * nameToReference.size())/ 3;
int moduleCount = nameToReference.size();

// the "reads" graph starts as a module dependence graph and
// is iteratively updated to be the readability graph
Map<ResolvedModule, Set<ResolvedModule>> g1 = new HashMap<>(capacity);
Map<ResolvedModule, Set<ResolvedModule>> g1 = HashMap.newHashMap(moduleCount);

// the "requires transitive" graph, contains requires transitive edges only
Map<ResolvedModule, Set<ResolvedModule>> g2;
Expand All @@ -512,7 +511,7 @@ private Map<ResolvedModule, Set<ResolvedModule>> makeGraph(Configuration cf) {
// as there may be selected modules that have a dependency on modules in
// the parent configuration.
if (ModuleLayer.boot() == null) {
g2 = new HashMap<>(capacity);
g2 = HashMap.newHashMap(moduleCount);
} else {
g2 = parents.stream()
.flatMap(Configuration::configurations)
Expand All @@ -539,7 +538,7 @@ private Map<ResolvedModule, Set<ResolvedModule>> makeGraph(Configuration cf) {

// populate g1 and g2 with the dependences from the selected modules

Map<String, ResolvedModule> nameToResolved = new HashMap<>(capacity);
Map<String, ResolvedModule> nameToResolved = HashMap.newHashMap(moduleCount);

for (ModuleReference mref : nameToReference.values()) {
ModuleDescriptor descriptor = mref.descriptor();
Expand Down
Expand Up @@ -245,7 +245,7 @@ private void readObject(ObjectInputStream ois)
} else if (size < 0) {
throw new IOException("size cannot be negative");
} else {
extensions = new HashMap<>(size > 20 ? 20 : size);
extensions = HashMap.newHashMap(size > 20 ? 20 : size);
}

// Read in the extensions and put the mappings in the extensions map
Expand Down
Expand Up @@ -197,7 +197,7 @@ public void setOcspResponses(Map<X509Certificate, byte[]> responses)
if (responses == null) {
this.ocspResponses = Collections.<X509Certificate, byte[]>emptyMap();
} else {
Map<X509Certificate, byte[]> copy = new HashMap<>(responses.size());
Map<X509Certificate, byte[]> copy = HashMap.newHashMap(responses.size());
for (Map.Entry<X509Certificate, byte[]> e : responses.entrySet()) {
copy.put(e.getKey(), e.getValue().clone());
}
Expand All @@ -216,7 +216,7 @@ public void setOcspResponses(Map<X509Certificate, byte[]> responses)
* Returns an empty map if no responses have been specified.
*/
public Map<X509Certificate, byte[]> getOcspResponses() {
Map<X509Certificate, byte[]> copy = new HashMap<>(ocspResponses.size());
Map<X509Certificate, byte[]> copy = HashMap.newHashMap(ocspResponses.size());
for (Map.Entry<X509Certificate, byte[]> e : ocspResponses.entrySet()) {
copy.put(e.getKey(), e.getValue().clone());
}
Expand Down
36 changes: 36 additions & 0 deletions src/java.base/share/classes/java/util/HashMap.java
Expand Up @@ -433,6 +433,10 @@ static final int tableSizeFor(int cap) {
* Constructs an empty {@code HashMap} with the specified initial
* capacity and load factor.
*
* @apiNote
* To create a {@code HashMap} with an initial capacity that accommodates
* an expected number of mappings, use {@link #newHashMap(int) newHashMap}.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
Expand All @@ -455,6 +459,10 @@ public HashMap(int initialCapacity, float loadFactor) {
* Constructs an empty {@code HashMap} with the specified initial
* capacity and the default load factor (0.75).
*
* @apiNote
* To create a {@code HashMap} with an initial capacity that accommodates
* an expected number of mappings, use {@link #newHashMap(int) newHashMap}.
*
* @param initialCapacity the initial capacity.
* @throws IllegalArgumentException if the initial capacity is negative.
*/
Expand Down Expand Up @@ -2545,4 +2553,32 @@ static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
}
}

/**
* Calculate initial capacity for HashMap based classes, from expected size and default load factor (0.75).
*
* @param numMappings the expected number of mappings
* @return initial capacity for HashMap based classes.
* @since 19
*/
static int calculateHashMapCapacity(int numMappings) {
return (int) Math.ceil(numMappings / (double) DEFAULT_LOAD_FACTOR);
}

/**
* Creates a new, empty HashMap suitable for the expected number of mappings.
* The returned map uses the default load factor of 0.75, and its initial capacity is
* generally large enough so that the expected number of mappings can be added
* without resizing the map.
*
* @param numMappings the expected number of mappings
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
* @return the newly created map
* @throws IllegalArgumentException if numMappings is negative
* @since 19
*/
public static <K, V> HashMap<K, V> newHashMap(int numMappings) {
return new HashMap<>(calculateHashMapCapacity(numMappings));
}

}
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/util/HashSet.java
Expand Up @@ -117,7 +117,7 @@ public HashSet() {
* @throws NullPointerException if the specified collection is null
*/
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
map = HashMap.newHashMap(Math.max(c.size(), 12));
addAll(c);
}

Expand Down
24 changes: 24 additions & 0 deletions src/java.base/share/classes/java/util/LinkedHashMap.java
Expand Up @@ -339,6 +339,10 @@ void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
* Constructs an empty insertion-ordered {@code LinkedHashMap} instance
* with the specified initial capacity and load factor.
*
* @apiNote
* To create a {@code LinkedHashMap} with an initial capacity that accommodates
* an expected number of mappings, use {@link #newLinkedHashMap(int) newLinkedHashMap}.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
Expand All @@ -353,6 +357,10 @@ public LinkedHashMap(int initialCapacity, float loadFactor) {
* Constructs an empty insertion-ordered {@code LinkedHashMap} instance
* with the specified initial capacity and a default load factor (0.75).
*
* @apiNote
* To create a {@code LinkedHashMap} with an initial capacity that accommodates
* an expected number of mappings, use {@link #newLinkedHashMap(int) newLinkedHashMap}.
*
* @param initialCapacity the initial capacity
* @throws IllegalArgumentException if the initial capacity is negative
*/
Expand Down Expand Up @@ -788,5 +796,21 @@ final class LinkedEntryIterator extends LinkedHashIterator
public final Map.Entry<K,V> next() { return nextNode(); }
}

/**
* Creates a new, empty, insertion-ordered LinkedHashMap suitable for the expected number of mappings.
* The returned map uses the default load factor of 0.75, and its initial capacity is
* generally large enough so that the expected number of mappings can be added
* without resizing the map.
*
* @param numMappings the expected number of mappings
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
* @return the newly created map
* @throws IllegalArgumentException if numMappings is negative
* @since 19
*/
public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int numMappings) {
XenoAmess marked this conversation as resolved.
Show resolved Hide resolved
return new LinkedHashMap<>(HashMap.calculateHashMapCapacity(numMappings));
}

}
Expand Up @@ -193,7 +193,7 @@ private synchronized void loadLookup() {
return;

Object[][] contents = getContents();
HashMap<String,Object> temp = new HashMap<>(contents.length);
HashMap<String,Object> temp = HashMap.newHashMap(contents.length);
for (Object[] content : contents) {
// key must be non-null String, value must be non-null
String key = (String) content[0];
Expand Down
25 changes: 25 additions & 0 deletions src/java.base/share/classes/java/util/WeakHashMap.java
Expand Up @@ -198,6 +198,10 @@ private Entry<K,V>[] newTable(int n) {
* Constructs a new, empty {@code WeakHashMap} with the given initial
* capacity and the given load factor.
*
* @apiNote
* To create a {@code WeakHashMap} with an initial capacity that accommodates
* an expected number of mappings, use {@link #newWeakHashMap(int) newWeakHashMap}.
*
* @param initialCapacity The initial capacity of the {@code WeakHashMap}
* @param loadFactor The load factor of the {@code WeakHashMap}
* @throws IllegalArgumentException if the initial capacity is negative,
Expand All @@ -223,6 +227,10 @@ public WeakHashMap(int initialCapacity, float loadFactor) {
* Constructs a new, empty {@code WeakHashMap} with the given initial
* capacity and the default load factor (0.75).
*
* @apiNote
* To create a {@code WeakHashMap} with an initial capacity that accommodates
* an expected number of mappings, use {@link #newWeakHashMap(int) newWeakHashMap}.
*
* @param initialCapacity The initial capacity of the {@code WeakHashMap}
* @throws IllegalArgumentException if the initial capacity is negative
*/
Expand Down Expand Up @@ -1335,4 +1343,21 @@ public int characteristics() {
}
}

/**
* Creates a new, empty WeakHashMap suitable for the expected number of mappings.
* The returned map uses the default load factor of 0.75, and its initial capacity is
* generally large enough so that the expected number of mappings can be added
* without resizing the map.
*
* @param numMappings the expected number of mappings
* @param <K> the type of keys maintained by this map
* @param <V> the type of mapped values
* @return the newly created map
* @throws IllegalArgumentException if numMappings is negative
* @since 19
*/
public static <K, V> WeakHashMap<K, V> newWeakHashMap(int numMappings) {
return new WeakHashMap<>(HashMap.calculateHashMapCapacity(numMappings));
}

}
4 changes: 2 additions & 2 deletions src/java.base/share/classes/java/util/jar/Attributes.java
Expand Up @@ -69,7 +69,7 @@ public class Attributes implements Map<Object,Object>, Cloneable {
* Constructs a new, empty Attributes object with default size.
*/
public Attributes() {
this(11);
this(16);
}

/**
Expand All @@ -79,7 +79,7 @@ public Attributes() {
* @param size the initial number of attributes
*/
public Attributes(int size) {
map = new LinkedHashMap<>(size);
map = LinkedHashMap.newLinkedHashMap(size);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/util/jar/JarVerifier.java
Expand Up @@ -672,7 +672,7 @@ private synchronized Map<String, CodeSigner[]> signerMap() {
* only about the asserted signatures. Verification of
* signature validity happens via the JarEntry apis.
*/
signerMap = new HashMap<>(verifiedSigners.size() + sigFileSigners.size());
signerMap = HashMap.newHashMap(verifiedSigners.size() + sigFileSigners.size());
signerMap.putAll(verifiedSigners);
signerMap.putAll(sigFileSigners);
}
Expand Down
Expand Up @@ -588,7 +588,7 @@ private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
String algorithm = cpool.getUtf8(algorithm_index);

int hash_count = in.readUnsignedShort();
Map<String, byte[]> map = new HashMap<>(hash_count);
Map<String, byte[]> map = HashMap.newHashMap(hash_count);
for (int i=0; i<hash_count; i++) {
int module_name_index = in.readUnsignedShort();
String mn = cpool.getModuleName(module_name_index);
Expand Down
Expand Up @@ -307,7 +307,7 @@ public OCSPResponse(byte[] bytes) throws IOException {

// responses
DerValue[] singleResponseDer = seqDerIn.getSequence(1);
singleResponseMap = new HashMap<>(singleResponseDer.length);
singleResponseMap = HashMap.newHashMap(singleResponseDer.length);
if (debug != null) {
debug.println("OCSP number of SingleResponses: "
+ singleResponseDer.length);
Expand Down Expand Up @@ -751,7 +751,7 @@ public String toString() {
parseExtensions(DerValue derVal) throws IOException {
DerValue[] extDer = derVal.data.getSequence(3);
Map<String, java.security.cert.Extension> extMap =
new HashMap<>(extDer.length);
HashMap.newHashMap(extDer.length);

for (DerValue extDerVal : extDer) {
Extension ext = new Extension(extDerVal);
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/sun/security/util/Cache.java
Expand Up @@ -481,7 +481,7 @@ public synchronized void accept(CacheVisitor<K,V> visitor) {
}

private Map<K,V> getCachedEntries() {
Map<K,V> kvmap = new HashMap<>(cacheMap.size());
Map<K,V> kvmap = HashMap.newHashMap(cacheMap.size());

for (CacheEntry<K,V> entry : cacheMap.values()) {
kvmap.put(entry.getKey(), entry.getValue());
Expand Down
Expand Up @@ -157,7 +157,7 @@ private void loadLookup() {
* Default uses HashMap.
*/
protected <K, V> Map<K, V> createMap(int size) {
return new HashMap<>(size);
return HashMap.newHashMap(size);
}

protected <E> Set<E> createSet() {
Expand Down
Expand Up @@ -96,7 +96,7 @@ public Object handleGetObject(String key) {
*/
@Override
protected <K, V> Map<K, V> createMap(int size) {
return new LinkedHashMap<>(size);
return LinkedHashMap.newLinkedHashMap(size);
}

/**
Expand Down