Package org.apache.uima.cas.impl

Source Code of org.apache.uima.cas.impl.TypeSystemImpl$ListIterator

/*
* 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.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Vector;

import org.apache.uima.cas.CAS;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeNameSpace;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.admin.CASAdminException;
import org.apache.uima.cas.admin.TypeSystemMgr;
import org.apache.uima.internal.util.IntVector;
import org.apache.uima.internal.util.StringToIntMap;
import org.apache.uima.internal.util.SymbolTable;
import org.apache.uima.internal.util.rb_trees.IntRedBlackTree;
import org.apache.uima.internal.util.rb_trees.RedBlackTree;

/**
* Type system implementation.
*
*/
public class TypeSystemImpl implements TypeSystemMgr, LowLevelTypeSystem {

  private static class ListIterator implements Iterator {

    private final List list;

    private final int len;

    private int pos = 0;

    private ListIterator(List list, int max) {
      super();
      this.list = list;
      this.len = (max < list.size()) ? max : list.size();
    }

    public boolean hasNext() {
      return this.pos < this.len;
    }

    public Object next() {
      if (!hasNext()) {
        throw new NoSuchElementException();
      }
      Object o = this.list.get(this.pos);
      ++this.pos;
      return o;
    }

    public void remove() {
      throw new UnsupportedOperationException();
    }

  }

  // static maps ok for now - only built-in mappings stored here
  // which are the same for all type system instances
  private static HashMap arrayComponentTypeNameMap = new HashMap();

  private static HashMap arrayTypeComponentNameMap = new HashMap();

  private static final String arrayTypeSuffix = "[]";

  static {
    arrayComponentTypeNameMap.put(CAS.TYPE_NAME_TOP, CAS.TYPE_NAME_FS_ARRAY);
    arrayComponentTypeNameMap.put(CAS.TYPE_NAME_BOOLEAN, CAS.TYPE_NAME_BOOLEAN_ARRAY);
    arrayComponentTypeNameMap.put(CAS.TYPE_NAME_BYTE, CAS.TYPE_NAME_BYTE_ARRAY);
    arrayComponentTypeNameMap.put(CAS.TYPE_NAME_SHORT, CAS.TYPE_NAME_SHORT_ARRAY);
    arrayComponentTypeNameMap.put(CAS.TYPE_NAME_INTEGER, CAS.TYPE_NAME_INTEGER_ARRAY);
    arrayComponentTypeNameMap.put(CAS.TYPE_NAME_FLOAT, CAS.TYPE_NAME_FLOAT_ARRAY);
    arrayComponentTypeNameMap.put(CAS.TYPE_NAME_LONG, CAS.TYPE_NAME_LONG_ARRAY);
    arrayComponentTypeNameMap.put(CAS.TYPE_NAME_DOUBLE, CAS.TYPE_NAME_DOUBLE_ARRAY);
    arrayComponentTypeNameMap.put(CAS.TYPE_NAME_STRING, CAS.TYPE_NAME_STRING_ARRAY);
  }

  static {
    arrayTypeComponentNameMap.put(CAS.TYPE_NAME_FS_ARRAY, CAS.TYPE_NAME_TOP);
    arrayTypeComponentNameMap.put(CAS.TYPE_NAME_BOOLEAN_ARRAY, CAS.TYPE_NAME_BOOLEAN);
    arrayTypeComponentNameMap.put(CAS.TYPE_NAME_BYTE_ARRAY, CAS.TYPE_NAME_BYTE);
    arrayTypeComponentNameMap.put(CAS.TYPE_NAME_SHORT_ARRAY, CAS.TYPE_NAME_SHORT);
    arrayTypeComponentNameMap.put(CAS.TYPE_NAME_INTEGER_ARRAY, CAS.TYPE_NAME_INTEGER);
    arrayTypeComponentNameMap.put(CAS.TYPE_NAME_FLOAT_ARRAY, CAS.TYPE_NAME_FLOAT);
    arrayTypeComponentNameMap.put(CAS.TYPE_NAME_LONG_ARRAY, CAS.TYPE_NAME_LONG);
    arrayTypeComponentNameMap.put(CAS.TYPE_NAME_DOUBLE_ARRAY, CAS.TYPE_NAME_DOUBLE);
    arrayTypeComponentNameMap.put(CAS.TYPE_NAME_STRING_ARRAY, CAS.TYPE_NAME_STRING);
  }

  // Current implementation has online update. Look-up could be made
  // more efficient by computing some tables, but the assumption is
  // that the type system will not be queried often enough to justify
  // the effort.

  private SymbolTable typeNameST; // Symbol table of type names

  // Symbol table of feature names, containing only one entry per feature,
  // i.e.,
  // its normal form.
  private SymbolTable featureNameST;

  // A map from the full space of feature names to feature codes. A feature
  // may
  // be know by many different names (one for each subtype of the type the
  // feature is declared on).
  private StringToIntMap featureMap;

  private ArrayList tree; // Vector of IntVectors encoding type tree

  private ArrayList subsumes; // Vector of BitSets for subsumption relation

  private IntVector intro;

  // Indicates which type introduces a feature (domain)
  private IntVector featRange; // Indicates range type of features

  private ArrayList approp; // For each type, an IntVector of appropriate

  // features

  // Code of root of hierarchy (will be 1 with current implementation)
  private int top;

  // A vector of TypeImpl objects.
  private ArrayList types;

  // A vector of FeatureImpl objects.
  private ArrayList features;

  // List of parent types.
  private final IntVector parents;

  // String sets for string subtypes.
  private final ArrayList stringSets;

 
  // This map contains an entry for every subtype of the string type.  The value is a pointer into
  // the stringSets array list.
  private final IntRedBlackTree stringSetMap;

  // For each type, remember of an array of this component type has already
  // been created.
  private final IntRedBlackTree componentToArrayTypeMap;

  // A mapping from array types to their component types.
  private final IntRedBlackTree arrayToComponentTypeMap;

  // A mapping from array type codes to array type objects.
  private final RedBlackTree arrayCodeToTypeMap;

  // Is the type system locked?
  private boolean locked = false;

  // Must be able to lock type system info in the CAS, so need a handle to
  // embedding CAS.
  // Deleted (MIS 6/06) - Type Systems shared by many CASes, can't point to
  // one.
  // private CASImpl cas;

  private static final int LEAST_TYPE_CODE = 1;

  // private static final int INVALID_TYPE_CODE = 0;
  private static final int LEAST_FEATUE_CODE = 1;

  // private int topTypeCode;
  private int booleanTypeCode = UNKNOWN_TYPE_CODE;

  private int byteTypeCode = UNKNOWN_TYPE_CODE;

  private int shortTypeCode = UNKNOWN_TYPE_CODE;

  private int intTypeCode = UNKNOWN_TYPE_CODE;

  private int floatTypeCode = UNKNOWN_TYPE_CODE;

  private int longTypeCode = UNKNOWN_TYPE_CODE;

  private int doubleTypeCode = UNKNOWN_TYPE_CODE;

  private int stringTypeCode = UNKNOWN_TYPE_CODE;

  private int arrayBaseTypeCode = UNKNOWN_TYPE_CODE;

  private int booleanArrayTypeCode = UNKNOWN_TYPE_CODE;

  private int byteArrayTypeCode = UNKNOWN_TYPE_CODE;

  private int shortArrayTypeCode = UNKNOWN_TYPE_CODE;

  private int intArrayTypeCode = UNKNOWN_TYPE_CODE;

  private int floatArrayTypeCode = UNKNOWN_TYPE_CODE;

  private int longArrayTypeCode = UNKNOWN_TYPE_CODE;

  private int doubleArrayTypeCode = UNKNOWN_TYPE_CODE;

  private int stringArrayTypeCode = UNKNOWN_TYPE_CODE;

  private int fsArrayTypeCode = UNKNOWN_TYPE_CODE;

  private int numCommittedTypes = 0;

  /**
   * Default constructor.
   *
   * @deprecated Use 0 arg constructor. Type Systems are shared by many CASes, and can't point to
   *             one. Change also your possible calls to ts.commit() - see comment on that method.
   */
  public TypeSystemImpl(CASImpl cas) {
    this();
  }

  public TypeSystemImpl() {
    super();
    // Changed numbering to start at 1. Hope this doesn't break
    // anything. If it does, I know who's fault it is...
    this.typeNameST = new SymbolTable(1);
    this.featureNameST = new SymbolTable(1);
    this.featureMap = new StringToIntMap();
    // In each Vector, add null as first element, since we start
    // counting at 1.
    this.tree = new ArrayList();
    this.tree.add(null);
    this.subsumes = new ArrayList();
    this.subsumes.add(null);
    this.intro = new IntVector();
    this.intro.add(0);
    this.featRange = new IntVector();
    this.featRange.add(0);
    this.approp = new ArrayList();
    this.approp.add(null);
    this.types = new ArrayList();
    this.types.add(null);
    this.features = new ArrayList();
    this.features.add(null);
    this.stringSets = new ArrayList();
    this.stringSetMap = new IntRedBlackTree();
    this.componentToArrayTypeMap = new IntRedBlackTree();
    this.arrayToComponentTypeMap = new IntRedBlackTree();
    this.arrayCodeToTypeMap = new RedBlackTree();
    this.parents = new IntVector();
    this.parents.add(0);
  }

  // Some implementation helpers for users of the type system.
  final int getSmallestType() {
    return LEAST_TYPE_CODE;
  }

  final int getSmallestFeature() {
    return LEAST_FEATUE_CODE;
  }

  final int getTypeArraySize() {
    return getNumberOfTypes() + getSmallestType();
  }

  public Vector getIntroFeatures(Type type) {
    Vector feats = new Vector();
    List appropFeats = type.getFeatures();
    final int max = appropFeats.size();
    Feature feat;
    for (int i = 0; i < max; i++) {
      feat = (Feature) appropFeats.get(i);
      if (feat.getDomain() == type) {
        feats.add(feat);
      }
    }
    return feats;
  }

  public Type getParent(Type t) {
    return ((TypeImpl) t).getSuperType();
  }

  public int ll_getParentType(int typeCode) {
    return this.parents.get(typeCode);
  }

  int ll_computeArrayParentFromComponentType(int componentType) {
    if (ll_isPrimitiveType(componentType) ||
    // note: not using this.top - until we can confirm this is set
            // in all cases
            (ll_getTypeForCode(componentType).getName().equals(CAS.TYPE_NAME_TOP))) {
      return ll_getCodeForTypeName(CAS.TYPE_NAME_ARRAY_BASE);
    }
    // is a subtype of FSArray.
    // note: not using this.fsArray - until we can confirm this is set in
    // all cases
    return ll_getCodeForTypeName(CAS.TYPE_NAME_FS_ARRAY);
    // return ll_getArrayType(ll_getParentType(componentType));
  }

  /**
   * Check if feature is appropriate for type (i.e., type is subsumed by domain type of feature).
   */
  public boolean isApprop(int type, int feat) {
    return subsumes(intro(feat), type);
  }

  public final int getLargestTypeCode() {
    return getNumberOfTypes();
  }

  public boolean isType(int type) {
    return ((type > 0) && (type <= getLargestTypeCode()));
  }

  /**
   * Get a type object for a given code.
   *
   * @param typeCode
   *          The code of the type.
   * @return A type object, or <code>null</code> if no such type exists.
   */
  public Type getType(int typeCode) {
    return (Type) this.types.get(typeCode);
  }

  public String getTypeName(int typeCode) {
    return this.typeNameST.getSymbol(typeCode);
  }

  public String getFeatureName(int featCode) {
    return this.featureNameST.getSymbol(featCode);
  }

  /**
   * Get a type object for a given name.
   *
   * @param typeName
   *          The name of the type.
   * @return A type object, or <code>null</code> if no such type exists.
   */
  public Type getType(String typeName) {
    final int typeCode = ll_getCodeForTypeName(typeName);
    if (typeCode < LEAST_TYPE_CODE) {
      return null;
    }
    return (Type) this.types.get(typeCode);
  }

  /**
   * Get an feature object for a given code.
   *
   * @param featCode
   *          The code of the feature.
   * @return A feature object, or <code>null</code> if no such feature exists.
   */
  public Feature getFeature(int featCode) {
    return (Feature) this.features.get(featCode);
  }

  /**
   * Get an feature object for a given name.
   *
   * @param featureName
   *          The name of the feature.
   * @return An feature object, or <code>null</code> if no such feature exists.
   */
  public Feature getFeatureByFullName(String featureName) {
    if (!this.featureMap.containsKey(featureName)) {
      return null;
    }
    final int featCode = this.featureMap.get(featureName);
    return (Feature) this.features.get(featCode);
  }

  private static final String getArrayTypeName(String typeName) {
    if (arrayComponentTypeNameMap.containsKey(typeName)) {
      return (String) arrayComponentTypeNameMap.get(typeName);
    }
    return typeName + arrayTypeSuffix;
  }

  private static final String getBuiltinArrayComponent(String typeName) {
    if (arrayTypeComponentNameMap.containsKey(typeName)) {
      return (String) arrayTypeComponentNameMap.get(typeName);
    }
    return null;
  }

  /**
   * Add a new type to the type system.
   *
   * @param typeName
   *          The name of the new type.
   * @param mother
   *          The type node under which the new type should be attached.
   * @return The new type, or <code>null</code> if <code>typeName</code> is already in use.
   */
  public Type addType(String typeName, Type mother) throws CASAdminException {
    if (this.locked) {
      throw new CASAdminException(CASAdminException.TYPE_SYSTEM_LOCKED);
    }
    if (mother.isInheritanceFinal()) {
      CASAdminException e = new CASAdminException(CASAdminException.TYPE_IS_INH_FINAL);
      e.addArgument(mother.getName());
      throw e;
    }
    // Check type name syntax.
    String componentTypeName = getBuiltinArrayComponent(typeName);
    if (componentTypeName != null) {
      return getArrayType(getType(componentTypeName));
    }
    checkTypeSyntax(typeName);
    final int typeCode = this.addType(typeName, ((TypeImpl) mother).getCode());
    if (typeCode < this.typeNameST.getStart()) {
      return null;
    }
    return (Type) this.types.get(typeCode);
  }

  /**
   * Method checkTypeSyntax.
   *
   * @param typeName
   */
  private void checkTypeSyntax(String name) throws CASAdminException {
    if (!TypeSystemUtils.isTypeName(name)) {
      CASAdminException e = new CASAdminException(CASAdminException.BAD_TYPE_SYNTAX);
      e.addArgument(name);
      throw e;
    }
  }

  int addType(String name, int superType) {
    return addType(name, superType, false);
  }

  /**
   * Internal code for adding a new type. Warning: no syntax check on type name, must be done by
   * caller. This method is not private because it's used by the serialization code.
   */
  int addType(String name, int superType, boolean isStringType) {
    if (this.typeNameST.contains(name)) {
      return -1;
    }
    // assert (isType(superType)); //: "Supertype is not a known type:
    // "+superType;
    // Add the new type to the symbol table.
    final int type = this.typeNameST.set(name);
    // Create space for new type.
    newType();
    // Add an edge to the tree.
    ((IntVector) this.tree.get(superType)).add(type);
    // Update subsumption relation.
    updateSubsumption(type, superType);
    // Add inherited features.
    final IntVector superApprop = (IntVector) this.approp.get(superType);
    // superApprop.add(0);
    final IntVector typeApprop = (IntVector) this.approp.get(type);
    // typeApprop.add(0);
    final int max = superApprop.size();
    int featCode;
    for (int i = 0; i < max; i++) {
      featCode = superApprop.get(i);
      typeApprop.add(featCode);
      // Add inherited feature names.
      String feat = name + TypeSystem.FEATURE_SEPARATOR + getFeature(featCode).getShortName();
      // System.out.println("Adding name: " + feat);
      this.featureMap.put(feat, featCode);
    }
    TypeImpl t;
    if (isStringType) {
      final int stringSetCode = this.stringSets.size();
      this.stringSetMap.put(type, stringSetCode);
      t = new StringTypeImpl(name, type, this);
    } else {
      t = new TypeImpl(name, type, this);
    }
    this.types.add(t);
    this.parents.add(superType);
    this.numCommittedTypes = this.types.size();
    return type;
  }

  public Feature addFeature(String featureName, Type domainType, Type rangeType)
          throws CASAdminException {
    return addFeature(featureName, domainType, rangeType, true);
  }

  /**
   * @see TypeSystemMgr#addFeature(String, Type, Type)
   */
  public Feature addFeature(String featureName, Type domainType, Type rangeType,
          boolean multipleReferencesAllowed) throws CASAdminException {
    // assert(featureName != null);
    // assert(domainType != null);
    // assert(rangeType != null);
    if (this.locked) {
      throw new CASAdminException(CASAdminException.TYPE_SYSTEM_LOCKED);
    }
    Feature f = domainType.getFeatureByBaseName(featureName);
    if (f != null && f.getRange().equals(rangeType)) {
      return f;
    }
    if (domainType.isFeatureFinal()) {
      CASAdminException e = new CASAdminException(CASAdminException.TYPE_IS_FEATURE_FINAL);
      e.addArgument(domainType.getName());
      throw e;
    }
    checkFeatureNameSyntax(featureName);
    final int featCode = this.addFeature(featureName, ((TypeImpl) domainType).getCode(),
            ((TypeImpl) rangeType).getCode(), multipleReferencesAllowed);
    if (featCode < this.featureNameST.getStart()) {
      return null;
    }
    return (Feature) this.features.get(featCode);
  }

  /**
   * Method checkFeatureNameSyntax.
   */
  private void checkFeatureNameSyntax(String name) throws CASAdminException {
    if (!TypeSystemUtils.isIdentifier(name)) {
      CASAdminException e = new CASAdminException(CASAdminException.BAD_FEATURE_SYNTAX);
      e.addArgument(name);
      throw e;
    }
  }

  /**
   * Get an iterator over all types, in no particular order.
   *
   * @return The iterator.
   */
  public Iterator getTypeIterator() {
    Iterator it = new ListIterator(this.types, this.numCommittedTypes);
    // The first element is null, so skip it.
    it.next();
    return it;
  }

  public Iterator getFeatures() {
    Iterator it = this.features.iterator();
    // The first element is null, so skip it.
    it.next();
    return it;
  }

  /**
   * Get the top type, i.e., the root of the type system.
   *
   * @return The top type.
   */
  public Type getTopType() {
    return (Type) this.types.get(this.top);
  }

  /**
   * Return the list of all types subsumed by the input type. Note: the list does not include the
   * type itself.
   *
   * @param type
   *          Input type.
   * @return The list of types subsumed by <code>type</code>.
   */
  public List getProperlySubsumedTypes(Type type) {
    ArrayList subList = new ArrayList();
    Iterator typeIt = getTypeIterator();
    while (typeIt.hasNext()) {
      Type t = (Type) typeIt.next();
      if (type != t && subsumes(type, t)) {
        subList.add(t);
      }
    }
    return subList;
  }

  /**
   * Get a vector of the types directly subsumed by a given type.
   *
   * @param type
   *          The input type.
   * @return A vector of the directly subsumed types.
   */
  public Vector getDirectlySubsumedTypes(Type type) {
    return new Vector(getDirectSubtypes(type));
  }

  public List getDirectSubtypes(Type type) {
    if (type.isArray()) {
      return new ArrayList();
    }
    ArrayList list = new ArrayList();
    IntVector sub = (IntVector) this.tree.get(((TypeImpl) type).getCode());
    final int max = sub.size();
    for (int i = 0; i < max; i++) {
      list.add(this.types.get(sub.get(i)));
    }
    return list;
  }

  public boolean directlySubsumes(int t1, int t2) {
    IntVector sub = (IntVector) this.tree.get(t1);
    return sub.contains(t2);
  }

  /**
   * Does one type inherit from the other?
   *
   * @param superType
   *          Supertype.
   * @param subType
   *          Subtype.
   * @return <code>true</code> iff <code>sub</code> inherits from <code>super</code>.
   */
  public boolean subsumes(Type superType, Type subType) {
    // assert(superType != null);
    // assert(subType != null);
    return this.subsumes(((TypeImpl) superType).getCode(), ((TypeImpl) subType).getCode());
  }

  /**
   * Get the code for a feature, given its name.
   */
  public int getFeatureCode(String feat) {
    return ll_getCodeForFeatureName(feat);
  }

  /**
   * Get an array of the appropriate features for this type.
   */
  public int[] ll_getAppropriateFeatures(int type) {
    if (type < LEAST_TYPE_CODE || type > getNumberOfTypes()) {
      return null;
    }
    // We have to copy the array since we don't have const.
    return ((IntVector) this.approp.get(type)).toArrayCopy();
  }

  public int[] getAppropriateFeatures(int type) {
    return ll_getAppropriateFeatures(type);
  }

  /**
   * @return An offset <code>&gt;0</code> if <code>feat</code> exists; <code>0</code>, else.
   */
  int getFeatureOffset(int feat) {
    return ((IntVector) this.approp.get(this.intro.get(feat))).position(feat) + 1;
  }

  /**
   * Get the overall number of features defined in the type system.
   */
  public int getNumberOfFeatures() {
    return this.featureNameST.size();
  }

  /**
   * Get the overall number of types defined in the type system.
   */
  public int getNumberOfTypes() {
    return this.typeNameST.size();
  }

  /**
   * Get the domain type for a feature.
   */
  public int intro(int feat) {
    return this.intro.get(feat);
  }

  /**
   * Get the range type for a feature.
   */
  public int range(int feat) {
    return this.featRange.get(feat);
  }

  // Unification is trivial, since we don't have multiple inheritance.
  public int unify(int t1, int t2) {
    if (this.subsumes(t1, t2)) {
      return t2;
    } else if (this.subsumes(t2, t1)) {
      return t1;
    } else {
      return -1;
    }
  }

  int addFeature(String shortName, int domain, int range) {
    return addFeature(shortName, domain, range, true);
  }

  /**
   * Add a new feature to the type system.
   */
  int addFeature(String shortName, int domain, int range, boolean multiRefsAllowed) {
    // Since we just looked up the domain in the symbol table, we know it
    // exists.
    String name = this.typeNameST.getSymbol(domain) + TypeSystem.FEATURE_SEPARATOR + shortName;
    // Create a list of the domain type and all its subtypes.
    // Type t = getType(domain);
    // if (t == null) {
    // System.out.println("Type is null");
    // }
    List typesLocal = getProperlySubsumedTypes(getType(domain));
    typesLocal.add(getType(domain));
    // For each type, check that the feature doesn't already exist.
    int max = typesLocal.size();
    for (int i = 0; i < max; i++) {
      String featureName = ((Type) typesLocal.get(i)).getName() + FEATURE_SEPARATOR + shortName;
      if (this.featureMap.containsKey(featureName)) {
        // We have already added this feature. If the range of the
        // duplicate
        // feature is identical, we don't do anything and just return.
        // Else,
        // we throw an exception.
        Feature oldFeature = getFeatureByFullName(featureName);
        Type oldDomain = oldFeature.getDomain();
        Type oldRange = oldFeature.getRange();
        if (range == ll_getCodeForType(oldRange)) {
          return -1;
        }
        CASAdminException e = new CASAdminException(CASAdminException.DUPLICATE_FEATURE);
        e.addArgument(shortName);
        e.addArgument(ll_getTypeForCode(domain).getName());
        e.addArgument(ll_getTypeForCode(range).getName());
        e.addArgument(oldDomain.getName());
        e.addArgument(oldRange.getName());
        throw e;
      }
    } // Add name to symbol table.
    int feat = this.featureNameST.set(name);
    // Add entries for all subtypes.
    for (int i = 0; i < max; i++) {
      this.featureMap.put(((Type) typesLocal.get(i)).getName() + FEATURE_SEPARATOR + shortName,
              feat);
    }
    this.intro.add(domain);
    this.featRange.add(range);
    max = this.typeNameST.size();
    for (int i = 1; i <= max; i++) {
      if (subsumes(domain, i)) {
        ((IntVector) this.approp.get(i)).add(feat);
      }
    }
    this.features.add(new FeatureImpl(feat, name, this, multiRefsAllowed));
    return feat;
  }

  /**
   * Add a top type to the (empty) type system.
   */
  public Type addTopType(String name) {
    final int code = this.addTopTypeInternal(name);
    if (code < 1) {
      return null;
    }
    return (Type) this.types.get(code);
  }

  private int addTopTypeInternal(String name) {
    if (this.typeNameST.size() > 0) {
      // System.out.println("Size of type table > 0.");
      return 0;
    } // Add name of top type to symbol table.
    this.top = this.typeNameST.set(name);
    // System.out.println("Size of name table is: " + typeNameST.size());
    // assert (typeNameST.size() == 1);
    // System.out.println("Code of top type is: " + this.top);
    // Create space for top type.
    newType();
    // Make top subsume itself.
    addSubsubsumption(this.top, this.top);
    this.types.add(new TypeImpl(name, this.top, this));
    this.parents.add(LowLevelTypeSystem.UNKNOWN_TYPE_CODE);
    this.numCommittedTypes = this.types.size();
    return this.top;
  }

  /**
   * Check if the first argument subsumes the second
   */
  public boolean subsumes(int superType, int type) {
    return this.ll_subsumes(superType, type);
  }

  private boolean ll_isPrimitiveArrayType(int type) {
    return type == this.floatArrayTypeCode || type == this.intArrayTypeCode
            || type == this.booleanArrayTypeCode || type == this.shortArrayTypeCode
            || type == this.byteArrayTypeCode || type == this.longArrayTypeCode
            || type == this.doubleArrayTypeCode || type == this.stringArrayTypeCode;
  }

  public boolean ll_subsumes(int superType, int type) {
    // Add range check.
    // assert (isType(superType));
    // assert (isType(type));

    // Need special handling for arrays, as they're generated on the fly and
    // not added to the subsumption table.

    // speedup code.
    if (superType == type)
      return true;

    // Yes, the code below is intentional. Until we actually support real
    // arrays of some
    // particular fs,
    // we have FSArray is the supertype of xxxx[] AND
    // xxx[] is the supertype of FSArray
    // (this second relation because all we can generate are instances of
    // FSArray
    // and we must be able to assign them to xxx[] )
    if (superType == this.fsArrayTypeCode) {
      return !ll_isPrimitiveArrayType(type) && ll_isArrayType(type);
    }

    if (type == this.fsArrayTypeCode) {
      return superType == this.top || superType == this.arrayBaseTypeCode
              || (!ll_isPrimitiveArrayType(superType) && ll_isArrayType(superType));
    }

    // at this point, we could have arrays of other primitive types, or
    // arrays of specific types: xxx[]

    final boolean isSuperArray = ll_isArrayType(superType);
    final boolean isSubArray = ll_isArrayType(type);
    if (isSuperArray) {
      if (isSubArray) {
        // If both types are arrays, simply compare the components.
        return ll_subsumes(ll_getComponentType(superType), ll_getComponentType(type));
      }
      // An array can never subsume a non-array.
      return false;
    } else if (isSubArray) {
      // If the subtype is an array, and the supertype is not, then the
      // supertype must be top, or the abstract array base.
      return ((superType == this.top) || (superType == this.arrayBaseTypeCode));
    }
    return ((BitSet) this.subsumes.get(superType)).get(type);
  }

  private void updateSubsumption(int type, int superType) {
    final int max = this.typeNameST.size();
    for (int i = 1; i <= max; i++) {
      if (subsumes(i, superType)) {
        addSubsubsumption(i, type);
      }
    }
    addSubsubsumption(type, type);
  }

  private void addSubsubsumption(int superType, int type) {
    ((BitSet) this.subsumes.get(superType)).set(type);
  }

  private void newType() {
    // The assumption for the implementation is that new types will
    // always be added at the end.
    this.tree.add(new IntVector());
    this.subsumes.add(new BitSet());
    this.approp.add(new IntVector());
  }

  public SymbolTable getTypeNameST() {
    return this.typeNameST;
  }

  public SymbolTable getFeatureNameST() {
    return this.featureNameST;
  }

  public int getTypeCode(String typeName) {
    return this.typeNameST.get(typeName);
  }

  private final String getTypeString(Type t) {
    return t.getName() + " (" + ll_getCodeForType(t) + ")";
  }

  private final String getFeatureString(Feature f) {
    return f.getName() + " (" + ll_getCodeForFeature(f) + ")";
  }

  /**
   * This writes out the type hierarchy in a human-readable form. Files in this form can be read in
   * by a {@link TypeSystemParser TypeSystemParser}.
   */
  public String toString() {
    // This code is maximally readable, not maximally efficient.
    StringBuffer buf = new StringBuffer();
    // Print top type.
    buf.append("~" + getTypeString(this.getTopType()) + ";\n");
    // Iterate over types and print declarations.
    final int numTypes = this.typeNameST.size();
    Type t;
    for (int i = 2; i <= numTypes; i++) {
      t = this.getType(i);
      buf.append(getTypeString(t) + " < " + getTypeString(this.getParent(t)) + ";\n");
    } // Print feature declarations.
    final int numFeats = this.featureNameST.size();
    Feature f;
    for (int i = 1; i <= numFeats; i++) {
      f = this.getFeature(i);
      buf.append(getFeatureString(f) + ": " + getTypeString(f.getDomain()) + " > "
              + getTypeString(f.getRange()) + ";\n");
    }
    return buf.toString();
  }

  /**
   * @see org.apache.uima.cas.admin.TypeSystemMgr#commit()
   */
  public void commit() {
    if (this.locked == true)
      return; // might be called multiple times, but only need to do once
    this.locked = true;
    initTypeCodes(); // needs to preceed cas.commitTypeSystem()
    // because subsumes depends on it
    // and generator initialization uses subsumes
    this.numCommittedTypes = this.types.size(); // do before
    // cas.commitTypeSystem -
    // because it will call the type system iterator

    // ts should never point to a CAS. Many CASes can share one ts.
    // if (this.cas != null) {
    // this.cas.commitTypeSystem();
    // }
  }

  private final void initTypeCodes() {
    this.booleanTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_BOOLEAN);
    this.byteTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_BYTE);
    this.shortTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_SHORT);
    this.intTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_INTEGER);
    this.floatTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_FLOAT);
    this.longTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_LONG);
    this.doubleTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_DOUBLE);
    this.stringTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_STRING);

    this.arrayBaseTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_ARRAY_BASE);
    this.booleanArrayTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_BOOLEAN_ARRAY);
    this.byteArrayTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_BYTE_ARRAY);
    this.shortArrayTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_SHORT_ARRAY);
    this.intArrayTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_INTEGER_ARRAY);
    this.floatArrayTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_FLOAT_ARRAY);
    this.longArrayTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_LONG_ARRAY);
    this.doubleArrayTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_DOUBLE_ARRAY);
    this.stringArrayTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_STRING_ARRAY);
    this.fsArrayTypeCode = ll_getCodeForTypeName(CAS.TYPE_NAME_FS_ARRAY);
  }

  /**
   * @see org.apache.uima.cas.admin.TypeSystemMgr#isCommitted()
   */
  public boolean isCommitted() {
    return this.locked;
  }

  public void setCommitted(boolean b) {
    this.locked = b;
  }

  /**
   * @deprecated
   */
  public Feature getFeature(String featureName) {
    return getFeatureByFullName(featureName);
  }

  /**
   * @see org.apache.uima.cas.admin.TypeSystemMgr#setFeatureFinal(org.apache.uima.cas.Type)
   */
  public void setFeatureFinal(Type type) {
    ((TypeImpl) type).setFeatureFinal();
  }

  /**
   * @see org.apache.uima.cas.admin.TypeSystemMgr#setInheritanceFinal(org.apache.uima.cas.Type)
   */
  public void setInheritanceFinal(Type type) {
    ((TypeImpl) type).setInheritanceFinal();
  }

  /**
   * @see org.apache.uima.cas.admin.TypeSystemMgr#addStringSubtype
   */
  public Type addStringSubtype(String typeName, String[] stringList) throws CASAdminException {
    // final int stringSetCode = this.stringSets.size();
    Type mother = getStringType();
    // Check type name syntax.
    checkTypeSyntax(typeName);
    // Create the type.
    final int typeCode = this.addType(typeName, ((TypeImpl) mother).getCode(), true);
    // If the type code is less than 1, it means that a type of that name
    // already exists.
    if (typeCode < this.typeNameST.getStart()) {
      return null;
    } // Get the created type.
    StringTypeImpl type = (StringTypeImpl) this.types.get(typeCode);
    type.setFeatureFinal();
    type.setInheritanceFinal();
    // Sort the String array.
    Arrays.sort(stringList);
    // Add the string array to the string sets.
    this.stringSets.add(stringList);
    return type;
  }

  Type getStringType() {
    return this.getType(CAS.TYPE_NAME_STRING);
  }

  public String[] getStringSet(int i) // public for ref from JCas TOP type,
  // impl FeatureStructureImpl
  {
    return (String[]) this.stringSets.get(i);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.apache.uima.cas.TypeSystem#getTypeNameSpace(java.lang.String)
   */
  public TypeNameSpace getTypeNameSpace(String name) {
    if (!TypeSystemUtils.isTypeNameSpaceName(name)) {
      return null;
    }
    return new TypeNameSpaceImpl(name, this);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.apache.uima.cas.impl.LowLevelTypeSystem#ll_getCodeForTypeName(java.lang.String)
   */
  public int ll_getCodeForTypeName(String typeName) {
    if (typeName == null) {
      throw new NullPointerException();
    }
    return this.typeNameST.get(typeName);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.apache.uima.cas.impl.LowLevelTypeSystem#ll_getCodeForType(org.apache.uima.cas.Type)
   */
  public int ll_getCodeForType(Type type) {
    return ((TypeImpl) type).getCode();
  }

  public int ll_getCodeForFeatureName(String featureName) {
    if (featureName == null) {
      throw new NullPointerException();
    }
    if (!this.featureMap.containsKey(featureName)) {
      return UNKNOWN_FEATURE_CODE;
    }
    return this.featureMap.get(featureName);
  }

  public int ll_getCodeForFeature(Feature feature) {
    return ((FeatureImpl) feature).getCode();
  }

  public Type ll_getTypeForCode(int typeCode) {
    if (isType(typeCode)) {
      return (Type) this.types.get(typeCode);
    }
    return null;
  }

  public final int getLargestFeatureCode() {
    return this.getNumberOfFeatures();
  }

  public final boolean isFeature(int featureCode) {
    return ((featureCode > UNKNOWN_FEATURE_CODE) && (featureCode <= getLargestFeatureCode()));
  }

  public Feature ll_getFeatureForCode(int featureCode) {
    if (isFeature(featureCode)) {
      return (Feature) this.features.get(featureCode);
    }
    return null;
  }

  public int ll_getDomainType(int featureCode) {
    return intro(featureCode);
  }

  public int ll_getRangeType(int featureCode) {
    return range(featureCode);
  }

  public LowLevelTypeSystem getLowLevelTypeSystem() {
    return this;
  }

  public boolean ll_isStringSubtype(int type) {
    return this.stringSetMap.containsKey(type);
  }

  public boolean ll_isRefType(int typeCode) {
    final int typeClass = ll_getTypeClass(typeCode);
    switch (typeClass) {
      case LowLevelCAS.TYPE_CLASS_BOOLEAN:
      case LowLevelCAS.TYPE_CLASS_BYTE:
      case LowLevelCAS.TYPE_CLASS_SHORT:
      case LowLevelCAS.TYPE_CLASS_INT:
      case LowLevelCAS.TYPE_CLASS_FLOAT:
      case LowLevelCAS.TYPE_CLASS_LONG:
      case LowLevelCAS.TYPE_CLASS_DOUBLE:
      case LowLevelCAS.TYPE_CLASS_STRING: {
        return false;
      }
      default: {
        return true;
      }
    }
  }

  public Type getArrayType(Type componentType) {
    final int arrayTypeCode = ll_getArrayType(ll_getCodeForType(componentType));
    if (arrayTypeCode == UNKNOWN_TYPE_CODE) {
      return null;
    }
    return (Type) this.types.get(arrayTypeCode);
  }

  public final int ll_getTypeClass(int typeCode) {
    if (typeCode == this.booleanTypeCode) {
      return LowLevelCAS.TYPE_CLASS_BOOLEAN;
    }
    if (typeCode == this.byteTypeCode) {
      return LowLevelCAS.TYPE_CLASS_BYTE;
    }
    if (typeCode == this.shortTypeCode) {
      return LowLevelCAS.TYPE_CLASS_SHORT;
    }
    if (typeCode == this.intTypeCode) {
      return LowLevelCAS.TYPE_CLASS_INT;
    }
    if (typeCode == this.floatTypeCode) {
      return LowLevelCAS.TYPE_CLASS_FLOAT;
    }
    if (typeCode == this.longTypeCode) {
      return LowLevelCAS.TYPE_CLASS_LONG;
    }
    if (typeCode == this.doubleTypeCode) {
      return LowLevelCAS.TYPE_CLASS_DOUBLE;
    }
    if (this.ll_subsumes(this.stringTypeCode, typeCode)) {
      return LowLevelCAS.TYPE_CLASS_STRING;
    }
    if (typeCode == this.booleanArrayTypeCode) {
      return LowLevelCAS.TYPE_CLASS_BOOLEANARRAY;
    }
    if (typeCode == this.byteArrayTypeCode) {
      return LowLevelCAS.TYPE_CLASS_BYTEARRAY;
    }
    if (typeCode == this.shortArrayTypeCode) {
      return LowLevelCAS.TYPE_CLASS_SHORTARRAY;
    }
    if (typeCode == this.intArrayTypeCode) {
      return LowLevelCAS.TYPE_CLASS_INTARRAY;
    }
    if (typeCode == this.floatArrayTypeCode) {
      return LowLevelCAS.TYPE_CLASS_FLOATARRAY;
    }
    if (typeCode == this.longArrayTypeCode) {
      return LowLevelCAS.TYPE_CLASS_LONGARRAY;
    }
    if (typeCode == this.doubleArrayTypeCode) {
      return LowLevelCAS.TYPE_CLASS_DOUBLEARRAY;
    }
    if (typeCode == this.stringArrayTypeCode) {
      return LowLevelCAS.TYPE_CLASS_STRINGARRAY;
    }
    if (typeCode == this.fsArrayTypeCode) {
      return LowLevelCAS.TYPE_CLASS_FSARRAY;
    }
    return LowLevelCAS.TYPE_CLASS_FS;
  }

  public int ll_getArrayType(int componentTypeCode) {
    if (this.componentToArrayTypeMap.containsKey(componentTypeCode)) {
      return this.componentToArrayTypeMap.get(componentTypeCode);
    }
    return addArrayType(ll_getTypeForCode(componentTypeCode),
            ll_getTypeForCode(ll_computeArrayParentFromComponentType(componentTypeCode)));
  }

  int addArrayType(Type componentType, Type mother) {
    return ll_addArrayType(ll_getCodeForType(componentType), ll_getCodeForType(mother));
  }

  int ll_addArrayType(int componentTypeCode, int motherCode) {

    if (!ll_isValidTypeCode(componentTypeCode)) {
      return UNKNOWN_TYPE_CODE;
    }
    // The array type is new and needs to be created.
    String arrayTypeName = getArrayTypeName(ll_getTypeForCode(componentTypeCode).getName());
    int arrayTypeCode = this.typeNameST.set(arrayTypeName);
    this.componentToArrayTypeMap.put(componentTypeCode, arrayTypeCode);
    this.arrayToComponentTypeMap.put(arrayTypeCode, componentTypeCode);
    // Dummy call to keep the counts ok. Will never use these data
    // structures for array types.
    newType();
    TypeImpl arrayType = new TypeImpl(arrayTypeName, arrayTypeCode, this);
    this.types.add(arrayType);
    this.parents.add(motherCode);
    if (!isCommitted())
      this.numCommittedTypes = this.types.size();
    this.arrayCodeToTypeMap.put(arrayTypeCode, arrayType);
    // For built-in arrays, we need to add the abstract base array as parent
    // to the inheritance tree. This sucks. Assumptions about the base
    // array are all over the place. Would be nice to just remove it.
    // Add an edge to the tree.
    if (!isCommitted()) {
      final int arrayBaseType = ll_getCodeForTypeName(CAS.TYPE_NAME_ARRAY_BASE);
      ((IntVector) this.tree.get(arrayBaseType)).add(arrayTypeCode);
      // Update subsumption relation.
      updateSubsumption(arrayTypeCode, this.arrayBaseTypeCode);
    }
    return arrayTypeCode;
  }

  public boolean ll_isValidTypeCode(int typeCode) {
    return (this.typeNameST.getSymbol(typeCode) != null)
            || this.arrayToComponentTypeMap.containsKey(typeCode);
  }

  public boolean ll_isArrayType(int typeCode) {
    if (!ll_isValidTypeCode(typeCode)) {
      return false;
    }
    return this.arrayCodeToTypeMap.containsKey(typeCode);
  }

  public int ll_getComponentType(int arrayTypeCode) {
    if (ll_isArrayType(arrayTypeCode)) {
      return this.arrayToComponentTypeMap.get(arrayTypeCode);
    }
    return UNKNOWN_TYPE_CODE;
  }

  /* note that subtypes of String are considered primitive */
  public boolean ll_isPrimitiveType(int typeCode) {
    return !ll_isRefType(typeCode);
  }

  public String[] ll_getStringSet(int typeCode) {
    if (!ll_isValidTypeCode(typeCode)) {
      return null;
    }
    if (!ll_isStringSubtype(typeCode)) {
      return null;
    }
    return (String[]) this.stringSets.get(this.stringSetMap.get(typeCode));
  }

}
TOP

Related Classes of org.apache.uima.cas.impl.TypeSystemImpl$ListIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.