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 2016/01/04 03:08:40 UTC

svn commit: r1722785 - /uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java

Author: schor
Date: Mon Jan  4 02:08:40 2016
New Revision: 1722785

URL: http://svn.apache.org/viewvc?rev=1722785&view=rev
Log:
[UIMA-4674] update cas compare - more specific generics, identity hashmaps for FSs

Modified:
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java?rev=1722785&r1=1722784&r2=1722785&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparer.java Mon Jan  4 02:08:40 2016
@@ -23,15 +23,15 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.ConcurrentModificationException;
-import java.util.HashSet;
+import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Set;
+import java.util.function.IntUnaryOperator;
 
 import org.apache.uima.cas.ArrayFS;
 import org.apache.uima.cas.BooleanArrayFS;
 import org.apache.uima.cas.ByteArrayFS;
 import org.apache.uima.cas.CAS;
-import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.DoubleArrayFS;
 import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.Feature;
@@ -44,7 +44,24 @@ import org.apache.uima.cas.SofaFS;
 import org.apache.uima.cas.StringArrayFS;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.cas.impl.FeatureImpl;
+import org.apache.uima.cas.impl.SlotKinds.SlotKind;
+import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.internal.util.IntVector;
+import org.apache.uima.jcas.cas.BooleanArray;
+import org.apache.uima.jcas.cas.ByteArray;
+import org.apache.uima.jcas.cas.CommonArray;
+import org.apache.uima.jcas.cas.DoubleArray;
+import org.apache.uima.jcas.cas.EmptyList;
+import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.FloatArray;
+import org.apache.uima.jcas.cas.IntegerArray;
+import org.apache.uima.jcas.cas.LongArray;
+import org.apache.uima.jcas.cas.ShortArray;
+import org.apache.uima.jcas.cas.Sofa;
+import org.apache.uima.jcas.cas.StringArray;
+import org.apache.uima.jcas.cas.TOP;
+import org.apache.uima.util.Misc;
 
 import junit.framework.Assert;
 
@@ -61,21 +78,29 @@ public class CasComparer {
   enum ARRAY_TYPE {
     FS, STRING, BOOLEAN, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE,
   }
+  
+  final private Set<TOP> sortCompareSeen = Collections.newSetFromMap(new IdentityHashMap<>());
+  final private Set<TOP> alreadyCompared = Collections.newSetFromMap(new IdentityHashMap<>());
 
   public static void assertEquals(CAS c1, CAS c2) {
+     new CasComparer().assertEqualsInner(c1, c2);
+  }
+  
+  public void assertEqualsInner(CAS c1, CAS c2) {
+    alreadyCompared.clear();
     
     // this code handles initial views with no SofaFS
     CAS initialView1 = c1.getView(CAS.NAME_DEFAULT_SOFA);
     CAS initialView2 = c2.getView(CAS.NAME_DEFAULT_SOFA);
-    assertEqualViews(initialView1, initialView2);
+    assertEqualViewsInner(initialView1, initialView2);
     // this code skips the initial view, if it doesn't have a sofa FS
-    FSIterator<SofaFS> sofaIter = c1.getSofaIterator();
+    FSIterator<Sofa> sofaIter = c1.getSofaIterator();
     int c1Sofas = 0;
     while (sofaIter.hasNext()) {
       SofaFS sofa = sofaIter.next();
       CAS tcas1 = c1.getView(sofa);
       CAS tcas2 = c2.getView(tcas1.getViewName());
-      assertEqualViews(tcas1, tcas2);
+      assertEqualViewsInner(tcas1, tcas2);
       c1Sofas++;
     }
     sofaIter = c2.getSofaIterator();
@@ -89,25 +114,25 @@ public class CasComparer {
 
   public static void assertEqualViews(CAS c1, CAS c2) {
     CasComparer instance = new CasComparer();
-    instance.assertEqualViews(c1,  c2,  new HashSet<FeatureStructure>());
+    instance.assertEqualViewsInner(c1,  c2);
   }
   
   public static void assertEquals(FeatureStructure fs1, FeatureStructure fs2) {
     CasComparer instance = new CasComparer();
-    Assert.assertTrue(0 == instance.compare1(fs1,  fs2));
+   instance.assertEqualsInner((TOP)fs1,  (TOP)fs2);
   }
   
   
-  private void assertEqualViews(CAS c1, CAS c2, Set<FeatureStructure> visited) {
+  private void assertEqualViewsInner(CAS c1, CAS c2) {
     
     // allow for different ordering in the getAllIndexedFSs
     
-    List<FeatureStructure> list1 = populate(c1.getIndexRepository().getAllIndexedFS(c1.getTypeSystem().getTopType()), visited);
-    List<FeatureStructure> list2 = populate(c2.getIndexRepository().getAllIndexedFS(c2.getTypeSystem().getTopType()), visited);
+    List<TOP> list1 = populate(c1.getIndexRepository().getAllIndexedFS(c1.getTypeSystem().getTopType()), alreadyCompared);
+    List<TOP> list2 = populate(c2.getIndexRepository().getAllIndexedFS(c2.getTypeSystem().getTopType()), alreadyCompared);
     
     Assert.assertEquals(list1.size(),  list2.size());
     
-    isSortUse = true;  // while sorting
+    isSortUse = true;  // while sorting; i.e., for next two calls. Affects how visited is used
     Collections.sort(list1, fsComparator);
     Collections.sort(list2, fsComparator);
 
@@ -115,7 +140,7 @@ public class CasComparer {
     int i = 0;
     try {
       for (; i < list1.size(); i++) {
-        compare1(list1.get(i), list2.get(i), visited);
+        compare1(list1.get(i), list2.get(i), alreadyCompared);
       }
     } catch (ConcurrentModificationException e) {
       Assert.fail();
@@ -127,14 +152,9 @@ public class CasComparer {
    */
   private boolean isSortUse = true;
   private TypeSystem ts;
-  private Type casStringType;
+//  private Type casStringType;
   
-  private Comparator<FeatureStructure> fsComparator = new Comparator<FeatureStructure>() {
-    @Override
-    public int compare(FeatureStructure o1, FeatureStructure o2) {
-      return compare1(o1, o2);
-    }   
-  };
+  private Comparator<TOP> fsComparator = (o1, o2) -> compare1(o1, o2);
    
   /**
    * Comparator that establishes an ordering among all FSs in a view.
@@ -144,41 +164,114 @@ public class CasComparer {
    * @param fs2
    */
 
-  public int compare1(FeatureStructure fs1, FeatureStructure fs2) {
-    return compare1(fs1, fs2, new HashSet<FeatureStructure>());
+  public int compare1(TOP fs1, TOP fs2) {
+    sortCompareSeen.clear();
+    return compare1(fs1, fs2, sortCompareSeen);
   }
   
-  private int compare1(FeatureStructure fs1, FeatureStructure fs2, Set<FeatureStructure> visited) {
-    if (fs1 == null && fs2 == null) {
-      return 0;
+  private void assertEqualsInner(TOP fs1, TOP fs2) {
+    alreadyCompared.clear();
+    chkEqual(compare1(fs1, fs2, alreadyCompared), "Feature Structures not equal: %n%s%n%s", fs1, fs2);
+  }
+  
+  /**
+   * 
+   * @param fs1
+   * @param fs2
+   * @param visited when called for sorting FSs, is sortCompareSeen(cleared); 
+   *                when called for comparing for equality, holds FSs already compared in other views
+   * @return
+   */
+  private int compare1(TOP fs1, TOP fs2, Set<TOP> visited) {
+    if (!isSortUse) {  // only do null check for non- sort use
+      if (fs1 == null && fs2 == null) {
+        return 0;
+      }
+      if (fs1 == null) return chkEqual(-1, "fs1 was null and fs2 was not");
+      if (fs2 == null) return chkEqual(1,  "fs2 was null and fs1 was not");
     }
-    if (fs1 == null) return chkEqual(-1, "fs1 was null and fs2 was not");
-    if (fs2 == null) return chkEqual(1,  "fs2 was null and fs1 was not");
     
-    if (!visited.add(fs1)) {
+    boolean wasPresent1 = !visited.add(fs1);
+    boolean wasPresent2 = !visited.add(fs2);
+    
+    if (wasPresent1 && wasPresent2) {
       return 0;  // already checked and found equal
     }
+    
+    if (!wasPresent1 && !wasPresent2) {
+      int r;
+      TypeImpl t1, t2;
+      if (0 != (r = compStr((t1 = (TypeImpl) fs1.getType()).getName(), (t2 = (TypeImpl) fs2.getType()).getName()))) {
+        return chkEqual(r, "Types of FSs are different: Type1 = %s, Type2 = %s", t1, t2);
+      }
+      // types are the same
+      
+      if (CAS.TYPE_NAME_SOFA.equals(t1.getName())) {
+        if (isSortUse) {
+          return Integer.compare(((Sofa)fs1).getSofaNum(), ((Sofa)fs2).getSofaNum());
+        }
+        return 0;  // skip comparing sofa so this routine can be used for cas copier testing
+      }
+
+      if (t1.isArray()) {
+        final int len1 = ((CommonArray)fs1).size();
+        if (0 != (r = Integer.compare(len1, ((CommonArray)fs2).size()))) {
+          return r;
+        }
+        
+        SlotKind kind = t1.getComponentSlotKind();
         
-    int r;
-    Type t1, t2;
-    if (0 != (r = compStr((t1 = fs1.getType()).getName(), (t2 = fs2.getType()).getName()))) {
-      return chkEqual(r, "Types of FSs are different: Type1 = %s, Type2 = %s", t1, t2);
+        switch(kind) {
+        case Slot_BooleanRef: return compareAllArrayElements(len1, i -> Boolean.compare(((BooleanArray  )fs1).get(i), ((BooleanArray)fs2).get(i)), "Miscompare Boolean Arrays %n%s%n%s", fs1, fs2);
+        case Slot_ByteRef:    return compareAllArrayElements(len1, i -> Byte   .compare(((ByteArray     )fs1).get(i), ((ByteArray   )fs2).get(i)), "Miscompare Byte Arrays %n%s%n%s"   , fs1, fs2);
+        case Slot_ShortRef:   return compareAllArrayElements(len1, i -> Short  .compare(((ShortArray    )fs1).get(i), ((ShortArray  )fs2).get(i)), "Miscompare Short Arrays %n%s%n%s"  , fs1, fs2);
+        case Slot_Int:     return compareAllArrayElements   (len1, i -> Integer.compare(((IntegerArray  )fs1).get(i), ((IntegerArray)fs2).get(i)), "Miscompare Integer Arrays %n%s%n%s", fs1, fs2);
+        case Slot_LongRef:    return compareAllArrayElements(len1, i -> Long   .compare(((LongArray     )fs1).get(i), ((LongArray   )fs2).get(i)), "Miscompare Long Arrays %n%s%n%s", fs1, fs2);
+        case Slot_Float:   return compareAllArrayElements   (len1, i -> Integer.compare(Float.floatToRawIntBits   (((FloatArray )fs1).get(i)), 
+                                                                                        Float.floatToRawIntBits   (((FloatArray )fs2).get(i))),    "Miscompare Float Arrays %n%s%n%s", fs1, fs2);
+        case Slot_DoubleRef:  return compareAllArrayElements(len1, i -> Long   .compare(Double.doubleToRawLongBits(((DoubleArray)fs1).get(i)), 
+                                                                                        Double.doubleToRawLongBits(((DoubleArray)fs2).get(i))),    "Miscompare Double Arrays %n%s%n%s", fs1, fs2);
+        case Slot_HeapRef: return    compareAllArrayElements(len1, i ->        compare1(((FSArray       )fs1).get(i), ((FSArray     )fs2).get(i), visited), "Miscompare FS Arrays %n%s%n%s", fs1, fs2);
+        case Slot_StrRef:  return    compareAllArrayElements(len1, i -> Misc.compareStrings(((StringArray   )fs1).get(i), ((StringArray )fs2).get(i)), "Miscompare String Arrays %n%s%n%s", fs1, fs2);
+        default: 
+          assert(false); return 0;  // only to avoid a compile error
+        }        
+      }
+      
+      ts = fs1.getCAS().getTypeSystem();
+      return compareFeatures(fs1, fs2, t1.getFeatureImpls(), t2.getFeatureImpls(), visited);           
     }
-    // types are the same
     
-    if (CAS.TYPE_NAME_SOFA.equals(t1.getName())) {
-      return 0;  // skip comparing sofa so this routine can be used for cas copier testing
+    // getting here: one was already traversed, the other not.  Possible use case:
+    //   fs1 is a list with a loop; fs2 is a list without a loop
+    //   arbitrarily return the one with a loop first
+    
+    if (fs1 instanceof EmptyList) { 
+      return 0;  // allow different or shared EmptyList instances to compare equal
+      // because some deserializers or user code can create them as shared or not
     }
-
-    ts = fs1.getCAS().getTypeSystem();
-    casStringType = ts.getType(CAS.TYPE_NAME_STRING);
-    return compareFeatures(fs1, fs2, t1.getFeatures(), t2.getFeatures(), visited);     
+    if (wasPresent1) {
+      return chkEqual(-1, "First element had a ref loop %s%n, second didn't so far %s", fs1, fs2);
+    }
+    return chkEqual(-1, "Second element had a ref loop %s%n, first didn't so far %s", fs2, fs1);
+    
+  }
+  
+  private int compareAllArrayElements(final int len, IntUnaryOperator c, String msg, TOP fs1, TOP fs2) {
+    for (int i = 0; i < len; i++) {
+      int r = chkEqual(c.applyAsInt(i), String.format(msg, fs1, fs2));
+      if (0 != r) {
+        return r;
+      }
+    }
+    return 0;
   }
+
     
   private int compareFeatures(
-      FeatureStructure fs1, FeatureStructure fs2, 
-      List<Feature> feats1, List<Feature> feats2,
-      Set<FeatureStructure> visited) {
+      TOP fs1, TOP fs2, 
+      List<FeatureImpl> feats1, List<FeatureImpl> feats2,
+      Set<TOP> visited) {
     
     IntVector fsCompares = new IntVector(2);
     for (int i = 0; i < feats1.size(); i++) {
@@ -193,7 +286,7 @@ public class CasComparer {
       // range types are the same
       
       //String or subtypes of it
-      if (ts.subsumes(casStringType, rangeType)) {  
+      if (rangeType.isStringOrStringSubtype()) {  
         if (0 != (r = compStr(fs1.getStringValue(feat1), fs2.getStringValue(feat2)))) {
           return chkEqual(r, "String features miscompare, s1 = %s, s2 = %s", fs1.getStringValue(feat1), fs2.getStringValue(feat2));
         }
@@ -257,7 +350,7 @@ public class CasComparer {
   }
       
   private int compLong(long v1, long v2) {
-    return chkEqual(Long.compare(v1, v2), "Intregal format number miscompare,  v1 = %,d v2 = %,d", v1, v2);
+    return chkEqual(Long.compare(v1, v2), "Integral format number miscompare,  v1 = %,d v2 = %,d", v1, v2);
   }
 
   private int compDouble(double v1, double v2) {
@@ -275,13 +368,13 @@ public class CasComparer {
   }
   
   /* 
-   * When populating, skip items already visted and compared in other views
+   * When populating, skip items already visted and compared in other views (but always include sofas)
    */
-  private static List<FeatureStructure> populate(FSIterator<FeatureStructure> it, Set<FeatureStructure> visited) {
-    List<FeatureStructure> s = new ArrayList<FeatureStructure>();
+  private static List<TOP> populate(FSIterator<TOP> it, Set<TOP> visited) {
+    List<TOP> s = new ArrayList<TOP>();
     while (it.hasNext()) {
-      FeatureStructure fs = it.next();
-      if (!(fs instanceof SofaFS) && !visited.contains(fs)) {
+      TOP fs = it.next();
+      if (!(fs instanceof Sofa) && !visited.contains(fs)) {
         s.add(fs);
       }
     }
@@ -289,17 +382,17 @@ public class CasComparer {
   }
   
   // returns true if the items were arrays
-  private int compareArrayFSs(FeatureStructure arrayFS1fs, Feature feat1, FeatureStructure arrayFS2fs, Feature feat2, Set<FeatureStructure> visited) {
+  private int compareArrayFSs(TOP arrayFS1fs, Feature feat1, TOP arrayFS2fs, Feature feat2, Set<TOP> visited) {
   
-    CommonArrayFS arrayFS1 = (CommonArrayFS)arrayFS1fs.getFeatureValue(feat1);
-    CommonArrayFS arrayFS2 = (CommonArrayFS)arrayFS2fs.getFeatureValue(feat2);
+    CommonArray arrayFS1 = (CommonArray)arrayFS1fs.getFeatureValue(feat1);
+    CommonArray arrayFS2 = (CommonArray)arrayFS2fs.getFeatureValue(feat2);
     
     if (null == arrayFS1 && null == arrayFS2)return 0; // are equal
     if (null == arrayFS1) return chkEqual(-1,  "Array FS1 is null, but Array FS2 is not");
     if (null == arrayFS2) return chkEqual(-1,  "Array FS2 is null, but Array FS1 is not");
 
     int r, len;
-    if (0 != (r = compLong(len = arrayFS1.size(), arrayFS2.size()))) {
+    if (0 != (r = Integer.compare(len = arrayFS1.size(), arrayFS2.size()))) {
       return chkEqual(r, "ArrayFSs are different sizes, fs1 size is %d, fs2 size is %d", arrayFS1.size(), arrayFS2.size());
     }
     // are same size
@@ -309,7 +402,7 @@ public class CasComparer {
     switch(getArrayType(arrayFS1)) {
     case FS:
       for (int j = 0; j < len; j++) {
-        if (0 != (r = compare1(((ArrayFS)arrayFS1).get(j), ((ArrayFS)arrayFS2).get(j), visited))) return r;
+        if (0 != (r = compare1(((FSArray)arrayFS1).get(j), ((FSArray)arrayFS2).get(j), visited))) return r;
       }
       break;
     case BOOLEAN:
@@ -358,7 +451,7 @@ public class CasComparer {
     return 0;  // all were equal
   }
     
-  private ARRAY_TYPE getArrayType(CommonArrayFS c) {
+  private ARRAY_TYPE getArrayType(CommonArray c) {
     if (c instanceof ArrayFS) return ARRAY_TYPE.FS; 
     if (c instanceof StringArrayFS) return ARRAY_TYPE.STRING; 
     if (c instanceof BooleanArrayFS) return ARRAY_TYPE.BOOLEAN; 
@@ -371,7 +464,7 @@ public class CasComparer {
     return null;
   }
   
-  private int validateSameType(CommonArrayFS a1, CommonArrayFS a2) {
+  private int validateSameType(CommonArray a1, CommonArray a2) {
     if (a1.getClass() == a2.getClass()) {
       return 0;
     }