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/01 13:55:59 UTC
svn commit: r1711743 -
/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java
Author: schor
Date: Sun Nov 1 12:55:58 2015
New Revision: 1711743
URL: http://svn.apache.org/viewvc?rev=1711743&view=rev
Log:
[UIMA-4665][UIMA-4663] Make FeatureStructureImplC the top level of the Java Feature Structure classes, supporting the non-JCas style of accessing.
Modified:
uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/FeatureStructureImplC.java
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=1711743&r1=1711742&r2=1711743&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 Sun Nov 1 12:55:58 2015
@@ -19,66 +19,910 @@
package org.apache.uima.cas.impl;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.IntFunction;
+
import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.CASRuntimeException;
+import org.apache.uima.cas.CommonArrayFS;
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.SofaFS;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.function.JCas_getter_boolean;
+import org.apache.uima.cas.function.JCas_getter_double;
+import org.apache.uima.cas.function.JCas_getter_generic;
+import org.apache.uima.cas.function.JCas_getter_int;
+import org.apache.uima.cas.function.JCas_getter_long;
+import org.apache.uima.cas.function.JCas_setter_boolean;
+import org.apache.uima.cas.function.JCas_setter_byte;
+import org.apache.uima.cas.function.JCas_setter_float;
+import org.apache.uima.cas.function.JCas_setter_generic;
+import org.apache.uima.cas.function.JCas_setter_int;
+import org.apache.uima.cas.function.JCas_setter_long;
+import org.apache.uima.cas.function.JCas_setter_short;
+import org.apache.uima.internal.util.StringUtils;
+import org.apache.uima.jcas.JCas;
+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.FloatArray;
+import org.apache.uima.jcas.cas.IntegerArray;
+import org.apache.uima.jcas.cas.JavaObjectArray;
+import org.apache.uima.jcas.cas.LongArray;
+import org.apache.uima.jcas.cas.ShortArray;
+import org.apache.uima.jcas.cas.StringArray;
+import org.apache.uima.jcas.impl.JCasImpl;
+import org.apache.uima.util.Misc;
/**
- * Feature structure implementation.
+ * Feature structure implementation (for non JCas and JCas)
*
+ * Each FS has
+ * - int data
+ * - used for boolean, byte, short, int, long, float, double data
+ * -- long and double use 2 int slots
+ * - may be null if all slots are in JCas cover objects as fields
+ * - ref data
+ * - used for references to other Java objects, such as
+ * -- strings
+ * -- other feature structures
+ * -- arbitrary Java Objects
+ * - may be null if all slots are in JCas cover objects as fields
+ * - an id: an incrementing integer, starting at 1, per CAS, of all FSs created for that CAS
+ * - a ref to the casView where this FS was created
+ * - a ref to the TypeImpl for this class
+ * -- can't be static - may be multiple type systems in use
*
*/
-public class FeatureStructureImplC extends FeatureStructureImpl {
-
- final protected CASImpl casImpl;
-
- final protected int addr;
+public class FeatureStructureImplC implements FeatureStructure, Cloneable {
- protected FeatureStructureImplC() {
- this.casImpl = null;
- this.addr = 0;
+ // note: these must be enabled to make the test cases work
+ public static final String DISABLE_RUNTIME_FEATURE_VALIDATION = "uima.disable_runtime_feature_validation";
+ public static final boolean IS_ENABLE_RUNTIME_FEATURE_VALIDATION = !Misc.getNoValueSystemProperty(DISABLE_RUNTIME_FEATURE_VALIDATION);
+
+ public static final String DISABLE_RUNTIME_FEATURE_VALUE_VALIDATION = "uima.disable_runtime_feature_validation";
+ public static final boolean IS_ENABLE_RUNTIME_FEATURE_VALUE_VALIDATION = !Misc.getNoValueSystemProperty(DISABLE_RUNTIME_FEATURE_VALUE_VALIDATION);
+
+ // data storage
+ // slots start with _ to prevent name collision with JCas style getters and setters.
+
+ protected final int[] _intData;
+ protected final Object[] _refData;
+ protected final int _id; // a separate slot for access without loading _intData object
+
+
+ /**
+ * These next two object references are the same for every FS of this class created in one view.
+ * So, they could be stored in a shared object
+ * But that would trade off saving one "reference" for adding one extra load to get to the value
+ * This design uses more space instead.
+ */
+
+ /**
+ * The view this Feature Structure was originally created in.
+ * Feature Structures may be indexed in multiple views, or in no views.
+ *
+ * Also used to access other metadata including the type system
+ */
+ protected final CASImpl _casView;
+
+ protected final TypeImpl _typeImpl;
+
+ // Called only to generate a dummy value for the REMOVED flag in bag indexes
+
+ public FeatureStructureImplC() {
+ _casView = null;
+ _typeImpl = null;
+ _intData = null;
+ _refData = null;
+ _id = 0;
}
- FeatureStructureImplC(CASImpl casImpl, int addr) {
- // assert(addr > 0);
- this.addr = addr;
- this.casImpl = casImpl;
+
+ /**
+ * For non-JCas use
+ * @param casView -
+ * @param type -
+ */
+ protected FeatureStructureImplC(TypeImpl type, CASImpl casView) {
+ _casView = casView;
+ _typeImpl = type;
+
+ int c = _typeImpl.nbrOfUsedIntDataSlots;
+ _intData = (c == 0) ? null : new int[c];
+
+ c = _typeImpl.nbrOfUsedRefDataSlots;
+ _refData = (c == 0) ? null : new Object[c];
+
+ _id = casView.setId2fs(this);
}
-// public void setUp(CASImpl casImpl, int addr) {
-// this.addr = addr;
-// this.casImpl = casImpl;
-// }
+ /**
+ * For JCas use (done this way to allow "final")
+ * The TypeImpl is derived from the JCas cover class name
+ * @param jcasImpl - the view this is being created in
+ */
+
+ protected FeatureStructureImplC(JCasImpl jcasImpl) {
+ _casView = jcasImpl.getCasImpl();
+ _typeImpl = _casView.getTypeSystemImpl().getJCasRegisteredType(getTypeIndexID());
+
+ if (null == _typeImpl) {
+ throw new CASRuntimeException(CASRuntimeException.JCAS_TYPE_NOT_IN_CAS, this.getClass().getName());
+ }
+
+ int c = _typeImpl.nbrOfUsedIntDataSlots;
+ _intData = (c == 0) ? null : new int[c];
+
+ c = _typeImpl.nbrOfUsedRefDataSlots;
+ _refData = (c == 0) ? null : new Object[c];
+
+ _id = _casView.setId2fs(this);
+ }
+
+
+ // Only for clone use
+ private FeatureStructureImplC(CASImpl casView, TypeImpl type, int[] intData, Object[] refData) {
+ this._casView = casView;
+ this._typeImpl = type;
+ _intData = intData.clone();
+ _refData = refData.clone();
+ _id = casView.setId2fs(this);
+ }
+
+ /* ***********************
+ * Index Add Remove
+ * ***********************/
+
+ /** add the corresponding FeatureStructure to all Cas indexes in the view where this FS was created*/
+ public void addToIndexes() {
+ _casView.addFsToIndexes(this);
+ }
+
+ /**
+ * add this FS to indexes in a specific view, perhaps different from the creation view
+ * @param jcas the JCas
+ */
+ public void addToIndexes(JCas jcas) {
+ jcas.getCas().addFsToIndexes(this);
+ }
+
+ public void addToIndexes(CAS cas) {
+ cas.addFsToIndexes(this);
+ }
+
- public int getAddress() {
- return this.addr;
+ /** remove the corresponding FeatureStructure from all Cas indexes in the view where this FS was created */
+ public void removeFromIndexes() {
+ removeFromIndexes(_casView);
}
- public CAS getCAS() {
- return this.casImpl;
+ /**
+ * remove this FS from indexes in a specific view, perhaps different from the view where this was created.
+ * @param cas the Cas
+ */
+ public void removeFromIndexes(CAS cas) {
+ cas.removeFsFromIndexes(this);
}
- public CASImpl getCASImpl() { // was package private 9-03
- return this.casImpl;
+
+ /* *******************************
+ * IDs and Type
+ *********************************/
+ /**
+ * NOTE: Possible name collision
+ * @return the internal id of this fs - unique to this CAS, a positive int
+ */
+ public final int getAddress() { return _id; };
+
+ @Override
+ public final int get_id() {return _id; };
+
+ // backwards compatibility
+ @Override
+ public Type getType() {
+ return _typeImpl;
+ }
+
+ public int _getTypeCode() {
+ return _typeImpl.getCode();
}
- public boolean equals(Object o) {
- if (this == o) {
+ /* *********************************************************
+ * Get and Set features indirectly, via Feature objects
+ *
+ * There are two implementations, depending on whether or not
+ * the feature has a JCas getter/setter.
+ * - If yes, then these just delegate to that (via a
+ * functional interface stored in the Feature)
+ * -- there are multiple functional interfaces, corresponding
+ * to the all the different (primitive) return values:
+ * boolean, byte, short, int, long, float, double, and "Object"
+ * used for String and FeatureStructures
+ * - if no, then converge the code to an _intData or _refData reference
+ ***********************************************************/
+ protected void featureValidation(Feature feat) {
+ if (!_typeImpl.isAppropriateFeature(feat)) {
+ /* Feature "{0}" is not defined for type "{1}". */
+ throw new CASRuntimeException(CASRuntimeException.INAPPROP_FEAT, feat.getName(), _typeImpl.getName());
+ }
+ }
+
+ protected void featureValueValidation(Feature feat, Object v) {
+ TypeImpl range = (TypeImpl)feat.getRange();
+ if ((range.isArray() && !isOkArray(range, v)) ||
+ (!range.isArray() && (!range.subsumesValue(v)))) {
+ throw new CASRuntimeException(CASRuntimeException.INAPPROP_RANGE, feat.getName(), range.getName(), v.getClass().getName());
+ }
+ }
+
+ // called when range isArray() is true, only
+ private boolean isOkArray(TypeImpl range, Object v) {
+ if (v == null) {
return true;
}
- if (o == null) {
- return false;
+
+ final int rtc = range.getCode();
+
+ /* The assignment is stricter than the Java rules - must match */
+ switch (rtc) {
+ case TypeSystemImpl.booleanArrayTypeCode:
+ return v instanceof BooleanArray;
+ case TypeSystemImpl.byteArrayTypeCode:
+ return v instanceof ByteArray;
+ case TypeSystemImpl.shortArrayTypeCode:
+ return v instanceof ShortArray;
+ case TypeSystemImpl.intArrayTypeCode:
+ return v instanceof IntegerArray;
+ case TypeSystemImpl.floatArrayTypeCode:
+ return v instanceof FloatArray;
+ case TypeSystemImpl.longArrayTypeCode:
+ return v instanceof LongArray;
+ case TypeSystemImpl.doubleArrayTypeCode:
+ return v instanceof DoubleArray;
+ case TypeSystemImpl.stringArrayTypeCode:
+ return v instanceof StringArray;
+ case TypeSystemImpl.javaObjectArrayTypeCode:
+ return v instanceof JavaObjectArray;
}
- if (!(o instanceof FeatureStructureImplC)) {
- return false;
+
+ if (!(v instanceof FeatureStructureImplC)) { return false; }
+ final TypeImpl vType = ((FeatureStructureImplC) v)._typeImpl;
+ if (!vType.isArray()) { return false; }
+
+ if (rtc == TypeSystemImpl.fsArrayTypeCode) {
+ return !vType.isPrimitive();
}
- FeatureStructureImplC fs = (FeatureStructureImplC) o;
- if ((this.addr == fs.addr) && (this.casImpl.getBaseCAS() == fs.casImpl.getBaseCAS())) {
+
+ // because we cannot create xyz[] instances (10/2015)
+ // but can only create instances of FSArray
+ // we violate the typing restrictions and allow
+ // assigning FSArray == TOP[] to some xyz[] type.
+ // This should be fixed.
+ final int vCode = vType.getCode();
+ if (vCode == TypeSystemImpl.fsArrayTypeCode) {
+ // range type isArray
+ // range type is not one of the built-in primitive arrays
+ //
+ // case where range type is TOP or ArrayBase is handled by
+ // the caller
return true;
}
+
+ // Both range and value are arrays, but
+ // - neither are primitive arrays, and
+ // - neither are fsArrays.
+
+ // this case will only happen if we can create non FSArrays
+ // of particular types
+
+ System.out.println("Debug - should never hit this");
return false;
+
+// return (range.getComponentType() == ((TypeImpl)(vc._typeImpl)).getComponentType());
}
+ /**
+ * Setters for values which could be keys in indexes have to do index corruption checking
+ *
+ * All setters may have to journal which fs, feature (and for arrays, element) is being set.
+ */
+
+ protected void setIntValueCJ(FeatureImpl fi, int v) {
+ if (!fi.isInInt) {
+ /** Trying to access value of feature "{0}" as "{1}", but range of feature is "{2}".*/
+ throw new CASRuntimeException(CASRuntimeException.INAPPROP_RANGE, fi.getName(), "int", fi.getRange().getName());
+ }
+ if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(fi);
+ _casView.setWithCheckAndJournal(this, fi.getCode(), () -> _intData[fi.getAdjustedOffset()] = v);
+ }
+
+ protected void setRefValueCJ(FeatureImpl feat, Object v) {
+ _casView.setWithCheckAndJournal(this, feat.getCode(), () -> _refData[feat.getAdjustedOffset()] = v);
+ }
+
+ @Override
+ public void setBooleanValue(Feature feat, boolean v) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object setter = fi.getJCasSetter();
+ if (setter != null) {
+ ((JCas_setter_boolean)setter).set(this, v);
+ } else {
+ setIntValueCJ(fi, v ? 1 : 0);
+ }
+ }
+
+ @Override
+ public void setByteValue(Feature feat, byte v) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object setter = fi.getJCasSetter();
+ if (setter != null) {
+ ((JCas_setter_byte)setter).set(this, v);
+ } else {
+ setIntValueCJ(fi, v);
+ }
+ }
+
+ @Override
+ public void setShortValue(Feature feat, short v) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object setter = fi.getJCasSetter();
+ if (setter != null) {
+ ((JCas_setter_short)setter).set(this, v);
+ } else {
+ setIntValueCJ(fi, v);
+ }
+}
+
+ @Override
+ public void setIntValue(Feature feat, int v) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object setter = fi.getJCasSetter();
+ if (setter != null) {
+ ((JCas_setter_int)setter).set(this, v);
+ } else {
+ setIntValueCJ(fi, v);
+ }
+ }
+
+ @Override
+ public void setLongValue(Feature feat, long v) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object setter = fi.getJCasSetter();
+ if (setter != null) {
+ ((JCas_setter_long)setter).set(this, v);
+ } else {
+ if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+ _casView.setFeatureValue(this, (FeatureImpl) feat, (int)(v & 0xffffffff), (int)(v >> 32));
+ }
+ }
+
+ @Override
+ public void setFloatValue(Feature feat, float v) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object setter = fi.getJCasSetter();
+ if (setter != null) {
+ ((JCas_setter_float)setter).set(this, v);
+ } else {
+ setIntValueCJ(fi, CASImpl.float2int(v));
+ }
+ }
+
+ @Override
+ public void setDoubleValue(Feature feat, double v) {
+ setLongValue(feat, CASImpl.double2long(v));}
+
+ @Override
+ public void setStringValue(Feature feat, String v) {
+ TypeImpl range = (TypeImpl) feat.getRange();
+ if (range.isStringSubtype()) {
+ if (v != null) {
+ TypeImplStringSubtype tiSubtype = (TypeImplStringSubtype) range;
+ tiSubtype.validateIsInAllowedValues(v);
+ }
+ } else if (range.getCode() != TypeSystemImpl.stringTypeCode) {
+ /** Expected value of type "{0}", but found "{1}". */
+ throw new CASRuntimeException(CASRuntimeException.INAPPROP_TYPE, range.getName(), "Java String");
+ }
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object setter = fi.getJCasSetter();
+ if (setter != null) {
+ ((JCas_setter_generic<String>)setter).set(this, v);
+ } else {
+ setRefValueCJ(fi, v);
+ }
+ }
+
+
+ @Override
+ public void setFeatureValue(Feature feat, FeatureStructure v) {
+ FeatureImpl fi = (FeatureImpl) feat;
+
+ if (fi.isInInt) {
+ /** Trying to access value of feature "{0}" as feature structure, but is primitive type. */
+ throw new CASRuntimeException(CASRuntimeException.PRIMITIVE_VAL_FEAT, feat.getName());
+ }
+ if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+ if (IS_ENABLE_RUNTIME_FEATURE_VALUE_VALIDATION) featureValueValidation(feat, v);
+
+ Object setter = fi.getJCasSetter();
+ if (setter != null) {
+ ((JCas_setter_generic<FeatureStructureImplC>)setter).set(this, (FeatureStructureImplC) v);
+ } else {
+ setRefValueCJ(fi, v);
+ }
+ }
+
+ @Override
+ public void setJavaObjectValue(Feature feat, Object v) {
+ if (v instanceof String) {
+ setStringValue(feat, (String) v); // in order to do proper string subtype checking
+ } else {
+ FeatureImpl fi = (FeatureImpl) feat;
+
+ if (fi.isInInt) {
+ /** Trying to access value of feature "{0}" as feature structure, but is primitive type. */
+ throw new CASRuntimeException(CASRuntimeException.PRIMITIVE_VAL_FEAT, feat.getName());
+ }
+ if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+ if (IS_ENABLE_RUNTIME_FEATURE_VALUE_VALIDATION) featureValueValidation(feat, v);
+
+ Object setter = fi.getJCasSetter();
+ if (setter != null) {
+ ((JCas_setter_generic<Object>)setter).set(this, v);
+ } else {
+ final int adjustedOffset = ((FeatureImpl)feat).getAdjustedOffset();
+ if (-1 == adjustedOffset) {
+ /** JCas Class "{0}" is missing required field accessor, or access not permitted, for field "{1}" during {2} operation. */
+ throw new CASRuntimeException(CASRuntimeException.JCAS_MISSING_FIELD_ACCESSOR,
+ fi.getHighestDefiningType().javaClass.getName(),
+ fi.getShortName(),
+ "set");
+ }
+ setRefValueCJ(fi, v);
+ }
+ }
+ }
+
+ @Override
+ public void setFeatureValueFromString(Feature feat, String s) throws CASRuntimeException {
+ if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+ _casView.setFeatureValueFromString(this, (FeatureImpl) feat, s);
+ }
+
+ /** G E T T E R S **/
+
+ @Override
+ public boolean getBooleanValue(Feature feat) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object getter = fi.getJCasGetter();
+ return (getter != null) ? ((JCas_getter_boolean)getter).get(this)
+ : getIntValue(feat) == 1;
+ }
+
+ @Override
+ public byte getByteValue(Feature feat) { return (byte) getIntValue(feat); }
+
+ @Override
+ public short getShortValue(Feature feat) { return (short) getIntValue(feat); }
+
+ @Override
+ public int getIntValue(Feature feat) {
+ return getIntValue((FeatureImpl)feat);
+ }
+
+ public int getIntValue(FeatureImpl feat) {
+ if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+ Object getter = feat.getJCasGetter();
+ return (getter != null) ? ((JCas_getter_int)getter).get(this)
+ : _intData[feat.getAdjustedOffset()];
+ }
+
+ @Override
+ public long getLongValue(Feature feat) {
+ if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object getter = fi.getJCasGetter();
+ return (getter != null) ? ((JCas_getter_long)getter).get(this)
+ : getLongValueOffset(fi.getAdjustedOffset());
+ }
+
+ /**
+ * When converting the lower 32 bits to a long, sign extension is done, so have to
+ * 0 out those bits before or-ing in the high order 32 bits.
+ * @param offset -
+ * @return -
+ */
+ public long getLongValueOffset(int offset) {
+ return (((long)_intData[offset]) & 0x00000000ffffffffL) | (((long)_intData[offset + 1]) << 32);
+ }
+
+ @Override
+ public float getFloatValue(Feature feat) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object getter = fi.getJCasGetter();
+ return (getter != null) ? ((JCas_getter_long)getter).get(this)
+ : (float) CASImpl.int2float(getIntValue(feat));
+ }
+
+ @Override
+ public double getDoubleValue(Feature feat) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object getter = fi.getJCasGetter();
+ return (getter != null) ? ((JCas_getter_double)getter).get(this)
+ : CASImpl.long2double(getLongValue(feat)); }
+
+ public double getDoubleValueOffset(int offset) {
+ return CASImpl.long2double(getLongValueOffset(offset));
+ }
+
+ @Override
+ public String getStringValue(Feature feat) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object getter = fi.getJCasGetter();
+ return (getter != null) ? ((JCas_getter_generic<String>)getter).get(this)
+ : (String) getJavaObjectValue(feat);
+ }
+
+ @Override
+ public FeatureStructure getFeatureValue(Feature feat) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object getter = fi.getJCasSetter();
+ return (getter != null) ? ((JCas_getter_generic<FeatureStructure>)getter).get(this)
+ : (FeatureStructure) getJavaObjectValue(feat);
+ }
+
+ @Override
+ public Object getJavaObjectValue(Feature feat) {
+ if (IS_ENABLE_RUNTIME_FEATURE_VALIDATION) featureValidation(feat);
+ FeatureImpl fi = (FeatureImpl) feat;
+ Object getter = fi.getJCasGetter();
+ if (getter == null) {
+ final int adjustedOffset = ((FeatureImpl)feat).getAdjustedOffset();
+ if (-1 == adjustedOffset) {
+ /** JCas Class "{0}" is missing required field accessor, or access not permitted, for field "{1}" during {2} operation. */
+ throw new CASRuntimeException(CASRuntimeException.JCAS_MISSING_FIELD_ACCESSOR,
+ fi.getHighestDefiningType().javaClass.getName(),
+ fi.getShortName(),
+ "get");
+ }
+ return _refData[((FeatureImpl)feat).getAdjustedOffset()];
+ }
+ return ((JCas_getter_generic<Object>)getter).get(this);
+ }
+
+ @Override
+ public String getFeatureValueAsString(Feature feat) throws CASRuntimeException {
+ return _casView.getFeatureValueAsString(this, (FeatureImpl) feat);
+ }
+
+ /**
+ * @return the CAS view where this FS was created
+ */
+ @Override
+ public CAS getCAS() {
+ return this._casView;
+ }
+
+ protected CASImpl _casView() { // was package private 9-03
+ return this._casView;
+ }
+
+ /**
+ * See http://www.javaworld.com/article/2076332/java-se/how-to-avoid-traps-and-correctly-override-methods-from-java-lang-object.html
+ * for suggestions on avoiding bugs in implementing clone
+ *
+ * Because we have final fields for _intData, _refData, and _id, we can't use clone.
+ * Instead, we use the createFS to create the FS of the right type. This will use the generators.
+ *
+ * Strategy for cloning:
+ * Goal is to create an independent instance of some subtype of this class, with
+ * all the fields properly copied from this instance.
+ * - some fields could be in the _intData and _refData
+ * - some fields could be stored as features
+ *
+ * Subcases to handle:
+ * - arrays - these have no features.
+ *
+ * @return a new Feature Structure as a new instance of the same class,
+ * with a new _id field,
+ * with its features set to the values of the features in this Feature Structure
+ * @throws CASRuntimeException (different from Object.clone()) if an exception occurs
+ */
+ @Override
+ public FeatureStructureImplC clone() throws CASRuntimeException {
+
+ if (_typeImpl.isArray()) {
+ CommonArray original = (CommonArray) this;
+ CommonArray copy = _casView.createArray(_typeImpl.getCode(), original.size());
+ copy.copyValuesFrom(original);
+ return copy;
+ }
+
+ FeatureStructureImplC fs = _casView.createFS(_typeImpl);
+
+ final int sofaFeatCode = TypeSystemImpl.annotSofaFeatCode;
+
+ /* 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
+ } // end of for loop
+ return fs;
+ }
+
+ @Override
public int hashCode() {
- return this.addr;
+ return _id;
+ }
+
+ // ///////////////////////////////////////////////////////////////////////////
+ // Pretty printing.
+
+ private static class PrintReferences {
+
+ static final int NO_LABEL = 0;
+
+ static final int WITH_LABEL = 1;
+
+ static final int JUST_LABEL = 2;
+
+ private static final String refNamePrefix = "#";
+
+ // map from fs to special string #nnnn for printing refs
+ // three states:
+ // 1) key not in map
+ // 2) key in map, but value is "seen once" - first time value seen
+ // 3) key in map, value is #nnnn - when value is seen more than once
+ private Map<FeatureStructure, String> tree = new HashMap<FeatureStructure, String>();
+
+ private Set<FeatureStructure> seen = new HashSet<FeatureStructure>();
+
+ private int count;
+
+ private PrintReferences() {
+ super();
+ this.count = 0;
+ }
+
+ /**
+ * @param fs -
+ * @return true if seen before
+ */
+ boolean addReference(FeatureStructure fs) {
+ String v = tree.get(fs);
+ if (null == v) {
+ tree.put(fs, "seen once");
+ return false;
+ }
+ if (v.equals("seen once")) {
+ tree.put(fs, refNamePrefix + Integer.toString(this.count++));
+ }
+ return true;
+ }
+
+ String getLabel(FeatureStructure ref) {
+ return this.tree.get(ref);
+ }
+
+ int printInfo(FeatureStructure ref) {
+ if (this.tree.get(ref) == null) {
+ return NO_LABEL;
+ }
+ if (this.seen.contains(ref)) {
+ return JUST_LABEL;
+ }
+ this.seen.add(ref);
+ return WITH_LABEL;
+ }
+
+ }
+
+ private final void getPrintRefs(PrintReferences printRefs) {
+ getPrintRefs(printRefs, this);
+ }
+
+ private final void getPrintRefs(PrintReferences printRefs, FeatureStructure fs) {
+ boolean seenBefore = printRefs.addReference(fs);
+ if (seenBefore) {
+ return;
+ }
+
+ final TypeImpl ti = this._typeImpl;
+ ti.getFeaturesAsStream()
+ .filter(fi -> fi.getRangeImpl().isRefType) // is ref type
+ .map(fi -> this.getFeatureValue(fi)) // get the feature value
+ .filter(refFs -> refFs != null) // skip null ones
+ .forEachOrdered(refFs -> getPrintRefs(printRefs, refFs));
+ }
+
+ @Override
+ public String toString() {
+ return toString(3);
+ }
+
+ public String toString(int indent) {
+ StringBuilder buf = new StringBuilder();
+ prettyPrint(0, indent, buf, true, null);
+ return buf.toString();
+ }
+
+ public void prettyPrint(int indent, int incr, StringBuilder buf, boolean useShortNames) {
+ prettyPrint(indent, incr, buf, useShortNames, null);
+ }
+
+ public void prettyPrint(int indent, int incr, StringBuilder buf, boolean useShortNames, String s) {
+ PrintReferences printRefs = new PrintReferences();
+ getPrintRefs(printRefs);
+ prettyPrint(indent, incr, buf, useShortNames, s, printRefs);
+ }
+
+ public void prettyPrint(
+ int indent,
+ int incr,
+ StringBuilder buf,
+ boolean useShortNames,
+ String s,
+ PrintReferences printRefs) {
+ indent += incr;
+ final int printInfo = printRefs.printInfo(this);
+ if (printInfo != PrintReferences.NO_LABEL) {
+ String label = printRefs.getLabel(this);
+ if (!label.equals("seen once")) {
+ buf.append(printRefs.getLabel(this));
+ }
+ if (printInfo == PrintReferences.JUST_LABEL) {
+ buf.append('\n');
+ return;
+ }
+ buf.append(' ');
+ }
+ if (useShortNames) {
+ buf.append(getType().getShortName());
+ } else {
+ buf.append(getType().getName());
+ }
+ buf.append(':').append(_id);
+ if (s != null) {
+ buf.append(" \"" + s + "\"");
+ }
+ buf.append('\n');
+
+// final int typeClass = this._casView.ll_getTypeClass(this.getType());
+
+
+ switch (_getTypeCode()) {
+ case TypeSystemImpl.stringArrayTypeCode: {
+ StringArray a = (StringArray) this;
+ printArrayElements(a.size(), a::get, indent, buf);
+ return;
+ }
+ case TypeSystemImpl.intArrayTypeCode: {
+ IntegerArray a = (IntegerArray) this;
+ printArrayElements(a.size(), i -> Integer.toString(a.get(i)), indent, buf);
+ return;
+ }
+ case TypeSystemImpl.floatArrayTypeCode: {
+ FloatArray a = (FloatArray) this;
+ printArrayElements(a.size(), i -> Float.toString(a.get(i)), indent, buf);
+ return;
+ }
+ case TypeSystemImpl.booleanArrayTypeCode: {
+ BooleanArray a = (BooleanArray) this;
+ printArrayElements(a.size(), i -> Boolean.toString(a.get(i)), indent, buf);
+ return;
+ }
+ case TypeSystemImpl.byteArrayTypeCode: {
+ ByteArray a = (ByteArray) this;
+ printArrayElements(a.size(), i -> Byte.toString(a.get(i)), indent, buf);
+ return;
+ }
+ case TypeSystemImpl.shortArrayTypeCode: {
+ ShortArray a = (ShortArray) this;
+ printArrayElements(a.size(), i -> Short.toString(a.get(i)), indent, buf);
+ return;
+ }
+ case TypeSystemImpl.longArrayTypeCode: {
+ LongArray a = (LongArray) this;
+ printArrayElements(a.size(), i -> Long.toString(a.get(i)), indent, buf);
+ return;
+ }
+ case TypeSystemImpl.doubleArrayTypeCode: {
+ DoubleArray a = (DoubleArray) this;
+ printArrayElements(a.size(), i -> Double.toString(a.get(i)), indent, buf);
+ return;
+ }
+ }
+
+ for (Feature feat : _typeImpl.getFeatures()) {
+ FeatureImpl fi = (FeatureImpl) feat;
+ StringUtils.printSpaces(indent, buf);
+ buf.append(fi.getShortName() + ": ");
+ TypeImpl range = (TypeImpl) fi.getRange();
+
+ if (range.getCode() == TypeSystemImpl.stringTypeCode ||
+ range.isStringSubtype()) {
+ String stringVal = getStringValue(fi);
+ stringVal = (null == stringVal) ? "<null>" : "\"" + stringVal + "\"";
+ buf.append(stringVal + '\n');
+ continue;
+ }
+
+ if (!range.isPrimitive()) {
+ // not primitive
+ FeatureStructure val = null;
+ boolean hadException = false;
+ try {
+ val = getFeatureValue(fi);
+ } catch (Exception e) {
+ buf.append("<exception ").append(e.getMessage()).append(">\n");
+ hadException = true;
+ }
+ if (!hadException) {
+ if (val != null && !feat.getName().equals(CAS.TYPE_NAME_SOFA)) {
+ ((FeatureStructureImplC) val).prettyPrint(indent, incr, buf, useShortNames, null, printRefs);
+ } else {
+ buf.append((val == null) ? "<null>\n" : ((SofaFS) val).getSofaID() + '\n');
+ }
+ }
+
+ } else {
+ // is primitive
+ buf.append(this.getFeatureValueAsString(feat) + "\n");
+ }
+ }
}
+ private void printArrayElements(int arrayLen, IntFunction<String> f, int indent, StringBuilder buf) {
+ StringUtils.printSpaces(indent, buf);
+ buf.append("Array length: " + arrayLen + "\n");
+ if (arrayLen > 0) {
+ StringUtils.printSpaces(indent, buf);
+ buf.append("Array elements: [");
+ int numToPrint = Math.min(15, arrayLen); // print 15 or fewer elements
+
+ for (int i = 0; i < numToPrint; i++) {
+ if (i > 0) {
+ buf.append(", ");
+ }
+ String element = f.apply(i); //this._casView.ll_getStringArrayValue(this.getAddress(), i);
+ buf.append("\"" + element + "\"");
+ }
+
+ if (arrayLen > numToPrint) {
+ buf.append(", ...");
+ }
+ buf.append("]\n");
+ }
+ }
+
+ public int getTypeIndexID() {
+ throw new CASRuntimeException(CASRuntimeException.INTERNAL_ERROR); // dummy, always overridden
+ }
+
}