diff options
Diffstat (limited to 'subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java')
-rw-r--r-- | subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java new file mode 100644 index 00000000..4da609fa --- /dev/null +++ b/subprojects/store-dse/src/main/java/tools/refinery/store/dse/transition/actions/BoundAction.java | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.dse.transition.actions; | ||
7 | |||
8 | import org.jetbrains.annotations.Nullable; | ||
9 | import tools.refinery.store.model.Model; | ||
10 | import tools.refinery.store.tuple.Tuple; | ||
11 | |||
12 | public class BoundAction { | ||
13 | private final Action action; | ||
14 | private final Model model; | ||
15 | private BoundActionLiteral @Nullable [] boundLiterals; | ||
16 | private Tuple activation; | ||
17 | private final int[] localVariables; | ||
18 | |||
19 | BoundAction(Action action, Model model) { | ||
20 | this.action = action; | ||
21 | this.model = model; | ||
22 | localVariables = new int[action.getLocalVariables().size()]; | ||
23 | } | ||
24 | |||
25 | public boolean fire(Tuple activation) { | ||
26 | model.checkCancelled(); | ||
27 | if (this.activation != null) { | ||
28 | throw new IllegalStateException("Reentrant firing is not allowed"); | ||
29 | } | ||
30 | this.activation = activation; | ||
31 | if (boundLiterals == null) { | ||
32 | boundLiterals = bindLiterals(); | ||
33 | } | ||
34 | try { | ||
35 | int size = boundLiterals.length; | ||
36 | for (int i = 0; i < size; i++) { | ||
37 | var inputAllocation = action.getInputAllocation(i); | ||
38 | var boundLiteral = boundLiterals[i]; | ||
39 | var input = getInputTuple(inputAllocation); | ||
40 | var output = boundLiteral.fire(input); | ||
41 | if (output == null) { | ||
42 | return false; | ||
43 | } | ||
44 | var outputAllocation = this.action.getOutputAllocation(i); | ||
45 | setOutputTuple(outputAllocation, output); | ||
46 | } | ||
47 | } finally { | ||
48 | this.activation = null; | ||
49 | } | ||
50 | return true; | ||
51 | } | ||
52 | |||
53 | private BoundActionLiteral[] bindLiterals() { | ||
54 | var actionLiterals = action.getActionLiterals(); | ||
55 | int size = actionLiterals.size(); | ||
56 | var boundLiteralsArray = new BoundActionLiteral[size]; | ||
57 | for (int i = 0; i < size; i++) { | ||
58 | boundLiteralsArray[i] = actionLiterals.get(i).bindToModel(model); | ||
59 | } | ||
60 | return boundLiteralsArray; | ||
61 | } | ||
62 | |||
63 | private Tuple getInputTuple(int @Nullable [] inputAllocation) { | ||
64 | if (inputAllocation == null) { | ||
65 | // Identity allocation. | ||
66 | return activation; | ||
67 | } | ||
68 | return switch (inputAllocation.length) { | ||
69 | case 0 -> Tuple.of(); | ||
70 | case 1 -> Tuple.of(getInput(inputAllocation[0])); | ||
71 | case 2 -> Tuple.of(getInput(inputAllocation[0]), getInput(inputAllocation[1])); | ||
72 | case 3 -> Tuple.of(getInput(inputAllocation[0]), getInput(inputAllocation[1]), | ||
73 | getInput(inputAllocation[2])); | ||
74 | case 4 -> Tuple.of(getInput(inputAllocation[0]), getInput(inputAllocation[1]), | ||
75 | getInput(inputAllocation[2]), getInput(inputAllocation[3])); | ||
76 | default -> { | ||
77 | var elements = new int[inputAllocation.length]; | ||
78 | for (var i = 0; i < inputAllocation.length; i++) { | ||
79 | elements[i] = getInput(inputAllocation[i]); | ||
80 | } | ||
81 | yield Tuple.of(elements); | ||
82 | } | ||
83 | }; | ||
84 | } | ||
85 | |||
86 | private int getInput(int index) { | ||
87 | int arity = action.getArity(); | ||
88 | return index < arity ? activation.get(index) : localVariables[index - arity]; | ||
89 | } | ||
90 | |||
91 | private void setOutputTuple(int @Nullable [] outputAllocation, Tuple output) { | ||
92 | if (outputAllocation == null || outputAllocation.length == 0) { | ||
93 | return; | ||
94 | } | ||
95 | switch (outputAllocation.length) { | ||
96 | case 1 -> localVariables[outputAllocation[0]] = output.get(0); | ||
97 | case 2 -> { | ||
98 | localVariables[outputAllocation[0]] = output.get(0); | ||
99 | localVariables[outputAllocation[1]] = output.get(1); | ||
100 | } | ||
101 | case 3 -> { | ||
102 | localVariables[outputAllocation[0]] = output.get(0); | ||
103 | localVariables[outputAllocation[1]] = output.get(1); | ||
104 | localVariables[outputAllocation[2]] = output.get(2); | ||
105 | } | ||
106 | case 4 -> { | ||
107 | localVariables[outputAllocation[0]] = output.get(0); | ||
108 | localVariables[outputAllocation[1]] = output.get(1); | ||
109 | localVariables[outputAllocation[2]] = output.get(2); | ||
110 | localVariables[outputAllocation[3]] = output.get(3); | ||
111 | } | ||
112 | default -> { | ||
113 | for (int i = 0; i < outputAllocation.length; i++) { | ||
114 | localVariables[outputAllocation[i]] = output.get(i); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | } | ||