-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Description
1. What are you trying to do?
Summary:
This contribution introduces SmallImmutableSet, a specialized implementation for sets containing 2, 3, or 4 elements. By replacing the standard hash table with a simple linear-scan array, we significantly reduce the memory footprint and improve CPU cache locality.
Key Improvements:
Memory Efficiency: Eliminates the int[] hash table array, saving ~32–48 bytes per instance. Performance: For n \le 4, linear search outperforms hashing by avoiding hashCode() computations and hash table probing. Reduced GC Pressure: Reduces the object count per set creation from two arrays to one. L1 Cache Locality: Small arrays stay entirely within a single CPU cache line, making contains() operations faster.
Impact:
This is particularly beneficial for high-scale applications (e.g., dependency graphs, metadata mapping) where millions of small sets are held in memory.
Code:
package com.google.common.collect;
import com.google.common.annotations.GwtCompatible;
import java.util.Spliterator;
import java.util.Spliterators;
import javax.annotation.CheckForNull;
/**
- Optimized implementation of {@code ImmutableSet} for 2 to 4 elements.
- Uses linear scan to avoid hash table overhead, improving memory footprint
- and L1 cache locality for small collections.
*/
@GwtCompatible(serializable = true, emulated = true)
final class SmallImmutableSet extends ImmutableSet {
private final transient Object[] elements;
SmallImmutableSet(Object[] elements) {
this.elements = elements;
}
@OverRide
public int size() {
return elements.length;
}
@OverRide
public boolean contains(@checkfornull Object target) {
if (target == null) return false;
// Linear scan is faster than hashing for n <= 4
for (Object element : elements) {
if (element.equals(target)) {
return true;
}
}
return false;
}
@OverRide
public UnmodifiableIterator iterator() {
return (UnmodifiableIterator) Iterators.forArray(elements);
}
@OverRide
public Spliterator spliterator() {
return Spliterators.spliterator(elements, SPLITERATOR_CHARACTERISTICS);
}
@OverRide
boolean isPartialView() {
return false;
}
@OverRide
int copyIntoArray(Object[] dst, int offset) {
System.arraycopy(elements, 0, dst, offset, elements.length);
return offset + elements.length;
}
@OverRide
ImmutableList createAsList() {
return ImmutableList.asImmutableList(elements);
}
}
Integration point:
private static ImmutableSet construct(int n, Object... elements) {
switch (n) {
case 0:
return of();
case 1:
@SuppressWarnings("unchecked")
E elem = (E) elements[0];
return of(elem);
case 2:
case 3:
case 4:
// NEW: Memory and CPU optimization for tiny sets
return new SmallImmutableSet(elements);
default:
return RegularImmutableSet.create(n, elements);
}
}
2. What's the best code you can write to accomplish that without the new feature?
Possible i try to optimized this idea if is a good idea for the project
3. What would that same code look like if we added your feature?
If the specialized engeneer can do best for this code implement the engeneer contribution
(Optional) What would the method signatures for your feature look like?
Concrete Use Cases
Memory, calculated ecc
Packages
No response
Checklist
-
I agree to follow the code of conduct.
-
I have read and understood the contribution guidelines.
-
I have read and understood Guava's philosophy, and I strongly believe that this proposal aligns with it.
-
I have visited the idea graveyard, and did not see anything similar to this idea.