You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2019/02/25 22:59:18 UTC
svn commit: r1854342 -
/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasCompare.java
Author: schor
Date: Mon Feb 25 22:59:18 2019
New Revision: 1854342
URL: http://svn.apache.org/viewvc?rev=1854342&view=rev
Log:
[UIMA-5991] augment CasCompare
Modified:
uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasCompare.java
Modified: uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasCompare.java
URL: http://svn.apache.org/viewvc/uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasCompare.java?rev=1854342&r1=1854341&r2=1854342&view=diff
==============================================================================
--- uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasCompare.java (original)
+++ uima/uv3/uimaj-v3/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CasCompare.java Mon Feb 25 22:59:18 2019
@@ -22,11 +22,14 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -34,6 +37,8 @@ import java.util.stream.Collectors;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CommonArrayFS;
import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.impl.SlotKinds.SlotKind;
import org.apache.uima.internal.util.Int2ObjHashMap;
import org.apache.uima.internal.util.Misc;
@@ -41,6 +46,7 @@ import org.apache.uima.internal.util.Obj
import org.apache.uima.internal.util.Pair;
import org.apache.uima.internal.util.PositiveIntSet;
import org.apache.uima.internal.util.PositiveIntSet_impl;
+import org.apache.uima.internal.util.function.Consumer2;
import org.apache.uima.jcas.cas.BooleanArray;
import org.apache.uima.jcas.cas.ByteArray;
import org.apache.uima.jcas.cas.CommonList;
@@ -108,7 +114,9 @@ import org.apache.uima.util.IntEntry;
* - 2 arrays:
* -- all FSs in any index in any view
* -- the above, plus all FSs reachable via references
- *
+ * -- but omit some types: only of interest when reached via ref,
+ * e.g. String/Int/Float/Boolean arrays
+ *
* The comparison of FSs is done, one FS at a time.
* - in order to determine the right FSs to compare with each other, the FSs for each CAS
* are sorted.
@@ -134,7 +142,7 @@ import org.apache.uima.util.IntEntry;
* comparing values:
* primitives - value comparison
* refs - compare the ref'd FS, while recording reference paths
- * - stop when reach a compare point where the pair being compaired has been seen
+ * - stop when reach a compare point where the pair being compared has been seen
* - stop at any point if the two FSs compare unequal
* - at the stop point, if compare is equal, check the reference paths, and
* report unequal reference paths (different cycle lengths, or different total lengths,
@@ -385,6 +393,13 @@ public class CasCompare {
/** if true, continues comparison and reporting after finding the first miscompare */
private boolean isCompareAll = false;
private boolean isCompareIds = false;
+ final private Set<String> excludedRootNames = new HashSet(0);
+ final private Set<String> includedTypeNames = new HashSet(0);
+ /** key is feature long name (with type) */
+ final private Set<String> fsArraysToSort = new HashSet<>();
+ /** key is feature long name (with type) */
+ final private Set<String> stringArraysToSort = new HashSet<>();
+
// private boolean compareFSArraysAsSets = false;
// /** true when that FS._id (an Array of some kind) has been sorted */
@@ -408,6 +423,7 @@ public class CasCompare {
private boolean isSrcCas; // used for sorting with a CAS, to differentiate between src and target CASes
final private StringBuilder mismatchSb = new StringBuilder();
private boolean inSortContext = false;
+ private boolean isSkipMismatch = false;
private boolean isTypeMapping;
private final CasTypeSystemMapper typeMapper;
@@ -422,7 +438,14 @@ public class CasCompare {
private int maxId1;
private int maxId2;
-
+
+ /**
+ * Make an instance of this class to set up a compare operation,
+ * and optionally use to configure the compare.
+ *
+ * @param c1 one CAS to compare
+ * @param c2 the other CAS to compare
+ */
public CasCompare(CASImpl c1, CASImpl c2) {
this.c1 = c1;
this.c2 = c2;
@@ -446,17 +469,219 @@ public class CasCompare {
// }
/**
- * Continues the comparison after a miscompare (or not)
- * @param v true to continue the comparison after a miscompare
+ * Continues the comparison after a miscompare (or not).
+ * This is useful when you want to see all of the miscompares.
+ *
+ * @param v defaults to false, set to true to continue the comparison after a miscompare
*/
public void compareAll(boolean v) {
isCompareAll = v;
}
+ /**
+ * Normally, compares ignore the Feature Structure ID when comparing.
+ *
+ * @param v defaults to false, set to true to include the Feature Structure ID in the compare.
+ */
public void compareIds(boolean v) {
isCompareIds = v;
}
+ /**
+ * Many times some customation needs to be applied to both CASs being compared.
+ * This routine does that
+ * @param c the customization to be applied to both CASs
+ */
+ public void applyToBoth(Consumer<CASImpl> c) {
+ c.accept(c1);
+ c.accept(c2);
+ }
+
+ /**
+ * Before comparing, you can adjust specific features of specific types, arbitrarily.
+ * This routine applies the adjustments to both CASs.
+ *
+ * @param typeName the fully qualified name of the type
+ * @param featureBaseName the short feature name to adjust
+ * @param c a function to do the adjustment
+ */
+
+ public void applyToTypeFeature(String typeName, String featureBaseName, Consumer2<TOP, Feature> c) {
+ applyToTypeFeature_inner(c1, typeName, featureBaseName, c);
+ applyToTypeFeature_inner(c2, typeName, featureBaseName, c);
+ }
+
+ private void applyToTypeFeature_inner(CASImpl cas, String typeName, String featureBaseName, Consumer2<TOP, Feature> c) {
+ TypeSystem ts = cas.getTypeSystem();
+ Type type = ts.getType(typeName);
+ Feature feat = type.getFeatureByBaseName(featureBaseName);
+
+ cas.select(type).allViews().forEach(fs -> c.accept2(fs, feat));
+
+ }
+
+ /**
+ * Before comparing, you can create pending values for specific types / features, and return
+ * a list of runnables, which when run, plug in those pending values.
+ *
+ * @param typeName
+ * @param featureBaseName
+ * @param c
+ * @return
+ */
+ public List<Runnable> type_feature_to_runnable(String typeName, String featureBaseName, BiFunction<TOP, Feature, Runnable> c) {
+ List<Runnable> r = new ArrayList<>();
+ r.addAll(type_feature_to_runnable(c1, typeName, featureBaseName, c));
+ r.addAll(type_feature_to_runnable(c2, typeName, featureBaseName, c));
+ return r;
+ }
+
+ private List<Runnable> type_feature_to_runnable(CASImpl cas, String typeName, String featureBaseName, BiFunction<TOP, Feature, Runnable> c) {
+ TypeSystem ts = cas.getTypeSystem();
+ Type type = ts.getType(typeName);
+ Feature feat = type.getFeatureByBaseName(featureBaseName);
+ return cas.select(type).allViews().map((TOP fs) ->
+ c.apply(fs, feat)).collect(Collectors.toList());
+ }
+
+ /**
+ * Before comparing, you can, for a selected type and feature which has a string value belonging
+ * to one of a set of strings, change the value to another (fixed) string which will of course
+ * compare equal.
+ *
+ * Use this to ignore selected string-valued features having particular values.
+ *
+ * @param typeName the fully qualified type name
+ * @param featureBaseName the feature
+ * @param items_to_change an array of strings to change if matched to one of these
+ * @param canonical_value the new value
+ */
+ public void canonicalizeString(String typeName, String featureBaseName, String[] items_to_change, String canonical_value) {
+ applyToTypeFeature(typeName, featureBaseName,
+ (fs, feat) -> {
+
+ if (Misc.contains(items_to_change, fs.getStringValue(feat))) {
+ fs.setStringValue(feat, canonical_value);
+ }
+
+ });
+ }
+
+ public List<Runnable> sortFSArray(String typeName, String featureBaseName) {
+ fsArraysToSort.add(typeName + ":" + featureBaseName);
+ return type_feature_to_runnable(typeName, featureBaseName, (fs, feat) ->
+ sortFSArray((FSArray<?>)fs.getFeatureValue(feat)));
+ }
+
+ public List<Runnable> sortStringArray(String typeName, String featureBaseName) {
+ stringArraysToSort.add(typeName + ":" + featureBaseName);
+ return type_feature_to_runnable(typeName, featureBaseName, (fs, feat) ->
+ sortStringArray((StringArray)fs.getFeatureValue(feat)));
+ }
+
+ /**
+ * The compare can find FeatureStructures to compare either from
+ * - being in some index in some view, or
+ * - being referenced through some chain which starts with the above.
+ *
+ * It sometimes helps to exclude miscompares of FeatureStructure like
+ * StringArrays which (for some reason) are indexed, in favor of finding
+ * these only via refs.
+ *
+ * You can exclude these from being found via indexes by setting types
+ * here. They could still be found via refs from other
+ * Feature Structures.
+ *
+ * Calling this disables any includeOnlyTheseTypesFromIndexes call;
+ *
+ * @param excluded_typeNames
+ */
+ public void excludeRootTypesFromIndexes(Set<String> excluded_typeNames) {
+ includedTypeNames.clear();
+ excludedRootNames.addAll(excluded_typeNames);
+ }
+
+ /**
+ * The compare can find FeatureStructures to compare either from
+ * - being in some index in some view, or
+ * - being referenced through some chain which starts with the above.
+ *
+ * It sometimes helps to exclude miscompares of FeatureStructure like
+ * StringArrays which (for some reason) are indexed, in favor of finding
+ * these only via refs.
+ *
+ * Call this to exclude the array types:
+ * boolean, byte, short, integer, long, float, double, string and fs arrays
+ * from being found via indexes. They could still be found via refs from other
+ * Feature Structures.
+ *
+ * Calling this disables any includeOnlyTheseTypesFromIndexes call;
+ *
+ * @param filter
+ */
+ public void excludeCollectionsTypesFromIndexes() {
+ includedTypeNames.clear();
+ excludedRootNames.addAll(Arrays.asList(
+ CAS.TYPE_NAME_BOOLEAN_ARRAY,
+ CAS.TYPE_NAME_BYTE_ARRAY,
+ CAS.TYPE_NAME_SHORT_ARRAY,
+ CAS.TYPE_NAME_INTEGER_ARRAY,
+ CAS.TYPE_NAME_LONG_ARRAY,
+ CAS.TYPE_NAME_FLOAT_ARRAY,
+ CAS.TYPE_NAME_DOUBLE_ARRAY,
+ CAS.TYPE_NAME_STRING_ARRAY,
+ CAS.TYPE_NAME_FS_ARRAY,
+ "org.apache.uima.jcas.cas.FSArrayList",
+ "org.apache.uima.jcas.cas.FSHashSet",
+ "org.apache.uima.jcas.cas.IntegerArrayList",
+ "org.apache.uima.jcas.cas.FSLinkedHashSet",
+ "org.apache.uima.jcas.cas.Int2FS"
+ ));
+ }
+
+ /**
+ * The compare can find FeatureStructures to compare either from
+ * - being in some index in some view, or
+ * - being referenced through some chain which starts with the above.
+ *
+ * It sometimes helps to exclude miscompares of List FeatureStructures like
+ * StringLists which (for some reason) are indexed, in favor of finding
+ * these only via refs.
+ *
+ * Call this to exclude the list types non-empty Float/Integer/String list elements
+ * from being found in the index. They could still be found via refs from other
+ * Feature Structures.
+ *
+ * Calling this disables any includeOnlyTheseTypesFromIndexes call;
+ *
+ */
+ public void excludeListTypesFromIndexes() {
+ includedTypeNames.clear();
+ excludedRootNames.addAll(Arrays.asList(
+ CAS.TYPE_NAME_NON_EMPTY_FLOAT_LIST,
+ CAS.TYPE_NAME_NON_EMPTY_INTEGER_LIST,
+ CAS.TYPE_NAME_NON_EMPTY_STRING_LIST
+ ));
+ }
+
+ /**
+ * The compare can find FeatureStructures to compare either from
+ * - being in some index in some view, or
+ * - being referenced through some chain which starts with the above.
+ *
+ * It sometimes helps to exclude all types except for a few selected ones
+ * which are indexed, in favor of finding these only via refs.
+ *
+ * Calling this disables any excludeXXXTypesFromIndexes calls;
+ *
+ * @param includedTypeNames fully qualified type names to include
+ * when finding Feature Structures to compare via the indexes.
+ */
+ public void includeOnlyTheseTypesFromIndexes(List<String> includedTypeNames) {
+ excludedRootNames.clear();
+ this.includedTypeNames.addAll(includedTypeNames);
+ }
+
// public void compareCanonicalEmptyLists(boolean v) {
// isCanonicalEmptyLists = v;
// }
@@ -464,17 +689,17 @@ public class CasCompare {
/**
* Add a set of strings that should be considered equal when doing string comparisons.
* This is conditioned on the typename and feature name
- * @param t the fully qualified type name
- * @param f the feature short name
- * @param set a set of strings that should compare equal, if testing the type / feature
+ * @param typeName the fully qualified type name
+ * @param featureBaseName the feature short name
+ * @param set_of_strings_that_are_equivalent a set of strings that should compare equal, if testing the type / feature
* @param index if the item being compared is a reference to a string array, which index should be compared.
* Use -1 if not applicable.
*/
- public void addStringCongruenceSet(String t, String f, String[] set, int index) {
- TypeImpl t1 = ts1.getType(t);
+ public void addStringCongruenceSet(String typeName, String featureBaseName, String[] set_of_strings_that_are_equivalent, int index) {
+ TypeImpl t1 = ts1.getType(typeName);
stringCongruenceSets.put(
- new ScsKey(t1, t1.getFeatureByBaseName(f), index),
- set);
+ new ScsKey(t1, t1.getFeatureByBaseName(featureBaseName), index),
+ set_of_strings_that_are_equivalent);
isUsingStringCongruenceSets = true;
}
@@ -493,7 +718,7 @@ public class CasCompare {
// processIndexedFeatureStructures(c1, false);
Predicate<TOP> includeFilter = isTypeMapping ? (fs -> isTypeInTgt(fs)) : null;
- // get just the indexed ones
+ // this next call doesn't get just the indexed ones, it includes the "reachable" ones too
c1FoundFSs = new AllFSs(c1, null, includeFilter, isTypeMapping ? typeMapper : null)
.getAllFSsAllViews_sofas_reachable()
.getAllFSs();
@@ -505,7 +730,32 @@ public class CasCompare {
.getAllFSsAllViews_sofas_reachable()
.getAllFSs(); // get just the indexed ones.
-
+ // filter out items only of interest when reached via ref
+ if (excludedRootNames.size() > 0) {
+ System.out.println("Excluding Root Names with: " +
+ Misc.ppList(Arrays.asList(excludedRootNames.toArray())));
+ c1FoundFSs = c1FoundFSs.stream()
+ .filter(
+ fs -> !excludedRootNames.contains(fs.getType().getName()))
+ .collect(Collectors.toCollection(ArrayList::new));
+ c2FoundFSs = c2FoundFSs.stream()
+ .filter(
+ fs -> !excludedRootNames.contains(fs.getType().getName()))
+ .collect(Collectors.toCollection(ArrayList::new));
+ } else if (includedTypeNames.size() > 0) {
+ System.out.println("Including only Root Names: " +
+ Misc.ppList(Arrays.asList(includedTypeNames.toArray())));
+ c1FoundFSs = c1FoundFSs.stream()
+ .filter(
+ fs -> includedTypeNames.contains(fs.getType().getName()))
+ .collect(Collectors.toCollection(ArrayList::new));
+ c2FoundFSs = c2FoundFSs.stream()
+ .filter(
+ fs -> includedTypeNames.contains(fs.getType().getName()))
+ .collect(Collectors.toCollection(ArrayList::new));
+
+ }
+
// if type systems are "isEqual()" still need to map because of feature validation testing
int i1 = 0;
@@ -705,10 +955,25 @@ public class CasCompare {
}
/**
- * Sort an fsArray. During the sort, links are followed.
+ * This is an optional pre-compare operation.
+ *
+ * Somtimes, when comparing FSArrays, the order of the elements is not significant,
+ * and the compare should be done ignoring order differences.
+ *
+ * This is accomplished by sorting the elements, before the compare is done,
+ * using this method. The sort order is not significant; it just needs to be
+ * the same order for otherwise equal FSArrays.
+ *
+ * Use this routine to accomplish the sort, on particular FSArrays you designate.
+ * Call it for each one you want to sort.
+ *
+ * During the sort, links are followed.
+ *
* The sorting is done in a clone of the array, and the original array is not updated.
* Instead, a Runnable is returned, which may be invoked later to update the original array with the sorted copy.
- * This allows sorting to be done on the original item values.
+ * This allows sorting to be done on the original item values
+ * (in case the links refer back to the originals)
+
* @param fsArray the array to be sorted
* @return a runnable, which (when invoked) updates the original array with the sorted result.
*/
@@ -725,6 +990,36 @@ public class CasCompare {
return () -> System.arraycopy(a, 0, fsArray._getTheArray(), 0, fsArray.size());
}
+ /**
+ * This is an optional pre-compare operation.
+ *
+ * Somtimes, when comparing StringArrays, the order of the elements is not significant,
+ * and the compare should be done ignoring order differences.
+ *
+ * This is accomplished by sorting the elements, before the compare is done,
+ * using this method.
+ *
+ * Use this routine to accomplish the sort, on particular StringArrays you designate.
+ * Call it for each one you want to sort.
+ *
+ * The sorting is done in a clone of the array, and the original array is not updated.
+ * Instead, a Runnable is returned, which may be invoked later to update the original array with the sorted copy.
+ * This allows sorting to be done while keeping the original values until a later time
+ *
+ * @param fsArray the array to be sorted
+ * @return null or a runnable, which (when invoked) updates the original array with the sorted result.
+ * callers should insure the runnable is garbage collected after use
+ */
+ public Runnable sortStringArray(StringArray stringArray) {
+ if (stringArray == null || stringArray.size() < 2) {
+ return null;
+ }
+ String[] a = stringArray._getTheArray().clone();
+ inSortContext = true;
+ Arrays.sort(a);
+ return () -> System.arraycopy(a, 0, stringArray._getTheArray(), 0, stringArray.size());
+ }
+
/* *******************************************************************************
* Convert UIMA Lists to arrays, to make the compare go faster
* *******************************************************************************/
@@ -959,14 +1254,14 @@ public class CasCompare {
r = ti1.compareTo(ti2);
if (r != 0) {
if (!inSortContext) {
- mismatchFs(fs1, fs2, "Different Types"); // types mismatch
+ mismatchFs(fs1, fs2, "Different Types", callerTi, callerFi); // types mismatch
}
return r;
}
if (isCompareIds && !inSortContext) {
if (fs1._id < maxId1 && fs2._id < maxId2 && fs1._id != fs2._id) {
- mismatchFs(fs1, fs2, "IDs miscompare");
+ mismatchFs(fs1, fs2, "IDs miscompare", callerTi, callerFi);
return Integer.compare(fs1._id, fs2._id);
}
}
@@ -984,6 +1279,9 @@ public class CasCompare {
for (FeatureImpl[] featSet : featLists.featsByEase) {
for (FeatureImpl fi1 : featSet) {
if (0 != (r = compareFeature(fs1, fs2, ti1, fi1))) {
+ if (! inSortContext && IS_DEBUG_STOP_ON_MISCOMPARE) {
+ System.out.println("debug stop");
+ }
return r;
}
}
@@ -1083,7 +1381,7 @@ public class CasCompare {
r = Integer.compare(len1, len2);
if (r != 0) {
if (!inSortContext) {
- mismatchFs(fs1, fs2);
+ mismatchFs(fs1, fs2, callerTi, callerFi);
}
return r;
}
@@ -1099,52 +1397,118 @@ public class CasCompare {
switch(kind) {
case Slot_BooleanRef: r = compareAllArrayElements(fs1, fs2, len1, i -> Boolean.compare(
((BooleanArray)a1).get(i),
- ((BooleanArray)a2).get(i)));
+ ((BooleanArray)a2).get(i)), callerTi, callerFi);
break;
case Slot_ByteRef: r = compareAllArrayElements(fs1, fs2, len1, i -> Byte.compare(
((ByteArray )a1).get(i),
- ((ByteArray )a2).get(i)));
+ ((ByteArray )a2).get(i)), callerTi, callerFi);
break;
case Slot_ShortRef: r = compareAllArrayElements(fs1, fs2, len1, i -> Short.compare(
((ShortArray )a1).get(i),
- ((ShortArray )a2).get(i)));
+ ((ShortArray )a2).get(i)), callerTi, callerFi);
break;
case Slot_Int: r = compareAllArrayElements(fs1, fs2, len1, i -> Integer.compare(
((IntegerArray)a1).get(i),
- ((IntegerArray)a2).get(i)));
+ ((IntegerArray)a2).get(i)), callerTi, callerFi);
break;
case Slot_LongRef: r = compareAllArrayElements(fs1, fs2, len1, i -> Long.compare(
((LongArray )a1).get(i),
- ((LongArray )a2).get(i)));
+ ((LongArray )a2).get(i)), callerTi, callerFi);
break;
// don't compare floats / doubles directly - because two "equal" NaN are defined to miscompare
case Slot_Float: r = compareAllArrayElements(fs1, fs2, len1, i -> Integer.compare(
CASImpl.float2int(((FloatArray )a1).get(i)),
- CASImpl.float2int(((FloatArray )a2).get(i))));
+ CASImpl.float2int(((FloatArray )a2).get(i))), callerTi, callerFi);
break;
// don't compare floats / doubles directly - because two "equal" NaN are defined to miscompare
case Slot_DoubleRef: r = compareAllArrayElements(fs1, fs2, len1, i -> Long.compare(
CASImpl.double2long(((DoubleArray)a1).get(i)),
- CASImpl.double2long(((DoubleArray)a2).get(i))));
+ CASImpl.double2long(((DoubleArray)a2).get(i))), callerTi, callerFi);
break;
- case Slot_HeapRef: r = compareAllArrayElements(fs1, fs2, len1, i -> compareRefs((TOP) ((FSArray<?>) a1).get(i),
+ case Slot_HeapRef: {
+ if (! inSortContext) {
+ isSkipMismatch = true;
+ r = compareAllArrayElements(fs1, fs2, len1, i -> compareRefs((TOP) ((FSArray<?>) a1).get(i),
+ (TOP) ((FSArray<?>) a2).get(i),
+ callerTi,
+ callerFi), callerTi, callerFi);
+ isSkipMismatch = false;
+ if (r != 0) { // a miscompare - see if we were supposed to sort these
+ if (fsArraysToSort.contains(callerFi.getName())) {
+ sortFSArray((FSArray<?>) a1)
+ .run();
+ sortFSArray((FSArray<?>) a2)
+ .run();
+ inSortContext = false;
+ r = compareAllArrayElements(fs1, fs2, len1, i -> compareRefs((TOP) ((FSArray<?>) a1).get(i),
+ (TOP) ((FSArray<?>) a2).get(i),
+ callerTi,
+ callerFi), callerTi, callerFi);
+ } else { // no special sorting, but was unequal, redo to capture msg
+ r = compareAllArrayElements(fs1, fs2, len1, i -> compareRefs((TOP) ((FSArray<?>) a1).get(i),
+ (TOP) ((FSArray<?>) a2).get(i),
+ callerTi,
+ callerFi), callerTi, callerFi);
+ }
+ } // else compared ==
+ } else { // was in sort context
+ r = compareAllArrayElements(fs1, fs2, len1, i -> compareRefs((TOP) ((FSArray<?>) a1).get(i),
(TOP) ((FSArray<?>) a2).get(i),
callerTi,
- callerFi));
+ callerFi), callerTi, callerFi);
+ }
break;
- case Slot_StrRef: r = compareAllArrayElements(fs1, fs2, len1, i -> compareStringsWithNull(
- ((StringArray)a1).get(i),
- ((StringArray)a2).get(i),
- callerTi,
- callerFi,
- i));
+ }
+ case Slot_StrRef: {
+ if (! inSortContext) {
+ isSkipMismatch = true;
+ r = compareAllArrayElements(fs1, fs2, len1, i -> compareStringsWithNull(
+ ((StringArray)a1).get(i),
+ ((StringArray)a2).get(i),
+ callerTi,
+ callerFi,
+ i), callerTi, callerFi);
+ isSkipMismatch = false;
+ if (r != 0) {
+ if (stringArraysToSort.contains(callerFi.getName())) {
+ String[] a = ((StringArray)a1)._getTheArray();
+ Arrays.sort(a);
+ a = ((StringArray)a2)._getTheArray();
+ Arrays.sort(a);
+ r = compareAllArrayElements(fs1, fs2, len1, i -> compareStringsWithNull(
+ ((StringArray)a1).get(i),
+ ((StringArray)a2).get(i),
+ callerTi,
+ callerFi,
+ i), callerTi, callerFi);
+ } else { // no special sorting, but was unequal, redo to capture msg
+ r = compareAllArrayElements(fs1, fs2, len1, i -> compareStringsWithNull(
+ ((StringArray)a1).get(i),
+ ((StringArray)a2).get(i),
+ callerTi,
+ callerFi,
+ i), callerTi, callerFi);
+ }
+ } // r was 0, nothing more to do
+ } else { // was in sort context
+ r = compareAllArrayElements(fs1, fs2, len1, i -> compareStringsWithNull(
+ ((StringArray)a1).get(i),
+ ((StringArray)a2).get(i),
+ callerTi,
+ callerFi,
+ i), callerTi, callerFi);
+ }
break;
+ }
default:
throw Misc.internalError();
}
+ if (r != 0 && ! inSortContext && IS_DEBUG_STOP_ON_MISCOMPARE) {
+ System.out.println("debug stop");
+ }
return r;
}
@@ -1244,7 +1608,7 @@ public class CasCompare {
typeMapper.mapTypeTgt2Src(rfs2._getTypeImpl()) == null) {
return 0;
} else {
- if (IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {
+ if (! inSortContext && IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {
System.out.println("debug stop");
}
return -1;
@@ -1264,7 +1628,7 @@ public class CasCompare {
typeMapper.mapTypeSrc2Tgt(rfs1._getTypeImpl()) == null) {
return 0;
} else {
- if (IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {
+ if (! inSortContext && IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {
System.out.println("debug stop");
}
return 1;
@@ -1294,7 +1658,7 @@ public class CasCompare {
if (v == 0) {
return compareRefResult(rfs1, rfs2); // stop recursion, return based on loops
} else {
- if (IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {
+ if (! inSortContext && IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {
System.out.println("debug stop");
}
return v;
@@ -1368,7 +1732,7 @@ public class CasCompare {
int r = prev1.compareCycleLen(prev2);
if (r != 0) {
- if (IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {
+ if (! inSortContext && IS_DEBUG_STOP_ON_MISCOMPARE && !inSortContext) {
System.out.println("debug stop");
}
return r;
@@ -1386,13 +1750,13 @@ public class CasCompare {
}
}
- private int compareAllArrayElements(TOP fs1, TOP fs2, int len, IntUnaryOperator c) {
+ private int compareAllArrayElements(TOP fs1, TOP fs2, int len, IntUnaryOperator c, TypeImpl callerTi, FeatureImpl callerFi) {
int r = 0;
for (int i = 0; i < len; i++) {
r = c.applyAsInt(i);
if (r != 0) {
if (!inSortContext) {
- mismatchFs(fs1, fs2, "Comparing array of length " + len);
+ mismatchFs(fs1, fs2, "Comparing array of length " + len, callerTi, callerFi);
}
return r;
}
@@ -1476,8 +1840,12 @@ public class CasCompare {
mismatchSb.setLength(0);
}
- private void mismatchFs(TOP fs1, TOP fs2) {
- mismatchSb.append(String.format("Mismatched Feature Structures:%n %s%n %s%n", ps(fs1), ps(fs2)));
+ private void mismatchFs(TOP fs1, TOP fs2, TypeImpl callerTi, FeatureImpl callerFi) {
+ if (! isSkipMismatch) {
+ mismatchSb.append(String.format("Mismatched Feature Structures refd from %s %s:%n %s%n %s%n",
+ (callerTi == null) ? "null" : callerTi.getName(), (callerFi == null) ? "null" : callerFi.getName(),
+ ps(fs1), ps(fs2)));
+ }
// // debug
// System.out.println("adding to miscompares: " + fs1._id + " " + fs2._id);
// miscompares.add(new Pair<>(fs1, fs2));
@@ -1495,16 +1863,21 @@ public class CasCompare {
// }
private void mismatchFs(TOP fs1, TOP fs2, Feature fi, Feature fi2) {
- String mapmsg = fi.equals(fi2)
- ? ""
- : "which mapped to target feature " + fi2.getShortName() + " ";
- mismatchSb.append(String.format("Mismatched Feature Structures in feature %s %s%n %s%n %s%n",
- fi.getShortName(), mapmsg, ps(fs1), ps(fs2)));
+ if (! isSkipMismatch) {
+ String mapmsg = fi.equals(fi2)
+ ? ""
+ : "which mapped to target feature " + fi2.getShortName() + " ";
+ mismatchSb.append(String.format("Mismatched Feature Structures in feature %s %s%n %s%n %s%n",
+ fi.getShortName(), mapmsg, ps(fs1), ps(fs2)));
+ }
}
- private void mismatchFs(TOP fs1, TOP fs2, String msg) {
- mismatchSb.append(String.format("Mismatched Feature Structures, %s%n %s%n %s%n",
- msg, ps(fs1), ps(fs2)));
+ private void mismatchFs(TOP fs1, TOP fs2, String msg, TypeImpl callerTi, FeatureImpl callerFi) {
+ if (! isSkipMismatch) {
+ mismatchSb.append(String.format("Mismatched Feature Structures refd from %s %s, %s%n %s%n %s%n",
+ (callerTi == null) ? "null" : callerTi.getName(), (callerFi == null) ? "null" : callerFi.getName(),
+ msg, ps(fs1), ps(fs2)));
+ }
}
/** called to sort all the FSs before doing the equality compares */
@@ -1619,7 +1992,7 @@ public class CasCompare {
} else {
sba.append("\nDifferent numbers of types");
}
- return sba;
+ return sba.append('\n');
}
}