package net.minecraft.util; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import com.mojang.serialization.DynamicOps; import java.util.Objects; import net.minecraft.nbt.Tag; public class EncoderCache { private final LoadingCache, DataResult> cache; public EncoderCache(final int maximumSize) { this.cache = CacheBuilder.newBuilder() .maximumSize(maximumSize) .concurrencyLevel(1) .softValues() .build(new CacheLoader, DataResult>() { { Objects.requireNonNull(EncoderCache.this); } public DataResult load(final EncoderCache.Key key) { return key.resolve(); } }); } public Codec wrap(final Codec codec) { return new Codec() { { Objects.requireNonNull(EncoderCache.this); } @Override public DataResult> decode(final DynamicOps ops, final T input) { return codec.decode(ops, input); } @Override public DataResult encode(final A input, final DynamicOps ops, final T prefix) { return EncoderCache.this.cache.getUnchecked(new EncoderCache.Key<>(codec, input, ops)).map(value -> value instanceof Tag tag ? tag.copy() : value); } }; } private record Key(Codec codec, A value, DynamicOps ops) { public DataResult resolve() { return this.codec.encodeStart(this.ops, this.value); } public boolean equals(final Object obj) { if (this == obj) { return true; } else { return !(obj instanceof EncoderCache.Key key) ? false : this.codec == key.codec && this.value.equals(key.value) && this.ops.equals(key.ops); } } public int hashCode() { int result = System.identityHashCode(this.codec); result = 31 * result + this.value.hashCode(); return 31 * result + this.ops.hashCode(); } } }