diff options
Diffstat (limited to 'subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeFactory.java')
-rw-r--r-- | subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeFactory.java | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeFactory.java b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeFactory.java new file mode 100644 index 00000000..3e4ea4e0 --- /dev/null +++ b/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/network/NodeFactory.java | |||
@@ -0,0 +1,376 @@ | |||
1 | /******************************************************************************* | ||
2 | * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro | ||
3 | * Copyright (c) 2023 The Refinery Authors <https://refinery.tools> | ||
4 | * This program and the accompanying materials are made available under the | ||
5 | * terms of the Eclipse Public License v. 2.0 which is available at | ||
6 | * http://www.eclipse.org/legal/epl-v20.html. | ||
7 | * | ||
8 | * SPDX-License-Identifier: EPL-2.0 | ||
9 | *******************************************************************************/ | ||
10 | package tools.refinery.viatra.runtime.rete.network; | ||
11 | |||
12 | import org.apache.log4j.Logger; | ||
13 | import org.eclipse.emf.common.util.EMap; | ||
14 | import tools.refinery.viatra.runtime.rete.itc.alg.representative.RepresentativeElectionAlgorithm; | ||
15 | import tools.refinery.viatra.runtime.rete.itc.alg.representative.StronglyConnectedComponentAlgorithm; | ||
16 | import tools.refinery.viatra.runtime.rete.itc.alg.representative.WeaklyConnectedComponentAlgorithm; | ||
17 | import tools.refinery.viatra.runtime.matchers.context.IPosetComparator; | ||
18 | import tools.refinery.viatra.runtime.matchers.psystem.IExpressionEvaluator; | ||
19 | import tools.refinery.viatra.runtime.matchers.psystem.IRelationEvaluator; | ||
20 | import tools.refinery.viatra.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; | ||
21 | import tools.refinery.viatra.runtime.matchers.tuple.TupleMask; | ||
22 | import tools.refinery.viatra.runtime.matchers.tuple.Tuples; | ||
23 | import tools.refinery.viatra.runtime.rete.aggregation.ColumnAggregatorNode; | ||
24 | import tools.refinery.viatra.runtime.rete.aggregation.CountNode; | ||
25 | import tools.refinery.viatra.runtime.rete.aggregation.IAggregatorNode; | ||
26 | import tools.refinery.viatra.runtime.rete.aggregation.timely.FaithfulParallelTimelyColumnAggregatorNode; | ||
27 | import tools.refinery.viatra.runtime.rete.aggregation.timely.FaithfulSequentialTimelyColumnAggregatorNode; | ||
28 | import tools.refinery.viatra.runtime.rete.aggregation.timely.FirstOnlyParallelTimelyColumnAggregatorNode; | ||
29 | import tools.refinery.viatra.runtime.rete.aggregation.timely.FirstOnlySequentialTimelyColumnAggregatorNode; | ||
30 | import tools.refinery.viatra.runtime.rete.boundary.ExternalInputEnumeratorNode; | ||
31 | import tools.refinery.viatra.runtime.rete.boundary.ExternalInputStatelessFilterNode; | ||
32 | import tools.refinery.viatra.runtime.rete.eval.EvaluatorCore; | ||
33 | import tools.refinery.viatra.runtime.rete.eval.MemorylessEvaluatorNode; | ||
34 | import tools.refinery.viatra.runtime.rete.eval.OutputCachingEvaluatorNode; | ||
35 | import tools.refinery.viatra.runtime.rete.eval.RelationEvaluatorNode; | ||
36 | import tools.refinery.viatra.runtime.rete.index.ExistenceNode; | ||
37 | import tools.refinery.viatra.runtime.rete.index.Indexer; | ||
38 | import tools.refinery.viatra.runtime.rete.index.JoinNode; | ||
39 | import tools.refinery.viatra.runtime.rete.matcher.TimelyConfiguration; | ||
40 | import tools.refinery.viatra.runtime.rete.matcher.TimelyConfiguration.AggregatorArchitecture; | ||
41 | import tools.refinery.viatra.runtime.rete.matcher.TimelyConfiguration.TimelineRepresentation; | ||
42 | import tools.refinery.viatra.runtime.rete.misc.ConstantNode; | ||
43 | import tools.refinery.viatra.runtime.rete.recipes.*; | ||
44 | import tools.refinery.viatra.runtime.rete.single.*; | ||
45 | import tools.refinery.viatra.runtime.rete.traceability.TraceInfo; | ||
46 | |||
47 | import java.util.HashMap; | ||
48 | import java.util.List; | ||
49 | import java.util.Map; | ||
50 | |||
51 | /** | ||
52 | * Factory for instantiating Rete nodes. The created nodes are not connected to the network yet. | ||
53 | * | ||
54 | * @author Bergmann Gabor | ||
55 | * | ||
56 | */ | ||
57 | class NodeFactory { | ||
58 | Logger logger; | ||
59 | |||
60 | public NodeFactory(Logger logger) { | ||
61 | super(); | ||
62 | this.logger = logger; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * PRE: parent node must already be created | ||
67 | */ | ||
68 | public Indexer createIndexer(ReteContainer reteContainer, IndexerRecipe recipe, Supplier parentNode, | ||
69 | TraceInfo... traces) { | ||
70 | |||
71 | if (recipe instanceof ProjectionIndexerRecipe) { | ||
72 | return parentNode.constructIndex(toMask(recipe.getMask()), traces); | ||
73 | // already traced | ||
74 | } else if (recipe instanceof AggregatorIndexerRecipe) { | ||
75 | int indexOfAggregateResult = recipe.getParent().getArity(); | ||
76 | int resultPosition = recipe.getMask().getSourceIndices().lastIndexOf(indexOfAggregateResult); | ||
77 | |||
78 | IAggregatorNode aggregatorNode = (IAggregatorNode) parentNode; | ||
79 | final Indexer result = (resultPosition == -1) ? aggregatorNode.getAggregatorOuterIndexer() | ||
80 | : aggregatorNode.getAggregatorOuterIdentityIndexer(resultPosition); | ||
81 | |||
82 | for (TraceInfo traceInfo : traces) | ||
83 | result.assignTraceInfo(traceInfo); | ||
84 | return result; | ||
85 | } else | ||
86 | throw new IllegalArgumentException("Unkown Indexer recipe: " + recipe); | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * PRE: recipe is not an indexer recipe. | ||
91 | */ | ||
92 | public Supplier createNode(ReteContainer reteContainer, ReteNodeRecipe recipe, TraceInfo... traces) { | ||
93 | if (recipe instanceof IndexerRecipe) | ||
94 | throw new IllegalArgumentException("Indexers are not created by NodeFactory: " + recipe); | ||
95 | |||
96 | Supplier result = instantiateNodeDispatch(reteContainer, recipe); | ||
97 | for (TraceInfo traceInfo : traces) | ||
98 | result.assignTraceInfo(traceInfo); | ||
99 | return result; | ||
100 | } | ||
101 | |||
102 | private Supplier instantiateNodeDispatch(ReteContainer reteContainer, ReteNodeRecipe recipe) { | ||
103 | |||
104 | // Parentless | ||
105 | |||
106 | if (recipe instanceof ConstantRecipe) | ||
107 | return instantiateNode(reteContainer, (ConstantRecipe) recipe); | ||
108 | if (recipe instanceof InputRecipe) | ||
109 | return instantiateNode(reteContainer, (InputRecipe) recipe); | ||
110 | |||
111 | // SingleParentNodeRecipe | ||
112 | |||
113 | // if (recipe instanceof ProjectionIndexer) | ||
114 | // return instantiateNode((ProjectionIndexer)recipe); | ||
115 | if (recipe instanceof InputFilterRecipe) | ||
116 | return instantiateNode(reteContainer, (InputFilterRecipe) recipe); | ||
117 | if (recipe instanceof InequalityFilterRecipe) | ||
118 | return instantiateNode(reteContainer, (InequalityFilterRecipe) recipe); | ||
119 | if (recipe instanceof EqualityFilterRecipe) | ||
120 | return instantiateNode(reteContainer, (EqualityFilterRecipe) recipe); | ||
121 | if (recipe instanceof TransparentRecipe) | ||
122 | return instantiateNode(reteContainer, (TransparentRecipe) recipe); | ||
123 | if (recipe instanceof TrimmerRecipe) | ||
124 | return instantiateNode(reteContainer, (TrimmerRecipe) recipe); | ||
125 | if (recipe instanceof TransitiveClosureRecipe) | ||
126 | return instantiateNode(reteContainer, (TransitiveClosureRecipe) recipe); | ||
127 | if (recipe instanceof RepresentativeElectionRecipe) | ||
128 | return instantiateNode(reteContainer, (RepresentativeElectionRecipe) recipe); | ||
129 | if (recipe instanceof RelationEvaluationRecipe) | ||
130 | return instantiateNode(reteContainer, (RelationEvaluationRecipe) recipe); | ||
131 | if (recipe instanceof ExpressionEnforcerRecipe) | ||
132 | return instantiateNode(reteContainer, (ExpressionEnforcerRecipe) recipe); | ||
133 | if (recipe instanceof CountAggregatorRecipe) | ||
134 | return instantiateNode(reteContainer, (CountAggregatorRecipe) recipe); | ||
135 | if (recipe instanceof SingleColumnAggregatorRecipe) | ||
136 | return instantiateNode(reteContainer, (SingleColumnAggregatorRecipe) recipe); | ||
137 | if (recipe instanceof DiscriminatorDispatcherRecipe) | ||
138 | return instantiateNode(reteContainer, (DiscriminatorDispatcherRecipe) recipe); | ||
139 | if (recipe instanceof DiscriminatorBucketRecipe) | ||
140 | return instantiateNode(reteContainer, (DiscriminatorBucketRecipe) recipe); | ||
141 | |||
142 | // MultiParentNodeRecipe | ||
143 | if (recipe instanceof UniquenessEnforcerRecipe) | ||
144 | return instantiateNode(reteContainer, (UniquenessEnforcerRecipe) recipe); | ||
145 | if (recipe instanceof ProductionRecipe) | ||
146 | return instantiateNode(reteContainer, (ProductionRecipe) recipe); | ||
147 | |||
148 | // BetaNodeRecipe | ||
149 | if (recipe instanceof JoinRecipe) | ||
150 | return instantiateNode(reteContainer, (JoinRecipe) recipe); | ||
151 | if (recipe instanceof SemiJoinRecipe) | ||
152 | return instantiateNode(reteContainer, (SemiJoinRecipe) recipe); | ||
153 | if (recipe instanceof AntiJoinRecipe) | ||
154 | return instantiateNode(reteContainer, (AntiJoinRecipe) recipe); | ||
155 | |||
156 | // ... else | ||
157 | throw new IllegalArgumentException("Unsupported recipe type: " + recipe); | ||
158 | } | ||
159 | |||
160 | // INSTANTIATION for recipe types | ||
161 | |||
162 | private Supplier instantiateNode(ReteContainer reteContainer, InputRecipe recipe) { | ||
163 | return new ExternalInputEnumeratorNode(reteContainer); | ||
164 | } | ||
165 | |||
166 | private Supplier instantiateNode(ReteContainer reteContainer, InputFilterRecipe recipe) { | ||
167 | return new ExternalInputStatelessFilterNode(reteContainer, toMaskOrNull(recipe.getMask())); | ||
168 | } | ||
169 | |||
170 | private Supplier instantiateNode(ReteContainer reteContainer, CountAggregatorRecipe recipe) { | ||
171 | return new CountNode(reteContainer); | ||
172 | } | ||
173 | |||
174 | private Supplier instantiateNode(ReteContainer reteContainer, TransparentRecipe recipe) { | ||
175 | return new TransparentNode(reteContainer); | ||
176 | } | ||
177 | |||
178 | private Supplier instantiateNode(ReteContainer reteContainer, ExpressionEnforcerRecipe recipe) { | ||
179 | final IExpressionEvaluator evaluator = toIExpressionEvaluator(recipe.getExpression()); | ||
180 | final Map<String, Integer> posMapping = toStringIndexMap(recipe.getMappedIndices()); | ||
181 | final int sourceTupleWidth = recipe.getParent().getArity(); | ||
182 | EvaluatorCore core = null; | ||
183 | if (recipe instanceof CheckRecipe) { | ||
184 | core = new EvaluatorCore.PredicateEvaluatorCore(logger, evaluator, posMapping, sourceTupleWidth); | ||
185 | } else if (recipe instanceof EvalRecipe) { | ||
186 | final boolean isUnwinding = ((EvalRecipe) recipe).isUnwinding(); | ||
187 | core = new EvaluatorCore.FunctionEvaluatorCore(logger, evaluator, posMapping, sourceTupleWidth, isUnwinding); | ||
188 | } else { | ||
189 | throw new IllegalArgumentException("Unhandled expression enforcer recipe: " + recipe.getClass() + "!"); | ||
190 | } | ||
191 | if (recipe.isCacheOutput()) { | ||
192 | return new OutputCachingEvaluatorNode(reteContainer, core); | ||
193 | } else { | ||
194 | return new MemorylessEvaluatorNode(reteContainer, core); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | @SuppressWarnings({ "rawtypes", "unchecked" }) | ||
199 | private Supplier instantiateNode(ReteContainer reteContainer, SingleColumnAggregatorRecipe recipe) { | ||
200 | final IMultisetAggregationOperator operator = recipe.getMultisetAggregationOperator(); | ||
201 | TupleMask coreMask = null; | ||
202 | if (recipe.getOptionalMonotonicityInfo() != null) { | ||
203 | coreMask = toMask(recipe.getOptionalMonotonicityInfo().getCoreMask()); | ||
204 | } else { | ||
205 | coreMask = toMask(recipe.getGroupByMask()); | ||
206 | } | ||
207 | |||
208 | if (reteContainer.isTimelyEvaluation()) { | ||
209 | final TimelyConfiguration timelyConfiguration = reteContainer.getTimelyConfiguration(); | ||
210 | final AggregatorArchitecture aggregatorArchitecture = timelyConfiguration.getAggregatorArchitecture(); | ||
211 | final TimelineRepresentation timelineRepresentation = timelyConfiguration.getTimelineRepresentation(); | ||
212 | |||
213 | TupleMask posetMask = null; | ||
214 | |||
215 | if (recipe.getOptionalMonotonicityInfo() != null) { | ||
216 | posetMask = toMask(recipe.getOptionalMonotonicityInfo().getPosetMask()); | ||
217 | } else { | ||
218 | final int aggregatedColumn = recipe.getAggregableIndex(); | ||
219 | posetMask = TupleMask.selectSingle(aggregatedColumn, coreMask.sourceWidth); | ||
220 | } | ||
221 | |||
222 | if (timelineRepresentation == TimelineRepresentation.FIRST_ONLY | ||
223 | && aggregatorArchitecture == AggregatorArchitecture.SEQUENTIAL) { | ||
224 | return new FirstOnlySequentialTimelyColumnAggregatorNode(reteContainer, operator, coreMask, posetMask); | ||
225 | } else if (timelineRepresentation == TimelineRepresentation.FIRST_ONLY | ||
226 | && aggregatorArchitecture == AggregatorArchitecture.PARALLEL) { | ||
227 | return new FirstOnlyParallelTimelyColumnAggregatorNode(reteContainer, operator, coreMask, posetMask); | ||
228 | } else if (timelineRepresentation == TimelineRepresentation.FAITHFUL | ||
229 | && aggregatorArchitecture == AggregatorArchitecture.SEQUENTIAL) { | ||
230 | return new FaithfulSequentialTimelyColumnAggregatorNode(reteContainer, operator, coreMask, posetMask); | ||
231 | } else if (timelineRepresentation == TimelineRepresentation.FAITHFUL | ||
232 | && aggregatorArchitecture == AggregatorArchitecture.PARALLEL) { | ||
233 | return new FaithfulParallelTimelyColumnAggregatorNode(reteContainer, operator, coreMask, posetMask); | ||
234 | } else { | ||
235 | throw new IllegalArgumentException("Unsupported timely configuration!"); | ||
236 | } | ||
237 | } else if (recipe.isDeleteRederiveEvaluation() && recipe.getOptionalMonotonicityInfo() != null) { | ||
238 | final TupleMask posetMask = toMask(recipe.getOptionalMonotonicityInfo().getPosetMask()); | ||
239 | final IPosetComparator posetComparator = (IPosetComparator) recipe.getOptionalMonotonicityInfo() | ||
240 | .getPosetComparator(); | ||
241 | return new ColumnAggregatorNode(reteContainer, operator, recipe.isDeleteRederiveEvaluation(), coreMask, | ||
242 | posetMask, posetComparator); | ||
243 | } else { | ||
244 | final int aggregatedColumn = recipe.getAggregableIndex(); | ||
245 | return new ColumnAggregatorNode(reteContainer, operator, coreMask, aggregatedColumn); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | private Supplier instantiateNode(ReteContainer reteContainer, TransitiveClosureRecipe recipe) { | ||
250 | return new TransitiveClosureNode(reteContainer); | ||
251 | } | ||
252 | |||
253 | private Supplier instantiateNode(ReteContainer reteContainer, RepresentativeElectionRecipe recipe) { | ||
254 | RepresentativeElectionAlgorithm.Factory algorithmFactory = switch (recipe.getConnectivity()) { | ||
255 | case STRONG -> StronglyConnectedComponentAlgorithm::new; | ||
256 | case WEAK -> WeaklyConnectedComponentAlgorithm::new; | ||
257 | }; | ||
258 | return new RepresentativeElectionNode(reteContainer, algorithmFactory); | ||
259 | } | ||
260 | |||
261 | private Supplier instantiateNode(ReteContainer reteContainer, RelationEvaluationRecipe recipe) { | ||
262 | return new RelationEvaluatorNode(reteContainer, toIRelationEvaluator(recipe.getEvaluator())); | ||
263 | } | ||
264 | |||
265 | private Supplier instantiateNode(ReteContainer reteContainer, ProductionRecipe recipe) { | ||
266 | if (reteContainer.isTimelyEvaluation()) { | ||
267 | return new TimelyProductionNode(reteContainer, toStringIndexMap(recipe.getMappedIndices())); | ||
268 | } else if (recipe.isDeleteRederiveEvaluation() && recipe.getOptionalMonotonicityInfo() != null) { | ||
269 | TupleMask coreMask = toMask(recipe.getOptionalMonotonicityInfo().getCoreMask()); | ||
270 | TupleMask posetMask = toMask(recipe.getOptionalMonotonicityInfo().getPosetMask()); | ||
271 | IPosetComparator posetComparator = (IPosetComparator) recipe.getOptionalMonotonicityInfo() | ||
272 | .getPosetComparator(); | ||
273 | return new DefaultProductionNode(reteContainer, toStringIndexMap(recipe.getMappedIndices()), | ||
274 | recipe.isDeleteRederiveEvaluation(), coreMask, posetMask, posetComparator); | ||
275 | } else { | ||
276 | return new DefaultProductionNode(reteContainer, toStringIndexMap(recipe.getMappedIndices()), | ||
277 | recipe.isDeleteRederiveEvaluation()); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | private Supplier instantiateNode(ReteContainer reteContainer, UniquenessEnforcerRecipe recipe) { | ||
282 | if (reteContainer.isTimelyEvaluation()) { | ||
283 | return new TimelyUniquenessEnforcerNode(reteContainer, recipe.getArity()); | ||
284 | } else if (recipe.isDeleteRederiveEvaluation() && recipe.getOptionalMonotonicityInfo() != null) { | ||
285 | TupleMask coreMask = toMask(recipe.getOptionalMonotonicityInfo().getCoreMask()); | ||
286 | TupleMask posetMask = toMask(recipe.getOptionalMonotonicityInfo().getPosetMask()); | ||
287 | IPosetComparator posetComparator = (IPosetComparator) recipe.getOptionalMonotonicityInfo() | ||
288 | .getPosetComparator(); | ||
289 | return new UniquenessEnforcerNode(reteContainer, recipe.getArity(), recipe.isDeleteRederiveEvaluation(), | ||
290 | coreMask, posetMask, posetComparator); | ||
291 | } else { | ||
292 | return new UniquenessEnforcerNode(reteContainer, recipe.getArity(), recipe.isDeleteRederiveEvaluation()); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | private Supplier instantiateNode(ReteContainer reteContainer, ConstantRecipe recipe) { | ||
297 | final List<Object> constantValues = recipe.getConstantValues(); | ||
298 | final Object[] constantArray = constantValues.toArray(new Object[constantValues.size()]); | ||
299 | return new ConstantNode(reteContainer, Tuples.flatTupleOf(constantArray)); | ||
300 | } | ||
301 | |||
302 | private Supplier instantiateNode(ReteContainer reteContainer, DiscriminatorBucketRecipe recipe) { | ||
303 | return new DiscriminatorBucketNode(reteContainer, recipe.getBucketKey()); | ||
304 | } | ||
305 | |||
306 | private Supplier instantiateNode(ReteContainer reteContainer, DiscriminatorDispatcherRecipe recipe) { | ||
307 | return new DiscriminatorDispatcherNode(reteContainer, recipe.getDiscriminationColumnIndex()); | ||
308 | } | ||
309 | |||
310 | private Supplier instantiateNode(ReteContainer reteContainer, TrimmerRecipe recipe) { | ||
311 | return new TrimmerNode(reteContainer, toMask(recipe.getMask())); | ||
312 | } | ||
313 | |||
314 | private Supplier instantiateNode(ReteContainer reteContainer, InequalityFilterRecipe recipe) { | ||
315 | Tunnel result = new InequalityFilterNode(reteContainer, recipe.getSubject(), | ||
316 | TupleMask.fromSelectedIndices(recipe.getParent().getArity(), recipe.getInequals())); | ||
317 | return result; | ||
318 | } | ||
319 | |||
320 | private Supplier instantiateNode(ReteContainer reteContainer, EqualityFilterRecipe recipe) { | ||
321 | final int[] equalIndices = TupleMask.integersToIntArray(recipe.getIndices()); | ||
322 | return new EqualityFilterNode(reteContainer, equalIndices); | ||
323 | } | ||
324 | |||
325 | private Supplier instantiateNode(ReteContainer reteContainer, AntiJoinRecipe recipe) { | ||
326 | return new ExistenceNode(reteContainer, true); | ||
327 | } | ||
328 | |||
329 | private Supplier instantiateNode(ReteContainer reteContainer, SemiJoinRecipe recipe) { | ||
330 | return new ExistenceNode(reteContainer, false); | ||
331 | } | ||
332 | |||
333 | private Supplier instantiateNode(ReteContainer reteContainer, JoinRecipe recipe) { | ||
334 | return new JoinNode(reteContainer, toMask(recipe.getRightParentComplementaryMask())); | ||
335 | } | ||
336 | |||
337 | // HELPERS | ||
338 | |||
339 | private IExpressionEvaluator toIExpressionEvaluator(ExpressionDefinition expressionDefinition) { | ||
340 | final Object evaluator = expressionDefinition.getEvaluator(); | ||
341 | if (evaluator instanceof IExpressionEvaluator) { | ||
342 | return (IExpressionEvaluator) evaluator; | ||
343 | } | ||
344 | throw new IllegalArgumentException("No runtime support for expression evaluator: " + evaluator); | ||
345 | } | ||
346 | |||
347 | private IRelationEvaluator toIRelationEvaluator(ExpressionDefinition expressionDefinition) { | ||
348 | final Object evaluator = expressionDefinition.getEvaluator(); | ||
349 | if (evaluator instanceof IRelationEvaluator) { | ||
350 | return (IRelationEvaluator) evaluator; | ||
351 | } | ||
352 | throw new IllegalArgumentException("No runtime support for relation evaluator: " + evaluator); | ||
353 | } | ||
354 | |||
355 | private Map<String, Integer> toStringIndexMap(final EMap<String, Integer> mappedIndices) { | ||
356 | final HashMap<String, Integer> result = new HashMap<String, Integer>(); | ||
357 | for (java.util.Map.Entry<String, Integer> entry : mappedIndices) { | ||
358 | result.put(entry.getKey(), entry.getValue()); | ||
359 | } | ||
360 | return result; | ||
361 | } | ||
362 | |||
363 | /** Mask can be null */ | ||
364 | private TupleMask toMaskOrNull(Mask mask) { | ||
365 | if (mask == null) | ||
366 | return null; | ||
367 | else | ||
368 | return toMask(mask); | ||
369 | } | ||
370 | |||
371 | /** Mask is non-null. */ | ||
372 | private TupleMask toMask(Mask mask) { | ||
373 | return TupleMask.fromSelectedIndices(mask.getSourceArity(), mask.getSourceIndices()); | ||
374 | } | ||
375 | |||
376 | } | ||