CommunitySet: defer creating a copy until lookup miss
@@ -33,10 +33,25 @@ public final class CommunitySet implements Serializable {
public static @Nonnull CommunitySet of(Set<? extends Community> communities) {
if (communities.isEmpty()) {
+ // Skip cache if the collection is empty.
return empty();
}
- ImmutableSet<Community> immutableValue = ImmutableSet.copyOf(communities);
- return CACHE.getUnchecked(immutableValue);
+ if (communities instanceof ImmutableSet) {
+ // Skip a cache operation if the input is immutable.
+ @SuppressWarnings("unchecked") // safe since you cannot insert into ImmutableSet
+ ImmutableSet<Community> immutableKey = (ImmutableSet<Community>) communities;
+ return CACHE.getUnchecked(immutableKey);
+ }
+ // Skip a copy if a mutable copy of the key is already present.
+ CommunitySet ret = CACHE.getIfPresent(communities);
+ if (ret != null) {
+ return ret;
+ }
+ // The input communities might be mutable, so freeze them before caching.
+ ImmutableSet<Community> immutableKey = ImmutableSet.copyOf(communities);
+ ret = new CommunitySet(immutableKey);
+ CACHE.put(immutableKey, ret);
+ return ret;
}
public @Nonnull Set<Community> getCommunities() {
@@ -90,11 +105,16 @@ public final class CommunitySet implements Serializable {
// Soft values: let it be garbage collected in times of pressure.
// Maximum size 2^16: Just some upper bound on cache size, well less than GiB.
- private static final LoadingCache<ImmutableSet<Community>, CommunitySet> CACHE =
+ private static final LoadingCache<Set<Community>, CommunitySet> CACHE =
CacheBuilder.newBuilder()
.softValues()
.maximumSize(1 << 16)
- .build(CacheLoader.from(CommunitySet::new));
+ .build(
+ CacheLoader.from(
+ set -> {
+ assert set instanceof ImmutableSet;
+ return new CommunitySet((ImmutableSet<Community>) set);
+ }));
/* Cache the hashcode */
private transient int _hashCode = 0;
