Presize collections in MapBinder and Multibinder providers.
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=75399675
diff --git a/extensions/multibindings/src/com/google/inject/multibindings/MapBinder.java b/extensions/multibindings/src/com/google/inject/multibindings/MapBinder.java
index 68610a3..4e5ec78 100644
--- a/extensions/multibindings/src/com/google/inject/multibindings/MapBinder.java
+++ b/extensions/multibindings/src/com/google/inject/multibindings/MapBinder.java
@@ -539,15 +539,19 @@
}
@Override public Map<K, V> get() {
- Map<K, V> map = new LinkedHashMap<K, V>();
- for (Entry<K, Provider<V>> entry : mapProvider.get().entrySet()) {
- V value = entry.getValue().get();
- K key = entry.getKey();
+ // We can initialize the internal table efficiently this way and then swap the values
+ // one by one.
+ Map<K, Object> map = new LinkedHashMap<K, Object>(mapProvider.get());
+ for (Entry<K, Object> entry : map.entrySet()) {
+ @SuppressWarnings("unchecked") // we initialized the entries with providers
+ V value = ((Provider<V>) entry.getValue()).get();
checkConfiguration(value != null,
- "Map injection failed due to null value for key \"%s\"", key);
- map.put(key, value);
+ "Map injection failed due to null value for key \"%s\"", entry.getKey());
+ entry.setValue(value);
}
- return Collections.unmodifiableMap(map);
+ @SuppressWarnings("unchecked") // if we exited the loop then we replaced all Providers
+ Map<K, V> typedMap = (Map<K, V>) map;
+ return Collections.unmodifiableMap(typedMap);
}
@Override public Set<Dependency<?>> getDependencies() {
diff --git a/extensions/multibindings/src/com/google/inject/multibindings/Multibinder.java b/extensions/multibindings/src/com/google/inject/multibindings/Multibinder.java
index 98db1e4..50ce9c1 100644
--- a/extensions/multibindings/src/com/google/inject/multibindings/Multibinder.java
+++ b/extensions/multibindings/src/com/google/inject/multibindings/Multibinder.java
@@ -17,6 +17,7 @@
package com.google.inject.multibindings;
import static com.google.common.base.Predicates.equalTo;
+import static com.google.common.primitives.Ints.MAX_POWER_OF_TWO;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.inject.multibindings.Element.Type.MULTIBINDER;
@@ -315,6 +316,16 @@
this.binder = null;
}
+ // This is forked from com.google.common.collect.Maps.capacity
+ private static int mapCapacity(int numBindings) {
+ if (numBindings < 3) {
+ return numBindings + 1;
+ } else if (numBindings < MAX_POWER_OF_TWO) {
+ return (int) (numBindings / 0.75F + 1.0F);
+ }
+ return Integer.MAX_VALUE;
+ }
+
boolean permitsDuplicates(Injector injector) {
return injector.getBindings().containsKey(permitDuplicatesKey);
}
@@ -333,7 +344,7 @@
public Set<T> get() {
checkConfiguration(isInitialized(), "Multibinder is not initialized");
- Map<T, Binding<T>> result = new LinkedHashMap<T, Binding<T>>();
+ Map<T, Binding<T>> result = new LinkedHashMap<T, Binding<T>>(mapCapacity(bindings.size()));
for (Binding<T> binding : bindings) {
final T newValue = binding.getProvider().get();
checkConfiguration(newValue != null, "Set injection failed due to null element");
@@ -423,12 +434,13 @@
implements ProviderWithDependencies<Collection<Provider<T>>> {
@Override public Collection<Provider<T>> get() {
checkConfiguration(isInitialized(), "Multibinder is not initialized");
-
- ImmutableList.Builder<Provider<T>> resultBuilder = new ImmutableList.Builder<Provider<T>>();
- for (Binding<T> binding : bindings) {
- resultBuilder.add(binding.getProvider());
+ int size = bindings.size();
+ @SuppressWarnings("unchecked") // safe because we only put Provider<T> into it.
+ Provider<T>[] providers = new Provider[size];
+ for (int i = 0; i < size; i++) {
+ providers[i] = bindings.get(i).getProvider();
}
- return resultBuilder.build();
+ return ImmutableList.copyOf(providers);
}
@Override public Set<Dependency<?>> getDependencies() {