diff --git a/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java b/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java index 5cce3228af..34bb51baf3 100644 --- a/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java +++ b/java/fury-core/src/main/java/org/apache/fury/builder/BaseObjectCodecBuilder.java @@ -48,7 +48,6 @@ import static org.apache.fury.type.TypeUtils.isPrimitive; import static org.apache.fury.util.Preconditions.checkArgument; -import com.google.common.collect.ImmutableSet; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -450,11 +449,7 @@ protected Expression writeForNotNullNonFinalObject( buffer, inputObject)); return invokeGenerated( - ctx, - ImmutableSet.of(buffer, inputObject), - writeClassAndObject, - "writeClassAndObject", - false); + ctx, ofHashSet(buffer, inputObject), writeClassAndObject, "writeClassAndObject", false); } /** @@ -666,7 +661,7 @@ protected Expression serializeForCollection( serializer = invokeGenerated( ctx, - ImmutableSet.of(buffer, collection), + ofHashSet(buffer, collection), writeClassAction, "writeCollectionClassInfo", false); @@ -685,7 +680,7 @@ protected Expression serializeForCollection( actions.add(write); if (generateNewMethod) { return invokeGenerated( - ctx, ImmutableSet.of(buffer, collection, serializer), actions, "writeCollection", false); + ctx, ofHashSet(buffer, collection, serializer), actions, "writeCollection", false); } return actions; } @@ -970,7 +965,7 @@ protected Expression serializeForMap( // Spit this into a separate method to avoid method too big to inline. serializer = invokeGenerated( - ctx, ImmutableSet.of(buffer, map), writeClassAction, "writeMapClassInfo", false); + ctx, ofHashSet(buffer, map), writeClassAction, "writeMapClassInfo", false); } } else if (!AbstractMapSerializer.class.isAssignableFrom(serializer.type().getRawType())) { serializer = new Cast(serializer, TypeRef.of(AbstractMapSerializer.class), "mapSerializer"); @@ -981,7 +976,7 @@ protected Expression serializeForMap( jitWriteMap(buffer, map, serializer, typeRef), new Invoke(serializer, "write", buffer, map)); if (generateNewMethod) { - return invokeGenerated(ctx, ImmutableSet.of(buffer, map), write, "writeMap", false); + return invokeGenerated(ctx, ofHashSet(buffer, map), write, "writeMap", false); } return write; } diff --git a/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecBuilder.java b/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecBuilder.java index 2e2df420cb..d1d8bc57a0 100644 --- a/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecBuilder.java +++ b/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecBuilder.java @@ -22,6 +22,7 @@ import static org.apache.fury.codegen.Code.LiteralValue.FalseLiteral; import static org.apache.fury.codegen.Expression.Invoke.inlineInvoke; import static org.apache.fury.codegen.ExpressionUtils.add; +import static org.apache.fury.collection.Collections.ofHashSet; import static org.apache.fury.type.TypeUtils.OBJECT_ARRAY_TYPE; import static org.apache.fury.type.TypeUtils.OBJECT_TYPE; import static org.apache.fury.type.TypeUtils.PRIMITIVE_BYTE_ARRAY_TYPE; @@ -32,8 +33,6 @@ import static org.apache.fury.type.TypeUtils.getSizeOfPrimitiveType; import static org.apache.fury.type.TypeUtils.isPrimitive; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -162,17 +161,12 @@ public Expression buildEncodeExpression() { } expressions.addAll(serializePrimitives(bean, buffer, objectCodecOptimizer.primitiveGroups)); int numGroups = getNumGroups(objectCodecOptimizer); - for (List group : - Iterables.concat( - objectCodecOptimizer.boxedWriteGroups, - objectCodecOptimizer.finalWriteGroups, - objectCodecOptimizer.otherWriteGroups)) { - if (group.isEmpty()) { - continue; - } - boolean inline = group.size() == 1 && numGroups < 10; - expressions.add(serializeGroup(group, bean, buffer, inline)); - } + addGroupExpressions( + objectCodecOptimizer.boxedWriteGroups, numGroups, expressions, bean, buffer); + addGroupExpressions( + objectCodecOptimizer.finalWriteGroups, numGroups, expressions, bean, buffer); + addGroupExpressions( + objectCodecOptimizer.otherWriteGroups, numGroups, expressions, bean, buffer); for (Descriptor descriptor : objectCodecOptimizer.descriptorGrouper.getCollectionDescriptors()) { expressions.add(serializeGroup(Collections.singletonList(descriptor), bean, buffer, false)); @@ -183,6 +177,21 @@ public Expression buildEncodeExpression() { return expressions; } + private void addGroupExpressions( + List> writeGroup, + int numGroups, + ListExpression expressions, + Expression bean, + Reference buffer) { + for (List group : writeGroup) { + if (group.isEmpty()) { + continue; + } + boolean inline = group.size() == 1 && numGroups < 10; + expressions.add(serializeGroup(group, bean, buffer, inline)); + } + } + private int getNumGroups(ObjectCodecOptimizer objectCodecOptimizer) { return objectCodecOptimizer.boxedWriteGroups.size() + objectCodecOptimizer.finalWriteGroups.size() @@ -291,7 +300,7 @@ private List serializePrimitivesUnCompressed( } else { expressions.add( objectCodecOptimizer.invokeGenerated( - ImmutableSet.of(bean, base, writerAddr), groupExpressions, "writeFields")); + ofHashSet(bean, base, writerAddr), groupExpressions, "writeFields")); } } Expression increaseWriterIndex = @@ -397,7 +406,7 @@ private List serializePrimitivesCompressed( } else { expressions.add( objectCodecOptimizer.invokeGenerated( - ImmutableSet.of(bean, buffer, base), groupExpressions, "writeFields")); + ofHashSet(bean, buffer, base), groupExpressions, "writeFields")); } } return expressions; @@ -445,17 +454,12 @@ public Expression buildDecodeExpression() { } expressions.addAll(deserializePrimitives(bean, buffer, objectCodecOptimizer.primitiveGroups)); int numGroups = getNumGroups(objectCodecOptimizer); - for (List group : - Iterables.concat( - objectCodecOptimizer.boxedReadGroups, - objectCodecOptimizer.finalReadGroups, - objectCodecOptimizer.otherReadGroups)) { - if (group.isEmpty()) { - continue; - } - boolean inline = group.size() == 1 && numGroups < 10; - expressions.add(deserializeGroup(group, bean, buffer, inline)); - } + deserializeReadGroup( + objectCodecOptimizer.boxedReadGroups, numGroups, expressions, bean, buffer); + deserializeReadGroup( + objectCodecOptimizer.finalReadGroups, numGroups, expressions, bean, buffer); + deserializeReadGroup( + objectCodecOptimizer.otherReadGroups, numGroups, expressions, bean, buffer); for (Descriptor d : objectCodecOptimizer.descriptorGrouper.getCollectionDescriptors()) { expressions.add(deserializeGroup(Collections.singletonList(d), bean, buffer, false)); } @@ -481,6 +485,21 @@ public Expression buildDecodeExpression() { return expressions; } + private void deserializeReadGroup( + List> readGroups, + int numGroups, + ListExpression expressions, + Expression bean, + Reference buffer) { + for (List group : readGroups) { + if (group.isEmpty()) { + continue; + } + boolean inline = group.size() == 1 && numGroups < 10; + expressions.add(deserializeGroup(group, bean, buffer, inline)); + } + } + protected Expression buildComponentsArray() { return new StaticInvoke( Platform.class, "copyObjectArray", OBJECT_ARRAY_TYPE, recordComponentDefaultValues); @@ -653,7 +672,7 @@ private List deserializeUnCompressedPrimitives( } else { expressions.add( objectCodecOptimizer.invokeGenerated( - ImmutableSet.of(bean, heapBuffer, readerAddr), groupExpressions, "readFields")); + ofHashSet(bean, heapBuffer, readerAddr), groupExpressions, "readFields")); } } Expression increaseReaderIndex = @@ -742,7 +761,7 @@ private List deserializeCompressedPrimitives( } else { expressions.add( objectCodecOptimizer.invokeGenerated( - ImmutableSet.of(bean, buffer, heapBuffer), groupExpressions, "readFields")); + ofHashSet(bean, buffer, heapBuffer), groupExpressions, "readFields")); } } return expressions; diff --git a/java/fury-core/src/main/java/org/apache/fury/codegen/CodegenContext.java b/java/fury-core/src/main/java/org/apache/fury/codegen/CodegenContext.java index d60fb6a736..624e55e91c 100644 --- a/java/fury-core/src/main/java/org/apache/fury/codegen/CodegenContext.java +++ b/java/fury-core/src/main/java/org/apache/fury/codegen/CodegenContext.java @@ -19,13 +19,13 @@ package org.apache.fury.codegen; +import static java.util.Collections.unmodifiableSet; import static org.apache.fury.codegen.Code.ExprCode; import static org.apache.fury.codegen.CodeGenerator.alignIndent; import static org.apache.fury.codegen.CodeGenerator.indent; import static org.apache.fury.type.TypeUtils.getArrayType; import static org.apache.fury.type.TypeUtils.getRawType; -import com.google.common.collect.ImmutableSet; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -114,7 +114,7 @@ public class CodegenContext { "true", "false", "null")); - JAVA_RESERVED_WORDS = ImmutableSet.copyOf(JAVA_RESERVED_WORDS); + JAVA_RESERVED_WORDS = unmodifiableSet(JAVA_RESERVED_WORDS); } private static Map> nameConflicts = new ConcurrentHashMap<>(); diff --git a/java/fury-core/src/main/java/org/apache/fury/collection/LazyMap.java b/java/fury-core/src/main/java/org/apache/fury/collection/LazyMap.java index 972f4eb515..3614772701 100644 --- a/java/fury-core/src/main/java/org/apache/fury/collection/LazyMap.java +++ b/java/fury-core/src/main/java/org/apache/fury/collection/LazyMap.java @@ -19,17 +19,22 @@ package org.apache.fury.collection; -import com.google.common.collect.ForwardingMap; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; import org.apache.fury.util.Preconditions; /** A map which populate lazily until the first map query happens to reduce map#put cost. */ -public class LazyMap extends ForwardingMap { - private List> entries; +public class LazyMap implements Map { + private List> entries; + private Map map; public LazyMap() { entries = new ArrayList<>(); @@ -39,19 +44,16 @@ public LazyMap(int size) { entries = new ArrayList<>(size); } - public LazyMap(List> entries) { + public LazyMap(List> entries) { this.entries = entries; } - private Map map; - - @Override public Map delegate() { Map m = this.map; if (m == null) { - List> e = this.entries; + List> e = this.entries; m = new HashMap<>(e.size()); - for (Entry entry : e) { + for (Entry entry : e) { m.put(entry.getKey(), entry.getValue()); } this.map = m; @@ -59,6 +61,11 @@ public Map delegate() { return m; } + public void setEntries(List> entries) { + Preconditions.checkArgument(map == null); + this.entries = entries; + } + @Override public V put(K key, V value) { Map m = map; @@ -71,13 +78,195 @@ public V put(K key, V value) { } } - public void setEntries(List> entries) { - Preconditions.checkArgument(map == null); - this.entries = entries; + @Override + public V getOrDefault(Object key, V defaultValue) { + return delegate().getOrDefault(key, defaultValue); + } + + @Override + public void forEach(BiConsumer action) { + Map m = map; + if (m == null) { + for (Entry entry : entries) { + action.accept(entry.getKey(), entry.getValue()); + } + } else { + m.forEach(action); + } + } + + @Override + public void replaceAll(BiFunction function) { + delegate().replaceAll(function); + } + + @Override + public V putIfAbsent(K key, V value) { + return delegate().putIfAbsent(key, value); + } + + @Override + public boolean remove(Object key, Object value) { + return delegate().remove(key, value); + } + + @Override + public V remove(Object key) { + return delegate().remove(key); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + return delegate().replace(key, oldValue, newValue); + } + + @Override + public V replace(K key, V value) { + return delegate().replace(key, value); + } + + @Override + public V computeIfAbsent(K key, Function mappingFunction) { + return delegate().computeIfAbsent(key, mappingFunction); + } + + @Override + public V computeIfPresent( + K key, BiFunction remappingFunction) { + return delegate().computeIfPresent(key, remappingFunction); + } + + @Override + public V compute(K key, BiFunction remappingFunction) { + return delegate().compute(key, remappingFunction); + } + + @Override + public V merge(K key, V value, BiFunction remappingFunction) { + return delegate().merge(key, value, remappingFunction); + } + + @Override + public int size() { + Map m = map; + return m == null ? entries.size() : m.size(); + } + + @Override + public boolean isEmpty() { + Map m = map; + return m == null ? entries.isEmpty() : m.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return delegate().containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return delegate().containsValue(value); + } + + @Override + public V get(Object key) { + return delegate().get(key); + } + + @Override + public void putAll(Map m) { + Map map = this.map; + if (map == null) { + // avoid map put cost when deserialization this map. + entries.addAll(m.entrySet()); + } else { + map.putAll(m); + } + } + + @Override + public void clear() { + Map m = map; + if (m == null) { + entries.clear(); + } else { + m.clear(); + } } + @Override + public Set keySet() { + return delegate().keySet(); + } + + @Override + public Collection values() { + return delegate().values(); + } + + @Override + public Set> entrySet() { + return delegate().entrySet(); + } + + @Override + public boolean equals(Object obj) { + Map m = map; + if (m != null) { + return m.equals(obj); + } + + if (obj == this) { + return true; + } + + if (!(obj instanceof Map)) { + return false; + } + Map map = (Map) obj; + List> entries = this.entries; + if (map.size() != entries.size()) { + return false; + } + + try { + for (Entry e : entries) { + K key = e.getKey(); + V value = e.getValue(); + if (value == null) { + if (!(map.get(key) == null && map.containsKey(key))) { + return false; + } + } else { + if (!value.equals(map.get(key))) { + return false; + } + } + } + } catch (ClassCastException | NullPointerException unused) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + Map m = map; + if (m != null) { + return m.hashCode(); + } + + int h = 0; + for (Entry entry : entries) { + h += entry.hashCode(); + } + return h; + } + + @Override public String toString() { - Iterator> i = entries.iterator(); + Iterator> i = entries.iterator(); if (!i.hasNext()) { return "{}"; } @@ -85,7 +274,7 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append('{'); for (; ; ) { - Entry e = i.next(); + Entry e = i.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key); diff --git a/java/fury-core/src/main/java/org/apache/fury/serializer/collection/ChildContainerSerializers.java b/java/fury-core/src/main/java/org/apache/fury/serializer/collection/ChildContainerSerializers.java index 23187e9300..fdb8c18fc4 100644 --- a/java/fury-core/src/main/java/org/apache/fury/serializer/collection/ChildContainerSerializers.java +++ b/java/fury-core/src/main/java/org/apache/fury/serializer/collection/ChildContainerSerializers.java @@ -19,7 +19,8 @@ package org.apache.fury.serializer.collection; -import com.google.common.collect.ImmutableSet; +import static org.apache.fury.collection.Collections.ofHashSet; + import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; @@ -122,7 +123,7 @@ public static Class getMapSerializerClass(Class cls) { public static class ChildCollectionSerializer extends CollectionSerializer { public static Set> superClasses = - ImmutableSet.of( + ofHashSet( ArrayList.class, LinkedList.class, ArrayDeque.class, Vector.class, HashSet.class // PriorityQueue/TreeSet/ConcurrentSkipListSet need comparator as constructor argument ); @@ -172,7 +173,7 @@ public T newCollection(MemoryBuffer buffer) { */ public static class ChildMapSerializer extends MapSerializer { public static Set> superClasses = - ImmutableSet.of( + ofHashSet( HashMap.class, LinkedHashMap.class, ConcurrentHashMap.class // TreeMap/ConcurrentSkipListMap need comparator as constructor argument );