JAL-3253-applet JAL-3397 JAL-3383 fast IntervalStore for JavaScript
[jalview.git] / src / jalview / datamodel / features / FeatureStore.java
index 8db35a3..1451892 100644 (file)
@@ -33,6 +33,11 @@ public abstract class FeatureStore implements FeatureStoreI
 {
 
   /**
+   * track last start for quick insertion of ordered features
+   */
+  protected int lastStart = -1, lastContactStart = -1;
+
+  /**
    * Answers the 'length' of the feature, counting 0 for non-positional features
    * and 1 for contact features
    * 
@@ -87,12 +92,13 @@ public abstract class FeatureStore implements FeatureStoreI
     /*
      * locate the first entry in the list which does not precede the feature
      */
-    int pos = findFirstBegin(list, feature.begin);
+    int begin = feature.begin;
+    int pos = findFirstBegin(list, begin);
     int len = list.size();
     while (pos < len)
     {
       SequenceFeature sf = list.get(pos);
-      if (sf.begin > feature.begin)
+      if (sf.begin > begin)
       {
         return -1; // no match found
       }
@@ -253,30 +259,55 @@ public abstract class FeatureStore implements FeatureStoreI
   @Override
   public boolean addFeature(SequenceFeature feature)
   {
-    if (contains(feature))
-    {
-      return false;
-    }
-
-    /*
-     * keep a record of feature groups
-     */
-    if (!feature.isNonPositional())
-    {
-      positionalFeatureGroups.add(feature.getFeatureGroup());
-    }
+    // if (contains(feature))
+    // {
+    // return false;
+    // }
+
+    // /*
+    // * keep a record of feature groups
+    // */
+    // if (!feature.isNonPositional())
+    // {
+    // positionalFeatureGroups.add(feature.getFeatureGroup());
+    // }
 
     if (feature.isContactFeature())
     {
+      if (containsContactFeature(feature))
+      {
+        return false;
+      }
+      positionalFeatureGroups.add(feature.getFeatureGroup());
+      if (feature.begin > lastContactStart)
+      {
+        lastContactStart = feature.begin;
+      }
       addContactFeature(feature);
     }
     else if (feature.isNonPositional())
     {
+      if (containsNonPositional(feature))
+      {
+        return false;
+      }
+
       addNonPositionalFeature(feature);
     }
     else
     {
-      addPositionalFeature(feature);
+      // allow for check with
+      if (checkContainsPositionalFeatureForAdd(feature)
+              || !addPositionalFeature(feature))
+      {
+        return false;
+      }
+      positionalFeatureGroups.add(feature.getFeatureGroup());
+      // addPositionalFeature(feature);
+      if (feature.begin > lastStart)
+      {
+        lastStart = feature.begin;
+      }
     }
 
     /*
@@ -329,8 +360,10 @@ public abstract class FeatureStore implements FeatureStoreI
   /**
    * Adds one feature to the IntervalStore that can manage nested features
    * (creating the IntervalStore if necessary)
+   * 
+   * @return true if added -- allowing for late checking during addition
    */
-  abstract protected void addPositionalFeature(SequenceFeature feature);
+  abstract protected boolean addPositionalFeature(SequenceFeature feature);
 
   /**
    * Adds the feature to the list of non-positional features (with lazy
@@ -367,19 +400,50 @@ public abstract class FeatureStore implements FeatureStoreI
   {
     if (feature.isNonPositional())
     {
-      return nonPositionalFeatures == null ? false
-              : nonPositionalFeatures.contains(feature);
+      return containsNonPositional(feature);
+
     }
 
     if (feature.isContactFeature())
     {
-      return contactFeatureStarts != null
-              && listContains(contactFeatureStarts, feature);
+      return containsContactFeature(feature);
+
     }
 
-    return features == null ? false : containsFeature(feature);
+    return containsPositionalFeature(feature);
+
   }
 
+  /**
+   * A check that can be overridden if the check is being done during the add
+   * operation itself.
+   * 
+   * @param feature
+   * @return
+   */
+  protected boolean checkContainsPositionalFeatureForAdd(
+          SequenceFeature feature)
+  {
+    return containsPositionalFeature(feature);
+  }
+
+  private boolean containsPositionalFeature(SequenceFeature feature)
+  {
+    return features == null || feature.begin > lastStart ? false
+            : containsFeature(feature);
+  }
+
+  private boolean containsContactFeature(SequenceFeature feature)
+  {
+    return contactFeatureStarts != null && feature.begin <= lastContactStart
+            && listContains(contactFeatureStarts, feature);
+  }
+
+  private boolean containsNonPositional(SequenceFeature feature)
+  {
+    return nonPositionalFeatures == null ? false
+            : nonPositionalFeatures.contains(feature);
+  }
 
   abstract protected boolean containsFeature(SequenceFeature feature);