aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime/src/main/java/tools/refinery/viatra/runtime/matchers/tuple/AbstractTuple.java
blob: a26d919344044405521b05e41e8a685a9efdccc2 (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
/*******************************************************************************
 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
 * 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.viatra.runtime.matchers.tuple;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * Common implementation methods for immutable and volatile tuples. The class should not be used directly in client
 * code, except for the definition of new tuple implementations.
 * 
 * @author Zoltan Ujhelyi
 * @since 1.7
 */
public abstract class AbstractTuple implements ITuple {

    /**
     * As the tuple is supposed to be immutable, do not modify the returned array.
     * 
     * @return the array containing all elements of this Tuple
     */
    @Override
    public Object[] getElements() {
        Object[] allElements = new Object[getSize()];
        for (int i = 0; i < allElements.length; ++i)
            allElements[i] = get(i);
        return allElements;
    }

    /**
     * @return the set containing all distinct elements of this Tuple, cast as type T
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> Set<T> getDistinctElements() {
        Set<T> result = new HashSet<T>();
        Object[] elements = getElements();
        for (Object object : elements) {
            result.add((T) object);
        }
        return result;
    }

    /**
     * Calculates an inverted index of the elements of this pattern. For each element, the index of the (last)
     * occurrence is calculated.
     * 
     * @return the inverted index mapping each element of this pattern to its index in the array
     */
    @Override
    public Map<Object, Integer> invertIndex() {
        Map<Object, Integer> result = new HashMap<Object, Integer>();
        for (int i = 0; i < getSize(); i++)
            result.put(get(i), i);
        return result;
    }

    /**
     * Calculates an inverted index of the elements of this pattern. For each element, the index of all of its
     * occurrences is calculated.
     * 
     * @return the inverted index mapping each element of this pattern to its index in the array
     */
    @Override
    public Map<Object, List<Integer>> invertIndexWithMupliplicity() {
        Map<Object, List<Integer>> result = new HashMap<Object, List<Integer>>();
        for (int i = 0; i < getSize(); i++) {
            Object value = get(i);
            List<Integer> indices = result.computeIfAbsent(value, v -> new ArrayList<>());
            indices.add(i);
        }
        return result;
    }

    /**
     * @since 1.7
     */
    protected IndexOutOfBoundsException raiseIndexingError(int index) {
        return new IndexOutOfBoundsException(
                String.format("No value at position %d for %s instance %s", index, getClass().getSimpleName(), this));
    }

    /**
     * Compares the elements stored in this tuple to another tuple
     */
    protected boolean internalEquals(ITuple other) {
        if (getSize() != other.getSize())
            return false;
        boolean result = true;
        for (int i = 0; result && i < getSize(); ++i) {
            Object ours = get(i);
            Object theirs = other.get(i);
            result = result && Objects.equals(ours, theirs);
        }
        return result;
    }

    @Override
    public String toString() {
        StringBuilder s = new StringBuilder();
        s.append("T(");
        for (Object o : getElements()) {
            s.append(o == null ? "null" : o.toString());
            s.append(';');
        }
        s.append(')');
        return s.toString();
    }

    /**
     * @since 1.7
     */
    protected int doCalcHash() {
        final int PRIME = 31;
        int hash = 1;
        for (int i = 0; i < getSize(); i++) {
            hash = PRIME * hash;
            Object element = get(i);
            if (element != null)
                hash += element.hashCode();
        }
        return hash;
    }

}