ReductionSignature.java

1
/*******************************************************************************
2
 * Copyright (C) 2026, Leo Galambos
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 *
11
 * 2. Redistributions in binary form must reproduce the above copyright notice,
12
 *    this list of conditions and the following disclaimer in the documentation
13
 *    and/or other materials provided with the distribution.
14
 *
15
 * 3. Neither the name of the copyright holder nor the names of its contributors
16
 *    may be used to endorse or promote products derived from this software
17
 *    without specific prior written permission.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
 * POSSIBILITY OF SUCH DAMAGE.
30
 ******************************************************************************/
31
package org.egothor.stemmer.trie;
32
33
import java.util.ArrayList;
34
import java.util.Collections;
35
import java.util.List;
36
import java.util.Map;
37
import java.util.Objects;
38
39
import org.egothor.stemmer.ReductionSettings;
40
41
/**
42
 * Immutable reduction signature of a full subtree.
43
 *
44
 * @param <V> value type
45
 */
46
public final class ReductionSignature<V> {
47
48
    /**
49
     * Local semantic descriptor.
50
     */
51
    private final Object localDescriptor;
52
53
    /**
54
     * Child edge descriptors in sorted edge order.
55
     */
56
    private final List<ChildDescriptor<V>> childDescriptors;
57
58
    /**
59
     * Whether the represented node accepts any remaining lookup input.
60
     */
61
    private final boolean acceptsRemainingInput;
62
63
    /**
64
     * Optional identity token separating a modified reconstructed node from its
65
     * unchanged compiled-source peers.
66
     */
67
    private final Object mergeDiscriminator;
68
69
    /**
70
     * Creates an immutable signature from an already-normalized local descriptor
71
     * and sorted child descriptors.
72
     *
73
     * @param localDescriptor       semantic descriptor of node-local values
74
     * @param childDescriptors      immutable child-edge descriptors
75
     * @param acceptsRemainingInput whether the node accepts an unmatched input
76
     *                              remainder
77
     * @param mergeDiscriminator    optional copy-on-write identity token, or
78
     *                              {@code null}
79
     */
80
    private ReductionSignature(final Object localDescriptor, final List<ChildDescriptor<V>> childDescriptors,
81
            final boolean acceptsRemainingInput, final Object mergeDiscriminator) {
82
        this.localDescriptor = localDescriptor;
83
        this.childDescriptors = childDescriptors;
84
        this.acceptsRemainingInput = acceptsRemainingInput;
85
        this.mergeDiscriminator = mergeDiscriminator;
86
    }
87
88
    /**
89
     * Creates a subtree signature according to the selected reduction mode.
90
     *
91
     * @param localSummary local value summary
92
     * @param children     reduced children
93
     * @param settings     reduction settings
94
     * @param acceptsRemainingInput whether this node accepts any remaining lookup
95
     *                              input
96
     * @param <V>          value type
97
     * @return subtree signature
98
     * @throws NullPointerException if {@code localSummary}, {@code children}, or
99
     *                              {@code settings} is {@code null}
100
     */
101
    public static <V> ReductionSignature<V> create(final LocalValueSummary<V> localSummary,
102
            final Map<Character, ReducedNode<V>> children, final ReductionSettings settings,
103
            final boolean acceptsRemainingInput) {
104 1 1. create : replaced return value with null for org/egothor/stemmer/trie/ReductionSignature::create → KILLED
        return create(localSummary, children, settings, acceptsRemainingInput, null);
105
    }
106
107
    /**
108
     * Creates a subtree signature with an optional copy-on-write merge boundary.
109
     *
110
     * <p>
111
     * A non-null discriminator is compared by its normal object identity (the
112
     * reconstruction code supplies a fresh plain {@link Object}) and therefore
113
     * prevents a locally modified expanded DAG node from being merged with an
114
     * unchanged peer. Descendant discriminators propagate naturally through child
115
     * descriptors.
116
     * </p>
117
     *
118
     * @param localSummary          local value summary
119
     * @param children              reduced children
120
     * @param settings              reduction settings
121
     * @param acceptsRemainingInput whether this node accepts any remaining input
122
     * @param mergeDiscriminator    unique copy-on-write token, or {@code null}
123
     * @param <V>                   value type
124
     * @return subtree signature
125
     * @throws NullPointerException if {@code localSummary}, {@code children}, or
126
     *                              {@code settings} is {@code null}
127
     */
128
    public static <V> ReductionSignature<V> create(final LocalValueSummary<V> localSummary,
129
            final Map<Character, ReducedNode<V>> children, final ReductionSettings settings,
130
            final boolean acceptsRemainingInput, final Object mergeDiscriminator) {
131
        final Object localDescriptor = switch (settings.reductionMode()) {
132
            case MERGE_SUBTREES_WITH_EQUIVALENT_RANKED_GET_ALL_RESULTS ->
133
                RankedLocalDescriptor.of(localSummary.orderedValues());
134
            case MERGE_SUBTREES_WITH_EQUIVALENT_UNORDERED_GET_ALL_RESULTS ->
135
                UnorderedLocalDescriptor.of(localSummary.orderedValues());
136
            case MERGE_SUBTREES_WITH_EQUIVALENT_DOMINANT_GET_RESULTS -> {
137 1 1. create : negated conditional → KILLED
                if (localSummary.hasQualifiedDominantWinner(settings)) {
138
                    yield new DominantLocalDescriptor<>(localSummary.dominantValue);
139
                } else {
140
                    yield RankedLocalDescriptor.of(localSummary.orderedValues());
141
                }
142
            }
143
        };
144
145
        final List<Map.Entry<Character, ReducedNode<V>>> entries = new ArrayList<>(children.entrySet());
146 1 1. create : removed call to java/util/List::sort → KILLED
        entries.sort(Map.Entry.comparingByKey());
147
148
        final List<ChildDescriptor<V>> childDescriptors = new ArrayList<>(entries.size());
149
150
        for (Map.Entry<Character, ReducedNode<V>> entry : entries) {
151
            childDescriptors.add(new ChildDescriptor<>(entry.getKey(), entry.getValue().signature()));
152
        }
153
154 1 1. create : replaced return value with null for org/egothor/stemmer/trie/ReductionSignature::create → KILLED
        return new ReductionSignature<>(localDescriptor, Collections.unmodifiableList(childDescriptors),
155
                acceptsRemainingInput, mergeDiscriminator);
156
    }
157
158
    /**
159
     * Creates a non-accepting subtree signature according to the selected reduction
160
     * mode.
161
     *
162
     * @param localSummary local value summary
163
     * @param children     reduced children
164
     * @param settings     reduction settings
165
     * @param <V>          value type
166
     * @return subtree signature
167
     */
168
    public static <V> ReductionSignature<V> create(final LocalValueSummary<V> localSummary,
169
            final Map<Character, ReducedNode<V>> children, final ReductionSettings settings) {
170 1 1. create : replaced return value with null for org/egothor/stemmer/trie/ReductionSignature::create → KILLED
        return create(localSummary, children, settings, false);
171
    }
172
173
    @Override
174
    public int hashCode() {
175 1 1. hashCode : replaced int return with 0 for org/egothor/stemmer/trie/ReductionSignature::hashCode → TIMED_OUT
        return Objects.hash(this.localDescriptor, this.childDescriptors, this.acceptsRemainingInput,
176
                this.mergeDiscriminator);
177
    }
178
179
    @Override
180
    public boolean equals(final Object other) {
181 1 1. equals : negated conditional → KILLED
        if (this == other) {
182 1 1. equals : replaced boolean return with false for org/egothor/stemmer/trie/ReductionSignature::equals → NO_COVERAGE
            return true;
183
        }
184 1 1. equals : negated conditional → KILLED
        if (!(other instanceof ReductionSignature<?>)) {
185 1 1. equals : replaced boolean return with true for org/egothor/stemmer/trie/ReductionSignature::equals → NO_COVERAGE
            return false;
186
        }
187
        final ReductionSignature<?> that = (ReductionSignature<?>) other;
188 2 1. equals : replaced boolean return with true for org/egothor/stemmer/trie/ReductionSignature::equals → KILLED
2. equals : negated conditional → KILLED
        return Objects.equals(this.localDescriptor, that.localDescriptor)
189 2 1. equals : negated conditional → KILLED
2. equals : negated conditional → KILLED
                && Objects.equals(this.childDescriptors, that.childDescriptors)
190
                && this.acceptsRemainingInput == that.acceptsRemainingInput
191 1 1. equals : negated conditional → KILLED
                && Objects.equals(this.mergeDiscriminator, that.mergeDiscriminator);
192
    }
193
}

Mutations

104

1.1
Location : create
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldPreserveRankedGetAllSemanticsInRankedMode()]
replaced return value with null for org/egothor/stemmer/trie/ReductionSignature::create → KILLED

137

1.1
Location : create
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldFallBackToRankedDescriptorWhenDominantWinnerDoesNotQualify()]
negated conditional → KILLED

146

1.1
Location : create
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldSortChildDescriptorsByEdgeRegardlessOfMapInsertionOrder()]
removed call to java/util/List::sort → KILLED

154

1.1
Location : create
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldPreserveRankedGetAllSemanticsInRankedMode()]
replaced return value with null for org/egothor/stemmer/trie/ReductionSignature::create → KILLED

170

1.1
Location : create
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldPreserveRankedGetAllSemanticsInRankedMode()]
replaced return value with null for org/egothor/stemmer/trie/ReductionSignature::create → KILLED

175

1.1
Location : hashCode
Killed by : none
replaced int return with 0 for org/egothor/stemmer/trie/ReductionSignature::hashCode → TIMED_OUT

181

1.1
Location : equals
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldPreserveRankedGetAllSemanticsInRankedMode()]
negated conditional → KILLED

182

1.1
Location : equals
Killed by : none
replaced boolean return with false for org/egothor/stemmer/trie/ReductionSignature::equals → NO_COVERAGE

184

1.1
Location : equals
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldIgnoreLocalOrderingInUnorderedMode()]
negated conditional → KILLED

185

1.1
Location : equals
Killed by : none
replaced boolean return with true for org/egothor/stemmer/trie/ReductionSignature::equals → NO_COVERAGE

188

1.1
Location : equals
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldPreserveRankedGetAllSemanticsInRankedMode()]
replaced boolean return with true for org/egothor/stemmer/trie/ReductionSignature::equals → KILLED

2.2
Location : equals
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldIgnoreLocalOrderingInUnorderedMode()]
negated conditional → KILLED

189

1.1
Location : equals
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldIgnoreLocalOrderingInUnorderedMode()]
negated conditional → KILLED

2.2
Location : equals
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldIgnoreLocalOrderingInUnorderedMode()]
negated conditional → KILLED

191

1.1
Location : equals
Killed by : org.egothor.stemmer.trie.ReductionSignatureTest.[engine:junit-jupiter]/[class:org.egothor.stemmer.trie.ReductionSignatureTest]/[method:shouldIgnoreLocalOrderingInUnorderedMode()]
negated conditional → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1