aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query-viatra
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 /subprojects/store-query-viatra
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.
Diffstat (limited to 'subprojects/store-query-viatra')
-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
10 files changed, 326 insertions, 86 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)));