diff options
author | Kristóf Marussy <kristof@marussy.com> | 2023-04-07 19:49:23 +0200 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2023-04-07 19:53:43 +0200 |
commit | 6ae4346b6248198cb687a9cbbeba3bfb9c37c4b5 (patch) | |
tree | af42f0e78812057f5730ba86838aad58bb5686a7 /subprojects/store/src/main | |
parent | Merge pull request #24 from kris7t/partial-interpretation (diff) | |
download | refinery-6ae4346b6248198cb687a9cbbeba3bfb9c37c4b5.tar.gz refinery-6ae4346b6248198cb687a9cbbeba3bfb9c37c4b5.tar.zst refinery-6ae4346b6248198cb687a9cbbeba3bfb9c37c4b5.zip |
refactor: remove TupleLike
* Directly transform VIATRA tuples into Refinery tuples, since creating
the additional wrapper object doesn't save any memory.
* Adds static arity Tuple3 and Tuple4 implementations to be more
aligned with VIATRA internals and save memory for queries with up to
4 parameters.
* Makes sure no new objects are allocated (for varargs handling) when a
static arity tuple is hashed.
Diffstat (limited to 'subprojects/store/src/main')
9 files changed, 184 insertions, 76 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java index bf844c6d..51e2895a 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java | |||
@@ -1,28 +1,37 @@ | |||
1 | package tools.refinery.store.tuple; | 1 | package tools.refinery.store.tuple; |
2 | 2 | ||
3 | public sealed interface Tuple extends TupleLike permits Tuple0, Tuple1, Tuple2, TupleN { | 3 | public sealed interface Tuple permits Tuple0, Tuple1, Tuple2, Tuple3, Tuple4, TupleN { |
4 | @Override | 4 | int getSize(); |
5 | default Tuple toTuple() { | 5 | |
6 | return this; | 6 | int get(int element); |
7 | } | ||
8 | 7 | ||
9 | static Tuple of() { | 8 | static Tuple0 of() { |
10 | return Tuple0.INSTANCE; | 9 | return Tuple0.INSTANCE; |
11 | } | 10 | } |
12 | 11 | ||
13 | static Tuple of(int value) { | 12 | static Tuple1 of(int value) { |
14 | return Tuple1.Cache.INSTANCE.getOrCreate(value); | 13 | return Tuple1.Cache.INSTANCE.getOrCreate(value); |
15 | } | 14 | } |
16 | 15 | ||
17 | static Tuple of(int value1, int value2) { | 16 | static Tuple2 of(int value1, int value2) { |
18 | return new Tuple2(value1, value2); | 17 | return new Tuple2(value1, value2); |
19 | } | 18 | } |
20 | 19 | ||
20 | static Tuple3 of(int value1, int value2, int value3) { | ||
21 | return new Tuple3(value1, value2, value3); | ||
22 | } | ||
23 | |||
24 | static Tuple4 of(int value1, int value2, int value3, int value4) { | ||
25 | return new Tuple4(value1, value2, value3, value4); | ||
26 | } | ||
27 | |||
21 | static Tuple of(int... values) { | 28 | static Tuple of(int... values) { |
22 | return switch (values.length) { | 29 | return switch (values.length) { |
23 | case 0 -> of(); | 30 | case 0 -> of(); |
24 | case 1 -> of(values[0]); | 31 | case 1 -> of(values[0]); |
25 | case 2 -> of(values[0], values[1]); | 32 | case 2 -> of(values[0], values[1]); |
33 | case 3 -> of(values[0], values[1], values[2]); | ||
34 | case 4 -> of(values[0], values[1], values[2], values[3]); | ||
26 | default -> new TupleN(values); | 35 | default -> new TupleN(values); |
27 | }; | 36 | }; |
28 | } | 37 | } |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java index 8eea5c3a..266e2cca 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java | |||
@@ -1,7 +1,13 @@ | |||
1 | package tools.refinery.store.tuple; | 1 | package tools.refinery.store.tuple; |
2 | 2 | ||
3 | public record Tuple0() implements Tuple { | 3 | import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN; |
4 | public static Tuple0 INSTANCE = new Tuple0(); | 4 | import static tools.refinery.store.tuple.TupleConstants.TUPLE_END; |
5 | |||
6 | public final class Tuple0 implements Tuple { | ||
7 | public static final Tuple0 INSTANCE = new Tuple0(); | ||
8 | |||
9 | private Tuple0() { | ||
10 | } | ||
5 | 11 | ||
6 | @Override | 12 | @Override |
7 | public int getSize() { | 13 | public int getSize() { |
@@ -14,12 +20,7 @@ public record Tuple0() implements Tuple { | |||
14 | } | 20 | } |
15 | 21 | ||
16 | @Override | 22 | @Override |
17 | public int[] toArray() { | ||
18 | return new int[]{}; | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | public String toString() { | 23 | public String toString() { |
23 | return "[]"; | 24 | return TUPLE_BEGIN + TUPLE_END; |
24 | } | 25 | } |
25 | } | 26 | } |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java index 07380966..bdcc47b5 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java | |||
@@ -4,7 +4,20 @@ import tools.refinery.store.model.TupleHashProvider; | |||
4 | 4 | ||
5 | import java.util.Arrays; | 5 | import java.util.Arrays; |
6 | 6 | ||
7 | public record Tuple1(int value0) implements Tuple { | 7 | import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN; |
8 | import static tools.refinery.store.tuple.TupleConstants.TUPLE_END; | ||
9 | |||
10 | public final class Tuple1 implements Tuple { | ||
11 | private final int value0; | ||
12 | |||
13 | private Tuple1(int value0) { | ||
14 | this.value0 = value0; | ||
15 | } | ||
16 | |||
17 | public int value0() { | ||
18 | return value0; | ||
19 | } | ||
20 | |||
8 | @Override | 21 | @Override |
9 | public int getSize() { | 22 | public int getSize() { |
10 | return 1; | 23 | return 1; |
@@ -19,13 +32,21 @@ public record Tuple1(int value0) implements Tuple { | |||
19 | } | 32 | } |
20 | 33 | ||
21 | @Override | 34 | @Override |
22 | public int[] toArray() { | 35 | public String toString() { |
23 | return new int[]{value0}; | 36 | return TUPLE_BEGIN + value0 + TUPLE_END; |
24 | } | 37 | } |
25 | 38 | ||
26 | @Override | 39 | @Override |
27 | public String toString() { | 40 | public boolean equals(Object o) { |
28 | return "[" + value0 + "]"; | 41 | if (this == o) return true; |
42 | if (o == null || getClass() != o.getClass()) return false; | ||
43 | Tuple1 tuple1 = (Tuple1) o; | ||
44 | return value0 == tuple1.value0; | ||
45 | } | ||
46 | |||
47 | @Override | ||
48 | public int hashCode() { | ||
49 | return 31 + value0; | ||
29 | } | 50 | } |
30 | 51 | ||
31 | /** | 52 | /** |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java index 0836a32d..fc0fbd8e 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java | |||
@@ -1,5 +1,7 @@ | |||
1 | package tools.refinery.store.tuple; | 1 | package tools.refinery.store.tuple; |
2 | 2 | ||
3 | import static tools.refinery.store.tuple.TupleConstants.*; | ||
4 | |||
3 | public record Tuple2(int value0, int value1) implements Tuple { | 5 | public record Tuple2(int value0, int value1) implements Tuple { |
4 | @Override | 6 | @Override |
5 | public int getSize() { | 7 | public int getSize() { |
@@ -16,12 +18,22 @@ public record Tuple2(int value0, int value1) implements Tuple { | |||
16 | } | 18 | } |
17 | 19 | ||
18 | @Override | 20 | @Override |
19 | public int[] toArray() { | 21 | public String toString() { |
20 | return new int[]{value0, value1}; | 22 | return TUPLE_BEGIN + value0 + TUPLE_SEPARATOR + value1 + TUPLE_END; |
21 | } | 23 | } |
22 | 24 | ||
23 | @Override | 25 | @Override |
24 | public String toString() { | 26 | public boolean equals(Object o) { |
25 | return "[" + value0 + ", " + value1 + "]"; | 27 | if (this == o) return true; |
28 | if (o == null || getClass() != o.getClass()) return false; | ||
29 | Tuple2 tuple2 = (Tuple2) o; | ||
30 | return value0 == tuple2.value0 && value1 == tuple2.value1; | ||
31 | } | ||
32 | |||
33 | @Override | ||
34 | public int hashCode() { | ||
35 | int hash = 31 + value0; | ||
36 | hash = 31 * hash + value1; | ||
37 | return hash; | ||
26 | } | 38 | } |
27 | } | 39 | } |
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java new file mode 100644 index 00000000..a6ec17b0 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java | |||
@@ -0,0 +1,41 @@ | |||
1 | package tools.refinery.store.tuple; | ||
2 | |||
3 | import static tools.refinery.store.tuple.TupleConstants.*; | ||
4 | |||
5 | public record Tuple3(int value0, int value1, int value2) implements Tuple { | ||
6 | @Override | ||
7 | public int getSize() { | ||
8 | return 3; | ||
9 | } | ||
10 | |||
11 | @Override | ||
12 | public int get(int element) { | ||
13 | return switch (element) { | ||
14 | case 0 -> value0; | ||
15 | case 1 -> value1; | ||
16 | case 2 -> value2; | ||
17 | default -> throw new ArrayIndexOutOfBoundsException(element); | ||
18 | }; | ||
19 | } | ||
20 | |||
21 | @Override | ||
22 | public String toString() { | ||
23 | return TUPLE_BEGIN + value0 + TUPLE_SEPARATOR + value1 + TUPLE_SEPARATOR + value2 + TUPLE_END; | ||
24 | } | ||
25 | |||
26 | @Override | ||
27 | public boolean equals(Object o) { | ||
28 | if (this == o) return true; | ||
29 | if (o == null || getClass() != o.getClass()) return false; | ||
30 | Tuple3 tuple3 = (Tuple3) o; | ||
31 | return value0 == tuple3.value0 && value1 == tuple3.value1 && value2 == tuple3.value2; | ||
32 | } | ||
33 | |||
34 | @Override | ||
35 | public int hashCode() { | ||
36 | int hash = 31 + value0; | ||
37 | hash = 31 * hash + value1; | ||
38 | hash = 31 * hash + value2; | ||
39 | return hash; | ||
40 | } | ||
41 | } | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java new file mode 100644 index 00000000..66cef32b --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java | |||
@@ -0,0 +1,44 @@ | |||
1 | package tools.refinery.store.tuple; | ||
2 | |||
3 | import static tools.refinery.store.tuple.TupleConstants.*; | ||
4 | |||
5 | public record Tuple4(int value0, int value1, int value2, int value3) implements Tuple { | ||
6 | @Override | ||
7 | public int getSize() { | ||
8 | return 4; | ||
9 | } | ||
10 | |||
11 | @Override | ||
12 | public int get(int element) { | ||
13 | return switch (element) { | ||
14 | case 0 -> value0; | ||
15 | case 1 -> value1; | ||
16 | case 2 -> value2; | ||
17 | case 3 -> value3; | ||
18 | default -> throw new ArrayIndexOutOfBoundsException(element); | ||
19 | }; | ||
20 | } | ||
21 | |||
22 | @Override | ||
23 | public String toString() { | ||
24 | return TUPLE_BEGIN + value0 + TUPLE_SEPARATOR + value1 + TUPLE_SEPARATOR + value2 + TUPLE_SEPARATOR + value3 + | ||
25 | TUPLE_END; | ||
26 | } | ||
27 | |||
28 | @Override | ||
29 | public boolean equals(Object o) { | ||
30 | if (this == o) return true; | ||
31 | if (o == null || getClass() != o.getClass()) return false; | ||
32 | Tuple4 tuple4 = (Tuple4) o; | ||
33 | return value0 == tuple4.value0 && value1 == tuple4.value1 && value2 == tuple4.value2 && value3 == tuple4.value3; | ||
34 | } | ||
35 | |||
36 | @Override | ||
37 | public int hashCode() { | ||
38 | int hash = 31 + value0; | ||
39 | hash = 31 * hash + value1; | ||
40 | hash = 31 * hash + value2; | ||
41 | hash = 31 * hash + value3; | ||
42 | return hash; | ||
43 | } | ||
44 | } | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java new file mode 100644 index 00000000..3d95a655 --- /dev/null +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java | |||
@@ -0,0 +1,12 @@ | |||
1 | package tools.refinery.store.tuple; | ||
2 | |||
3 | final class TupleConstants { | ||
4 | public static final int MAX_STATIC_ARITY_TUPLE_SIZE = 4; | ||
5 | public static final String TUPLE_BEGIN = "["; | ||
6 | public static final String TUPLE_SEPARATOR = ", "; | ||
7 | public static final String TUPLE_END = "]"; | ||
8 | |||
9 | private TupleConstants() { | ||
10 | throw new IllegalArgumentException("This is a static utility class an should not instantiated directly"); | ||
11 | } | ||
12 | } | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java deleted file mode 100644 index 953ea9f8..00000000 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | package tools.refinery.store.tuple; | ||
2 | |||
3 | import java.util.stream.Collectors; | ||
4 | import java.util.stream.IntStream; | ||
5 | |||
6 | public interface TupleLike { | ||
7 | int getSize(); | ||
8 | |||
9 | int get(int element); | ||
10 | |||
11 | default int[] toArray() { | ||
12 | int size = getSize(); | ||
13 | var array = new int[size]; | ||
14 | for (int i = 0; i < size; i++) { | ||
15 | array[i] = get(i); | ||
16 | } | ||
17 | return array; | ||
18 | } | ||
19 | |||
20 | default Tuple toTuple() { | ||
21 | return switch (getSize()) { | ||
22 | case 0 -> Tuple.of(); | ||
23 | case 1 -> Tuple.of(get(0)); | ||
24 | case 2 -> Tuple.of(get(0), get(1)); | ||
25 | default -> Tuple.of(toArray()); | ||
26 | }; | ||
27 | } | ||
28 | |||
29 | static String toString(TupleLike tuple) { | ||
30 | var valuesString = IntStream.range(0, tuple.getSize()) | ||
31 | .mapToObj(i -> Integer.toString(tuple.get(i))) | ||
32 | .collect(Collectors.joining(", ")); | ||
33 | return "[" + valuesString + "]"; | ||
34 | } | ||
35 | } | ||
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java index c3aed847..512bab49 100644 --- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java +++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java | |||
@@ -1,13 +1,18 @@ | |||
1 | package tools.refinery.store.tuple; | 1 | package tools.refinery.store.tuple; |
2 | 2 | ||
3 | import java.util.Arrays; | 3 | import java.util.Arrays; |
4 | import java.util.stream.Collectors; | ||
4 | 5 | ||
5 | public record TupleN(int[] values) implements Tuple { | 6 | import static tools.refinery.store.tuple.TupleConstants.*; |
6 | static final int CUSTOM_TUPLE_SIZE = 2; | ||
7 | 7 | ||
8 | public TupleN(int[] values) { | 8 | public final class TupleN implements Tuple { |
9 | if (values.length < CUSTOM_TUPLE_SIZE) | 9 | private final int[] values; |
10 | throw new IllegalArgumentException(); | 10 | |
11 | TupleN(int[] values) { | ||
12 | if (values.length < MAX_STATIC_ARITY_TUPLE_SIZE) { | ||
13 | throw new IllegalArgumentException("Tuples of size at most %d must use static arity Tuple classes" | ||
14 | .formatted(MAX_STATIC_ARITY_TUPLE_SIZE)); | ||
15 | } | ||
11 | this.values = Arrays.copyOf(values, values.length); | 16 | this.values = Arrays.copyOf(values, values.length); |
12 | } | 17 | } |
13 | 18 | ||
@@ -22,18 +27,11 @@ public record TupleN(int[] values) implements Tuple { | |||
22 | } | 27 | } |
23 | 28 | ||
24 | @Override | 29 | @Override |
25 | public int[] toArray() { | ||
26 | return values; | ||
27 | } | ||
28 | |||
29 | @Override | ||
30 | public String toString() { | 30 | public String toString() { |
31 | return TupleLike.toString(this); | 31 | var valuesString = Arrays.stream(values) |
32 | } | 32 | .mapToObj(Integer::toString) |
33 | 33 | .collect(Collectors.joining(TUPLE_SEPARATOR)); | |
34 | @Override | 34 | return TUPLE_BEGIN + valuesString + TUPLE_END; |
35 | public int hashCode() { | ||
36 | return Arrays.hashCode(values); | ||
37 | } | 35 | } |
38 | 36 | ||
39 | @Override | 37 | @Override |
@@ -47,4 +45,9 @@ public record TupleN(int[] values) implements Tuple { | |||
47 | TupleN other = (TupleN) obj; | 45 | TupleN other = (TupleN) obj; |
48 | return Arrays.equals(values, other.values); | 46 | return Arrays.equals(values, other.values); |
49 | } | 47 | } |
48 | |||
49 | @Override | ||
50 | public int hashCode() { | ||
51 | return Arrays.hashCode(values); | ||
52 | } | ||
50 | } | 53 | } |