aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java
blob: 96ac4a72f6f0a3247fd7253daf2a9ca16ea9149b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*******************************************************************************
 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-v20.html.
 * SPDX-License-Identifier: EPL-2.0
 *******************************************************************************/
package tools.refinery.store.query.viatra.internal.localsearch;

import org.eclipse.viatra.query.runtime.localsearch.MatchingFrame;
import org.eclipse.viatra.query.runtime.localsearch.matcher.ISearchContext;
import org.eclipse.viatra.query.runtime.localsearch.operations.IIteratingSearchOperation;
import org.eclipse.viatra.query.runtime.localsearch.operations.ISearchOperation;
import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask;
import org.eclipse.viatra.query.runtime.matchers.tuple.VolatileMaskedTuple;
import org.eclipse.viatra.query.runtime.matchers.util.Preconditions;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Zoltan Ujhelyi
 * @since 1.7
 */
public class GenericTypeExtend implements IIteratingSearchOperation {
    private class Executor extends ExtendOperationExecutor<Tuple> {
        private final VolatileMaskedTuple maskedTuple;

        public Executor() {
            this.maskedTuple = new VolatileMaskedTuple(callMask);
        }

        @Override
        protected Iterator<? extends Tuple> getIterator(MatchingFrame frame, ISearchContext context) {
            maskedTuple.updateTuple(frame);
            return context.getRuntimeContext().enumerateTuples(type, indexerMask, maskedTuple).iterator();
        }

        @Override
        protected boolean fillInValue(Tuple newTuple, MatchingFrame frame, ISearchContext context) {
            for (Integer position : unboundVariableIndices) {
                frame.setValue(position, null);
            }
            for (int i = 0; i < positions.length; i++) {
                Object newValue = newTuple.get(i);
                Object oldValue = frame.getValue(positions[i]);
                if (oldValue != null && !Objects.equals(oldValue, newValue)) {
                    // If positions tuple maps more than one values for the same element (e.g. loop), it means that
                    // these arguments are to unified by the caller. In this case if the callee assigns different values
                    // the frame shall be considered a failed match
                    return false;
                }
                frame.setValue(positions[i], newValue);
            }
            return true;
        }

        @Override
        protected void cleanup(MatchingFrame frame, ISearchContext context) {
            for (Integer position : unboundVariableIndices) {
                frame.setValue(position, null);
            }
        }

		@Override
        public ISearchOperation getOperation() {
            return GenericTypeExtend.this;
        }
    }

    private final IInputKey type;
    private final int[] positions;
    private final List<Integer> positionList;
    private final Set<Integer> unboundVariableIndices;
    private final TupleMask indexerMask;
    private final TupleMask callMask;

    /**
     *
     * @param type
     *            the type to execute the extend operation on
     * @param positions
     *            the parameter positions that represent the variables of the input key
     * @param unboundVariableIndices
     *            the set of positions that are bound at the start of the operation
     */
    public GenericTypeExtend(IInputKey type, int[] positions, TupleMask callMask, TupleMask indexerMask, Set<Integer> unboundVariableIndices) {
        Preconditions.checkArgument(positions.length == type.getArity(),
                "The type %s requires %d parameters, but %d positions are provided", type.getPrettyPrintableName(),
                type.getArity(), positions.length);
        List<Integer> modifiablePositionList = new ArrayList<>();
        for (int position : positions) {
            modifiablePositionList.add(position);
        }
        this.positionList = Collections.unmodifiableList(modifiablePositionList);
        this.positions = positions;
        this.type = type;

        this.unboundVariableIndices = unboundVariableIndices;
        this.indexerMask = indexerMask;
        this.callMask = callMask;
    }

    @Override
    public IInputKey getIteratedInputKey() {
        return type;
    }

    @Override
    public ISearchOperationExecutor createExecutor() {
        return new Executor();
    }

    @Override
    public List<Integer> getVariablePositions() {
        return positionList;
    }

    @Override
    public String toString() {
        return toString(Object::toString);
    }

    @Override
    public String toString(@SuppressWarnings("squid:S4276") Function<Integer, String> variableMapping) {
        return "extend    " + type.getPrettyPrintableName() + "("
                + positionList.stream()
                        .map(input -> String.format("%s%s", unboundVariableIndices.contains(input) ? "-" : "+", variableMapping.apply(input)))
                        .collect(Collectors.joining(", "))
                + ")";
    }

}