aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-04-07 19:49:23 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-04-07 19:53:43 +0200
commit6ae4346b6248198cb687a9cbbeba3bfb9c37c4b5 (patch)
treeaf42f0e78812057f5730ba86838aad58bb5686a7
parentMerge pull request #24 from kris7t/partial-interpretation (diff)
downloadrefinery-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.
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java13
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java6
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java84
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java23
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java10
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java7
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java10
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java23
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java234
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java2
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java7
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java6
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java4
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java7
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java25
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java17
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java31
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java20
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java41
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java44
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java12
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java35
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java35
23 files changed, 522 insertions, 174 deletions
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java
index 4daa14a1..52a83f69 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java
@@ -1,17 +1,16 @@
1package tools.refinery.store.query.viatra.internal.matcher; 1package tools.refinery.store.query.viatra.internal.matcher;
2 2
3import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
4import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer; 3import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer;
5import tools.refinery.store.map.Cursor; 4import tools.refinery.store.map.Cursor;
6import tools.refinery.store.tuple.TupleLike; 5import tools.refinery.store.tuple.Tuple;
7 6
8import java.util.Iterator; 7import java.util.Iterator;
9 8
10class FunctionalCursor<T> implements Cursor<TupleLike, T> { 9class FunctionalCursor<T> implements Cursor<Tuple, T> {
11 private final IterableIndexer indexer; 10 private final IterableIndexer indexer;
12 private final Iterator<Tuple> iterator; 11 private final Iterator<org.eclipse.viatra.query.runtime.matchers.tuple.Tuple> iterator;
13 private boolean terminated; 12 private boolean terminated;
14 private TupleLike key; 13 private Tuple key;
15 private T value; 14 private T value;
16 15
17 public FunctionalCursor(IterableIndexer indexer) { 16 public FunctionalCursor(IterableIndexer indexer) {
@@ -20,7 +19,7 @@ class FunctionalCursor<T> implements Cursor<TupleLike, T> {
20 } 19 }
21 20
22 @Override 21 @Override
23 public TupleLike getKey() { 22 public Tuple getKey() {
24 return key; 23 return key;
25 } 24 }
26 25
@@ -38,7 +37,7 @@ class FunctionalCursor<T> implements Cursor<TupleLike, T> {
38 public boolean move() { 37 public boolean move() {
39 if (!terminated && iterator.hasNext()) { 38 if (!terminated && iterator.hasNext()) {
40 var match = iterator.next(); 39 var match = iterator.next();
41 key = new ViatraTupleLike(match); 40 key = MatcherUtils.toRefineryTuple(match);
42 value = MatcherUtils.getSingleValue(indexer.get(match)); 41 value = MatcherUtils.getSingleValue(indexer.get(match));
43 return true; 42 return true;
44 } 43 }
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java
index 6aa45af2..adb34b8b 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java
@@ -11,7 +11,7 @@ import tools.refinery.store.query.ResultSet;
11import tools.refinery.store.query.dnf.FunctionalQuery; 11import tools.refinery.store.query.dnf.FunctionalQuery;
12import tools.refinery.store.query.dnf.Query; 12import tools.refinery.store.query.dnf.Query;
13import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; 13import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
14import tools.refinery.store.tuple.TupleLike; 14import tools.refinery.store.tuple.Tuple;
15 15
16/** 16/**
17 * Directly access the tuples inside a VIATRA pattern matcher.<p> 17 * Directly access the tuples inside a VIATRA pattern matcher.<p>
@@ -63,7 +63,7 @@ public class FunctionalViatraMatcher<T> implements ResultSet<T> {
63 } 63 }
64 64
65 @Override 65 @Override
66 public T get(TupleLike parameters) { 66 public T get(Tuple parameters) {
67 var tuple = MatcherUtils.toViatraTuple(parameters); 67 var tuple = MatcherUtils.toViatraTuple(parameters);
68 if (omitOutputIndexer == null) { 68 if (omitOutputIndexer == null) {
69 return MatcherUtils.getSingleValue(backend.getAllMatches(omitOutputMask, tuple).iterator()); 69 return MatcherUtils.getSingleValue(backend.getAllMatches(omitOutputMask, tuple).iterator());
@@ -73,7 +73,7 @@ public class FunctionalViatraMatcher<T> implements ResultSet<T> {
73 } 73 }
74 74
75 @Override 75 @Override
76 public Cursor<TupleLike, T> getAll() { 76 public Cursor<Tuple, T> getAll() {
77 if (omitOutputIndexer == null) { 77 if (omitOutputIndexer == null) {
78 var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf()); 78 var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf());
79 return new UnsafeFunctionalCursor<>(allMatches.iterator()); 79 return new UnsafeFunctionalCursor<>(allMatches.iterator());
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java
index 5d4be95d..d327c537 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java
@@ -3,8 +3,7 @@ package tools.refinery.store.query.viatra.internal.matcher;
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; 3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; 4import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
5import org.jetbrains.annotations.Nullable; 5import org.jetbrains.annotations.Nullable;
6import tools.refinery.store.tuple.Tuple; 6import tools.refinery.store.tuple.*;
7import tools.refinery.store.tuple.TupleLike;
8 7
9import java.util.Iterator; 8import java.util.Iterator;
10 9
@@ -13,25 +12,80 @@ final class MatcherUtils {
13 throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); 12 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
14 } 13 }
15 14
16 public static org.eclipse.viatra.query.runtime.matchers.tuple.Tuple toViatraTuple(TupleLike tuple) { 15 public static org.eclipse.viatra.query.runtime.matchers.tuple.Tuple toViatraTuple(Tuple refineryTuple) {
17 if (tuple instanceof ViatraTupleLike viatraTupleLike) { 16 if (refineryTuple instanceof Tuple0) {
18 return viatraTupleLike.wrappedTuple().toImmutable(); 17 return Tuples.staticArityFlatTupleOf();
18 } else if (refineryTuple instanceof Tuple1) {
19 return Tuples.staticArityFlatTupleOf(refineryTuple);
20 } else if (refineryTuple instanceof Tuple2 tuple2) {
21 return Tuples.staticArityFlatTupleOf(Tuple.of(tuple2.value0()), Tuple.of(tuple2.value1()));
22 } else if (refineryTuple instanceof Tuple3 tuple3) {
23 return Tuples.staticArityFlatTupleOf(Tuple.of(tuple3.value0()), Tuple.of(tuple3.value1()),
24 Tuple.of(tuple3.value2()));
25 } else if (refineryTuple instanceof Tuple4 tuple4) {
26 return Tuples.staticArityFlatTupleOf(Tuple.of(tuple4.value0()), Tuple.of(tuple4.value1()),
27 Tuple.of(tuple4.value2()), Tuple.of(tuple4.value3()));
28 } else {
29 int arity = refineryTuple.getSize();
30 var values = new Object[arity];
31 for (int i = 0; i < arity; i++) {
32 values[i] = Tuple.of(refineryTuple.get(i));
33 }
34 return Tuples.flatTupleOf(values);
19 } 35 }
20 int size = tuple.getSize(); 36 }
21 var array = new Object[size]; 37
22 for (int i = 0; i < size; i++) { 38 public static Tuple toRefineryTuple(ITuple viatraTuple) {
23 var value = tuple.get(i); 39 int arity = viatraTuple.getSize();
24 array[i] = Tuple.of(value); 40 if (arity == 1) {
41 return getWrapper(viatraTuple, 0);
25 } 42 }
26 return Tuples.flatTupleOf(array); 43 return prefixToRefineryTuple(viatraTuple, viatraTuple.getSize());
44 }
45
46 public static Tuple keyToRefineryTuple(ITuple viatraTuple) {
47 return prefixToRefineryTuple(viatraTuple, viatraTuple.getSize() - 1);
27 } 48 }
28 49
50 private static Tuple prefixToRefineryTuple(ITuple viatraTuple, int targetArity) {
51 if (targetArity < 0) {
52 throw new IllegalArgumentException("Requested negative prefix %d of %s"
53 .formatted(targetArity, viatraTuple));
54 }
55 return switch (targetArity) {
56 case 0 -> Tuple.of();
57 case 1 -> Tuple.of(unwrap(viatraTuple, 0));
58 case 2 -> Tuple.of(unwrap(viatraTuple, 0), unwrap(viatraTuple, 1));
59 case 3 -> Tuple.of(unwrap(viatraTuple, 0), unwrap(viatraTuple, 1), unwrap(viatraTuple, 2));
60 case 4 -> Tuple.of(unwrap(viatraTuple, 0), unwrap(viatraTuple, 1), unwrap(viatraTuple, 2),
61 unwrap(viatraTuple, 3));
62 default -> {
63 var entries = new int[targetArity];
64 for (int i = 0; i < targetArity; i++) {
65 entries[i] = unwrap(viatraTuple, i);
66 }
67 yield Tuple.of(entries);
68 }
69 };
70 }
71
72 private static Tuple1 getWrapper(ITuple viatraTuple, int index) {
73 if (!((viatraTuple.get(index)) instanceof Tuple1 wrappedObjectId)) {
74 throw new IllegalArgumentException("Element %d of tuple %s is not an object id"
75 .formatted(index, viatraTuple));
76 }
77 return wrappedObjectId;
78 }
79
80 private static int unwrap(ITuple viatraTuple, int index) {
81 return getWrapper(viatraTuple, index).value0();
82 }
29 83
30 public static <T> T getSingleValue(@Nullable Iterable<? extends ITuple> tuples) { 84 public static <T> T getSingleValue(@Nullable Iterable<? extends ITuple> viatraTuples) {
31 if (tuples == null) { 85 if (viatraTuples == null) {
32 return null; 86 return null;
33 } 87 }
34 return getSingleValue(tuples.iterator()); 88 return getSingleValue(viatraTuples.iterator());
35 } 89 }
36 90
37 public static <T> T getSingleValue(Iterator<? extends ITuple> iterator) { 91 public static <T> T getSingleValue(Iterator<? extends ITuple> iterator) {
@@ -42,7 +96,7 @@ final class MatcherUtils {
42 @SuppressWarnings("unchecked") 96 @SuppressWarnings("unchecked")
43 var result = (T) match.get(match.getSize() - 1); 97 var result = (T) match.get(match.getSize() - 1);
44 if (iterator.hasNext()) { 98 if (iterator.hasNext()) {
45 var input = new OmitOutputViatraTupleLike(match); 99 var input = keyToRefineryTuple(match);
46 throw new IllegalStateException("Query is not functional for input tuple: " + input); 100 throw new IllegalStateException("Query is not functional for input tuple: " + input);
47 } 101 }
48 return result; 102 return result;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java
deleted file mode 100644
index bd9301ba..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java
+++ /dev/null
@@ -1,23 +0,0 @@
1package tools.refinery.store.query.viatra.internal.matcher;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import tools.refinery.store.tuple.Tuple1;
5import tools.refinery.store.tuple.TupleLike;
6
7record OmitOutputViatraTupleLike(ITuple wrappedTuple) implements TupleLike {
8 @Override
9 public int getSize() {
10 return wrappedTuple.getSize() - 1;
11 }
12
13 @Override
14 public int get(int element) {
15 var wrappedValue = (Tuple1) wrappedTuple.get(element);
16 return wrappedValue.value0();
17 }
18
19 @Override
20 public String toString() {
21 return TupleLike.toString(this);
22 }
23}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java
index c2dcc565..e3df0441 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java
@@ -2,21 +2,21 @@ package tools.refinery.store.query.viatra.internal.matcher;
2 2
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; 3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import tools.refinery.store.map.Cursor; 4import tools.refinery.store.map.Cursor;
5import tools.refinery.store.tuple.TupleLike; 5import tools.refinery.store.tuple.Tuple;
6 6
7import java.util.Iterator; 7import java.util.Iterator;
8 8
9class RelationalCursor implements Cursor<TupleLike, Boolean> { 9class RelationalCursor implements Cursor<Tuple, Boolean> {
10 private final Iterator<? extends ITuple> tuplesIterator; 10 private final Iterator<? extends ITuple> tuplesIterator;
11 private boolean terminated; 11 private boolean terminated;
12 private TupleLike key; 12 private Tuple key;
13 13
14 public RelationalCursor(Iterator<? extends ITuple> tuplesIterator) { 14 public RelationalCursor(Iterator<? extends ITuple> tuplesIterator) {
15 this.tuplesIterator = tuplesIterator; 15 this.tuplesIterator = tuplesIterator;
16 } 16 }
17 17
18 @Override 18 @Override
19 public TupleLike getKey() { 19 public Tuple getKey() {
20 return key; 20 return key;
21 } 21 }
22 22
@@ -33,7 +33,7 @@ class RelationalCursor implements Cursor<TupleLike, Boolean> {
33 @Override 33 @Override
34 public boolean move() { 34 public boolean move() {
35 if (!terminated && tuplesIterator.hasNext()) { 35 if (!terminated && tuplesIterator.hasNext()) {
36 key = new ViatraTupleLike(tuplesIterator.next()); 36 key = MatcherUtils.toRefineryTuple(tuplesIterator.next());
37 return true; 37 return true;
38 } 38 }
39 terminated = true; 39 terminated = true;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java
index b9bc3f1e..9373709d 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java
@@ -12,7 +12,7 @@ import tools.refinery.store.query.ResultSet;
12import tools.refinery.store.query.dnf.Query; 12import tools.refinery.store.query.dnf.Query;
13import tools.refinery.store.query.dnf.RelationalQuery; 13import tools.refinery.store.query.dnf.RelationalQuery;
14import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; 14import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
15import tools.refinery.store.tuple.TupleLike; 15import tools.refinery.store.tuple.Tuple;
16 16
17/** 17/**
18 * Directly access the tuples inside a VIATRA pattern matcher.<p> 18 * Directly access the tuples inside a VIATRA pattern matcher.<p>
@@ -58,7 +58,7 @@ public class RelationalViatraMatcher implements ResultSet<Boolean> {
58 } 58 }
59 59
60 @Override 60 @Override
61 public Boolean get(TupleLike parameters) { 61 public Boolean get(Tuple parameters) {
62 var tuple = MatcherUtils.toViatraTuple(parameters); 62 var tuple = MatcherUtils.toViatraTuple(parameters);
63 if (emptyMaskIndexer == null) { 63 if (emptyMaskIndexer == null) {
64 return backend.hasMatch(identityMask, tuple); 64 return backend.hasMatch(identityMask, tuple);
@@ -68,7 +68,7 @@ public class RelationalViatraMatcher implements ResultSet<Boolean> {
68 } 68 }
69 69
70 @Override 70 @Override
71 public Cursor<TupleLike, Boolean> getAll() { 71 public Cursor<Tuple, Boolean> getAll() {
72 if (emptyMaskIndexer == null) { 72 if (emptyMaskIndexer == null) {
73 var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf()); 73 var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf());
74 return new RelationalCursor(allMatches.iterator()); 74 return new RelationalCursor(allMatches.iterator());
@@ -85,5 +85,4 @@ public class RelationalViatraMatcher implements ResultSet<Boolean> {
85 var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); 85 var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf());
86 return matches == null ? 0 : matches.size(); 86 return matches == null ? 0 : matches.size();
87 } 87 }
88
89} 88}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java
index 6c53fff1..e9540d1d 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java
@@ -2,7 +2,7 @@ package tools.refinery.store.query.viatra.internal.matcher;
2 2
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; 3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import tools.refinery.store.map.Cursor; 4import tools.refinery.store.map.Cursor;
5import tools.refinery.store.tuple.TupleLike; 5import tools.refinery.store.tuple.Tuple;
6 6
7import java.util.Iterator; 7import java.util.Iterator;
8 8
@@ -11,10 +11,10 @@ import java.util.Iterator;
11 * functional dependency of the output on the inputs is obeyed. 11 * functional dependency of the output on the inputs is obeyed.
12 * @param <T> The output type. 12 * @param <T> The output type.
13 */ 13 */
14class UnsafeFunctionalCursor<T> implements Cursor<TupleLike, T> { 14class UnsafeFunctionalCursor<T> implements Cursor<Tuple, T> {
15 private final Iterator<? extends ITuple> tuplesIterator; 15 private final Iterator<? extends ITuple> tuplesIterator;
16 private boolean terminated; 16 private boolean terminated;
17 private TupleLike key; 17 private Tuple key;
18 private T value; 18 private T value;
19 19
20 public UnsafeFunctionalCursor(Iterator<? extends ITuple> tuplesIterator) { 20 public UnsafeFunctionalCursor(Iterator<? extends ITuple> tuplesIterator) {
@@ -22,7 +22,7 @@ class UnsafeFunctionalCursor<T> implements Cursor<TupleLike, T> {
22 } 22 }
23 23
24 @Override 24 @Override
25 public TupleLike getKey() { 25 public Tuple getKey() {
26 return key; 26 return key;
27 } 27 }
28 28
@@ -40,7 +40,7 @@ class UnsafeFunctionalCursor<T> implements Cursor<TupleLike, T> {
40 public boolean move() { 40 public boolean move() {
41 if (!terminated && tuplesIterator.hasNext()) { 41 if (!terminated && tuplesIterator.hasNext()) {
42 var match = tuplesIterator.next(); 42 var match = tuplesIterator.next();
43 key = new OmitOutputViatraTupleLike(match); 43 key = MatcherUtils.keyToRefineryTuple(match);
44 @SuppressWarnings("unchecked") 44 @SuppressWarnings("unchecked")
45 var typedValue = (T) match.get(match.getSize() - 1); 45 var typedValue = (T) match.get(match.getSize() - 1);
46 value = typedValue; 46 value = typedValue;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java
deleted file mode 100644
index 76a3e40b..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java
+++ /dev/null
@@ -1,23 +0,0 @@
1package tools.refinery.store.query.viatra.internal.matcher;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import tools.refinery.store.tuple.Tuple1;
5import tools.refinery.store.tuple.TupleLike;
6
7record ViatraTupleLike(ITuple wrappedTuple) implements TupleLike {
8 @Override
9 public int getSize() {
10 return wrappedTuple.getSize();
11 }
12
13 @Override
14 public int get(int element) {
15 var wrappedValue = (Tuple1) wrappedTuple.get(element);
16 return wrappedValue.value0();
17 }
18
19 @Override
20 public String toString() {
21 return TupleLike.toString(this);
22 }
23}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java
new file mode 100644
index 00000000..ea0b15ec
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java
@@ -0,0 +1,234 @@
1package tools.refinery.store.query.viatra.internal.matcher;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.*;
4import org.junit.jupiter.api.Test;
5import tools.refinery.store.tuple.Tuple;
6import tools.refinery.store.tuple.*;
7
8import java.util.List;
9
10import static org.hamcrest.MatcherAssert.assertThat;
11import static org.hamcrest.Matchers.*;
12import static org.junit.jupiter.api.Assertions.assertThrows;
13
14class MatcherUtilsTest {
15 @Test
16 void toViatra0Test() {
17 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of());
18 assertThat(viatraTuple.getSize(), is(0));
19 assertThat(viatraTuple, instanceOf(FlatTuple0.class));
20 }
21
22 @Test
23 void toViatra1Test() {
24 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2));
25 assertThat(viatraTuple.getSize(), is(1));
26 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
27 assertThat(viatraTuple, instanceOf(FlatTuple1.class));
28 }
29
30 @Test
31 void toViatra2Test() {
32 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3));
33 assertThat(viatraTuple.getSize(), is(2));
34 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
35 assertThat(viatraTuple.get(1), is(Tuple.of(3)));
36 assertThat(viatraTuple, instanceOf(FlatTuple2.class));
37 }
38
39 @Test
40 void toViatra3Test() {
41 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5));
42 assertThat(viatraTuple.getSize(), is(3));
43 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
44 assertThat(viatraTuple.get(1), is(Tuple.of(3)));
45 assertThat(viatraTuple.get(2), is(Tuple.of(5)));
46 assertThat(viatraTuple, instanceOf(FlatTuple3.class));
47 }
48
49 @Test
50 void toViatra4Test() {
51 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5, 8));
52 assertThat(viatraTuple.getSize(), is(4));
53 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
54 assertThat(viatraTuple.get(1), is(Tuple.of(3)));
55 assertThat(viatraTuple.get(2), is(Tuple.of(5)));
56 assertThat(viatraTuple.get(3), is(Tuple.of(8)));
57 assertThat(viatraTuple, instanceOf(FlatTuple4.class));
58 }
59
60 @Test
61 void toViatra5Test() {
62 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5, 8, 13));
63 assertThat(viatraTuple.getSize(), is(5));
64 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
65 assertThat(viatraTuple.get(1), is(Tuple.of(3)));
66 assertThat(viatraTuple.get(2), is(Tuple.of(5)));
67 assertThat(viatraTuple.get(3), is(Tuple.of(8)));
68 assertThat(viatraTuple.get(4), is(Tuple.of(13)));
69 assertThat(viatraTuple, instanceOf(FlatTuple.class));
70 }
71
72 @Test
73 void toRefinery0Test() {
74 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf());
75 assertThat(refineryTuple.getSize(), is(0));
76 assertThat(refineryTuple, instanceOf(Tuple0.class));
77 }
78
79 @Test
80 void toRefinery1Test() {
81 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2)));
82 assertThat(refineryTuple.getSize(), is(1));
83 assertThat(refineryTuple.get(0), is(2));
84 assertThat(refineryTuple, instanceOf(Tuple1.class));
85 }
86
87 @Test
88 void toRefinery2Test() {
89 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3)));
90 assertThat(refineryTuple.getSize(), is(2));
91 assertThat(refineryTuple.get(0), is(2));
92 assertThat(refineryTuple.get(1), is(3));
93 assertThat(refineryTuple, instanceOf(Tuple2.class));
94 }
95
96 @Test
97 void toRefinery3Test() {
98 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5)));
99 assertThat(refineryTuple.getSize(), is(3));
100 assertThat(refineryTuple.get(0), is(2));
101 assertThat(refineryTuple.get(1), is(3));
102 assertThat(refineryTuple.get(2), is(5));
103 assertThat(refineryTuple, instanceOf(Tuple3.class));
104 }
105
106 @Test
107 void toRefinery4Test() {
108 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
109 Tuple.of(8)));
110 assertThat(refineryTuple.getSize(), is(4));
111 assertThat(refineryTuple.get(0), is(2));
112 assertThat(refineryTuple.get(1), is(3));
113 assertThat(refineryTuple.get(2), is(5));
114 assertThat(refineryTuple.get(3), is(8));
115 assertThat(refineryTuple, instanceOf(Tuple4.class));
116 }
117
118 @Test
119 void toRefinery5Test() {
120 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
121 Tuple.of(8), Tuple.of(13)));
122 assertThat(refineryTuple.getSize(), is(5));
123 assertThat(refineryTuple.get(0), is(2));
124 assertThat(refineryTuple.get(1), is(3));
125 assertThat(refineryTuple.get(2), is(5));
126 assertThat(refineryTuple.get(3), is(8));
127 assertThat(refineryTuple.get(4), is(13));
128 assertThat(refineryTuple, instanceOf(TupleN.class));
129 }
130
131 @Test
132 void toRefineryInvalidValueTest() {
133 var viatraTuple = Tuples.flatTupleOf(Tuple.of(2), -98);
134 assertThrows(IllegalArgumentException.class, () -> MatcherUtils.toRefineryTuple(viatraTuple));
135 }
136
137 @Test
138 void keyToRefinery0Test() {
139 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(-99));
140 assertThat(refineryTuple.getSize(), is(0));
141 assertThat(refineryTuple, instanceOf(Tuple0.class));
142 }
143
144 @Test
145 void keyToRefinery1Test() {
146 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), -99));
147 assertThat(refineryTuple.getSize(), is(1));
148 assertThat(refineryTuple.get(0), is(2));
149 assertThat(refineryTuple, instanceOf(Tuple1.class));
150 }
151
152 @Test
153 void keyToRefinery2Test() {
154 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), -99));
155 assertThat(refineryTuple.getSize(), is(2));
156 assertThat(refineryTuple.get(0), is(2));
157 assertThat(refineryTuple.get(1), is(3));
158 assertThat(refineryTuple, instanceOf(Tuple2.class));
159 }
160
161 @Test
162 void keyToRefinery3Test() {
163 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
164 -99));
165 assertThat(refineryTuple.getSize(), is(3));
166 assertThat(refineryTuple.get(0), is(2));
167 assertThat(refineryTuple.get(1), is(3));
168 assertThat(refineryTuple.get(2), is(5));
169 assertThat(refineryTuple, instanceOf(Tuple3.class));
170 }
171
172 @Test
173 void keyToRefinery4Test() {
174 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
175 Tuple.of(8), -99));
176 assertThat(refineryTuple.getSize(), is(4));
177 assertThat(refineryTuple.get(0), is(2));
178 assertThat(refineryTuple.get(1), is(3));
179 assertThat(refineryTuple.get(2), is(5));
180 assertThat(refineryTuple.get(3), is(8));
181 assertThat(refineryTuple, instanceOf(Tuple4.class));
182 }
183
184 @Test
185 void keyToRefinery5Test() {
186 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
187 Tuple.of(8), Tuple.of(13), -99));
188 assertThat(refineryTuple.getSize(), is(5));
189 assertThat(refineryTuple.get(0), is(2));
190 assertThat(refineryTuple.get(1), is(3));
191 assertThat(refineryTuple.get(2), is(5));
192 assertThat(refineryTuple.get(3), is(8));
193 assertThat(refineryTuple.get(4), is(13));
194 assertThat(refineryTuple, instanceOf(TupleN.class));
195 }
196
197 @Test
198 void keyToRefineryTooShortTest() {
199 var viatraTuple = Tuples.flatTupleOf();
200 assertThrows(IllegalArgumentException.class, () -> MatcherUtils.keyToRefineryTuple(viatraTuple));
201 }
202
203 @Test
204 void keyToRefineryInvalidValueTest() {
205 var viatraTuple = Tuples.flatTupleOf(Tuple.of(2), -98, -99);
206 assertThrows(IllegalArgumentException.class, () -> MatcherUtils.keyToRefineryTuple(viatraTuple));
207 }
208
209 @Test
210 void getSingleValueTest() {
211 var value = MatcherUtils.getSingleValue(List.of(Tuples.flatTupleOf(Tuple.of(2), -99)));
212 assertThat(value, is(-99));
213 }
214
215 // Static analysis accurately determines that the result is always {@code null}, but we check anyways.
216 @SuppressWarnings("ConstantValue")
217 @Test
218 void getSingleValueNullTest() {
219 var value = MatcherUtils.getSingleValue((Iterable<? extends ITuple>) null);
220 assertThat(value, nullValue());
221 }
222
223 @Test
224 void getSingleValueEmptyTest() {
225 var value = MatcherUtils.getSingleValue(List.of());
226 assertThat(value, nullValue());
227 }
228
229 @Test
230 void getSingleValueMultipleTest() {
231 var viatraTuples = List.of(Tuples.flatTupleOf(Tuple.of(2), -98), Tuples.flatTupleOf(Tuple.of(2), -99));
232 assertThrows(IllegalStateException.class, () -> MatcherUtils.getSingleValue(viatraTuples));
233 }
234}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
index 6f50ec73..2769621d 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
@@ -42,7 +42,7 @@ public final class QueryAssertions {
42 var cursor = resultSet.getAll(); 42 var cursor = resultSet.getAll();
43 while (cursor.move()) { 43 while (cursor.move()) {
44 var key = cursor.getKey(); 44 var key = cursor.getKey();
45 var previous = actual.put(key.toTuple(), cursor.getValue()); 45 var previous = actual.put(key, cursor.getValue());
46 assertThat("duplicate value for key " + key, previous, nullValue()); 46 assertThat("duplicate value for key " + key, previous, nullValue());
47 } 47 }
48 executables.add(() -> assertThat("results cursor", actual, is(filteredExpected))); 48 executables.add(() -> assertThat("results cursor", actual, is(filteredExpected)));
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java
index 9af73bdd..4c8eeab0 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java
@@ -3,7 +3,7 @@ package tools.refinery.store.query;
3import tools.refinery.store.map.Cursor; 3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.map.Cursors; 4import tools.refinery.store.map.Cursors;
5import tools.refinery.store.query.dnf.Query; 5import tools.refinery.store.query.dnf.Query;
6import tools.refinery.store.tuple.TupleLike; 6import tools.refinery.store.tuple.Tuple;
7 7
8public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) implements ResultSet<T> { 8public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) implements ResultSet<T> {
9 @Override 9 @Override
@@ -17,13 +17,12 @@ public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) imple
17 } 17 }
18 18
19 @Override 19 @Override
20 public T get(TupleLike parameters) { 20 public T get(Tuple parameters) {
21 return query.defaultValue(); 21 return query.defaultValue();
22 } 22 }
23 23
24
25 @Override 24 @Override
26 public Cursor<TupleLike, T> getAll() { 25 public Cursor<Tuple, T> getAll() {
27 return Cursors.empty(); 26 return Cursors.empty();
28 } 27 }
29 28
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java
index 3f6bc06f..2758c74f 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java
@@ -2,12 +2,12 @@ package tools.refinery.store.query;
2 2
3import tools.refinery.store.map.Cursor; 3import tools.refinery.store.map.Cursor;
4import tools.refinery.store.query.dnf.Query; 4import tools.refinery.store.query.dnf.Query;
5import tools.refinery.store.tuple.TupleLike; 5import tools.refinery.store.tuple.Tuple;
6 6
7public non-sealed interface ResultSet<T> extends AnyResultSet { 7public non-sealed interface ResultSet<T> extends AnyResultSet {
8 Query<T> getQuery(); 8 Query<T> getQuery();
9 9
10 T get(TupleLike parameters); 10 T get(Tuple parameters);
11 11
12 Cursor<TupleLike, T> getAll(); 12 Cursor<Tuple, T> getAll();
13} 13}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java
index 80bfa6f8..7c51e3df 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java
@@ -1,9 +1,9 @@
1package tools.refinery.store.reasoning.rule; 1package tools.refinery.store.reasoning.rule;
2 2
3import tools.refinery.store.reasoning.MergeResult; 3import tools.refinery.store.reasoning.MergeResult;
4import tools.refinery.store.tuple.TupleLike; 4import tools.refinery.store.tuple.Tuple;
5 5
6@FunctionalInterface 6@FunctionalInterface
7public interface RuleActionExecutor { 7public interface RuleActionExecutor {
8 MergeResult execute(TupleLike activationTuple); 8 MergeResult execute(Tuple activationTuple);
9} 9}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java
index 1e5322b4..c20645fc 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java
@@ -1,8 +1,8 @@
1package tools.refinery.store.reasoning.rule; 1package tools.refinery.store.reasoning.rule;
2 2
3import tools.refinery.store.reasoning.MergeResult;
4import tools.refinery.store.model.Model; 3import tools.refinery.store.model.Model;
5import tools.refinery.store.tuple.TupleLike; 4import tools.refinery.store.reasoning.MergeResult;
5import tools.refinery.store.tuple.Tuple;
6 6
7import java.util.List; 7import java.util.List;
8 8
@@ -24,7 +24,8 @@ public final class RuleExecutor {
24 public Model getModel() { 24 public Model getModel() {
25 return model; 25 return model;
26 } 26 }
27 public MergeResult execute(TupleLike activationTuple) { 27
28 public MergeResult execute(Tuple activationTuple) {
28 MergeResult mergeResult = MergeResult.UNCHANGED; 29 MergeResult mergeResult = MergeResult.UNCHANGED;
29 for (var actionExecutor : actionExecutors) { 30 for (var actionExecutor : actionExecutors) {
30 mergeResult = mergeResult.andAlso(actionExecutor.execute(activationTuple)); 31 mergeResult = mergeResult.andAlso(actionExecutor.execute(activationTuple));
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 @@
1package tools.refinery.store.tuple; 1package tools.refinery.store.tuple;
2 2
3public sealed interface Tuple extends TupleLike permits Tuple0, Tuple1, Tuple2, TupleN { 3public 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 @@
1package tools.refinery.store.tuple; 1package tools.refinery.store.tuple;
2 2
3public record Tuple0() implements Tuple { 3import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN;
4 public static Tuple0 INSTANCE = new Tuple0(); 4import static tools.refinery.store.tuple.TupleConstants.TUPLE_END;
5
6public 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
5import java.util.Arrays; 5import java.util.Arrays;
6 6
7public record Tuple1(int value0) implements Tuple { 7import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN;
8import static tools.refinery.store.tuple.TupleConstants.TUPLE_END;
9
10public 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 @@
1package tools.refinery.store.tuple; 1package tools.refinery.store.tuple;
2 2
3import static tools.refinery.store.tuple.TupleConstants.*;
4
3public record Tuple2(int value0, int value1) implements Tuple { 5public 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 @@
1package tools.refinery.store.tuple;
2
3import static tools.refinery.store.tuple.TupleConstants.*;
4
5public 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 @@
1package tools.refinery.store.tuple;
2
3import static tools.refinery.store.tuple.TupleConstants.*;
4
5public 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 @@
1package tools.refinery.store.tuple;
2
3final 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 @@
1package tools.refinery.store.tuple;
2
3import java.util.stream.Collectors;
4import java.util.stream.IntStream;
5
6public 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 @@
1package tools.refinery.store.tuple; 1package tools.refinery.store.tuple;
2 2
3import java.util.Arrays; 3import java.util.Arrays;
4import java.util.stream.Collectors;
4 5
5public record TupleN(int[] values) implements Tuple { 6import static tools.refinery.store.tuple.TupleConstants.*;
6 static final int CUSTOM_TUPLE_SIZE = 2;
7 7
8 public TupleN(int[] values) { 8public 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}