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 2015/11/24 21:52:03 UTC

svn commit: r1716257 - in /uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima: cas/impl/ util/

Author: schor
Date: Tue Nov 24 20:52:03 2015
New Revision: 1716257

URL: http://svn.apache.org/viewvc?rev=1716257&view=rev
Log:
[UIMA-4663] update CasCopier. 

Modified:
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
    uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java?rev=1716257&r1=1716256&r2=1716257&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java Tue Nov 24 20:52:03 2015
@@ -86,6 +86,7 @@ import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.cas.AnnotationBase;
 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.EmptyFSList;
 import org.apache.uima.jcas.cas.EmptyFloatList;
@@ -3195,6 +3196,14 @@ public class CASImpl extends AbstractCas
     return (T) docAnnot;    
   }
   
+  public <T extends Annotation> T createDocumentAnnotationNoRemoveNoIndex(int length) {
+    final TypeSystemImpl ts = getTypeSystemImpl();
+    AnnotationFS docAnnot = createAnnotation(ts.docType, 0, length);
+    docAnnot.setStringValue(ts.langFeat, CAS.DEFAULT_LANGUAGE_NAME);
+    addFsToIndexes(docAnnot);
+    return (T) docAnnot;    
+  }
+  
   
   public int ll_createDocumentAnnotation(int length) {
     final int fsRef = ll_createDocumentAnnotationNoIndex(0, length);
@@ -3252,7 +3261,7 @@ public class CASImpl extends AbstractCas
     }
   }
   
-  private <T extends Annotation> T getDocumentAnnotationNoCreate() {
+  public <T extends Annotation> T getDocumentAnnotationNoCreate() {
     if (this == this.svd.baseCAS) {
       // base CAS has no document
       return null;
@@ -3337,7 +3346,7 @@ public class CASImpl extends AbstractCas
   }
 
   public Sofa getSofa() {
-    return (Sofa) mySofaRef;
+    return mySofaRef;
   }
   
   /**
@@ -3772,7 +3781,7 @@ public class CASImpl extends AbstractCas
            (rangeCode == CasSerializerSupport.TYPE_CLASS_STRINGLIST) ? getEmptyStringList() :
                                                                        getEmptyFSList();
   }
-    
+  
   /**
    * Get an empty list from the type code of a list
    * @param rangeCode
@@ -3799,4 +3808,55 @@ public class CASImpl extends AbstractCas
   public TypeImpl getTypeImplFromJCasTypeIndex(int typeIndexID) {
     return getTypeSystemImpl().getJCasRegisteredType(typeIndexID);
   }
+  
+  /**
+   * Copies a feature, from one fs to another
+   *   FSs may belong to different CASes, but must have the same type system
+   *   Features must have compatible ranges
+   * @param fsSrc source FS
+   * @param fi Feature to copy
+   * @param fsTgt target FS
+   */
+  public static void copyFeature(TOP fsSrc, FeatureImpl fi, TOP fsTgt) {
+    if (!copyFeatureExceptFsRef(fsSrc, fi, fsTgt, fi)) {
+      if (!fi.isAnnotBaseSofaRef) {
+        fsTgt.setFeatureValue(fi, fsSrc.getFeatureValue(fi));
+      }
+    }
+  }
+  
+  /**
+   * Copies a feature from one fs to another
+   * FSs may be in different type systems 
+   *   Doesn't copy a feature ref, but instead returns false.  
+   *     This is because feature refs can't cross CASes
+   * @param fsSrc source FS
+   * @param fiSrc feature in source to copy
+   * @param fsTgt target FS
+   * @param fiTgt feature in target to set
+   * @return false if feature is an fsRef
+   */
+  public static boolean copyFeatureExceptFsRef(TOP fsSrc, FeatureImpl fiSrc, TOP fsTgt, FeatureImpl fiTgt) {
+    switch (fiSrc.getRangeImpl().getCode()) {
+    case TypeSystemImpl.booleanTypeCode    : fsTgt.setBooleanValue(   fiTgt, fsSrc.getBooleanValue(   fiSrc)); break;
+    case TypeSystemImpl.byteTypeCode       : fsTgt.setByteValue(      fiTgt, fsSrc.getByteValue(      fiSrc)); break;
+    case TypeSystemImpl.shortTypeCode      : fsTgt.setShortValue(     fiTgt, fsSrc.getShortValue(     fiSrc)); break;
+    case TypeSystemImpl.intTypeCode        : fsTgt.setIntValue(       fiTgt, fsSrc.getIntValue(       fiSrc)); break;
+    case TypeSystemImpl.longTypeCode       : fsTgt.setLongValue(      fiTgt, fsSrc.getLongValue(      fiSrc)); break;
+    case TypeSystemImpl.floatTypeCode      : fsTgt.setFloatValue(     fiTgt, fsSrc.getFloatValue(     fiSrc)); break;
+    case TypeSystemImpl.doubleTypeCode     : fsTgt.setDoubleValue(    fiTgt, fsSrc.getDoubleValue(    fiSrc)); break;
+    case TypeSystemImpl.stringTypeCode     : fsTgt.setStringValue(    fiTgt, fsSrc.getStringValue(    fiSrc)); break;
+    case TypeSystemImpl.javaObjectTypeCode : fsTgt.setJavaObjectValue(fiTgt, fsSrc.getJavaObjectValue(fiSrc)); break;
+               // skip setting sofaRef - it's final and can't be set
+    default: return false;
+    } // end of switch
+    return true;
+  }
+
+  public static CommonArray copyArray(TOP srcArray) {
+    CommonArray srcCA = (CommonArray) srcArray;
+    CommonArray copy = (CommonArray) srcArray._casView.createArray(srcArray._typeImpl, srcCA.size());
+    copy.copyValuesFrom(srcCA); 
+    return copy;
+  }
 }

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl.java?rev=1716257&r1=1716256&r2=1716257&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureImpl.java Tue Nov 24 20:52:03 2015
@@ -21,6 +21,7 @@ package org.apache.uima.cas.impl;
 
 import java.util.List;
 
+import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
@@ -48,7 +49,10 @@ public class FeatureImpl implements Feat
 //  private final TypeSystemImpl ts;
 
   private final boolean isMultipleRefsAllowed;
-  
+  /**
+   * true for the feature which is the AnnotationBase sofa reference.
+   */
+  public final boolean isAnnotBaseSofaRef;
   private final String shortName;     //         feat
     
   protected Object jcasGetter;  // null or the functional interface to call to get this feature
@@ -57,7 +61,17 @@ public class FeatureImpl implements Feat
   private final SlotKind slotKind;
   /** type class of the range, including CasSerializer List constants */
   public  final int rangeTypeClass; // set from CasSerializerSupport.classifyType
-    
+
+  private FeatureImpl() {
+    featureCode = 0;
+    isInInt = false;
+    rangeType = null;
+    isMultipleRefsAllowed = false;
+    isAnnotBaseSofaRef = false;
+    shortName = null;
+    slotKind = null;
+    rangeTypeClass = 0;
+  }
 
   FeatureImpl(TypeImpl typeImpl, String shortName, TypeImpl rangeType, TypeSystemImpl tsi, boolean isMultipleRefsAllowed, SlotKind slotKind) {
 //  this.code = code;
@@ -69,6 +83,7 @@ public class FeatureImpl implements Feat
   this.slotKind = slotKind;
   this.shortName = shortName;
   this.isMultipleRefsAllowed = isMultipleRefsAllowed;
+  this.isAnnotBaseSofaRef = (highestDefiningType.getCode() == TypeSystemImpl.annotBaseTypeCode) && shortName.equals(CAS.FEATURE_BASE_NAME_SOFA);
   this.isInInt = tsi.isInInt(rangeType);
   this.rangeTypeClass = CasSerializerSupport.classifyType(rangeType);
   typeImpl.addFeature(this);  // might throw if existing feature with different range
@@ -222,4 +237,6 @@ public class FeatureImpl implements Feat
     TypeImpl_stringSubtype ti = (TypeImpl_stringSubtype) getRangeImpl();
     ti.validateIsInAllowedValues(v);
   }
+  
+  public final static FeatureImpl singleton = new FeatureImpl();
 }

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java?rev=1716257&r1=1716256&r2=1716257&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java Tue Nov 24 20:52:03 2015
@@ -111,7 +111,7 @@ public class FeatureStructureImplC imple
    */
   protected final CASImpl _casView;  
   
-  protected final TypeImpl _typeImpl;
+  public final TypeImpl _typeImpl;
   
   // Called only to generate a dummy value for the REMOVED flag in bag indexes
 
@@ -223,12 +223,21 @@ public class FeatureStructureImplC imple
   @Override
   public final int id() {return _id; };
   
-  // backwards compatibility
+  /**
+   * Returns the UIMA TypeImpl value
+   */
   @Override
   public Type getType() {
     return _typeImpl;
   }
   
+  public TypeImpl getTypeImpl() {
+    return _typeImpl;
+  }
+  
+  /**
+   * @return the UIMA TypeImpl for this Feature Structure
+   */
   public int _getTypeCode() {
     return _typeImpl.getCode();
   }
@@ -667,31 +676,14 @@ public class FeatureStructureImplC imple
       return (FeatureStructureImplC) copy;
     }
     
-    FeatureStructureImplC fs = _casView.createFS(_typeImpl);
+    TOP fs = _casView.createFS(_typeImpl);
+    TOP srcFs = (TOP) this;
     
     final int sofaFeatCode = TypeSystemImpl.annotBaseSofaFeatCode;
 
     /* copy all the feature values except the sofa ref which is already set as part of creation */
     for (Feature feat : _typeImpl.getFeatures()) {
-      final FeatureImpl fi = (FeatureImpl) feat;
-      if (fi.getCode() == sofaFeatCode) continue;
-        
-      switch (fi.getRangeImpl().getCode()) {
-      case TypeSystemImpl.booleanTypeCode : fs.setBooleanValue(feat, getBooleanValue(feat)); break;
-      case TypeSystemImpl.byteTypeCode : fs.setByteValue(feat, getByteValue(feat)); break;
-      case TypeSystemImpl.shortTypeCode : fs.setShortValue(feat, getShortValue(feat)); break;
-      case TypeSystemImpl.intTypeCode : fs.setIntValue(feat, getIntValue(feat)); break;
-      case TypeSystemImpl.longTypeCode : fs.setLongValue(feat, getLongValue(feat)); break;
-      case TypeSystemImpl.floatTypeCode : fs.setFloatValue(feat, getFloatValue(feat)); break;
-      case TypeSystemImpl.doubleTypeCode : fs.setDoubleValue(feat, getDoubleValue(feat)); break;
-      case TypeSystemImpl.stringTypeCode : fs.setStringValue(feat, getStringValue(feat)); break;
-      default:  // for javaObject and fs ref
-        if (fi.getRangeImpl().isRefType) {
-          fs.setFeatureValue(feat, getFeatureValue(feat));
-        } else {
-          fs.setJavaObjectValue(feat, getJavaObjectValue(feat));
-        }
-      } // end of switch
+      _casView.copyFeature(srcFs, feat, fs, feat);
     }   // end of for loop
     return fs;
   }

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java?rev=1716257&r1=1716256&r2=1716257&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeImpl.java Tue Nov 24 20:52:03 2015
@@ -102,7 +102,7 @@ public class TypeImpl implements Type, C
   /**
    * false for primitives, strings, string subtypes, and JavaObjects
    */
-  protected final boolean isRefType;  // not a primitive, can be a FeatureStructure in the CAS, added to indexes etc.
+  public final boolean isRefType;  // not a primitive, can be a FeatureStructure in the CAS, added to indexes etc.
   
   
   /* ***************** type hierarchy *****************/
@@ -126,6 +126,24 @@ public class TypeImpl implements Type, C
   int highestIntOffset = -1;  
   int highestRefOffset = -1;  
   
+  private TypeImpl() {
+    this.name = null;
+    this.shortName = null;
+    this.superType = null;
+    
+    this.isInheritanceFinal = false;
+    this.isFeatureFinal = false;
+    this.isLongOrDouble = false;
+    this.isCreatableAndNotBuiltinArray = false;
+    this.tsi = null;
+    this.typeCode = 0; 
+    
+    this.isRefType = false;
+    this.javaClass = null;
+    getter_funct_intfc_class = null;
+    setter_funct_intfc_class = null;
+  }
+  
   /**
    * Create a new type. This should only be done by a <code>TypeSystemImpl</code>.
    */
@@ -406,7 +424,7 @@ public class TypeImpl implements Type, C
     return new ArrayList<>(staticMergedFeatures.values());
   }
   
-  Collection<FeatureImpl> getFeatureImpls() {
+  public Collection<FeatureImpl> getFeatureImpls() {
     return staticMergedFeatures.values();
   }
   
@@ -681,4 +699,6 @@ public class TypeImpl implements Type, C
     this.javaClass = javaClass;
   }
   
+  public final static TypeImpl singleton = new TypeImpl();
+  
 }

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java?rev=1716257&r1=1716256&r2=1716257&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/TypeSystemImpl.java Tue Nov 24 20:52:03 2015
@@ -71,7 +71,6 @@ import org.apache.uima.jcas.cas.DoubleAr
 import org.apache.uima.jcas.cas.EmptyFSList;
 import org.apache.uima.jcas.cas.EmptyFloatList;
 import org.apache.uima.jcas.cas.EmptyIntegerList;
-import org.apache.uima.jcas.cas.EmptyList;
 import org.apache.uima.jcas.cas.EmptyStringList;
 import org.apache.uima.jcas.cas.FSArray;
 import org.apache.uima.jcas.cas.FSList;

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java?rev=1716257&r1=1716256&r2=1716257&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java Tue Nov 24 20:52:03 2015
@@ -18,26 +18,31 @@
  */
 package org.apache.uima.util;
 
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.IdentityHashMap;
 import java.util.Iterator;
+import java.util.Map;
 
 import org.apache.uima.UIMARuntimeException;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.CASRuntimeException;
-import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.SofaFS;
-import org.apache.uima.cas.Type;
 import org.apache.uima.cas.impl.CASImpl;
-import org.apache.uima.cas.impl.FSIndexRepositoryImpl;
 import org.apache.uima.cas.impl.FeatureImpl;
-import org.apache.uima.cas.impl.FeatureStructureImpl;
-import org.apache.uima.cas.impl.LowLevelIterator;
 import org.apache.uima.cas.impl.TypeImpl;
 import org.apache.uima.cas.impl.TypeSystemImpl;
-import org.apache.uima.internal.util.Int2IntHashMap;
-import org.apache.uima.internal.util.IntVector;
+import org.apache.uima.internal.util.Int2ObjListMap;
 import org.apache.uima.internal.util.PositiveIntSet;
 import org.apache.uima.internal.util.PositiveIntSet_impl;
+import org.apache.uima.jcas.cas.CommonArray;
+import org.apache.uima.jcas.cas.CommonPrimitiveArray;
+import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.Sofa;
+import org.apache.uima.jcas.cas.TOP;
+import org.apache.uima.jcas.tcas.Annotation;
 
 /**
  * Utility class for doing deep copies of FeatureStructures from one CAS to another. To handle cases
@@ -60,114 +65,124 @@ import org.apache.uima.internal.util.Pos
  */
 public class CasCopier {
   
-  private static final int FRC_SKIP = 0;  // is the default, must be 0
-  private static final int FRC_STRING = 1;
-  private static final int FRC_LONG = 2;
-  private static final int FRC_DOUBLE = 3;
-  private static final int FRC_INT_LIKE = 4;
-  private static final int FRC_REF = 5;
-  
-  private static final int K_SRC_FEAT_OFFSET = 0;
-  private static final int K_TGT_FEAT_CODE = 1;
-  
-  private class TypeInfo {
-    final int[] codesAndOffsets;  // indexed with count * 2
-    final byte[] frc;
-    final int tgtTypeCode;
-        
-    TypeInfo(int srcTypeCode) {    
-
-      if (tgtTsi == srcTsi) {
-        tgtTypeCode = srcTypeCode;
-      } else {
-        Type srcType = srcTsi.ll_getTypeForCode(srcTypeCode);
-        Type tgtType = tgtTsi.getType(srcType.getName());
-        if (tgtType == null) {
-          // If in lenient mode, do not act on this FS. Instead just
-          // return (null) to the caller and let the caller deal with this case.
-          if (lenient) {
-            tgtTypeCode = 0;
-          } else {
-            throw new UIMARuntimeException(UIMARuntimeException.TYPE_NOT_FOUND_DURING_CAS_COPY,
-                new Object[] { srcType.getName() });
-          }
-        } else {
-          tgtTypeCode = tgtTsi.ll_getCodeForType(tgtType);
-        }
-      }
-                  
-      int[] srcFeatCodes = srcTsi.ll_getAppropriateFeatures(srcTypeCode);
-      int arrayLength = srcFeatCodes.length << 1;
-      
-      codesAndOffsets = new int[arrayLength];
-      frc = new byte[srcFeatCodes.length];
-
-      if (srcTsi == tgtTsi) {
-        for (int i = 0; i < srcFeatCodes.length; i++) {
-          final int srcFeatCode = srcFeatCodes[i];
-          Feature srcFeat = srcTsi.ll_getFeatureForCode(srcFeatCode);
-          setRangeClass((TypeImpl) srcFeat.getRange(), i);
-          final int i2 = i << 1;
-          codesAndOffsets[i2 + K_SRC_FEAT_OFFSET] = originalSrcCasImpl.getFeatureOffset(srcFeatCode);
-          codesAndOffsets[i2 + K_TGT_FEAT_CODE] = srcFeatCodes[i];
-        }
-      } else {        
-        for (int i = 0; i < srcFeatCodes.length; i++) { 
-         final int srcFeatCode = srcFeatCodes[i];
-         Feature srcFeat = srcTsi.ll_getFeatureForCode(srcFeatCode);
-          String srcFeatName = srcFeat.getName();
-          Feature tgtFeat = tgtTsi.getFeatureByFullName(srcFeatName);
-          if (tgtFeat == null) {
-            // If in lenient mode, ignore this feature and move on to the next
-            // feature in this FS (if one exists)
-            if (lenient) {
-              continue; // Ignore this feature in the source CAS since it doesn't exist in
-                        // in the target CAS.
-            } else {
-              throw new UIMARuntimeException(UIMARuntimeException.FEATURE_NOT_FOUND_DURING_CAS_COPY,
-                  new Object[] { srcFeatName });
-            }
-          } else {
-            final int i2 = i << 1;
-            int tgtFeatCode = ((FeatureImpl)tgtFeat).getCode();
-            codesAndOffsets[i2 + K_SRC_FEAT_OFFSET] = originalSrcCasImpl.getFeatureOffset(srcFeatCode);
-            codesAndOffsets[i2 + K_TGT_FEAT_CODE] = tgtFeatCode;
-          }
-
-          TypeImpl srcRangeType = (TypeImpl) srcFeat.getRange();
-          
-          // verify range types of features have the same name
-          if (!srcRangeType.getName().equals(
-               tgtFeat.getRange().getName())) {
-            throw new UIMARuntimeException(UIMARuntimeException.COPY_CAS_RANGE_TYPE_NAMES_NOT_EQUAL, 
-                new Object[] {srcFeatName, srcFeat.getRange().getName(), tgtFeat.getRange().getName()});
-          }
-          
-          setRangeClass(srcRangeType, i);
-        }
-      }        
-    }
-    
-    void setRangeClass(TypeImpl srcRangeType, int i) {
-      if (srcTsi.ll_subsumes(srcStringTypeCode, srcRangeType.getCode())) {
-        frc[i] = FRC_STRING;
-      } else if (srcRangeType == srcTsi.intType || 
-          srcRangeType == srcTsi.floatType ||
-          srcRangeType == srcTsi.booleanType ||
-          srcRangeType == srcTsi.byteType ||
-          srcRangeType == srcTsi.shortType) {
-        frc[i] = FRC_INT_LIKE;
-      } else if (srcRangeType == srcTsi.longType) {
-        frc[i] = FRC_LONG;
-      } else if (srcRangeType == srcTsi.doubleType) {
-        frc[i] = FRC_DOUBLE;
-      } else {
-        frc[i] = FRC_REF;
-      }
-    }
-  }
-    
-  private final TypeInfo[] tInfoArray;
+  private static final TypeImpl MISSING_TYPE = TypeImpl.singleton;
+  private static final FeatureImpl MISSING_FEAT = FeatureImpl.singleton;
+  
+//  private static final int FRC_SKIP = 0;  // is the default, must be 0
+//  private static final int FRC_STRING = 1;
+//  private static final int FRC_LONG = 2;
+//  private static final int FRC_DOUBLE = 3;
+//  private static final int FRC_INT_LIKE = 4;
+//  private static final int FRC_REF = 5;
+//  
+//  private static final int K_SRC_FEAT_OFFSET = 0;
+//  private static final int K_TGT_FEAT_CODE = 1;
+  
+//  /**
+//   * TypeInfo stores the mapping from the source to the target type system
+//   * It is set up once at the start, to avoid looking up this correspondence (by name) repeatedly 
+//   */
+//  private class TypeInfo {
+//    final int[] codesAndOffsets;  // indexed with count * 2
+//    /**
+//     * Feature Range class:  String, Long, double, int-like, ref, or skip for all others
+//     */
+//    final byte[] frc;
+//    final int tgtTypeCode;
+//        
+//    TypeInfo(int srcTypeCode) {    
+//
+//      if (tgtTsi == srcTsi) {
+//        tgtTypeCode = srcTypeCode;
+//      } else {
+//        Type srcType = srcTsi.ll_getTypeForCode(srcTypeCode);
+//        Type tgtType = tgtTsi.getType(srcType.getName());
+//        if (tgtType == null) {
+//          // If in lenient mode, do not act on this FS. Instead just
+//          // return (null) to the caller and let the caller deal with this case.
+//          if (lenient) {
+//            tgtTypeCode = 0;
+//          } else {
+//            throw new UIMARuntimeException(UIMARuntimeException.TYPE_NOT_FOUND_DURING_CAS_COPY,
+//                new Object[] { srcType.getName() });
+//          }
+//        } else {
+//          tgtTypeCode = tgtTsi.ll_getCodeForType(tgtType);
+//        }
+//      }
+//                  
+//      int[] srcFeatCodes = srcTsi.ll_getAppropriateFeatures(srcTypeCode);
+//      int arrayLength = srcFeatCodes.length << 1;
+//      
+//      codesAndOffsets = new int[arrayLength];
+//      frc = new byte[srcFeatCodes.length];
+//
+//      if (srcTsi == tgtTsi) {
+//        for (int i = 0; i < srcFeatCodes.length; i++) {
+//          final int srcFeatCode = srcFeatCodes[i];
+//          Feature srcFeat = srcTsi.ll_getFeatureForCode(srcFeatCode);
+//          setRangeClass((TypeImpl) srcFeat.getRange(), i);
+//          final int i2 = i << 1;
+//          codesAndOffsets[i2 + K_SRC_FEAT_OFFSET] = originalSrcCasImpl.getFeatureOffset(srcFeatCode);
+//          codesAndOffsets[i2 + K_TGT_FEAT_CODE] = srcFeatCodes[i];
+//        }
+//      } else {        
+//        for (int i = 0; i < srcFeatCodes.length; i++) { 
+//         final int srcFeatCode = srcFeatCodes[i];
+//         Feature srcFeat = srcTsi.ll_getFeatureForCode(srcFeatCode);
+//          String srcFeatName = srcFeat.getName();
+//          Feature tgtFeat = tgtTsi.getFeatureByFullName(srcFeatName);
+//          if (tgtFeat == null) {
+//            // If in lenient mode, ignore this feature and move on to the next
+//            // feature in this FS (if one exists)
+//            if (lenient) {
+//              continue; // Ignore this feature in the source CAS since it doesn't exist in
+//                        // in the target CAS.
+//            } else {
+//              throw new UIMARuntimeException(UIMARuntimeException.FEATURE_NOT_FOUND_DURING_CAS_COPY,
+//                  new Object[] { srcFeatName });
+//            }
+//          } else {
+//            final int i2 = i << 1;
+//            int tgtFeatCode = ((FeatureImpl)tgtFeat).getCode();
+//            codesAndOffsets[i2 + K_SRC_FEAT_OFFSET] = originalSrcCasImpl.getFeatureOffset(srcFeatCode);
+//            codesAndOffsets[i2 + K_TGT_FEAT_CODE] = tgtFeatCode;
+//          }
+//
+//          TypeImpl srcRangeType = (TypeImpl) srcFeat.getRange();
+//          
+//          // verify range types of features have the same name
+//          if (!srcRangeType.getName().equals(
+//               tgtFeat.getRange().getName())) {
+//            throw new UIMARuntimeException(UIMARuntimeException.COPY_CAS_RANGE_TYPE_NAMES_NOT_EQUAL, 
+//                new Object[] {srcFeatName, srcFeat.getRange().getName(), tgtFeat.getRange().getName()});
+//          }
+//          
+//          setRangeClass(srcRangeType, i);
+//        }
+//      }        
+//    }
+//    
+//    void setRangeClass(TypeImpl srcRangeType, int i) {
+//      if (srcTsi.ll_subsumes(srcStringTypeCode, srcRangeType.getCode())) {
+//        frc[i] = FRC_STRING;
+//      } else if (srcRangeType == srcTsi.intType || 
+//          srcRangeType == srcTsi.floatType ||
+//          srcRangeType == srcTsi.booleanType ||
+//          srcRangeType == srcTsi.byteType ||
+//          srcRangeType == srcTsi.shortType) {
+//        frc[i] = FRC_INT_LIKE;
+//      } else if (srcRangeType == srcTsi.longType) {
+//        frc[i] = FRC_LONG;
+//      } else if (srcRangeType == srcTsi.doubleType) {
+//        frc[i] = FRC_DOUBLE;
+//      } else {
+//        frc[i] = FRC_REF;
+//      }
+//    }
+//  }
+//    
+//  private final TypeInfo[] tInfoArray;
   
   // these next are called original, as they are the views used to create the CasCopier instance
   private final CAS originalSrcCas;
@@ -187,15 +202,18 @@ public class CasCopier {
   private final TypeSystemImpl srcTsi;
   private final TypeSystemImpl tgtTsi;
   
-  private final TypeImpl srcStringType;
-  private final int srcStringTypeCode;
+  private final Int2ObjListMap<TypeImpl>    src2TgtType = new Int2ObjListMap<>();  
+  private final Int2ObjListMap<FeatureImpl> src2TgtFeat = new Int2ObjListMap<>();
+  
+//  
+//  private final TypeImpl srcStringType;
   
   /**
    * true if the copyCasView api was used, and the target view name corresponding to the source view name is changed
    */
   private boolean isChangeViewName = false;
   
-  private int srcCasDocumentAnnotation = 0;
+  private Annotation srcCasDocumentAnnotation = null;
 //  /**
 //   * The source view name - may be null if the view is of the base CAS
 //   */
@@ -206,9 +224,7 @@ public class CasCopier {
 //   */
 //  private String mTgtCasViewName;
   
-  final private Feature mDestSofaFeature;
-  final private int mDestSofaFeatureCode;
-  final private int srcSofaTypeCode;
+//  final private Feature mDestSofaFeature;
   
   final private boolean lenient; //true: ignore feature structures and features that are not defined in the destination CAS
 
@@ -217,16 +233,12 @@ public class CasCopier {
    * Target not set for DocumentAnnotation or SofaFSs
    * Target not set if lenient specified and src type isn't in target
    */
-  final private Int2IntHashMap mFsMap = new Int2IntHashMap();
+  final private Map<TOP, TOP> mFsMap = new IdentityHashMap<>();
   
   /**
-   * feature structures whose slots need copying are put on this list, together with their source
-   * as pairs of ints.
-   *   First int is the target Cas ref
-   *   Second int is the source Cas ref
-   * List is operated as a stack, from the end, for efficiency
+   * Deferred calls to copy Features of a FS
    */
-  private IntVector fsToDo = new IntVector();
+  final private Deque<Runnable> fsToDo = new ArrayDeque<>();
 
 
   /**
@@ -272,14 +284,12 @@ public class CasCopier {
     srcTsi = originalSrcCasImpl.getTypeSystemImpl();
     tgtTsi = originalTgtCasImpl.getTypeSystemImpl();
     
-    tInfoArray = new TypeInfo[srcTsi.getLargestTypeCode() + 1];
+//    tInfoArray = new TypeInfo[srcTsi.getLargestTypeCode() + 1];
     
-    srcStringType = srcTsi.stringType;
-    srcStringTypeCode = srcStringType.getCode();
+//    srcStringType = srcTsi.stringType;
+//    srcStringTypeCode = srcStringType.getCode();
     
-    mDestSofaFeature = aDestCas.getTypeSystem().getFeatureByFullName(CAS.FEATURE_FULL_NAME_SOFA);
-    mDestSofaFeatureCode = ((FeatureImpl)mDestSofaFeature).getCode();
-    srcSofaTypeCode = originalSrcCasImpl.getTypeSystemImpl().sofaType.getCode();
+//    mDestSofaFeature = aDestCas.getTypeSystem().getFeatureByFullName(CAS.FEATURE_FULL_NAME_SOFA);
     this.lenient = lenient;
     
     // the next is to support the style of use where
@@ -354,7 +364,7 @@ public class CasCopier {
 //    }
     
     if (copier.originalSrcCasImpl.getBaseCAS() == copier.originalTgtCasImpl.getBaseCAS()) {
-      throw new UIMARuntimeException(UIMARuntimeException.ILLEGAL_CAS_COPY_TO_SAME_CAS, null);
+      throw new UIMARuntimeException(UIMARuntimeException.ILLEGAL_CAS_COPY_TO_SAME_CAS);
     }
     
     Iterator<CAS> viewIterator = aSrcCas.getViewIterator();
@@ -441,7 +451,7 @@ public class CasCopier {
 
   private void copyCasViewDifferentCASs(CAS aSrcCasView, CAS aTgtCasView, boolean aCopySofa) {
     if (originalSrcCasImpl.getBaseCAS() == originalTgtCasImpl.getBaseCAS()) {
-      throw new UIMARuntimeException(UIMARuntimeException.ILLEGAL_CAS_COPY_TO_SAME_CAS, null);
+      throw new UIMARuntimeException(UIMARuntimeException.ILLEGAL_CAS_COPY_TO_SAME_CAS);
     }
 
     copyCasView(aSrcCasView, aTgtCasView, aCopySofa);
@@ -490,10 +500,10 @@ public class CasCopier {
     isChangeViewName = !srcViewName.equals(tgtViewName);
 
     if ((aSrcCasView == srcCasViewImpl.getBaseCAS()) || (aTgtCasView == tgtCasViewImpl.getBaseCAS())) {
-      throw new UIMARuntimeException(UIMARuntimeException.UNSUPPORTED_CAS_COPY_TO_OR_FROM_BASE_CAS, null);
+      throw new UIMARuntimeException(UIMARuntimeException.UNSUPPORTED_CAS_COPY_TO_OR_FROM_BASE_CAS);
     }
     
-    srcCasDocumentAnnotation = 0;  // each view needs to get this once
+    srcCasDocumentAnnotation = null;  // each view needs to get this once
     
 //    mLowLevelDestCas = aTgtCasView.getLowLevelCAS();
 //    mLowLevelSrcCas = aSrcCasView.getLowLevelCAS();
@@ -507,13 +517,21 @@ public class CasCopier {
         // if the sofa doesn't exist in the target, these calls will create it
         //  (view can exist without Sofa, at least for the initial view)
         String sofaMime = sofa.getSofaMime();
-        if (srcCasViewImpl.getDocumentText() != null) {
-          aTgtCasView.setSofaDataString(srcCasViewImpl.getDocumentText(), sofaMime);
-        } else if (srcCasViewImpl.getSofaDataURI() != null) {
-          aTgtCasView.setSofaDataURI(srcCasViewImpl.getSofaDataURI(), sofaMime);
-        } else if (srcCasViewImpl.getSofaDataArray() != null) {
-          aTgtCasView.setSofaDataArray(copyFs2Fs(srcCasViewImpl.getSofaDataArray()), sofaMime);
-        }
+        String docTxt = srcCasViewImpl.getDocumentText();
+        if (docTxt != null) {
+          aTgtCasView.setSofaDataString(docTxt, sofaMime);
+        } else {
+          String sofaDataURI = srcCasViewImpl.getSofaDataURI();
+          if (sofaDataURI != null) {
+            aTgtCasView.setSofaDataURI(sofaDataURI, sofaMime);
+          } else {
+            TOP sofaDataArray = (TOP) srcCasViewImpl.getSofaDataArray();
+            if (sofaDataArray != null) {
+              aTgtCasView.setSofaDataArray(copyFs2Fs(sofaDataArray), sofaMime);
+            }
+          }
+        }  
+        
       }
     }
 
@@ -529,11 +547,11 @@ public class CasCopier {
     //   FSs when doing a full CAS copy with multiple views - the 2nd and subsequent
     //   views don't copy, but they do index.
     
-    LowLevelIterator it = ((FSIndexRepositoryImpl)(srcCasViewImpl.getIndexRepository())).ll_getAllIndexedFS(srcTsi.getTopType());
+    FSIterator<TOP> it = srcCasViewImpl.getIndexRepository().getAllIndexedFS(srcTsi.getTopType());
+//    LowLevelIterator it = ((FSIndexRepositoryImpl)(srcCasViewImpl.getIndexRepository())).ll_getAllIndexedFS(srcTsi.getTopType());
 
-    while (it.isValid()) {
-      final int fs = it.ll_get();
-      it.moveToNext();
+    while (it.hasNext()) {
+      final TOP fs = it.next();
 //    Iterator<LowLevelIndex> indexes = srcCasViewImpl.getIndexRepository().ll_getIndexes();
 //    while (indexes.hasNext()) {
 //      LowLevelIndex index = indexes.next();
@@ -541,12 +559,12 @@ public class CasCopier {
 //      while (iter.isValid()) {
 //        final int fs = iter.ll_get();
 //        iter.moveToNext();
-      if (!indexedFs.contains(fs)) {
-        final int copyOfFs = copyFs2(fs);
+      if (!indexedFs.contains(fs.id())) {
+        final TOP copyOfFs = copyFs2(fs);
         // If the lenient option is used, it's possible that no FS was
         // created (e.g., FS is not defined in the target CAS. So ignore
         // this FS in the source CAS and move on to the next FS.
-        if (lenient && copyOfFs == 0) {
+        if (lenient && copyOfFs == null) {
           continue; // Move to the next FS in the source CAS
         }
         // otherwise, won't be null (error thrown instead)
@@ -555,18 +573,19 @@ public class CasCopier {
         // if the annotations were created with the Low Level CAS API. If the
         // Sofa reference isn't set, attempting to add the FS to the indexes
         // will fail.
-        if (originalSrcCasImpl.isSubtypeOfAnnotationBaseType(originalSrcCasImpl.getTypeCode(fs))) {
-          int sofaRef = tgtCasViewImpl.ll_getRefValue(copyOfFs, mDestSofaFeatureCode);
-          if (0 == sofaRef) {
-            tgtCasViewImpl.ll_setRefValue(copyOfFs, mDestSofaFeatureCode, tgtCasViewImpl.getSofaRef());
-          }
-        }
+//        if (fs instanceof AnnotationBase) {
+//          AnnotationBase fsAb = (AnnotationBase) fs;
+//          int sofaRef = tgtCasViewImpl.ll_getRefValue(copyOfFs, mDestSofaFeatureCode);
+//          if (0 == sofaRef) {
+//            tgtCasViewImpl.ll_setRefValue(copyOfFs, mDestSofaFeatureCode, tgtCasViewImpl.getSofaRef());
+//          }
+//        }
 
         // also don't index the DocumentAnnotation (it's indexed by default)
         if (!isDocumentAnnotation(fs)) {
-          tgtCasViewImpl.ll_getIndexRepository().ll_addFS(copyOfFs);
+          tgtCasViewImpl.getIndexRepository().addFS(copyOfFs);
         }
-        indexedFs.add(fs);
+        indexedFs.add(fs.id());
       }
     }
   }
@@ -606,8 +625,8 @@ public class CasCopier {
     }
     
     // safety - insure DocumentAnnotation is tested.
-    srcCasDocumentAnnotation = 0;  
-    return copyFs2Fs(aFS);
+    srcCasDocumentAnnotation = null;  
+    return copyFs2Fs((TOP) aFS);
   }
   
   /**
@@ -618,57 +637,56 @@ public class CasCopier {
    * @param aFS a Feature Structure reference in the originalSrcCas
    * @return a Feature Structure reference in the originalTgtCas
    */
-  private int copyFs2(int aFS) {
+  private TOP copyFs2(TOP aFS) {
     
-    int copy = copyFsInner(aFS);  // doesn't copy the slot values, but enqueues them
+    TOP copy = copyFsInner(aFS);  // doesn't copy the slot values, but enqueues them
+    // the iteration is done this way because the body can add more to the queue
     while (fsToDo.size() > 0) {
-      int copyToFillSlots = fsToDo.remove(fsToDo.size()-1);
-      int srcToFillSlots = fsToDo.remove(fsToDo.size()-1);
-      copyFeatures(srcToFillSlots, copyToFillSlots);   
+      Runnable r = fsToDo.removeFirst();
+      r.run();
     }
     return copy;
   }
   
-  private FeatureStructure copyFs2Fs(FeatureStructure fs) {
-    return originalTgtCasImpl.ll_getFSForRef(copyFs2(((FeatureStructureImpl)fs).getAddress()));
+  private FeatureStructure copyFs2Fs(TOP fs) {
+    return copyFs2(fs);
   }
 
   /**
    * Copies a FS from the source CAS to the destination CAS. Also copies any referenced FSs, except
    * that previously copied FS will not be copied again.
    * 
-   * @param aFS
+   * @param srcFs
    *          the FS to copy. Must be contained within the source CAS.
    * @return the copy of <code>aFS</code> in the target CAS.
    */
-  private int copyFsInner(int aFS) {
+  private TOP copyFsInner(TOP srcFs) {
     // FS must be in the source CAS
     // this test must be done by the caller if wanted.
 //    assert (casViewsInSameCas(aFS.getCAS(), originalSrcCas));
 
     // check if we already copied this FS
-    int copy = mFsMap.get(aFS);
-    if (copy != 0)
+    TOP copy = mFsMap.get(srcFs);
+    if (copy != null) {
       return copy;
-
-    // get the type of the FS
-    final int srcTypeCode = originalSrcCasImpl.ll_getFSRefType(aFS);
-    final Type srcType = srcTsi.ll_getTypeForCode(srcTypeCode);
+    }
     
     // Certain types need to be handled specially
 
     // Sofa - cannot be created by normal methods. Instead, we return the Sofa with the
     // same Sofa ID in the target CAS. If it does not exist it will be created.
-    if (srcTypeCode == srcSofaTypeCode) {
-      String destSofaId = getDestSofaId(srcCasViewImpl.ll_getSofaID(aFS));
+    if (srcFs instanceof Sofa) {
+      Sofa srcSofa = (Sofa) srcFs;
+      String destSofaId = getDestSofaId(srcSofa.getSofaID());
       // note: not put into the mFsMap, because each view needs a separate copy
-      return ((CASImpl)getOrCreateView(originalTgtCas, destSofaId)).getSofaRef();
+      return ((CASImpl)getOrCreateView(originalTgtCas, destSofaId)).getSofa();
     }
 
     // DocumentAnnotation - instead of creating a new instance, reuse the automatically created
     // instance in the destination view.
-    if (isDocumentAnnotation(aFS)) {
-      String destViewName = getDestSofaId(srcCasViewImpl.ll_getSofaID(srcCasViewImpl.getSofaFeat(aFS)));
+    if (isDocumentAnnotation(srcFs)) {
+      Annotation da = (Annotation) srcFs;
+      String destViewName = getDestSofaId(da.getView().getViewName());
 
       // the DocumentAnnotation could be indexed in a different view than the one being copied
       //   if it was ref'd for the 1st time from a cross-indexed fs
@@ -677,15 +695,16 @@ public class CasCopier {
       //   indexing some other feature structure in this view, which, in turn,
       //   has a reference to the DocumentAnnotation FS belonging to another view
       CASImpl destView = (CASImpl) getOrCreateView(originalTgtCas, destViewName);
-      int destDocAnnot = destView.ll_getDocumentAnnotation();
-      if (destDocAnnot == 0) {
-        destDocAnnot = destView.ll_createDocumentAnnotationNoIndex(0, 0);
-        copyFeatures(aFS, destDocAnnot);
-        ((FSIndexRepositoryImpl)(destView.getIndexRepository())).addFS(destDocAnnot);
+      // do the no-create style so we can create it without adding it to the index yet
+      Annotation destDocAnnot = destView.getDocumentAnnotationNoCreate();  
+      if (destDocAnnot == null) {
+        destDocAnnot = destView.createDocumentAnnotationNoRemoveNoIndex(0);
+        copyFeatures(srcFs, destDocAnnot);
+        destView.getIndexRepository().addFS(destDocAnnot);
       } else {
         AutoCloseable ac = tgtCasViewImpl.protectIndexes();
         try {
-          copyFeatures(aFS, destDocAnnot);
+          copyFeatures(srcFs, destDocAnnot);
         } finally {
           try {
             ac.close();
@@ -698,30 +717,33 @@ public class CasCopier {
     }
 
     // Arrays - need to be created a populated differently than "normal" FS
-    if (srcType.isArray()) {
-      copy = copyArray(aFS);
-      mFsMap.put(aFS, copy);
+    if (srcFs instanceof CommonArray) {
+      copy = copyArray(srcFs);
+      mFsMap.put(srcFs, copy);
       return copy;
     }
-    
-    final TypeInfo tInfo = getTypeInfo(srcTypeCode);
-    final int tgtTypeCode = tInfo.tgtTypeCode;
-    if (tgtTypeCode == 0) {
-      return 0; // not in target, no FS to create
-    }
+
+    TypeImpl tgtTi = getTargetType(srcFs._typeImpl);
+    if (null == tgtTi) {
+      return null; // not in target, no FS to create
+    }
+//    final TypeInfo tInfo = getTypeInfo(srcTypeCode);
+//    final int tgtTypeCode = tInfo.tgtTypeCode;
+//    if (tgtTypeCode == 0) {
+//      return 0; // not in target, no FS to create
+//    }
     // We need to use the LowLevel CAS interface to create the FS, because the usual
     // CAS.createFS() call doesn't allow us to create subtypes of AnnotationBase from
     // a base CAS. In any case we don't need the Sofa reference to be automatically
     // set because we'll set it manually when in the copyFeatures method.
     
-    int tgtFsAddr = tgtCasViewImpl.ll_createFS(tgtTypeCode);
+    TOP tgtFs = tgtCasViewImpl.createFS(tgtTi);
 
     // add to map so we don't try to copy this more than once
-    mFsMap.put(aFS, tgtFsAddr);
+    mFsMap.put(srcFs, tgtFs);
 
-    fsToDo.add(aFS); // order important
-    fsToDo.add(tgtFsAddr);
-    return tgtFsAddr;
+    fsToDo.addLast(() -> copyFeatures(srcFs, tgtFs));
+    return tgtFs;
   }
   
   /**
@@ -738,13 +760,13 @@ public class CasCopier {
     return (isChangeViewName && id.equals(srcViewName)) ? tgtViewName : id;
   }
   
-  private TypeInfo getTypeInfo(int srcTypeCode) {
-    TypeInfo tInfo = tInfoArray[srcTypeCode];
-    if (tInfo == null) {
-      return tInfoArray[srcTypeCode] = new TypeInfo(srcTypeCode);
-    }
-    return tInfo;
-  }
+//  private TypeInfo getTypeInfo(int srcTypeCode) {
+//    TypeInfo tInfo = tInfoArray[srcTypeCode];
+//    if (tInfo == null) {
+//      return tInfoArray[srcTypeCode] = new TypeInfo(srcTypeCode);
+//    }
+//    return tInfo;
+//  }
   
   /**
    * Copy feature values from one FS to another. For reference-valued features, this does a deep
@@ -755,49 +777,69 @@ public class CasCopier {
    * @param tgtFS
    *          FeatureStructure to copy to, which must not be in the index (index corruption checks skipped)
    */
-  private void copyFeatures(int srcFS, int tgtFS) {
-    // set feature values
-    
-    final int srcTypeCode = srcCasViewImpl.getTypeCode(srcFS);
-    
-    final TypeInfo tInfo = getTypeInfo(srcTypeCode);
-        
-    tgtCasViewImpl.setCacheNotInIndex(tgtFS);
-        
-    for (int i = 0; i < tInfo.codesAndOffsets.length; i = i + 2) {
-      final int tgtFeatCode = tInfo.codesAndOffsets[i + K_TGT_FEAT_CODE];
-      if (0 == tgtFeatCode) {
-        continue; 
+  private void copyFeatures(TOP srcFS, TOP tgtFS) {
+    for (FeatureImpl fi : srcFS.getTypeImpl().getFeatureImpls()) {
+      FeatureImpl tgtFi = getTargetFeature(fi);
+      if (null == tgtFi) {
+        continue;  // skip copying features not in the target type system
       }
-      final int srcFeatOffset = tInfo.codesAndOffsets[i + K_SRC_FEAT_OFFSET];
-      switch (tInfo.frc[i >> 1]) {
-      case FRC_SKIP:
-        break;
-      case FRC_STRING:
-        // need feature code to check subtype constraints
-        tgtCasViewImpl.ll_setStringValue(tgtFS, tgtFeatCode, srcCasViewImpl.ll_getStringValueFeatOffset(srcFS, srcFeatOffset));
-        break;
-      case FRC_INT_LIKE:
-        tgtCasViewImpl.ll_setIntValue(tgtFS, tgtFeatCode, srcCasViewImpl.ll_getIntValueFeatOffset(srcFS, srcFeatOffset));
-        break;
-      case FRC_LONG:
-        tgtCasViewImpl.ll_setLongValue(tgtFS,  tgtFeatCode,  srcCasViewImpl.ll_getLongValueFeatOffset(srcFS,  srcFeatOffset));
-        break;
-      case FRC_DOUBLE:
-        tgtCasViewImpl.ll_setDoubleValue(tgtFS,  tgtFeatCode,  srcCasViewImpl.ll_getDoubleValueFeatOffset(srcFS,  srcFeatOffset));
-        break;
-      case FRC_REF:
-        int refFS = srcCasViewImpl.ll_getRefValueFeatOffset(srcFS, srcFeatOffset);
-        if (refFS != 0) {
-          int copyRefFs = copyFsInner(refFS);
-          tgtCasViewImpl.ll_setRefValue(tgtFS, tgtFeatCode, copyRefFs);
+      
+      if (!CASImpl.copyFeatureExceptFsRef(srcFS, fi, tgtFS, tgtFi)) {
+        // feature is a reference to another FS, so enqueue that to copy
+        //   unless it's the sofa feature for AnnotationBase - that's feature final, set when created
+        if (fi.isAnnotBaseSofaRef) {
+          continue;
+        }
+        TOP refFs = srcFS.getFeatureValue(fi);
+        if (null != refFs) {
+          tgtFS.setFeatureValue(tgtFi, copyFsInner(refFs));  
         }
-        break;
-      default:
-        throw new UIMARuntimeException();  // internal error
-      }      
+      }
     }
-  }
+  }    
+//    
+//    // set feature values
+//    
+////    final int srcTypeCode = srcCasViewImpl.getTypeCode(srcFS);
+//    
+////    final TypeInfo tInfo = getTypeInfo(srcTypeCode);
+//        
+//    tgtCasViewImpl.setCacheNotInIndex(tgtFS);
+//        
+//    for (int i = 0; i < tInfo.codesAndOffsets.length; i = i + 2) {
+//      final int tgtFeatCode = tInfo.codesAndOffsets[i + K_TGT_FEAT_CODE];
+//      if (0 == tgtFeatCode) {
+//        continue; 
+//      }
+//      final int srcFeatOffset = tInfo.codesAndOffsets[i + K_SRC_FEAT_OFFSET];
+//      switch (tInfo.frc[i >> 1]) {
+//      case FRC_SKIP:
+//        break;
+//      case FRC_STRING:
+//        // need feature code to check subtype constraints
+//        tgtCasViewImpl.ll_setStringValue(tgtFS, tgtFeatCode, srcCasViewImpl.ll_getStringValueFeatOffset(srcFS, srcFeatOffset));
+//        break;
+//      case FRC_INT_LIKE:
+//        tgtCasViewImpl.ll_setIntValue(tgtFS, tgtFeatCode, srcCasViewImpl.ll_getIntValueFeatOffset(srcFS, srcFeatOffset));
+//        break;
+//      case FRC_LONG:
+//        tgtCasViewImpl.ll_setLongValue(tgtFS,  tgtFeatCode,  srcCasViewImpl.ll_getLongValueFeatOffset(srcFS,  srcFeatOffset));
+//        break;
+//      case FRC_DOUBLE:
+//        tgtCasViewImpl.ll_setDoubleValue(tgtFS,  tgtFeatCode,  srcCasViewImpl.ll_getDoubleValueFeatOffset(srcFS,  srcFeatOffset));
+//        break;
+//      case FRC_REF:
+//        int refFS = srcCasViewImpl.ll_getRefValueFeatOffset(srcFS, srcFeatOffset);
+//        if (refFS != 0) {
+//          int copyRefFs = copyFsInner(refFS);
+//          tgtCasViewImpl.ll_setRefValue(tgtFS, tgtFeatCode, copyRefFs);
+//        }
+//        break;
+//      default:
+//        throw new UIMARuntimeException();  // internal error
+//      }      
+//    }
+//  }
   
   /**
    * Note: if lenient is in effect, this method will return false for
@@ -807,7 +849,7 @@ public class CasCopier {
    * @return true if the given FS has already been copied using this CasCopier.
    */
   public boolean alreadyCopied(FeatureStructure aFS) {
-    return alreadyCopied(((FeatureStructureImpl)aFS).getAddress());
+    return alreadyCopied(((TOP)aFS));
   }
   
   /**
@@ -817,96 +859,37 @@ public class CasCopier {
    * @param aFS a feature structure
    * @return true if the given FS has already been copied using this CasCopier.
    */
-  public boolean alreadyCopied(int aFS) {
-    return mFsMap.get(aFS) != 0;
+  public boolean alreadyCopied(TOP aFS) {
+    return mFsMap.get(aFS) != null;
   }
 
   /**
    * @param arrayFS
    * @return a copy of the array
    */
-  private int copyArray(int srcFS) {
-    // TODO: there should be a way to do this without enumerating all the array types!
+  private TOP copyArray(TOP srcFS) {
+    final CommonArray srcCA = (CommonArray) srcFS;
+    final int size = srcCA.size();
+    final TypeImpl tgtTi = getTargetType(srcFS._typeImpl);
     
-    final int len = srcCasViewImpl.ll_getArraySize(srcFS);
-    
-    int srcTypeCode = srcCasViewImpl.getTypeCode(srcFS);
-    
-    if (srcTypeCode == TypeSystemImpl.stringArrayTypeCode) {
-      final int tgtFS = tgtCasViewImpl.ll_createArray(TypeSystemImpl.stringArrayTypeCode, len);
-      for (int i = 0; i < len; i++) {
-        tgtCasViewImpl.ll_setStringArrayValue(tgtFS, i, srcCasViewImpl.ll_getStringArrayValue(srcFS, i));
-      }
-      return tgtFS;
+    if (srcFS instanceof CommonPrimitiveArray) {
+      CommonArray copy = (CommonArray) tgtCasViewImpl.createArray(tgtTi, size);
+      copy.copyValuesFrom(srcCA);
+      return (TOP) copy;
     }
     
-    if (srcTypeCode == TypeSystemImpl.intArrayTypeCode) {     
-      final int tgtFS = tgtCasViewImpl.ll_createArray(TypeSystemImpl.intArrayTypeCode, len);
-      for (int i = 0; i < len; i++) {
-        tgtCasViewImpl.ll_setIntArrayValue(tgtFS, i,  srcCasViewImpl.ll_getIntArrayValue(srcFS,  i));
-      }
-      return tgtFS;
-    }
-
-    if (srcTypeCode == TypeSystemImpl.floatArrayTypeCode) {     
-      final int tgtFS = tgtCasViewImpl.ll_createArray(TypeSystemImpl.floatArrayTypeCode, len);
-      for (int i = 0; i < len; i++) {
-        tgtCasViewImpl.ll_setFloatArrayValue(tgtFS, i,  srcCasViewImpl.ll_getFloatArrayValue(srcFS, i));
-      }
-      return tgtFS;
-    }
+    FSArray fsArray = (FSArray) tgtCasViewImpl.createArray(tgtTi, size);
 
-    if (srcTypeCode == TypeSystemImpl.fsArrayTypeCode) {     
-      final int tgtFS = tgtCasViewImpl.ll_createArray(TypeSystemImpl.fsArrayTypeCode, len);
-      for (int i = 0; i < len; i++) {
-        int srcItem = srcCasViewImpl.ll_getRefArrayValue(srcFS, i);
-        tgtCasViewImpl.ll_setRefArrayValue(tgtFS, i, (srcItem == 0) ? 0 : copyFsInner(srcItem));
-      }
-      return tgtFS;
-    }
-
-    if (srcTypeCode == TypeSystemImpl.byteArrayTypeCode) {
-      final int tgtFS = tgtCasViewImpl.ll_createByteArray(len);
-      for (int i = 0; i < len; i++) {
-        tgtCasViewImpl.ll_setByteArrayValue(tgtFS,  i, srcCasViewImpl.ll_getByteArrayValue(srcFS, i));
-      }
-      return tgtFS;      
-    }
-    
-    if (srcTypeCode == TypeSystemImpl.shortArrayTypeCode) {
-      final int tgtFS = tgtCasViewImpl.ll_createShortArray(len);
-      for (int i = 0; i < len; i++) {
-        tgtCasViewImpl.ll_setShortArrayValue(tgtFS,  i, srcCasViewImpl.ll_getShortArrayValue(srcFS, i));
-      }
-      return tgtFS;      
-    }
-
-    if (srcTypeCode == TypeSystemImpl.longArrayTypeCode) {
-      final int tgtFS = tgtCasViewImpl.ll_createLongArray(len);
-      for (int i = 0; i < len; i++) {
-        tgtCasViewImpl.ll_setLongArrayValue(tgtFS,  i, srcCasViewImpl.ll_getLongArrayValue(srcFS, i));
-      }
-      return tgtFS;      
-    }
+    int i = 0;
+    TOP[] tgtArray = fsArray._getTheArray();
     
-    if (srcTypeCode == TypeSystemImpl.doubleArrayTypeCode) {
-      final int tgtFS = tgtCasViewImpl.ll_createDoubleArray(len);
-      for (int i = 0; i < len; i++) {
-        tgtCasViewImpl.ll_setDoubleArrayValue(tgtFS,  i, srcCasViewImpl.ll_getDoubleArrayValue(srcFS, i));
+    for (TOP srcItem : ((FSArray)srcFS)._getTheArray()) {
+      if (null != srcItem) {
+        tgtArray[i] = copyFsInner(srcItem);
       }
-      return tgtFS;      
     }
 
-    if (srcTypeCode == TypeSystemImpl.booleanArrayTypeCode) {
-      final int tgtFS = tgtCasViewImpl.ll_createBooleanArray(len);
-      for (int i = 0; i < len; i++) {
-        tgtCasViewImpl.ll_setBooleanArrayValue(tgtFS,  i, srcCasViewImpl.ll_getBooleanArrayValue(srcFS, i));
-      }
-      return tgtFS;      
-    }
-    
-    assert false; // the set of array types should be exhaustive, so we should never get here
-    return 0;
+    return (TOP) fsArray;
   }
   
   /**
@@ -928,10 +911,12 @@ public class CasCopier {
    * This is more than just a type check; we actually check if it is the one "special"
    * DocumentAnnotation that CAS.getDocumentAnnotation() would return.
    */
-  private boolean isDocumentAnnotation(int aFS) {
-    if (srcCasDocumentAnnotation == 0) {
-      int docFs = srcCasViewImpl.ll_getDocumentAnnotation();
-      srcCasDocumentAnnotation = (docFs == 0) ? -1 : docFs; 
+  private boolean isDocumentAnnotation(TOP aFS) {
+    if (aFS._getTypeCode() != TypeSystemImpl.docTypeCode) {
+      return false;
+    }
+    if (srcCasDocumentAnnotation == null) {
+      srcCasDocumentAnnotation = srcCasViewImpl.getDocumentAnnotationNoCreate(); 
     }
     return aFS == srcCasDocumentAnnotation;
   }
@@ -953,4 +938,30 @@ public class CasCopier {
     
     return ci1.getBaseCAS() == ci2.getBaseCAS();
   }
+  
+  private TypeImpl getTargetType(TypeImpl srcTi) {
+    int srcTypeCode = srcTi.getCode();
+    TypeImpl r = src2TgtType.get(srcTypeCode);
+    if (r == null) {
+      r = tgtTsi.getType(srcTi.getName());
+      src2TgtType.put(srcTypeCode, (null == r) ? MISSING_TYPE : r);
+    }
+    return (r == MISSING_TYPE) ? null : r;
+  }
+  
+  private FeatureImpl getTargetFeature(FeatureImpl srcFi) {
+    int srcFeatCode = srcFi.getCode();
+    FeatureImpl r = src2TgtFeat.get(srcFeatCode);
+    if (r == null) {
+      TypeImpl d = (TypeImpl) srcFi.getDomain();
+      TypeImpl td = getTargetType(d);
+      if (td == null) {
+        return null;
+      }
+      r = td.getFeatureByBaseName(srcFi.getShortName());
+      src2TgtFeat.put(srcFeatCode, (null == r) ? MISSING_FEAT : r);
+    }
+    return (r == MISSING_FEAT) ? null : r;    
+  }
+  
 }