aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/viatra-runtime-rete/src/main/java/tools/refinery/viatra/runtime/rete/single/AbstractUniquenessEnforcerNode.java
blob: e92ce63f6f28ce3e138aa2c46655d1632860341a (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
138
/*******************************************************************************
 * Copyright (c) 2010-2019, Tamas Szabo, itemis AG, Gabor Bergmann, 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.rete.single;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import tools.refinery.viatra.runtime.matchers.tuple.Tuple;
import tools.refinery.viatra.runtime.matchers.tuple.TupleMask;
import tools.refinery.viatra.runtime.matchers.util.Direction;
import tools.refinery.viatra.runtime.rete.index.ProjectionIndexer;
import tools.refinery.viatra.runtime.rete.index.SpecializedProjectionIndexer.ListenerSubscription;
import tools.refinery.viatra.runtime.rete.network.ReteContainer;
import tools.refinery.viatra.runtime.rete.network.StandardNode;
import tools.refinery.viatra.runtime.rete.network.Supplier;
import tools.refinery.viatra.runtime.rete.network.Tunnel;
import tools.refinery.viatra.runtime.rete.network.communication.Timestamp;
import tools.refinery.viatra.runtime.rete.network.mailbox.Mailbox;
import tools.refinery.viatra.runtime.rete.traceability.TraceInfo;
import tools.refinery.viatra.runtime.rete.util.Options;

/**
 * Ensures that no identical copies get to the output. Only one replica of each pattern substitution may traverse this
 * node. There are both timeless and timely implementations.
 * 
 * @author Gabor Bergmann
 * @author Tamas Szabo
 * @noinstantiate This class is not intended to be instantiated by clients.
 * @noextend This class is not intended to be subclassed by clients.
 * @since 2.2
 */
public abstract class AbstractUniquenessEnforcerNode extends StandardNode implements Tunnel {

    protected final Collection<Supplier> parents;
    protected ProjectionIndexer memoryNullIndexer;
    protected ProjectionIndexer memoryIdentityIndexer;
    protected final int tupleWidth;
    // MUST BE INSTANTIATED IN THE CONCRETE SUBCLASSES AFTER ALL FIELDS ARE SET 
    protected Mailbox mailbox;
    protected final TupleMask nullMask;
    protected final TupleMask identityMask;
    protected final List<ListenerSubscription> specializedListeners;

    public AbstractUniquenessEnforcerNode(final ReteContainer reteContainer, final int tupleWidth) {
        super(reteContainer);
        this.parents = new ArrayList<Supplier>();
        this.specializedListeners = new ArrayList<ListenerSubscription>();
        this.tupleWidth = tupleWidth;
        this.nullMask = TupleMask.linear(0, tupleWidth);
        this.identityMask = TupleMask.identity(tupleWidth);
    }

    protected abstract Mailbox instantiateMailbox();

    @Override
    public Mailbox getMailbox() {
        return this.mailbox;
    }
    
    /**
     * @since 2.8
     */
    public abstract Set<Tuple> getTuples();

    /**
     * @since 2.4
     */
    protected void propagate(final Direction direction, final Tuple update, final Timestamp timestamp) {
        // See Bug 518434
        // trivial (non-active) indexers must be updated before other listeners
        // so that if they are joined against each other, trivial indexers lookups
        // will be consistent with their notifications;
        // also, their subscriptions must share a single order
        for (final ListenerSubscription subscription : specializedListeners) {
            subscription.propagate(direction, update, timestamp);
        }
        propagateUpdate(direction, update, timestamp);
    }

    @Override
    public ProjectionIndexer constructIndex(final TupleMask mask, final TraceInfo... traces) {
        if (Options.employTrivialIndexers) {
            if (nullMask.equals(mask)) {
                final ProjectionIndexer indexer = getNullIndexer();
                for (final TraceInfo traceInfo : traces) {
                    indexer.assignTraceInfo(traceInfo);
                }
                return indexer;
            }
            if (identityMask.equals(mask)) {
                final ProjectionIndexer indexer = getIdentityIndexer();
                for (final TraceInfo traceInfo : traces) {
                    indexer.assignTraceInfo(traceInfo);
                }
                return indexer;
            }
        }
        return super.constructIndex(mask, traces);
    }

    public abstract ProjectionIndexer getNullIndexer();

    public abstract ProjectionIndexer getIdentityIndexer();

    @Override
    public void appendParent(final Supplier supplier) {
        parents.add(supplier);
    }

    @Override
    public void removeParent(final Supplier supplier) {
        parents.remove(supplier);
    }

    @Override
    public Collection<Supplier> getParents() {
        return parents;
    }

    @Override
    public void assignTraceInfo(final TraceInfo traceInfo) {
        super.assignTraceInfo(traceInfo);
        if (traceInfo.propagateFromStandardNodeToSupplierParent()) {
            for (final Supplier parent : parents) {
                parent.acceptPropagatedTraceInfo(traceInfo);
            }
        }
    }

}