JAL-3383 tidy method signature and Javadoc
[jalview.git] / src / jalview / datamodel / features / FeatureStore.java
index 5c0336a..653d389 100644 (file)
@@ -21,7 +21,6 @@
 package jalview.datamodel.features;
 
 import jalview.datamodel.SequenceFeature;
-import jalview.util.Platform;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -36,12 +35,30 @@ import intervalstore.impl.BinarySearcher.Compare;
 
 public class FeatureStore
 {
+  public enum IntervalStoreType
+  {
+    /**
+     * original NCList-based IntervalStore
+     */
+    INTERVAL_STORE_NCLIST,
+
+    /**
+     * linked-list IntervalStore
+     */
+    INTERVAL_STORE_LINKED_LIST,
+
+    /**
+     * NCList as array buffer IntervalStore
+     */
+    INTERVAL_STORE_NCARRAY
+  }
+
   /*
-   * track last start for quick insertion of ordered features
+   * track largest start for quick insertion of ordered features
    */
-  protected int lastStart = -1;
+  protected int maxStart = -1;
 
-  protected int lastContactStart = -1;
+  protected int maxContactStart = -1;
 
   /*
    * Non-positional features have no (zero) start/end position.
@@ -91,38 +108,6 @@ public class FeatureStore
 
   float nonPositionalMaxScore;
 
-  public final static int INTERVAL_STORE_DEFAULT = -1;
-
-  /**
-   * original NCList-based IntervalStore
-   */
-  public final static int INTERVAL_STORE_NCLIST_OBJECT = 0;
-
-  /**
-   * linked-list IntervalStore
-   */
-  public final static int INTERVAL_STORE_LINKED_LIST = 1;
-
-  /**
-   * NCList as array buffer IntervalStore
-   */
-  public final static int INTERVAL_STORE_NCARRAY = 3;
-
-  static final int intervalStoreJavaOption = INTERVAL_STORE_NCLIST_OBJECT;
-
-  private final static boolean useJSOption = false;
-
-  private final static boolean isJSLinkedTest = true;
-
-  static final int intervalStoreJSOption = (!useJSOption
-          ? intervalStoreJavaOption
-          : isJSLinkedTest
-          ? INTERVAL_STORE_LINKED_LIST
-          : INTERVAL_STORE_NCARRAY);
-
-  // TODO: compare performance in real situations using
-  // INTERVAL_STORE_LINKED_LIST;
-
   /**
    * Answers the 'length' of the feature, counting 0 for non-positional features
    * and 1 for contact features
@@ -152,7 +137,7 @@ public class FeatureStore
    * @param feature
    * @return
    */
-  public boolean listContains(List<SequenceFeature> list,
+  public static boolean listContains(List<SequenceFeature> list,
           SequenceFeature feature)
   {
     if (list == null || feature == null)
@@ -223,23 +208,20 @@ public class FeatureStore
   }
 
   /**
-   * standard constructor
+   * Constructor that defaults to using NCList IntervalStore
    */
   public FeatureStore()
   {
-    this(INTERVAL_STORE_DEFAULT);
+    this(IntervalStoreType.INTERVAL_STORE_NCLIST);
   }
 
   /**
-   * constructor for testing only
+   * Constructor that allows an alternative IntervalStore implementation to be
+   * chosen
    */
-  public FeatureStore(int intervalStoreType)
+  public FeatureStore(IntervalStoreType intervalStoreType)
   {
-    features =
-            // Platform.isJS()
-            // ? new intervalstore.nonc.IntervalStore<>(true)
-            // : new intervalstore.impl.IntervalStore<>();
-            getIntervalStore(intervalStoreType);
+    features = getIntervalStore(intervalStoreType);
     positionalFeatureGroups = new HashSet<>();
     nonPositionalFeatureGroups = new HashSet<>();
     positionalMinScore = Float.NaN;
@@ -247,24 +229,28 @@ public class FeatureStore
     nonPositionalMinScore = Float.NaN;
     nonPositionalMaxScore = Float.NaN;
 
-    // we only construct nonPositionalFeatures, contactFeatures if we need to
+    // only construct nonPositionalFeatures or contactFeatures if needed
   }
 
-  private IntervalStoreI<SequenceFeature> getIntervalStore(int type)
+  /**
+   * Returns a new instance of IntervalStoreI of implementation as selected by
+   * the type parameter
+   * 
+   * @param type
+   * @return
+   */
+  private IntervalStoreI<SequenceFeature> getIntervalStore(
+          IntervalStoreType type)
   {
-    switch (type != INTERVAL_STORE_DEFAULT ? type : //
-            Platform.isJS() //
-                    ? intervalStoreJSOption
-                    : intervalStoreJavaOption)
+    switch (type)
     {
     default:
-    case INTERVAL_STORE_NCLIST_OBJECT:
+    case INTERVAL_STORE_NCLIST:
       return new intervalstore.impl.IntervalStore<>();
     case INTERVAL_STORE_NCARRAY:
-      // TODO: Couldn't figure out how to get rid of this warning
-      return new intervalstore.nonc.IntervalStoreImpl<>();
+      return new intervalstore.nonc.IntervalStore<>();
     case INTERVAL_STORE_LINKED_LIST:
-      return new intervalstore.nonc.IntervalStore0Impl<>();
+      return new intervalstore.nonc.IntervalStore0<>();
     }
   }
 
@@ -319,9 +305,9 @@ public class FeatureStore
         return false;
       }
       positionalFeatureGroups.add(feature.getFeatureGroup());
-      if (feature.begin > lastContactStart)
+      if (feature.begin > maxContactStart)
       {
-        lastContactStart = feature.begin;
+        maxContactStart = feature.begin;
       }
       addContactFeature(feature);
     }
@@ -341,9 +327,9 @@ public class FeatureStore
         return false;
       }
       positionalFeatureGroups.add(feature.getFeatureGroup());
-      if (feature.begin > lastStart)
+      if (feature.begin > maxStart)
       {
-        lastStart = feature.begin;
+        maxStart = feature.begin;
       }
     }
 
@@ -376,6 +362,14 @@ public class FeatureStore
     return true;
   }
 
+  /**
+   * A helper method that adds to the result list any features from the
+   * collection provided whose feature group matches the specified group
+   * 
+   * @param group
+   * @param sfs
+   * @param result
+   */
   private void addFeaturesForGroup(String group,
           Collection<SequenceFeature> sfs, List<SequenceFeature> result)
   {
@@ -437,12 +431,11 @@ public class FeatureStore
     }
 
     return containsPositionalFeature(feature);
-
   }
 
   private boolean containsPositionalFeature(SequenceFeature feature)
   {
-    return features == null || feature.begin > lastStart ? false
+    return features == null || feature.begin > maxStart ? false
             : features.contains(feature);
   }
 
@@ -455,7 +448,7 @@ public class FeatureStore
    */
   private boolean containsContactFeature(SequenceFeature feature)
   {
-    return contactFeatureStarts != null && feature.begin <= lastContactStart
+    return contactFeatureStarts != null && feature.begin <= maxContactStart
             && listContains(contactFeatureStarts, feature);
   }
 
@@ -521,30 +514,62 @@ public class FeatureStore
     return removed;
   }
 
-  public List<SequenceFeature> findOverlappingFeatures(long start, long end)
+  public List<SequenceFeature> findFeatures(long start, long end)
   {
-    return findOverlappingFeatures(start, end, null);
+    return findFeatures(start, end, null);
   }
 
+  /**
+   * Returns a (possibly empty) list of features whose extent overlaps the given
+   * range. The returned list is not ordered. Contact features are included if
+   * either of the contact points lies within the range. If the {@code result}
+   * parameter is not null, new entries are added to this list and the (possibly
+   * extended) list returned.
+   * 
+   * @param start
+   *          start position of overlap range (inclusive)
+   * @param end
+   *          end position of overlap range (inclusive)
+   * @param result
+   * @return
+   */
+  public List<SequenceFeature> findFeatures(long start, long end,
+          List<SequenceFeature> result)
+  {
+    if (result == null)
+    {
+      result = new ArrayList<>();
+    }
+
+    findContactFeatures(start, end, result);
+    features.findOverlaps(start, end, result);
+
+    return result;
+  }
+
+  /**
+   * Returns a (possibly empty) list of stored contact features
+   * 
+   * @return
+   */
   public List<SequenceFeature> getContactFeatures()
   {
-    return getContactFeatures(new ArrayList<>());
+    List<SequenceFeature> result = new ArrayList<>();
+    getContactFeatures(result);
+    return result;
   }
 
   /**
-   * Answers a list of all contact features. If there are none, returns an
-   * immutable empty list.
+   * Adds any stored contact features to the result list
    * 
    * @return
    */
-  public List<SequenceFeature> getContactFeatures(
-          List<SequenceFeature> result)
+  public void getContactFeatures(List<SequenceFeature> result)
   {
     if (contactFeatureStarts != null)
     {
       result.addAll(contactFeatureStarts);
     }
-    return result;
   }
 
   /**
@@ -562,8 +587,19 @@ public class FeatureStore
               : nonPositionalFeatures.size();
     }
 
-    return (contactFeatureStarts == null ? 0 : contactFeatureStarts.size())
-            + features.size();
+    int size = 0;
+
+    if (contactFeatureStarts != null)
+    {
+      // note a contact feature (start/end) counts as one
+      size += contactFeatureStarts.size();
+    }
+
+    if (features != null)
+    {
+      size += features.size();
+    }
+    return size;
   }
 
   /**
@@ -588,11 +624,6 @@ public class FeatureStore
     }
   }
 
-  public Collection<SequenceFeature> getFeatures()
-  {
-    return features;
-  }
-
   /**
    * Answers a list of all either positional or non-positional features whose
    * feature group matches the given group (which may be null)
@@ -654,41 +685,50 @@ public class FeatureStore
     return positional ? positionalMinScore : nonPositionalMinScore;
   }
 
+  /**
+   * Answers a (possibly empty) list of all non-positional features
+   * 
+   * @return
+   */
   public List<SequenceFeature> getNonPositionalFeatures()
   {
-    return getNonPositionalFeatures(new ArrayList<>());
+    List<SequenceFeature> result = new ArrayList<>();
+    getNonPositionalFeatures(result);
+    return result;
   }
 
   /**
-   * Answers a list of all non-positional features. If there are none, returns
-   * an immutable empty list.
+   * Adds any stored non-positional features to the result list
    * 
    * @return
    */
-  public List<SequenceFeature> getNonPositionalFeatures(
-          List<SequenceFeature> result)
+  public void getNonPositionalFeatures(List<SequenceFeature> result)
   {
     if (nonPositionalFeatures != null)
     {
       result.addAll(nonPositionalFeatures);
     }
-    return result;
   }
 
+  /**
+   * Returns a (possibly empty) list of all positional features stored
+   * 
+   * @return
+   */
   public List<SequenceFeature> getPositionalFeatures()
   {
-    return getPositionalFeatures(new ArrayList<>());
+    List<SequenceFeature> result = new ArrayList<>();
+    getPositionalFeatures(result);
+
+    return result;
   }
 
   /**
-   * Answers a list of all positional features stored, in no guaranteed order
-   * 
-   * @return
+   * Adds all positional features stored to the result list, in no guaranteed
+   * order, and with no check for duplicates
    */
-  public List<SequenceFeature> getPositionalFeatures(
-          List<SequenceFeature> result)
+  public void getPositionalFeatures(List<SequenceFeature> result)
   {
-
     /*
      * add any contact features - from the list by start position
      */
@@ -704,8 +744,6 @@ public class FeatureStore
     {
       result.addAll(features);
     }
-
-    return result;
   }
 
   /**
@@ -730,7 +768,7 @@ public class FeatureStore
             && !contactFeatureStarts.isEmpty())
             || (nonPositionalFeatures != null
                     && !nonPositionalFeatures.isEmpty())
-            || features.size() > 0;
+            || (features != null && features.size() > 0);
 
     return !hasFeatures;
   }
@@ -754,10 +792,9 @@ public class FeatureStore
      */
     if (nonPositionalFeatures != null)
     {
-      List<SequenceFeature> list = nonPositionalFeatures;
-      for (int i = 0, n = list.size(); i < n; i++)
+      for (int i = 0, n = nonPositionalFeatures.size(); i < n; i++)
       {
-        SequenceFeature sf = list.get(i);
+        SequenceFeature sf = nonPositionalFeatures.get(i);
         nonPositionalFeatureGroups.add(sf.getFeatureGroup());
         float score = sf.getScore();
         nonPositionalMinScore = min(nonPositionalMinScore, score);
@@ -765,14 +802,17 @@ public class FeatureStore
       }
     }
 
-    /*
-     * scan positional features for groups, scores and extents
-     */
-
     rescanPositional(contactFeatureStarts);
     rescanPositional(features);
   }
 
+  /**
+   * Scans the given features and updates cached feature groups, minimum and
+   * maximum feature score, and total feature extent (length) for positional
+   * features
+   * 
+   * @param sfs
+   */
   private void rescanPositional(Collection<SequenceFeature> sfs)
   {
     if (sfs == null)
@@ -963,32 +1003,4 @@ public class FeatureStore
     }
   }
 
-  /**
-   * Returns a (possibly empty) list of features whose extent overlaps the given
-   * range. The returned list is not ordered. Contact features are included if
-   * either of the contact points lies within the range. If the {@code result}
-   * parameter is not null, new entries are added to this list and the (possibly
-   * extended) list returned.
-   * 
-   * @param start
-   *          start position of overlap range (inclusive)
-   * @param end
-   *          end position of overlap range (inclusive)
-   * @param result
-   * @return
-   */
-  public List<SequenceFeature> findOverlappingFeatures(long start, long end,
-          List<SequenceFeature> result)
-  {
-    if (result == null)
-    {
-      result = new ArrayList<>();
-    }
-
-    findContactFeatures(start, end, result);
-    features.findOverlaps(start, end, result);
-
-    return result;
-  }
-
 }