blob: 7d7e238a8412a847986e94f137f7e08d72688666 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.cas.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.apache.uima.cas.BuiltinTypeKinds;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CommonArrayFS;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.admin.CASAdminException;
import org.apache.uima.cas.impl.SlotKinds.SlotKind;
import org.apache.uima.internal.util.Misc;
import org.apache.uima.jcas.cas.TOP;
import org.apache.uima.util.impl.Constants;
/**
* The implementation of types in the type system.
*
* UIMA Version 3
* Instances of this class are not shared by different type systems because they contain a ref to the TypeSystemImpl (needed by FeaturePath and maybe other things)
* - even for built-ins.
* - However, the JCas cover class definitions are shared by all type systems for built-in types
*
* Feature offsets are set from the (changing) value of nbrOfIntDataFields and nbrOfRefDataFields
*
*/
public class TypeImpl implements Type, Comparable<TypeImpl> {
private final String name; // x.y.Foo
private final String shortName; // Foo
private final short typeCode; // subtypes always have typecodes > this one and < typeCodeNextSibling
private short depthFirstCode; // assigned at commit time
private short depthFirstNextSibling; // for quick subsumption testing, set at commit time
private final TypeSystemImpl tsi ; // the Type System instance this type belongs to.
// This means that built-in types have multiple instances, so this field can vary.
final SlotKind slotKind;
/* the Java class for this type
* integer = int.class, etc.
* used for args in methodType
* set when type is committed and JCas cover classes are loaded
*/
protected Class<?> javaClass;
// next 2 not kept in the type, because there could be different versions for different class loaders
// private JCasClassInfo jcasClassInfo;
// private FsGenerator generator; // not used for arrays
// final protected Class<?> getter_funct_intfc_class;
// final protected Class<?> setter_funct_intfc_class;
/* ***************** boolean flags *****************/
protected boolean isFeatureFinal;
protected boolean isInheritanceFinal;
protected final boolean isLongOrDouble; // for code generation
int nbrOfLongOrDoubleFeatures = 0;
/**
* False for non creatable (as Feature Structures) values (e.g. byte, integer, string) and
* also false for array built-ins (which can be Feature Structures, can be added-to-indexes, etc.)
*/
protected final boolean isCreatableAndNotBuiltinArray;
/**
* false for primitives, strings, string subtypes
*/
public final boolean isRefType; // not a primitive, can be a FeatureStructure in the CAS, added to indexes etc.
/**
* true for FSarrays non-arrays having 1 or more refs to FSs
*/
boolean hasRefFeature; // true for FSarrays non-arrays having 1 or more refs to FSs
// /**
// * true if only has int slots, no ref slots
// */
// boolean hasOnlyInts;
// /**
// * true if only has ref slots, no int slots
// */
// boolean hasOnlyRefs;
//
// /**
// * true if has no int or data slots
// */
// boolean hasNoSlots;
/* ***************** type hierarchy *****************/
private final TypeImpl superType;
/**
* All supertypes, in order, starting with immediate (nearest) supertype
*/
private final TypeImpl[] allSuperTypes;
private final List<TypeImpl> directSubtypes = new ArrayList<>();
// ******** Features *********
private final Map<String, FeatureImpl> staticMergedFeatures = new LinkedHashMap<>(1); // set to null at commit time
private FeatureImpl[] staticMergedFeaturesList = null; // set after commit
private final List<FeatureImpl> staticMergedFeaturesIntroducedByThisType = new ArrayList<>(0);
/**
* Map from adjusted offset in int features to feature
* Corrects for Long/Double values taking 2 int slots
* Set at commit time
*/
private FeatureImpl[] staticMergedIntFeaturesList;
/**
* Map from adjusted offset in ref features to feature
* Set at commit time
*/
private FeatureImpl[] staticMergedRefFeaturesList;
/**
* Just the FS refs which are not sofa refs
*/
private FeatureImpl[] staticMergedNonSofaFsRefs;
/**
* The number of used slots needed = total number of features minus those represented by fields in JCas cover classes
*/
int nbrOfUsedIntDataSlots = -1;
int nbrOfUsedRefDataSlots = -1;
// for journalling allocation: This is a 0-based offset for all features in feature order
int highestOffset = -1;
// FeatureImpl featUimaUID = null; // null or the feature named uimaUID with range type long
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;
slotKind = TypeSystemImpl.getSlotKindFromType(this);
this.allSuperTypes = null;
}
/**
* Create a new type. This should only be done by a <code>TypeSystemImpl</code>.
*/
TypeImpl(String name, TypeSystemImpl tsi, final TypeImpl supertype) {
this(name, tsi, supertype, supertype.javaClass);
}
TypeImpl(String name, TypeSystemImpl tsi, final TypeImpl supertype, Class<?> javaClass) {
if (isStringSubtype() && supertype == tsi.stringType) {
tsi.newTypeCheckNoInheritanceFinalCheck(name, supertype);
} else {
tsi.newTypeChecks(name, supertype);
}
this.name = name;
final int pos = this.name.lastIndexOf(TypeSystem.NAMESPACE_SEPARATOR);
this.shortName = (pos >= 0) ? this.name.substring(pos + 1) : name;
this.superType = supertype;
this.isInheritanceFinal = false;
this.isFeatureFinal = false;
this.isLongOrDouble = name.equals(CAS.TYPE_NAME_LONG) || name.equals(CAS.TYPE_NAME_DOUBLE);
this.tsi = tsi;
if (tsi.types.size() > Short.MAX_VALUE) {
throw new RuntimeException("Too many types declared, max is 32767.");
}
this.typeCode = (short) tsi.types.size(); // initialized with one null; so first typeCode == 1
tsi.types.add(this);
TypeImpl node = supertype;
ArrayList<TypeImpl> a = new ArrayList<>();
while (node != null) {
a.add(node);
node = node.superType;
}
allSuperTypes = a.toArray(new TypeImpl[a.size()]);
if (null != this.superType) { // top has null super
// if (!superType.isArray()) {
// this because we have from V2: xyz[] is a subtype of FSArray, but FSArray doesn't list it as a direct subtype
// but this breaks commit
superType.directSubtypes.add(this);
// }
if (superType.staticMergedFeatures != null) {
staticMergedFeatures.putAll(superType.staticMergedFeatures);
}
}
this.isCreatableAndNotBuiltinArray =
// until stringType is set, skip this part of the test
(tsi.stringType == null || supertype != tsi.stringType) // string subtypes aren't FSs, they are only values
&& !BuiltinTypeKinds.nonCreatableTypesAndBuiltinArrays_contains(name);
this.isRefType = tsi.classifyAsRefType(name, supertype);
this.javaClass = javaClass;
tsi.typeName2TypeImpl.put(name, this);
// if (javaClass == boolean.class) {
// getter_funct_intfc_class = JCas_getter_boolean.class;
// setter_funct_intfc_class = JCas_setter_boolean.class;
// } else if (javaClass == byte.class) {
// getter_funct_intfc_class = JCas_getter_byte.class;
// setter_funct_intfc_class = JCas_setter_byte.class;
// } else if (javaClass == short.class) {
// getter_funct_intfc_class = JCas_getter_short.class;
// setter_funct_intfc_class = JCas_setter_short.class;
// } else if (javaClass == int.class) {
// getter_funct_intfc_class = JCas_getter_int.class;
// setter_funct_intfc_class = JCas_setter_int.class;
// } else if (javaClass == long.class) {
// getter_funct_intfc_class = JCas_getter_long.class;
// setter_funct_intfc_class = JCas_setter_long.class;
// } else if (javaClass == float.class) {
// getter_funct_intfc_class = JCas_getter_float.class;
// setter_funct_intfc_class = JCas_setter_float.class;
// } else if (javaClass == double.class) {
// getter_funct_intfc_class = JCas_getter_double.class;
// setter_funct_intfc_class = JCas_setter_double.class;
// } else {
// getter_funct_intfc_class = JCas_getter_generic.class;
// setter_funct_intfc_class = JCas_setter_generic.class;
// }
slotKind = TypeSystemImpl.getSlotKindFromType(this);
hasRefFeature = name.equals(CAS.TYPE_NAME_FS_ARRAY); // initialization of other cases done at commit time
}
/**
* Get the name of the type.
*
* @return The name of the type.
*/
@Override
public String getName() {
return this.name;
}
/**
* Get the super type.
*
* @return The super type or null for Top.
*/
public TypeImpl getSuperType() {
return this.superType;
}
/**
* Return the internal integer code for this type. This is only useful if you want to work with
* the low-level API.
*
* @return The internal code for this type, <code>&gt;=0</code>.
*/
public int getCode() {
return this.typeCode;
}
@Override
public String toString() {
// for backwards compatibility, must return just the name
return getName();
// return toString(0);
}
public String toString(int indent) {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName() + " [name: ").append(name).append(", superType: ").append((superType == null) ? "<null>" :superType.getName()).append(", ");
prettyPrintList(sb, "directSubtypes", directSubtypes, ti -> sb.append(ti.getName()));
sb.append(", ");
appendIntroFeats(sb, indent);
return sb.toString();
}
private <T> void prettyPrintList(StringBuilder sb, String title, List<T> items, Consumer<T> appender) {
sb.append(title).append(": ");
Misc.addElementsToStringBuilder(sb, items, appender);
}
private static final char[] blanks = new char[80];
static {Arrays.fill(blanks, ' ');}
public void prettyPrint(StringBuilder sb, int indent) {
indent(sb, indent).append(name).append(": super: ").append((null == superType) ? "<null>" : superType.getName());
if (staticMergedFeaturesIntroducedByThisType.size() > 0) {
sb.append(", ");
appendIntroFeats(sb, indent);
}
sb.append('\n');
}
private StringBuilder indent(StringBuilder sb, int indent) {
return sb.append(blanks, 0, Math.min(indent, blanks.length));
}
public void prettyPrintWithSubTypes(StringBuilder sb, int indent) {
prettyPrint(sb, indent);
int nextIndent = indent + 2;
directSubtypes.stream().forEachOrdered(ti -> ti.prettyPrint(sb, nextIndent));
}
private void appendIntroFeats(StringBuilder sb, int indent) {
prettyPrintList(sb, "FeaturesIntroduced/Range/multiRef", staticMergedFeaturesIntroducedByThisType,
fi -> indent(sb.append('\n'), indent + 2).append(fi.getShortName()).append('/')
.append(fi.getRange().getName()).append('/')
.append(fi.isMultipleReferencesAllowed() ? 'T' : 'F') );
}
/**
* Get a vector of the features for which this type is the domain. Features will be returned in no
* particular order.
*
* @return The vector.
* @deprecated use getFeatures()
*/
@Override
@Deprecated
public Vector<Feature> getAppropriateFeatures() {
return new Vector<Feature>(getFeatures());
}
/**
* Get the number of features for which this type defines the range.
*
* @return The number of features.
*/
@Override
public int getNumberOfFeatures() {
return staticMergedFeatures.size();
}
public boolean isAppropriateFeature(Feature feature) {
TypeImpl domain = (TypeImpl) feature.getDomain();
return domain.subsumes(this);
}
/**
* Check if this is an annotation type.
*
* @return <code>true</code>, if <code>this</code> is an annotation type or subtype; <code>false</code>,
* else.
*/
public boolean isAnnotationType() {
return false;
}
/**
* @return true for AnnotationBaseType or any subtype
*/
public boolean isAnnotationBaseType() {
return false;
}
public boolean isCreatableAndNotBuiltinArray() {
return isCreatableAndNotBuiltinArray;
}
/**
* Get the type hierarchy that this type belongs to.
*
* @return The type hierarchy.
*/
public TypeSystemImpl getTypeSystem() {
return this.tsi;
}
/**
* @see org.apache.uima.cas.Type#getFeatureByBaseName(String)
*/
@Override
public FeatureImpl getFeatureByBaseName(String featureShortName) {
return staticMergedFeatures.get(featureShortName);
}
/**
* @see org.apache.uima.cas.Type#getShortName()
*/
@Override
public String getShortName() {
return this.shortName;
}
/**
* @see org.apache.uima.cas.Type#isFeatureFinal()
*/
@Override
public boolean isFeatureFinal() {
return this.isFeatureFinal;
}
/**
* @see org.apache.uima.cas.Type#isInheritanceFinal()
*/
@Override
public boolean isInheritanceFinal() {
return this.isInheritanceFinal;
}
void setFeatureFinal() {
this.isFeatureFinal = true;
}
void setInheritanceFinal() {
this.isInheritanceFinal = true;
}
public boolean isLongOrDouble() {
return this.isLongOrDouble;
}
/**
* @deprecated use getFeatureByBaseName instead
* @param featureName -
* @return -
*/
@Deprecated
public Feature getFeature(String featureName) {
return getFeatureByBaseName(featureName);
}
/**
* guaranteed to be non-null, but might be empty list
* @return -
*/
@Override
public List<Feature> getFeatures() {
return new ArrayList<Feature>(Arrays.asList(getFeatureImpls()));
}
/**
* This impl depends on features never being removed from types, only added
* Minimal Java object generation, maximal reuse
* @return the list of feature impls
*/
public FeatureImpl[] getFeatureImpls() {
if (!tsi.isCommitted()) {
// recompute the list if needed
int nbrOfFeats = staticMergedFeatures.size();
if (staticMergedFeaturesList == null || nbrOfFeats != staticMergedFeaturesList.length) {
computeStaticMergedFeaturesList();
}
}
return staticMergedFeaturesList;
}
private void computeStaticMergedFeaturesList() {
synchronized (staticMergedFeaturesIntroducedByThisType) {
if (null == superType) { // is top type
staticMergedFeaturesList = Constants.EMPTY_FEATURE_ARRAY;
return;
}
int length1 = superType.getFeatureImpls().length;
int length2 = staticMergedFeaturesIntroducedByThisType.size();
staticMergedFeaturesList = new FeatureImpl[length1 + length2];
System.arraycopy(superType.getFeatureImpls(), 0, staticMergedFeaturesList, 0, length1);
int i = length1;
for (FeatureImpl fi : staticMergedFeaturesIntroducedByThisType) {
staticMergedFeaturesList[i++] = fi;
}
}
}
private void computeHasXxx() {
nbrOfLongOrDoubleFeatures = superType.getNbrOfLongOrDoubleFeatures();
if (superType.hasRefFeature) {
hasRefFeature = true;
}
for (FeatureImpl fi : staticMergedFeaturesIntroducedByThisType) {
if (!hasRefFeature && fi.getRangeImpl().isRefType) {
hasRefFeature = true;
}
if (fi.getRangeImpl().isLongOrDouble) {
nbrOfLongOrDoubleFeatures ++;
}
}
}
public Stream<FeatureImpl> getFeaturesAsStream() {
return Arrays.stream(getFeatureImpls());
}
public List<FeatureImpl> getMergedStaticFeaturesIntroducedByThisType() {
return staticMergedFeaturesIntroducedByThisType;
}
/**
* @param fi feature to be added
*/
void addFeature(FeatureImpl fi) {
checkExistingFeatureCompatible(staticMergedFeatures.get(fi.getShortName()), fi.getRange());
checkAndAdjustFeatureInSubtypes(this, fi);
staticMergedFeatures.put(fi.getShortName(), fi);
staticMergedFeaturesIntroducedByThisType.add(fi);
// if (fi.getShortName().equals(CAS.FEATURE_BASE_NAME_UIMA_UID) &&
// fi.getRangeImpl().getName().equals(CAS.TYPE_NAME_LONG)) {
// featUimaUID = fi;
// }
// List<FeatureImpl> featuresSharingRange = getFeaturesSharingRange(fi.getRange());
// if (featuresSharingRange == null) {
// featuresSharingRange = new ArrayList<>();
// range2AllFeaturesHavingThatRange.put((TypeImpl) fi.getRange(), featuresSharingRange);
// }
// featuresSharingRange.add(fi);
// getAllSubtypes().forEach(ti -> ti.addFeature(fi)); // add the same feature to all subtypes
}
/**
* It is possible that users may create type/subtype structure, and then add features (in any order) to that,
* including adding a subtype feature "foo", and subsequently adding a type feature "foo".
*
* To handle this:
* a feature added to type T should be
* - removed if present in all subtype's introfeatures
* - added to all subtypes merged features
* - a check done in case any of the subtypes had already added this, but with a different definition
* @param ti the type whose subtypes need checking
* @param fi the feature
*/
private void checkAndAdjustFeatureInSubtypes(TypeImpl ti, FeatureImpl fi) {
String featShortName = fi.getShortName();
for (TypeImpl subti : ti.directSubtypes) {
removeEqualFeatureNameMatch(subti.staticMergedFeaturesIntroducedByThisType, featShortName);
FeatureImpl existing = subti.staticMergedFeatures.get(featShortName);
checkExistingFeatureCompatible(existing, fi.getRange());
if (existing == null) {
subti.staticMergedFeatures.put(featShortName, fi);
}
checkAndAdjustFeatureInSubtypes(subti, fi);
}
}
private void removeEqualFeatureNameMatch(List<FeatureImpl> fiList, String aName) {
for (Iterator<FeatureImpl> it = fiList.iterator(); it.hasNext();) {
FeatureImpl fi = it.next();
if (fi.getShortName().equals(aName)) {
it.remove();
break;
}
}
}
void checkExistingFeatureCompatible(FeatureImpl existingFi, Type range) {
if (existingFi != null) {
if (existingFi.getRange() != range) {
/**
* Trying to define feature "{0}" on type "{1}" with range "{2}", but feature has already been
* defined on (super)type "{3}" with range "{4}".
*/
throw new CASAdminException(CASAdminException.DUPLICATE_FEATURE,
existingFi .getShortName(),
this .getName(),
range .getName(),
existingFi.getDomain().getName(),
existingFi.getRange() .getName());
}
}
}
// public String getJavaDescriptor() {
// // built-ins
// switch (typeCode) {
// case TypeSystemConstants.booleanTypeCode: return "Z";
// case TypeSystemConstants.byteTypeCode: return "B";
// case TypeSystemConstants.shortTypeCode: return "S";
// case TypeSystemConstants.intTypeCode: return "I";
// case TypeSystemConstants.floatTypeCode: return "F";
// case TypeSystemConstants.longTypeCode: return "J";
// case TypeSystemConstants.doubleTypeCode: return "D";
// case TypeSystemConstants.booleanArrayTypeCode: return "[Z";
// case TypeSystemConstants.byteArrayTypeCode: return "[B";
// case TypeSystemConstants.shortArrayTypeCode: return "[S";
// case TypeSystemConstants.intArrayTypeCode: return "[I";
// case TypeSystemConstants.floatArrayTypeCode: return "[F";
// case TypeSystemConstants.longArrayTypeCode: return "[J";
// case TypeSystemConstants.doubleArrayTypeCode: return "[D";
// case TypeSystemConstants.stringArrayTypeCode: return "[Ljava/lang/String;";
// }
//
// if (isStringSubtype()) {
// return "Ljava/lang/String;";
// }
//
// return (isArray() ? "[" : "") + "L" + nameWithSlashes + ";";
// }
/**
* Consolidate arrays of fsRefs to fsArrayType and ordinary fsRefs to TOP for generic getters and setters
* @param topType -
* @param fsArrayType -
* @return this type or one of the two passed in types
*/
TypeImpl consolidateType(TypeImpl topType, TypeImpl fsArrayType) {
if (!(isPrimitive())) {
return topType;
}
// is one of the primitive (non-array) types
return this;
}
/**
* @see org.apache.uima.cas.Type#isPrimitive()
*/
@Override
public boolean isPrimitive() {
return false; // overridden by primitive typeimpl
}
/**
* @see org.apache.uima.cas.Type#isArray()
*/
@Override
public boolean isArray() {
return false; // overridden by array subtype
}
/**
* model how v2 stores this - needed for backward compatibility / (de)serialization
* @return true if it is an array and is stored in the main heap (int, float, or string)
*/
boolean isHeapStoredArray() {
return false; // overridden by some array subtypes, used for backward compatibility
}
/**
* model how v2 stores this - needed for backward compatibility / (de)serialization
* @return true if it is an array and is one of the 3 aux arrays (byte (also used for boolean) short, long
*/
boolean isAuxStoredArray() {
return false; // overridden by array subtype, used for backward compatibility
}
/**
* @see org.apache.uima.cas.Type#isStringSubtype()
*/
@Override
public boolean isStringSubtype() {
return false; // overridden by string subtype
}
@Override
public boolean isStringOrStringSubtype() {
return false;
}
@Override
public TypeImpl getComponentType() {
return null; // not an array, array subtype overrides
}
public SlotKind getComponentSlotKind() { return null; /* not an array, array subtype overrides */ }
/**
*
* @return stream of all subtypes (excludes this type)
* in strict subsumption order
*/
Stream<TypeImpl> getAllSubtypes() {
return directSubtypes.stream().flatMap((TypeImpl ti) -> Stream.concat(Stream.of(ti), ti.getAllSubtypes()));
}
List<TypeImpl> getDirectSubtypes() {
return directSubtypes;
}
boolean hasSupertype(TypeImpl supertype) {
for (TypeImpl st : allSuperTypes) {
if (st == supertype) {
return true;
}
}
return false;
}
TypeImpl[] getAllSuperTypes() {
return allSuperTypes;
}
// public <T extends FeatureStructure> T createFS(CAS cas) {
// if (null == creator) {
// if (!tsi.isCommitted()) {
// /** Can't create FS of type "{0}" until the type system has been committed. */
// throw new CASRuntimeException(CASRuntimeException.CREATE_FS_BEFORE_TS_COMMITTED, getName());
// }
// generateJCasClass();
// }
// return (T) creator.apply(cas);
// }
//
// public TOP_Type create_Type(JCas jcas) {
// return creator_type.create(jcas, this);
// }
//
// /**
// * Only called if creator is null, meaning the JCas Type and _Type classes haven't been generated yet.
// * Not called for builtins with alternate names (because they're already there, by hand (not generated)
// *
// * This only happens for lazy loaded situations, where there's a UIMATypeSystemClassLoader in the class loader chain.
// * For non-lazy situations (no UIMATypeSystemClassLoader), all the JCas classes were "batch" generated at commit time.
// */
// void generateJCasClass() {
// TypeSystemImpl tsi = (TypeSystemImpl) this.getTypeSystem();
// ClassLoader cl =tsi.get.Class().getClassLoader();
// // load and run static initializers, using the class loader of this TypeImpl
// Class<?> jcasClass;
// try {
// jcasClass = Class.forName(name, true, cl); // generate if not already loaded.
// // the _Type class is statically referenced from the other, and will be loaded too if needed.
// Method getAccessorsMethod = jcasClass.getMethod("__getAccessors");
// Object[] aa = (Object[]) getAccessorsMethod.invoke(null);
// this.creator = (Function<AbstractCas, TOP>) aa[0];
// this.creator_type = (JCas_TypeCreator<?>) aa[1];
// if (isAnnotationType()) {
// ((TypeImplAnnot)this).creatorAnnot = (JCasAnnotCreator<?,?>) aa[2];
// }
// /**
// * Run a parallel loop: the list of static features introduced by this type, and the rest of the accessors
// * one feature may have 2 or 4 accessors (get/set and optionally array-get/set)
// */
// final int nbrFeat = getNumberOfFeatures();
// for (int acc_i = (isAnnotationType() ? 3 : 2), feat_i = 0; feat_i < nbrFeat; acc_i ++, feat_i ++) {
// FeatureImpl fi = staticMergedFeaturesIntroducedByThisType.get(feat_i);
// fi.setGetterMethodRef(aa[acc_i++]);
// fi.setSetterMethodRef(aa[acc_i++]);
// if (fi.getRange().isArray()) {
// ((FeatureArrayImpl)fi).setGetterArrayMethodRef(aa[acc_i++]);
// ((FeatureArrayImpl)fi).setSetterArrayMethodRef(aa[acc_i++]);
// }
// }
// } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// throw new UIMARuntimeException(e); // never happen
// }
// }
//
// public void setCreator(Function<JCas, TOP> fi, Function<>) {
// creator = fi;
// }
/**
* @param ti the subtype to check
* @return true if this type subsumes the subtype (is equal to or a supertype of the subtype)
*/
public boolean subsumes(TypeImpl ti) {
if (depthFirstCode <= ti.depthFirstCode && ti.depthFirstCode < depthFirstNextSibling) {
return true;
}
if (depthFirstNextSibling != 0) { // means that these codes are valid
return false;
}
return getTypeSystem().subsumes(this, ti);
}
/**
* @param ti the subtype to check
* @return true if this type subsumes the subtype (is equal to or a supertype of the subtype)
*/
public boolean subsumesStrictly(TypeImpl ti) {
if (depthFirstCode < ti.depthFirstCode && ti.depthFirstCode < depthFirstNextSibling) {
return true;
}
if (depthFirstNextSibling != 0) { // means that these codes are valid
return false;
}
if (this.equals(ti)) {
return false;
}
return getTypeSystem().subsumes(this, ti);
}
/**
*
* @param v the value to test
* @return true if value v can be assigned to an object of this type
*/
public boolean subsumesValue(Object v) {
return (v == null && (isRefType || isStringOrStringSubtype())) ||
(v instanceof String && isStringOrStringSubtype()) ||
((v instanceof FeatureStructureImplC) &&
subsumes( ((FeatureStructureImplC)v)._getTypeImpl()))
;
}
int computeDepthFirstCode(int level) {
// other work done for each type at commit time, just piggy backing on this method
/**************************************************************************************
* N O T E : *
* fixup the ordering of staticMergedFeatures: *
* - supers, then features introduced by this type. *
* - order may be "bad" if later feature merge introduced an additional feature *
**************************************************************************************/
if (level != 1) {
// skip for top level; no features there, but no super type either
getFeatureImpls(); // also done for side effect of computingcomputeStaticMergedFeaturesList();
computeHasXxx();
}
depthFirstCode = (short) ( level ++ );
for (TypeImpl subti : directSubtypes) {
level = subti.computeDepthFirstCode(level);
}
depthFirstNextSibling = (short) level;
return level;
}
/**
* Of limited use because the java class value, over time, is multi- valued; e.g. when PEARs are in use,
* or different extension classpaths are in use for multiple pipelines.
* @return the javaClass
*/
Class<?> getJavaClass() {
return javaClass;
}
/**
* @param javaClass the javaClass to set
*/
void setJavaClass(Class<?> javaClass) {
this.javaClass = javaClass;
}
/**
* Get the v2 heap size for types with features
* @return the main heap size for this FeatureStructure, assuming it's not a heap stored array (see below)
*/
public int getFsSpaceReq() {
return getFeatureImpls().length + 1; // number of feats + 1 for the type code
}
/**
* get the v2 heap size for types
* @param length for heap-stored arrays, the array length
* @return the main heap size for this FeatureStructure
*/
public int getFsSpaceReq(int length) {
return isHeapStoredArray()
? (2 + length)
: isArray()
? 3
: getFsSpaceReq();
}
public int getFsSpaceReq(TOP fs) {
return getFsSpaceReq(isHeapStoredArray()
? ((CommonArrayFS)fs).size()
: 0);
}
void setOffset2Feat(List<FeatureImpl> tempIntFis,
List<FeatureImpl> tempRefFis,
List<FeatureImpl> tempNsr,
FeatureImpl fi,
int next) {
if (fi.isInInt) {
assert tempIntFis.size() == next;
tempIntFis.add(fi);
if (fi.getRangeImpl().isLongOrDouble) {
tempIntFis.add(null);
}
} else {
assert tempRefFis.size() == next;
tempRefFis.add(fi);
TypeImpl range = fi.getRangeImpl();
if (range.isRefType &&
range.typeCode != TypeSystemConstants.sofaTypeCode) {
tempNsr.add(fi);
}
}
}
void initAdjOffset2FeatureMaps(List<FeatureImpl> tmpIntFis, List<FeatureImpl> tmpRefFis, List<FeatureImpl> tmpNsr) {
tmpIntFis.addAll(Arrays.asList(superType.staticMergedIntFeaturesList));
tmpRefFis.addAll(Arrays.asList(superType.staticMergedRefFeaturesList));
tmpNsr .addAll(Arrays.asList(superType.staticMergedNonSofaFsRefs));
}
FeatureImpl getFeatureByAdjOffset(int adjOffset, boolean isInInt) {
if (isInInt) {
return staticMergedIntFeaturesList[adjOffset];
} else {
return staticMergedRefFeaturesList[adjOffset];
}
}
int getAdjOffset(String featureShortName) {
return getFeatureByBaseName(featureShortName).getAdjustedOffset();
}
/**
* A special instance used in CasCopier to identify a missing type
*/
public final static TypeImpl singleton = new TypeImpl();
private int hashCode = 0;
private boolean hasHashCode = false;
@Override
public int hashCode() {
if (hasHashCode) return hashCode;
synchronized (this) {
int h = computeHashCode();
if (tsi.isCommitted()) {
hashCode = h;
hasHashCode = true;
}
return h;
}
}
/**
* works across type systems
* @return -
*/
private int computeHashCode() {
final int prime = 31;
int result = 1;
result = prime * result + name.hashCode();
result = prime * result + ((superType == null) ? 0 : superType.name.hashCode());
for (TypeImpl ti : directSubtypes) {
result = prime * result + ti.name.hashCode();
}
result = prime * result + (isFeatureFinal ? 1231 : 1237);
result = prime * result + (isInheritanceFinal ? 1231 : 1237);
for (FeatureImpl fi : getFeatureImpls()) {
result = prime * result + fi.hashCode();
}
return result;
}
/**
* Equal TypeImpl
* Works across type systems.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || !(obj instanceof TypeImpl)) return false;
TypeImpl other = (TypeImpl) obj;
if (hashCode() != other.hashCode()) return false;
if (!name.equals(other.name)) return false;
if (superType == null) {
if (other.superType != null) return false;
} else {
if (other.superType == null) return false;
if (!superType.name.equals(other.superType.name)) return false;
}
if (directSubtypes.size() != other.directSubtypes.size()) return false;
if (isFeatureFinal != other.isFeatureFinal) return false;
if (isInheritanceFinal != other.isInheritanceFinal) return false;
if (this.getNumberOfFeatures() != other.getNumberOfFeatures()) return false;
final FeatureImpl[] fis1 = getFeatureImpls();
final FeatureImpl[] fis2 = other.getFeatureImpls();
if (!Arrays.equals(fis1, fis2)) return false;
for (int i = 0; i < directSubtypes.size(); i++) {
if (!directSubtypes.get(i).name.equals(other.directSubtypes.get(i).name)) return false;
}
return true;
}
/**
* compareTo must return 0 for "equal" types
*
* use the fully qualified names as the comparison
* Note: you can only compare types from the same type system. If you compare types from different
* type systems, the result is undefined.
*/
@Override
public int compareTo(TypeImpl t) {
if (this == t) {
return 0;
}
int c = this.name.compareTo(t.name);
if (c != 0) return c;
c = Integer.compare(this.hashCode(), t.hashCode());
if (c != 0) return c;
// if get here, we have two types of the same name, and same hashcode
// may or may not be equal
// check the parts.
if (this.superType == null || t.superType == null) {
Misc.internalError();
};
c = this.superType.name.compareTo(t.superType.name);
if (c != 0) return c;
c = Integer.compare(this.directSubtypes.size(), t.directSubtypes.size());
if (c != 0) return c;
c = Integer.compare(this.getNumberOfFeatures(), t.getNumberOfFeatures());
if (c != 0) return c;
c = Boolean.compare(this.isFeatureFinal, t.isFeatureFinal);
if (c != 0) return c;
c = Boolean.compare(this.isInheritanceFinal, t.isInheritanceFinal);
if (c != 0) return c;
final FeatureImpl[] fis1 = getFeatureImpls();
final FeatureImpl[] fis2 = t.getFeatureImpls();
for (int i = 0; i < fis1.length; i++) {
c = fis1[i].compareTo(fis2[i]);
if (c != 0) return c;
}
for (int i = 0; i < directSubtypes.size(); i++) {
c = this.directSubtypes.get(i).compareTo(t.directSubtypes.get(i));
if (c != 0) return c;
}
return 0;
}
boolean isPrimitiveArrayType() {
if (!isArray()) {
return false;
}
switch(this.typeCode) {
case TypeSystemConstants.floatArrayTypeCode:
case TypeSystemConstants.intArrayTypeCode:
case TypeSystemConstants.booleanArrayTypeCode:
case TypeSystemConstants.shortArrayTypeCode:
case TypeSystemConstants.byteArrayTypeCode:
case TypeSystemConstants.longArrayTypeCode:
case TypeSystemConstants.doubleArrayTypeCode:
case TypeSystemConstants.stringArrayTypeCode:
// case TypeSystemConstants.javaObjectArrayTypeCode:
return true;
default: return false;
}
}
public boolean hasRefFeature() {
return hasRefFeature;
}
public int getNbrOfLongOrDoubleFeatures() {
return nbrOfLongOrDoubleFeatures;
}
/**
* @return true if this type is an array of specific (not TOP) Feature structures, not FSArray
*/
public boolean isTypedFsArray() {
return false;
}
void setStaticMergedIntFeaturesList(FeatureImpl[] v) {
staticMergedIntFeaturesList = v;
}
void setStaticMergedRefFeaturesList(FeatureImpl[] v) {
staticMergedRefFeaturesList = v;
}
void setStaticMergedNonSofaFsRefs(FeatureImpl[] v) {
staticMergedNonSofaFsRefs = v;
}
// FeatureImpl[] getStaticMergedRefFeatures() {
// return staticMergedRefFeaturesList;
// }
FeatureImpl[] getStaticMergedNonSofaFsRefs() {
return staticMergedNonSofaFsRefs;
}
public boolean isTopType() {
return superType == null;
}
// /**
// * @return the generator
// */
// FsGenerator getGenerator() {
// return generator;
// }
// /**
// * @return the jcasClassInfo
// */
// JCasClassInfo getJcasClassInfo() {
// return jcasClassInfo;
// }
// /**
// * @param jcasClassInfo the jcasClassInfo to set
// */
// void setJcasClassInfo(JCasClassInfo jcasClassInfo) {
// this.jcasClassInfo = jcasClassInfo;
// Object g = jcasClassInfo.generator;
// this.generator = (g instanceof FsGenerator) ? (FsGenerator)g : null;
// }
// public boolean hasOnlyInts() {
// return hasOnlyInts;
// }
//
// public boolean hasOnlyRefs() {
// return hasOnlyRefs;
// }
//
// public boolean hasNoSlots() {
// return hasNoSlots;
// }
}