From 6a06d9fa758f9be4b27e3c474c0caa5b8264822b Mon Sep 17 00:00:00 2001 From: mof-dev-3 <129163631+mof-dev-3@users.noreply.github.com> Date: Mon, 1 Jan 2024 15:36:01 +0800 Subject: [PATCH] [Java] refine Collection util data structure (#1287) (#1288) 1. use local reference when possible 2. make tuple value field final --------- Co-authored-by: yijun.li@datayes.com --- .../fury/builder/ObjectCodecOptimizer.java | 20 +++--- .../apache/fury/collection/FuryObjectMap.java | 1 + .../org/apache/fury/collection/LazyMap.java | 18 +++-- .../apache/fury/collection/MutableTuple2.java | 64 +++++++++++++++++ .../apache/fury/collection/MutableTuple3.java | 71 +++++++++++++++++++ .../org/apache/fury/collection/Tuple2.java | 11 +-- .../org/apache/fury/collection/Tuple3.java | 15 ++-- 7 files changed, 174 insertions(+), 26 deletions(-) create mode 100644 java/fury-core/src/main/java/org/apache/fury/collection/MutableTuple2.java create mode 100644 java/fury-core/src/main/java/org/apache/fury/collection/MutableTuple3.java diff --git a/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecOptimizer.java b/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecOptimizer.java index c2c5571ea4..9678cfd97b 100644 --- a/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecOptimizer.java +++ b/java/fury-core/src/main/java/org/apache/fury/builder/ObjectCodecOptimizer.java @@ -27,7 +27,7 @@ import org.apache.fury.codegen.CodegenContext; import org.apache.fury.codegen.Expression; import org.apache.fury.codegen.ExpressionOptimizer; -import org.apache.fury.collection.Tuple3; +import org.apache.fury.collection.MutableTuple3; import org.apache.fury.type.Descriptor; import org.apache.fury.type.DescriptorGrouper; import org.apache.fury.util.function.SerializableSupplier; @@ -106,23 +106,25 @@ private void buildGroups() { if (boxedRefTracking) { boxedReadWeight = 4; } - List, Integer, List>>> groups = + List, Integer, List>>> groups = Arrays.asList( - Tuple3.of( + MutableTuple3.of( new ArrayList<>(descriptorGrouper.getBoxedDescriptors()), boxedWriteWeight, boxedWriteGroups), - Tuple3.of( + MutableTuple3.of( new ArrayList<>(descriptorGrouper.getBoxedDescriptors()), boxedReadWeight, boxedReadGroups), - Tuple3.of( + MutableTuple3.of( new ArrayList<>(descriptorGrouper.getFinalDescriptors()), 9, finalWriteGroups), - Tuple3.of(new ArrayList<>(descriptorGrouper.getFinalDescriptors()), 5, finalReadGroups), - Tuple3.of(new ArrayList<>(descriptorGrouper.getOtherDescriptors()), 5, otherReadGroups), - Tuple3.of( + MutableTuple3.of( + new ArrayList<>(descriptorGrouper.getFinalDescriptors()), 5, finalReadGroups), + MutableTuple3.of( + new ArrayList<>(descriptorGrouper.getOtherDescriptors()), 5, otherReadGroups), + MutableTuple3.of( new ArrayList<>(descriptorGrouper.getOtherDescriptors()), 9, otherWriteGroups)); - for (Tuple3, Integer, List>> decs : groups) { + for (MutableTuple3, Integer, List>> decs : groups) { while (decs.f0.size() > 0) { int endIndex = Math.min(decs.f1, decs.f0.size()); decs.f2.add(decs.f0.subList(0, endIndex)); diff --git a/java/fury-core/src/main/java/org/apache/fury/collection/FuryObjectMap.java b/java/fury-core/src/main/java/org/apache/fury/collection/FuryObjectMap.java index bf0e65d9cc..528fc64369 100644 --- a/java/fury-core/src/main/java/org/apache/fury/collection/FuryObjectMap.java +++ b/java/fury-core/src/main/java/org/apache/fury/collection/FuryObjectMap.java @@ -312,6 +312,7 @@ private class MapIterator implements Iterator> { @Override public boolean hasNext() { + K[] keyTable = FuryObjectMap.this.keyTable; for (int i = nextIndex; i < keyTable.length; i++) { if (keyTable[i] != null) { nextIndex = i; 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 db64b91c6f..972f4eb515 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 @@ -47,23 +47,27 @@ public LazyMap(List> entries) { @Override public Map delegate() { - if (map == null) { - map = new HashMap<>(entries.size()); - for (Entry entry : entries) { - map.put(entry.getKey(), entry.getValue()); + Map m = this.map; + if (m == null) { + List> e = this.entries; + m = new HashMap<>(e.size()); + for (Entry entry : e) { + m.put(entry.getKey(), entry.getValue()); } + this.map = m; } - return map; + return m; } @Override public V put(K key, V value) { - if (map == null) { + Map m = map; + if (m == null) { // avoid map put cost when deserialization this map. entries.add(new MapEntry<>(key, value)); return null; } else { - return map.put(key, value); + return m.put(key, value); } } diff --git a/java/fury-core/src/main/java/org/apache/fury/collection/MutableTuple2.java b/java/fury-core/src/main/java/org/apache/fury/collection/MutableTuple2.java new file mode 100644 index 0000000000..71619dda18 --- /dev/null +++ b/java/fury-core/src/main/java/org/apache/fury/collection/MutableTuple2.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fury.collection; + +import java.io.Serializable; +import java.util.Objects; + +public class MutableTuple2 implements Serializable { + /** Field 0 of the tuple. */ + public T0 f0; + + /** Field 1 of the tuple. */ + public T1 f1; + + /** + * Creates a new tuple and assigns the given values to the tuple's fields, with field value + * nonFinal. Recommend use {@link Tuple2} if value do not need to change. + * + * @param value0 The value for field 0 + * @param value1 The value for field 1 + */ + public MutableTuple2(T0 value0, T1 value1) { + this.f0 = value0; + this.f1 = value1; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MutableTuple2 tuple2 = (MutableTuple2) o; + return Objects.equals(f0, tuple2.f0) && Objects.equals(f1, tuple2.f1); + } + + @Override + public int hashCode() { + return Objects.hash(f0, f1); + } + + public static MutableTuple2 of(T0 value0, T1 value1) { + return new MutableTuple2<>(value0, value1); + } +} diff --git a/java/fury-core/src/main/java/org/apache/fury/collection/MutableTuple3.java b/java/fury-core/src/main/java/org/apache/fury/collection/MutableTuple3.java new file mode 100644 index 0000000000..3df169c413 --- /dev/null +++ b/java/fury-core/src/main/java/org/apache/fury/collection/MutableTuple3.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.fury.collection; + +import java.io.Serializable; +import java.util.Objects; + +public class MutableTuple3 implements Serializable { + /** Field 0 of the tuple. */ + public T0 f0; + + /** Field 1 of the tuple. */ + public T1 f1; + + /** Field 2 of the tuple. */ + public T2 f2; + + /** + * Creates a new tuple and assigns the given values to the tuple's fields, with field value + * nonFinal. Recommend use {@link Tuple3} if value do not need to change + * + * @param value0 The value for field 0 + * @param value1 The value for field 1 + * @param value2 The value for field 2 + */ + public MutableTuple3(T0 value0, T1 value1, T2 value2) { + this.f0 = value0; + this.f1 = value1; + this.f2 = value2; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MutableTuple3 tuple3 = (MutableTuple3) o; + return Objects.equals(f0, tuple3.f0) + && Objects.equals(f1, tuple3.f1) + && Objects.equals(f2, tuple3.f2); + } + + @Override + public int hashCode() { + return Objects.hash(f0, f1, f2); + } + + public static MutableTuple3 of(T0 value0, T1 value1, T2 value2) { + return new MutableTuple3<>(value0, value1, value2); + } +} diff --git a/java/fury-core/src/main/java/org/apache/fury/collection/Tuple2.java b/java/fury-core/src/main/java/org/apache/fury/collection/Tuple2.java index 8e011d25f8..d03584283b 100644 --- a/java/fury-core/src/main/java/org/apache/fury/collection/Tuple2.java +++ b/java/fury-core/src/main/java/org/apache/fury/collection/Tuple2.java @@ -27,16 +27,19 @@ public class Tuple2 implements Serializable { private static final long serialVersionUID = 1L; /** Field 0 of the tuple. */ - public T0 f0; + public final T0 f0; /** Field 1 of the tuple. */ - public T1 f1; + public final T1 f1; /** Creates a new tuple where all fields are null. */ - public Tuple2() {} + public Tuple2() { + this(null, null); + } /** - * Creates a new tuple and assigns the given values to the tuple's fields. + * Creates a new tuple and assigns the given values to the tuple's fields, with field value final. + * In case field value is nonFinal, use {@link MutableTuple2} * * @param value0 The value for field 0 * @param value1 The value for field 1 diff --git a/java/fury-core/src/main/java/org/apache/fury/collection/Tuple3.java b/java/fury-core/src/main/java/org/apache/fury/collection/Tuple3.java index f551160583..c03d7372e5 100644 --- a/java/fury-core/src/main/java/org/apache/fury/collection/Tuple3.java +++ b/java/fury-core/src/main/java/org/apache/fury/collection/Tuple3.java @@ -26,19 +26,22 @@ public class Tuple3 implements Serializable { private static final long serialVersionUID = 1L; /** Field 0 of the tuple. */ - public T0 f0; + public final T0 f0; /** Field 1 of the tuple. */ - public T1 f1; + public final T1 f1; - /** Field 1 of the tuple. */ - public T2 f2; + /** Field 2 of the tuple. */ + public final T2 f2; /** Creates a new tuple where all fields are null. */ - public Tuple3() {} + public Tuple3() { + this(null, null, null); + } /** - * Creates a new tuple and assigns the given values to the tuple's fields. + * Creates a new tuple and assigns the given values to the tuple's fields, with field value final. + * In case field value is nonFinal, use {@link MutableTuple3} * * @param value0 The value for field 0 * @param value1 The value for field 1