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 | |
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.
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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.matcher; | 1 | package tools.refinery.store.query.viatra.internal.matcher; |
2 | 2 | ||
3 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; | ||
4 | import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer; | 3 | import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer; |
5 | import tools.refinery.store.map.Cursor; | 4 | import tools.refinery.store.map.Cursor; |
6 | import tools.refinery.store.tuple.TupleLike; | 5 | import tools.refinery.store.tuple.Tuple; |
7 | 6 | ||
8 | import java.util.Iterator; | 7 | import java.util.Iterator; |
9 | 8 | ||
10 | class FunctionalCursor<T> implements Cursor<TupleLike, T> { | 9 | class 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; | |||
11 | import tools.refinery.store.query.dnf.FunctionalQuery; | 11 | import tools.refinery.store.query.dnf.FunctionalQuery; |
12 | import tools.refinery.store.query.dnf.Query; | 12 | import tools.refinery.store.query.dnf.Query; |
13 | import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; | 13 | import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; |
14 | import tools.refinery.store.tuple.TupleLike; | 14 | import 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; | |||
3 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | 3 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; |
4 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; | 4 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; |
5 | import org.jetbrains.annotations.Nullable; | 5 | import org.jetbrains.annotations.Nullable; |
6 | import tools.refinery.store.tuple.Tuple; | 6 | import tools.refinery.store.tuple.*; |
7 | import tools.refinery.store.tuple.TupleLike; | ||
8 | 7 | ||
9 | import java.util.Iterator; | 8 | import 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.matcher; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
4 | import tools.refinery.store.tuple.Tuple1; | ||
5 | import tools.refinery.store.tuple.TupleLike; | ||
6 | |||
7 | record 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 | ||
3 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | 3 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; |
4 | import tools.refinery.store.map.Cursor; | 4 | import tools.refinery.store.map.Cursor; |
5 | import tools.refinery.store.tuple.TupleLike; | 5 | import tools.refinery.store.tuple.Tuple; |
6 | 6 | ||
7 | import java.util.Iterator; | 7 | import java.util.Iterator; |
8 | 8 | ||
9 | class RelationalCursor implements Cursor<TupleLike, Boolean> { | 9 | class 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; | |||
12 | import tools.refinery.store.query.dnf.Query; | 12 | import tools.refinery.store.query.dnf.Query; |
13 | import tools.refinery.store.query.dnf.RelationalQuery; | 13 | import tools.refinery.store.query.dnf.RelationalQuery; |
14 | import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; | 14 | import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; |
15 | import tools.refinery.store.tuple.TupleLike; | 15 | import 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 | ||
3 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | 3 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; |
4 | import tools.refinery.store.map.Cursor; | 4 | import tools.refinery.store.map.Cursor; |
5 | import tools.refinery.store.tuple.TupleLike; | 5 | import tools.refinery.store.tuple.Tuple; |
6 | 6 | ||
7 | import java.util.Iterator; | 7 | import 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 | */ |
14 | class UnsafeFunctionalCursor<T> implements Cursor<TupleLike, T> { | 14 | class 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.matcher; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; | ||
4 | import tools.refinery.store.tuple.Tuple1; | ||
5 | import tools.refinery.store.tuple.TupleLike; | ||
6 | |||
7 | record 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 @@ | |||
1 | package tools.refinery.store.query.viatra.internal.matcher; | ||
2 | |||
3 | import org.eclipse.viatra.query.runtime.matchers.tuple.*; | ||
4 | import org.junit.jupiter.api.Test; | ||
5 | import tools.refinery.store.tuple.Tuple; | ||
6 | import tools.refinery.store.tuple.*; | ||
7 | |||
8 | import java.util.List; | ||
9 | |||
10 | import static org.hamcrest.MatcherAssert.assertThat; | ||
11 | import static org.hamcrest.Matchers.*; | ||
12 | import static org.junit.jupiter.api.Assertions.assertThrows; | ||
13 | |||
14 | class 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; | |||
3 | import tools.refinery.store.map.Cursor; | 3 | import tools.refinery.store.map.Cursor; |
4 | import tools.refinery.store.map.Cursors; | 4 | import tools.refinery.store.map.Cursors; |
5 | import tools.refinery.store.query.dnf.Query; | 5 | import tools.refinery.store.query.dnf.Query; |
6 | import tools.refinery.store.tuple.TupleLike; | 6 | import tools.refinery.store.tuple.Tuple; |
7 | 7 | ||
8 | public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) implements ResultSet<T> { | 8 | public 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 | ||
3 | import tools.refinery.store.map.Cursor; | 3 | import tools.refinery.store.map.Cursor; |
4 | import tools.refinery.store.query.dnf.Query; | 4 | import tools.refinery.store.query.dnf.Query; |
5 | import tools.refinery.store.tuple.TupleLike; | 5 | import tools.refinery.store.tuple.Tuple; |
6 | 6 | ||
7 | public non-sealed interface ResultSet<T> extends AnyResultSet { | 7 | public 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 @@ | |||
1 | package tools.refinery.store.reasoning.rule; | 1 | package tools.refinery.store.reasoning.rule; |
2 | 2 | ||
3 | import tools.refinery.store.reasoning.MergeResult; | 3 | import tools.refinery.store.reasoning.MergeResult; |
4 | import tools.refinery.store.tuple.TupleLike; | 4 | import tools.refinery.store.tuple.Tuple; |
5 | 5 | ||
6 | @FunctionalInterface | 6 | @FunctionalInterface |
7 | public interface RuleActionExecutor { | 7 | public 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 @@ | |||
1 | package tools.refinery.store.reasoning.rule; | 1 | package tools.refinery.store.reasoning.rule; |
2 | 2 | ||
3 | import tools.refinery.store.reasoning.MergeResult; | ||
4 | import tools.refinery.store.model.Model; | 3 | import tools.refinery.store.model.Model; |
5 | import tools.refinery.store.tuple.TupleLike; | 4 | import tools.refinery.store.reasoning.MergeResult; |
5 | import tools.refinery.store.tuple.Tuple; | ||
6 | 6 | ||
7 | import java.util.List; | 7 | import 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 @@ | |||
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 | } |