JAL-3397 impl.IntervalStore and nonc.IntervalStore unified api
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Sat, 7 Sep 2019 14:44:52 +0000 (15:44 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Sat, 7 Sep 2019 14:44:52 +0000 (15:44 +0100)
39 files changed:
.classpath
lib/intervalstore-v1.0.jar [deleted file]
lib/intervalstore-v1.1.jar [new file with mode: 0644]
src/intervalstore/api/IntervalI.java [deleted file]
src/intervalstore/api/IntervalStoreI.java [deleted file]
src/intervalstore/impl/BinarySearcher.java [deleted file]
src/intervalstore/impl/IntervalStore.java [deleted file]
src/intervalstore/impl/NCList.java [deleted file]
src/intervalstore/impl/NCListBuilder.java [deleted file]
src/intervalstore/impl/NCNode.java [deleted file]
src/intervalstore/impl/Range.java [deleted file]
src/intervalstore/nonc/IntervalEndSorter.java [deleted file]
src/intervalstore/nonc/IntervalStore.java
src/intervalstore/nonc/IntervalStore0.java
src/jalview/api/AlignmentColsCollectionI.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AllColsCollection.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceFeature.java
src/jalview/datamodel/SequenceI.java
src/jalview/datamodel/VisibleColsCollection.java
src/jalview/datamodel/features/FeatureStore.java
src/jalview/datamodel/features/FeatureStoreI.java [deleted file]
src/jalview/datamodel/features/FeatureStoreImpl.java [deleted file]
src/jalview/datamodel/features/FeatureStoreJS.java [deleted file]
src/jalview/datamodel/features/SequenceFeatures.java
src/jalview/datamodel/features/SequenceFeaturesI.java
src/jalview/ext/ensembl/EnsemblFeatures.java
src/jalview/renderer/OverviewRenderer.java
src/jalview/renderer/OverviewResColourFinder.java
src/jalview/renderer/seqfeatures/FeatureColourFinder.java
src/jalview/renderer/seqfeatures/FeatureRenderer.java
test/intervalstore/nonc/IntervalStoreTest.java [new file with mode: 0644]
test/intervalstore/nonc/SimpleFeature.java [moved from src/intervalstore/impl/SimpleFeature.java with 74% similarity]
test/jalview/datamodel/features/FeatureStoreJSTest.java
test/jalview/datamodel/features/FeatureStoreJavaTest.java
test/jalview/datamodel/features/FeatureStoreLinkedTest.java
test/jalview/datamodel/features/FeatureStoreNCListBufferTest.java
test/jalview/datamodel/features/SequenceFeaturesTest.java

index 004d432..d3aa906 100644 (file)
@@ -61,7 +61,6 @@
        <classpathentry kind="lib" path="lib/jetty-http-9.2.10.v20150310.jar"/>
        <classpathentry kind="lib" path="lib/jetty-io-9.2.10.v20150310.jar"/>
        <classpathentry kind="lib" path="lib/java-json.jar"/>
-       <classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
        <classpathentry kind="lib" path="lib/biojava-core-4.1.0.jar"/>
        <classpathentry kind="lib" path="lib/biojava-ontology-4.1.0.jar"/>
        <classpathentry kind="lib" path="lib/htsjdk-2.12.0.jar"/>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
        <classpathentry exported="true" kind="con" path="GROOVY_DSL_SUPPORT"/>
        <classpathentry kind="lib" path="lib/Jmol-14.29.17.jar"/>
-       <classpathentry kind="lib" path="lib/intervalstore-v1.0.jar"/>
+       <classpathentry kind="lib" path="utils/testnglibs/bsh-2.0b4.jar"/>
+       <classpathentry kind="lib" path="utils/testnglibs/guava-base-r03.jar"/>
+       <classpathentry kind="lib" path="utils/testnglibs/guava-collections-r03.jar"/>
+       <classpathentry kind="lib" path="utils/testnglibs/jcommander.jar"/>
+       <classpathentry kind="lib" path="utils/testnglibs/junit-4.12.jar"/>
+       <classpathentry kind="lib" path="utils/testnglibs/snakeyaml.jar"/>
+       <classpathentry kind="lib" path="utils/testnglibs/testng-sources.jar"/>
+       <classpathentry kind="lib" path="utils/testnglibs/testng.jar"/>
+       <classpathentry kind="lib" path="lib/intervalstore-v1.1.jar"/>
        <classpathentry kind="output" path="classes"/>
 </classpath>
diff --git a/lib/intervalstore-v1.0.jar b/lib/intervalstore-v1.0.jar
deleted file mode 100644 (file)
index 4f6101c..0000000
Binary files a/lib/intervalstore-v1.0.jar and /dev/null differ
diff --git a/lib/intervalstore-v1.1.jar b/lib/intervalstore-v1.1.jar
new file mode 100644 (file)
index 0000000..668b543
Binary files /dev/null and b/lib/intervalstore-v1.1.jar differ
diff --git a/src/intervalstore/api/IntervalI.java b/src/intervalstore/api/IntervalI.java
deleted file mode 100644 (file)
index d2594b8..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
-BSD 3-Clause License
-
-Copyright (c) 2018, Mungo Carstairs
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-  this list of conditions and the following disclaimer in the documentation
-  and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-package intervalstore.api;
-
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-public interface IntervalI
-{
-
-  /**
-   * Compare intervals by start position ascending and end position descending.
-   * 
-   * BIGENDIAN sorts 10-100 ahead of 10-80 (original IntervalStoreJ method
-   * 
-   */
-  static Comparator<? super IntervalI> COMPARATOR_BIGENDIAN = new Comparator<IntervalI>()
-  {
-    @Override
-    public int compare(IntervalI o1, IntervalI o2)
-    {
-      int ret = Integer.signum(o1.getBegin() - o2.getBegin());
-      return (ret == 0 ? Integer.signum(o2.getEnd() - o1.getEnd()) : ret);
-    }
-  };
-
-  /**
-   * Compare intervals by start position ascending and end position descending.
-   * 
-   * LITTLEENDIAN sorts 10-100 after 10-80
-   * 
-   */
-  static Comparator<? super IntervalI> COMPARATOR_LITTLEENDIAN = new Comparator<IntervalI>()
-  {
-    @Override
-    public int compare(IntervalI o1, IntervalI o2)
-    {
-      int ret = Integer.signum(o1.getBegin() - o2.getBegin());
-      return (ret == 0 ? Integer.signum(o1.getEnd() - o2.getEnd()) : ret);
-    }
-  };
-
-  /**
-   * a comparator for sorting intervals by start position ascending
-   */
-  static Comparator<? super IntervalI> FORWARD_STRAND = new Comparator<IntervalI>()
-  {
-    @Override
-    public int compare(IntervalI o1, IntervalI o2)
-    {
-      return Integer.signum(o1.getBegin() - o2.getBegin());
-    }
-  };
-
-  /**
-   * a comparator for sorting intervals by end position descending
-   */
-  static Comparator<? super IntervalI> REVERSE_STRAND = new Comparator<IntervalI>()
-  {
-    @Override
-    public int compare(IntervalI o1, IntervalI o2)
-    {
-      return Integer.signum(o2.getEnd() - o1.getEnd());
-    }
-  };
-
-  static int NOT_CONTAINED = Integer.MIN_VALUE;
-  static int CONTAINMENT_UNKNOWN = 0;
-
-  int getBegin();
-  int getEnd();
-
-  /**
-   * Answers true if this interval contains (or matches) the given interval
-   * based solely on start and end.
-   * 
-   * @param i
-   * @return
-   */
-  default boolean containsInterval(IntervalI i)
-  {
-    return i != null && i.getBegin() >= getBegin()
-            && i.getEnd() <= getEnd();
-  }
-
-
-  /**
-   * Answers true if this interval properly contains the given interval, that
-   * is, it contains it and is larger than it
-   * 
-   * @param i
-   * @return
-   */
-  default boolean properlyContainsInterval(IntervalI i)
-  {
-    return containsInterval(i)
-            && (i.getBegin() > getBegin() || i.getEnd() < getEnd());
-  }
-
-  /**
-   * Slower than equalsInterval; also includes type.
-   * 
-   * Ensure that subclasses override equals(Object). For example:
-   * 
-   * public boolean equals(Object o) { return o != null && o instanceof XXX &&
-   * equalsInterval((XXX) i); }
-   * 
-   * 
-   * equalsInterval also must be overridden.
-   * 
-   * public boolean equalsInterval(IntervalI i) {return ((SimpleFeature)i).start
-   * == start && ((SimpleFeature)i).end == end && ((SimpleFeature)i).description
-   * == this.description; }
-   * 
-   * 
-   * @param o
-   * @return true if equal, including a type check
-   */
-  @Override
-  abstract boolean equals(Object o);
-
-
-
-  /**
-   * Check that two intervals are equal, in terms of end points, descriptions,
-   * or any other distinguishing features.
-   * 
-   * Used in IntervalStore in searches, since it is faster than equals(), as at
-   * that point we know that we have the correct type.
-   * 
-   * @param i
-   *          may be null
-   * @return true if equal; null value must return false, not throw
-   *         NullPointerException
-   */
-  abstract boolean equalsInterval(IntervalI i);
-
-  default boolean overlapsInterval(IntervalI i)
-  {
-    if (i == null)
-    {
-      return false;
-    }
-    if (i.getBegin() < getBegin())
-    {
-      return i.getEnd() >= getBegin();
-    }
-    if (i.getEnd() > getEnd())
-    {
-      return i.getBegin() <= getEnd();
-    }
-    return true; // i internal to this
-  }
-
-  /**
-   * Sorts the list by start position ascending (if forwardString==true), or by
-   * end position descending
-   * 
-   * @param intervals
-   * @param forwardStrand
-   */
-  static void sortIntervals(List<? extends IntervalI> intervals,
-          final boolean forwardStrand)
-  {
-    Collections.sort(intervals,
-            forwardStrand ? FORWARD_STRAND : REVERSE_STRAND);
-  }
-
-
-}
diff --git a/src/intervalstore/api/IntervalStoreI.java b/src/intervalstore/api/IntervalStoreI.java
deleted file mode 100644 (file)
index 43aea2b..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
-BSD 3-Clause License
-
-Copyright (c) 2018, Mungo Carstairs
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-  this list of conditions and the following disclaimer in the documentation
-  and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-package intervalstore.api;
-
-import java.util.Collection;
-import java.util.List;
-
-import intervalstore.impl.NCList;
-
-public interface IntervalStoreI<T extends IntervalI> extends Collection<T>
-{
-
-  /**
-   * Returns a (possibly empty) list of items whose extent overlaps the given
-   * range
-   * 
-   * @param from
-   *          start of overlap range (inclusive)
-   * @param to
-   *          end of overlap range (inclusive)
-   * @return
-   */
-  List<T> findOverlaps(long from, long to);
-
-  /**
-   * Ensures that the IntervalStore is ready for findOverlap.
-   * 
-   * @return true iff the data held satisfy the rules of construction of an
-   *         IntervalStore.
-   * 
-   */
-  boolean isValid();
-
-  /**
-   * Answers the level of nesting of intervals in the store, as
-   * <ul>
-   * <li>0 if the store is empty</li>
-   * <li>1 if all intervals are 'top level' (non nested)</li>
-   * <li>else 1 plus the depth of the enclosed NCList</li>
-   * </ul>
-   * 
-   * @return
-   * @see NCList#getDepth()
-   */
-  int getDepth();
-
-  /**
-   * Return the number of top-level (not-contained) intervals.
-   * 
-   * @return
-   */
-  int getWidth();
-
-  List<T> findOverlaps(long start, long end, List<T> result);
-
-  String prettyPrint();
-
-  /**
-   * Resort and rebuild links.
-   * 
-   * @return
-   */
-  boolean revalidate();
-
-  /**
-   * Get the i-th interval, whatever that means to this store.
-   * 
-   * @param i
-   * @return
-   */
-  IntervalI get(int i);
-
-  /**
-   * Check to see if this store can check for duplicates while adding.
-   * 
-   * @return
-   */
-  boolean canCheckForDuplicates();
-
-  /**
-   * Add with a check for duplicates, if possible.
-   * 
-   * @param interval
-   * @param checkForDuplicate
-   * @return false only if addition was unsuccessful because there was an
-   *         identical interval already in the store or because the store cannot
-   *         check for duplicates
-   */
-  boolean add(T interval, boolean checkForDuplicate);
-
-}
\ No newline at end of file
diff --git a/src/intervalstore/impl/BinarySearcher.java b/src/intervalstore/impl/BinarySearcher.java
deleted file mode 100644 (file)
index 6c598ce..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
-BSD 3-Clause License
-
-Copyright (c) 2018, Mungo Carstairs
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-  this list of conditions and the following disclaimer in the documentation
-  and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-package intervalstore.impl;
-
-import java.util.List;
-import java.util.function.ToIntFunction;
-
-import intervalstore.api.IntervalI;
-
-/**
- * Provides a method to perform binary search of an ordered list for the first
- * entry that satisfies a supplied condition
- * 
- * @author gmcarstairs
- */
-public final class BinarySearcher
-{
-
-  public static ToIntFunction<IntervalI> fbegin = new ToIntFunction<IntervalI>()
-  {
-
-    @Override
-    public int applyAsInt(IntervalI value)
-    {
-      return value.getBegin();
-    }
-
-  };
-
-  public static ToIntFunction<IntervalI> fend = new ToIntFunction<IntervalI>()
-  {
-
-    @Override
-    public int applyAsInt(IntervalI value)
-    {
-      return value.getEnd();
-    }
-
-  };
-
-  private BinarySearcher()
-  {
-  }
-
-  /**
-   * Performs a binary search of the list to find the index of the first entry
-   * for which the test returns true. Answers the length of the list if there is
-   * no such entry.
-   * <p>
-   * For correct behaviour, the provided list must be ordered consistent with
-   * the test, that is, any entries returning false must precede any entries
-   * returning true. Note that this means that this method is <em>not</em>
-   * usable to search for equality (to find a specific entry), as all unequal
-   * entries will answer false to the test. To do that, use
-   * <code>Collections.binarySearch</code> instead.
-   * 
-   * @param list
-   * @param test
-   * @return
-   * @see java.util.Collections#binarySearch(List, Object)
-   */
-  public static <T> int findFirst(List<? extends T> list, int pos,
-          ToIntFunction<T> test)
-  {
-    int start = 0;
-    int end = list.size() - 1;
-    int matched = list.size();
-  
-    while (start <= end)
-    {
-      int mid = (start + end) / 2;
-      T entry = list.get(mid);
-      boolean itsTrue = test.applyAsInt(entry) >= pos;
-      if (itsTrue)
-      {
-        matched = mid;
-        end = mid - 1;
-      }
-      else
-      {
-        start = mid + 1;
-      }
-    }
-  
-    return matched;
-  }
-}
diff --git a/src/intervalstore/impl/IntervalStore.java b/src/intervalstore/impl/IntervalStore.java
deleted file mode 100644 (file)
index 9faae7f..0000000
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
-BSD 3-Clause License
-
-Copyright (c) 2018, Mungo Carstairs
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-  this list of conditions and the following disclaimer in the documentation
-  and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-package intervalstore.impl;
-
-import java.util.AbstractCollection;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import intervalstore.api.IntervalI;
-import intervalstore.api.IntervalStoreI;
-
-/**
- * A collection class to store interval-associated data, with O(log N)
- * performance for overlap queries, insertion and deletion (where N is the size
- * of the store). Accepts duplicate entries but not null values.
- * 
- * @author gmcarstairs
- *
- * @param <T>
- *          any type providing <code>getBegin()</code> and <code>getEnd()</code>
- */
-public class IntervalStore<T extends IntervalI>
-        extends AbstractCollection<T> implements IntervalStoreI<T>
-{
-  /**
-   * An iterator over the intervals held in this store, with no particular
-   * ordering guaranteed. The iterator does not support the optional
-   * <code>remove</code> operation (throws
-   * <code>UnsupportedOperationException</code> if attempted).
-   * 
-   * @author gmcarstairs
-   *
-   * @param <V>
-   */
-  private class IntervalIterator<V extends IntervalI> implements Iterator<V>
-  {
-    /*
-     * iterator over top level non-nested intervals
-     */
-    Iterator<? extends IntervalI> topLevelIterator;
-
-    /*
-     * iterator over NCList (if any)
-     */
-    Iterator<? extends IntervalI> nestedIterator;
-
-    /**
-     * Constructor initialises iterators over the top level list and any nested
-     * NCList
-     * 
-     * @param intervalStore
-     */
-    public IntervalIterator(
-            IntervalStore<? extends IntervalI> intervalStore)
-    {
-      topLevelIterator = nonNested.iterator();
-      if (nested != null)
-      {
-        nestedIterator = nested.iterator();
-      }
-    }
-
-    @Override
-    public boolean hasNext()
-    {
-      return topLevelIterator.hasNext() ? true
-              : (nestedIterator != null && nestedIterator.hasNext());
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public V next()
-    {
-      if (topLevelIterator.hasNext())
-      {
-        return (V) topLevelIterator.next();
-      }
-      if (nestedIterator != null)
-      {
-        return (V) nestedIterator.next();
-      }
-      throw new NoSuchElementException();
-    }
-
-  }
-
-  private List<T> nonNested;
-
-  private NCList<T> nested;
-
-  /**
-   * Constructor
-   */
-  public IntervalStore()
-  {
-    nonNested = new ArrayList<>();
-  }
-
-  /**
-   * Constructor given a list of intervals. Note that the list may get sorted as
-   * a side-effect of calling this constructor.
-   */
-  public IntervalStore(List<T> intervals)
-  {
-    this();
-
-    /*
-     * partition into subranges whose root intervals
-     * have no mutual containment (if no intervals are nested,
-     * each subrange is of length 1 i.e. a single interval)
-     */
-    List<IntervalI> sublists = new NCListBuilder<T>()
-            .partitionNestedSublists(intervals);
-
-    /*
-     * add all 'subrange root intervals' (and any co-located intervals)
-     * to our top level list of 'non-nested' intervals; 
-     * put aside any left over for our NCList
-     */
-    List<T> nested = new ArrayList<>();
-
-    for (IntervalI subrange : sublists)
-    {
-      int listIndex = subrange.getBegin();
-      IntervalI root = intervals.get(listIndex);
-      while (listIndex <= subrange.getEnd())
-      {
-        T t = intervals.get(listIndex);
-        if (root.equalsInterval(t))
-        {
-          nonNested.add(t);
-        }
-        else
-        {
-          nested.add(t);
-        }
-        listIndex++;
-      }
-    }
-
-    if (!nested.isEmpty())
-    {
-      this.nested = new NCList<>(nested);
-    }
-  }
-
-  /**
-   * Adds one interval to the store.
-   * 
-   * @param interval
-   */
-  @Override
-  public boolean add(T interval)
-  {
-    if (interval == null)
-    {
-      return false;
-    }
-    if (!addNonNestedInterval(interval))
-    {
-      /*
-       * detected a nested interval - put it in the NCList structure
-       */
-      addNestedInterval(interval);
-    }
-    return true;
-  }
-
-  @Override
-  public boolean contains(Object entry)
-  {
-    if (listContains(nonNested, entry))
-    {
-      return true;
-    }
-
-    return nested == null ? false : nested.contains(entry);
-  }
-
-  protected boolean addNonNestedInterval(T entry)
-  {
-    synchronized (nonNested)
-    {
-      /*
-       * find the first stored interval which doesn't precede the new one
-       */
-      int insertPosition = BinarySearcher.findFirst(nonNested,
-              entry.getBegin(),
-              BinarySearcher.fbegin);
-      /*
-       * fail if we detect interval enclosure 
-       * - of the new interval by the one before or after it
-       * - of the next interval by the new one
-       */
-      if (insertPosition > 0)
-      {
-        if (nonNested.get(insertPosition - 1)
-                .properlyContainsInterval(entry))
-        {
-          return false;
-        }
-      }
-      if (insertPosition < nonNested.size())
-      {
-        T following = nonNested.get(insertPosition);
-        if (entry.properlyContainsInterval(following)
-                || following.properlyContainsInterval(entry))
-        {
-          return false;
-        }
-      }
-
-      /*
-       * checks passed - add the interval
-       */
-      nonNested.add(insertPosition, entry);
-
-      return true;
-    }
-  }
-
-  @Override
-  public List<T> findOverlaps(long from, long to)
-  {
-    List<T> result = new ArrayList<>();
-
-    findNonNestedOverlaps(from, to, result);
-
-    if (nested != null)
-    {
-      nested.findOverlaps(from, to, result);
-    }
-
-    return result;
-  }
-
-  @Override
-  public String prettyPrint()
-  {
-    String pp = nonNested.toString();
-    if (nested != null)
-    {
-      pp += '\n' + nested.prettyPrint();
-    }
-    return pp;
-  }
-
-  @Override
-  public boolean isValid()
-  {
-    for (int i = 0; i < nonNested.size() - 1; i++)
-    {
-      IntervalI i1 = nonNested.get(i);
-      IntervalI i2 = nonNested.get(i + 1);
-
-      if (i2.getBegin() < i1.getBegin())
-      {
-        System.err.println("nonNested wrong start order : " + i1.toString()
-                + ", " + i2.toString());
-        return false;
-      }
-      if (i1.properlyContainsInterval(i2)
-              || i2.properlyContainsInterval(i1))
-      {
-        System.err.println("nonNested invalid containment!: "
-                + i1.toString()
-                + ", " + i2.toString());
-        return false;
-      }
-    }
-    return nested == null ? true : nested.isValid();
-  }
-
-  @Override
-  public int size()
-  {
-    int i = nonNested.size();
-    if (nested != null)
-    {
-      i += nested.size();
-    }
-    return i;
-  }
-
-  @Override
-  public synchronized boolean remove(Object o)
-  {
-    if (o == null)
-    {
-      return false;
-    }
-    try
-    {
-      @SuppressWarnings("unchecked")
-      T entry = (T) o;
-
-      /*
-       * try the non-nested positional intervals first
-       */
-      boolean removed = removeNonNested(entry);
-
-      /*
-       * if not found, try nested intervals
-       */
-      if (!removed && nested != null)
-      {
-        removed = nested.remove(entry);
-      }
-
-      return removed;
-    } catch (ClassCastException e)
-    {
-      return false;
-    }
-  }
-
-  /**
-   * Removes the given entry from the list of non-nested entries, returning true
-   * if found and removed, or false if not found. Specifically, removes the
-   * first item in the list for which <code>item.equals(entry)</code>.
-   * 
-   * @param entry
-   * @return
-   */
-  protected boolean removeNonNested(T entry)
-  {
-    /*
-     * find the first interval that might match, i.e. whose 
-     * start position is not less than the target range start
-     * (NB inequality test ensures the first match if any is found)
-     */
-    int from = entry.getBegin();
-    int startIndex = BinarySearcher.findFirst(nonNested, from,
-            BinarySearcher.fbegin);
-
-    /*
-     * traverse intervals to look for a match
-     */
-
-    int i = startIndex;
-    int size = nonNested.size();
-    while (i < size)
-    {
-      T sf = nonNested.get(i);
-      if (sf.getBegin() > from)
-      {
-        break;
-      }
-      if (sf.equals(entry))
-      {
-        nonNested.remove(i);
-        return true;
-      }
-      i++;
-    }
-    return false;
-  }
-
-  @Override
-  public int getDepth()
-  {
-    if (size() == 0)
-    {
-      return 0;
-    }
-    return (nonNested.isEmpty() ? 0 : 1)
-            + (nested == null ? 0 : nested.getDepth());
-  }
-
-  /**
-   * Adds one interval to the NCList that can manage nested intervals (creating
-   * the NCList if necessary)
-   */
-  protected synchronized void addNestedInterval(T interval)
-  {
-    if (nested == null)
-    {
-      nested = new NCList<>();
-    }
-    nested.add(interval);
-  }
-
-  /**
-   * Answers true if the list contains the interval, else false. This method is
-   * optimised for the condition that the list is sorted on interval start
-   * position ascending, and will give unreliable results if this does not hold.
-   * 
-   * @param intervals
-   * @param entry
-   * @return
-   */
-  protected boolean listContains(List<T> intervals, Object entry)
-  {
-    if (intervals == null || entry == null || !(entry instanceof IntervalI))
-    {
-      return false;
-    }
-
-    IntervalI interval = (IntervalI) entry;
-
-    /*
-     * locate the first entry in the list which does not precede the interval
-     */
-    int from = interval.getBegin();
-    int pos = BinarySearcher.findFirst(intervals, from,
-            BinarySearcher.fbegin);
-    int len = intervals.size();
-    while (pos < len)
-    {
-      T sf = intervals.get(pos);
-      if (sf.getBegin() > from)
-      {
-        return false; // no match found
-      }
-      if (sf.equals(interval))
-      {
-        return true;
-      }
-      pos++;
-    }
-    return false;
-  }
-
-  /**
-   * Answers an iterator over the intervals in the store, with no particular
-   * ordering guaranteed. The iterator does not support the optional
-   * <code>remove</code> operation (throws
-   * <code>UnsupportedOperationException</code> if attempted).
-   */
-  @Override
-  public Iterator<T> iterator()
-  {
-    return new IntervalIterator<>(this);
-  }
-
-  @Override
-  public void clear()
-  {
-    this.nonNested.clear();
-    this.nested = new NCList<>();
-  }
-
-  /**
-   * Adds non-nested intervals to the result list that lie within the target
-   * range
-   * 
-   * @param from
-   * @param to
-   * @param result
-   */
-  protected void findNonNestedOverlaps(long from, long to,
-          List<T> result)
-  {
-    /*
-     * find the first interval whose end position is
-     * after the target range start
-     */
-    int startIndex = BinarySearcher.findFirst(nonNested, (int) from,
-            BinarySearcher.fend);
-    for (int i = startIndex, n = nonNested.size(); i < n; i++)
-    {
-      T sf = nonNested.get(i);
-      if (sf.getBegin() > to)
-      {
-        break;
-      }
-      if (sf.getEnd() >= from)
-      {
-        result.add(sf);
-      }
-    }
-  }
-
-  @Override
-  public String toString()
-  {
-    String s = nonNested.toString();
-    if (nested != null)
-    {
-      s = s + '\n'// + System.lineSeparator()
-              + nested.toString();
-    }
-    return s;
-  }
-
-  @Override
-  public int getWidth()
-  {
-    return (nonNested == null ? 0 : nonNested.size())
-            + (nested == null ? 0 : nested.size());
-  }
-
-  @Override
-  public List<T> findOverlaps(long start, long end, List<T> result)
-  {
-    return findOverlaps(start, end);
-  }
-
-  @Override
-  public boolean revalidate()
-  {
-    // not applicable
-    return true;
-  }
-
-  @Override
-  public IntervalI get(int i)
-  {
-    // not supported (but could be)
-    return null;
-  }
-
-  @Override
-  public boolean canCheckForDuplicates()
-  {
-    return false;
-  }
-
-  @Override
-  public boolean add(T interval, boolean checkForDuplicate)
-  {
-    return add(interval);
-  }
-}
diff --git a/src/intervalstore/impl/NCList.java b/src/intervalstore/impl/NCList.java
deleted file mode 100644 (file)
index 243192d..0000000
+++ /dev/null
@@ -1,830 +0,0 @@
-/*
-BSD 3-Clause License
-
-Copyright (c) 2018, Mungo Carstairs
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-  this list of conditions and the following disclaimer in the documentation
-  and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-package intervalstore.impl;
-
-import java.util.AbstractCollection;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import intervalstore.api.IntervalI;
-
-/**
- * An adapted implementation of NCList as described in the paper
- * 
- * <pre>
- * Nested Containment List (NCList): a new algorithm for accelerating
- * interval query of genome alignment and interval databases
- * - Alexander V. Alekseyenko, Christopher J. Lee
- * https://doi.org/10.1093/bioinformatics/btl647
- * </pre>
- */
-public class NCList<T extends IntervalI> extends AbstractCollection<T>
-{
-
-  // private static final boolean OPTION_FIND_ANY = false;
-
-  /**
-   * A depth-first iterator over the elements stored in the NCList
-   */
-  private class NCListIterator implements Iterator<T>
-  {
-    int subrangeIndex;
-
-    Iterator<T> nodeIterator;
-
-    /**
-     * Constructor bootstraps a pointer to an iterator over the first subrange
-     * (if any)
-     */
-    NCListIterator()
-    {
-      subrangeIndex = nextSubrange(-1);
-    }
-
-    /**
-     * Moves the subrange iterator to the next subrange, and answers its index
-     * in the list of subranges. If there are no more, sets the iterator to null
-     * and answers -1.
-     * 
-     * @return
-     */
-    private int nextSubrange(int after)
-    {
-      int nextIndex = after + 1;
-      if (nextIndex < subranges.size())
-      {
-        nodeIterator = subranges.get(nextIndex).iterator();
-        return nextIndex;
-      }
-      nodeIterator = null;
-      return -1;
-    }
-
-    @Override
-    public boolean hasNext()
-    {
-      return nodeIterator != null && nodeIterator.hasNext();
-    }
-
-    /**
-     * Answers the next element returned by the current NCNode's iterator, and
-     * advances the iterator (to the next NCNode if necessary)
-     */
-    @Override
-    public T next()
-    {
-      if (nodeIterator == null || !nodeIterator.hasNext())
-      {
-        throw new NoSuchElementException();
-      }
-      T result = nodeIterator.next();
-
-      if (!nodeIterator.hasNext())
-      {
-        subrangeIndex = nextSubrange(subrangeIndex);
-      }
-      return result;
-    }
-
-  }
-
-  /*
-   * the number of interval instances represented
-   */
-  private int size;
-
-  /*
-   * a list, in start position order, of sublists of ranges ordered so 
-   * that each contains (or is the same as) the one that follows it
-   */
-  private List<NCNode<T>> subranges;
-
-  /**
-   * Constructor given a list of things that are each located on a contiguous
-   * interval. Note that the constructor may reorder the list.
-   * <p>
-   * We assume here that for each range, start &lt;= end. Behaviour for reverse
-   * ordered ranges is undefined.
-   * 
-   * @param ranges
-   */
-  public NCList(List<T> ranges)
-  {
-    this();
-    build(ranges);
-  }
-
-  /**
-   * Sorts and groups ranges into sublists where each sublist represents an
-   * interval and its contained subintervals
-   * 
-   * @param ranges
-   */
-  protected void build(List<T> ranges)
-  {
-    /*
-     * sort and partition into subranges 
-     * which have no mutual containment
-     */
-    List<IntervalI> sublists = partitionNestedSublists(ranges);
-
-    /*
-     * convert each subrange to an NCNode consisting of a range and
-     * (possibly) its contained NCList
-     */
-    for (IntervalI sublist : sublists)
-    {
-      subranges.add(new NCNode<>(
-              ranges.subList(sublist.getBegin(), sublist.getEnd() + 1)));
-    }
-
-    size = ranges.size();
-  }
-
-  /**
-   * Default constructor
-   */
-  public NCList()
-  {
-    subranges = new ArrayList<>();
-  }
-
-  /**
-   * Sorts and traverses the ranges to identify sublists, whose start intervals
-   * are overlapping or disjoint but not mutually contained. Answers a list of
-   * start-end indices of the sorted list of ranges.
-   * 
-   * @param ranges
-   * @return
-   */
-  protected List<IntervalI> partitionNestedSublists(List<T> ranges)
-  {
-    List<IntervalI> sublists = new ArrayList<>();
-
-    if (ranges.isEmpty())
-    {
-      return sublists;
-    }
-
-    /*
-     * sort by start ascending, length descending, so that
-     * contained intervals follow their containing interval
-     */
-    Collections.sort(ranges, IntervalI.COMPARATOR_BIGENDIAN);
-
-    int listStartIndex = 0;
-
-    IntervalI lastParent = ranges.get(0);
-    boolean first = true;
-
-    for (int i = 0; i < ranges.size(); i++)
-    {
-      IntervalI nextInterval = ranges.get(i);
-      if (!first && !lastParent.properlyContainsInterval(nextInterval))
-      {
-        /*
-         * this interval is not properly contained in the parent; 
-         * close off the last sublist
-         */
-        sublists.add(new Range(listStartIndex, i - 1));
-        listStartIndex = i;
-        lastParent = nextInterval;
-      }
-      first = false;
-    }
-
-    sublists.add(new Range(listStartIndex, ranges.size() - 1));
-    return sublists;
-  }
-
-  /**
-   * Adds one entry to the stored set
-   * 
-   * @param entry
-   */
-  @Override
-  public synchronized boolean add(final T entry)
-  {
-    final NCNode<T> newNode = new NCNode<>(entry);
-    addNode(newNode);
-    return true;
-  }
-
-  /**
-   * Adds one NCNode to this NCList
-   * <p>
-   * This method does not update the <code>size</code> (interval count) of this
-   * NCList, as it may be used to rearrange nodes without changing their count.
-   * Callers should increment the count if needed.
-   * 
-   * @param newNode
-   */
-  protected void addNode(final NCNode<T> newNode)
-  {
-    final long start = newNode.getBegin();
-    final long end = newNode.getEnd();
-    size += newNode.size();
-
-    /*
-     * cases:
-     * 1) precedes all subranges - add as NCNode on front of list
-     * 2) follows all subranges - add as NCNode on end of list
-     * 3) matches a subrange - add as a sibling in the list
-     * 4) properly enclosed by a subrange - add recursively to subrange
-     * 5) properly encloses one or more subranges - push them inside it
-     * 6) spans two subranges - insert between them
-     */
-
-    /*
-     * find the first subrange whose end does not precede entry's start
-     */
-    int candidateIndex = findFirstOverlap(start);
-
-    /*
-     * search for maximal span of subranges i-k that the new entry
-     * encloses; or a subrange that encloses the new entry
-     */
-    boolean enclosing = false;
-    int firstEnclosed = 0;
-    int lastEnclosed = 0;
-
-    for (int j = candidateIndex; j < subranges.size(); j++)
-    {
-      NCNode<T> subrange = subranges.get(j);
-
-      if (subrange.equalsInterval(newNode))
-      {
-        /*
-         * matching interval - insert adjacent
-         */
-        subranges.add(j, newNode);
-        return;
-      }
-
-      if (end < subrange.getBegin() && !enclosing)
-      {
-        /*
-         * new entry lies between subranges j-1 j
-         */
-        subranges.add(j, newNode);
-        return;
-      }
-
-      if (subrange.properlyContainsInterval(newNode))
-      {
-        /*
-         * push new entry inside this subrange as it encloses it
-         */
-        subrange.addNode(newNode);
-        return;
-      }
-
-      if (start <= subrange.getBegin())
-      {
-        if (end >= subrange.getEnd())
-        {
-          /*
-           * new entry encloses this subrange (and possibly preceding ones);
-           * continue to find the maximal list it encloses
-           */
-          if (!enclosing)
-          {
-            firstEnclosed = j;
-          }
-          lastEnclosed = j;
-          enclosing = true;
-          continue;
-        }
-        else
-        {
-          /*
-           * entry spans from before this subrange to inside it
-           */
-          if (enclosing)
-          {
-            /*
-             * entry encloses one or more preceding subranges
-             */
-            push(newNode, firstEnclosed, lastEnclosed);
-          }
-          else
-          {
-            /*
-             * entry overlaps two subranges but doesn't enclose either
-             * so just add it 
-             */
-            subranges.add(j, newNode);
-          }
-          return;
-        }
-      }
-    }
-
-    /*
-     * drops through to here if new range encloses all others
-     * or overlaps the last one
-     */
-    if (enclosing)
-    {
-      push(newNode, firstEnclosed, lastEnclosed);
-    }
-    else
-    {
-      subranges.add(newNode);
-    }
-  }
-
-  @Override
-  public boolean contains(Object entry)
-  {
-    if (!(entry instanceof IntervalI))
-    {
-      return false;
-    }
-    IntervalI interval = (IntervalI) entry;
-
-    /*
-     * find the first sublist that might overlap, i.e. 
-     * the first whose end position is >= from
-     */
-    int candidateIndex = findFirstOverlap(interval.getBegin());
-
-    int to = interval.getEnd();
-
-    for (int i = candidateIndex; i < subranges.size(); i++)
-    {
-      NCNode<T> candidate = subranges.get(i);
-      if (candidate.getBegin() > to)
-      {
-        /*
-         * we are past the end of our target range
-         */
-        break;
-      }
-      if (candidate.contains(interval))
-      {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Update the tree so that the new node encloses current subranges i to j
-   * (inclusive). That is, replace subranges i-j (inclusive) with a new subrange
-   * that contains them.
-   * 
-   * @param node
-   * @param i
-   * @param j
-   * @throws IllegalArgumentException
-   *           if any of the subranges is not contained by the node's start-end
-   *           range
-   */
-  protected synchronized void push(NCNode<T> node, final int i,
-          final int j)
-  {
-    for (int k = i; k <= j; k++)
-    {
-      NCNode<T> n = subranges.get(k);
-      if (!node.containsInterval(n)) {
-        throw new IllegalArgumentException("Can't push " + n.toString()
-                + " inside " + node.toString());
-      }
-      node.addNode(n);
-    }
-
-    for (int k = j; k >= i; k--)
-    {
-      subranges.remove(k);
-    }
-    subranges.add(i, node);
-  }
-
-  /**
-   * Answers a list of contained intervals that overlap the given range
-   * 
-   * @param from
-   * @param to
-   * @return
-   */
-  public List<T> findOverlaps(long from, long to)
-  {
-    List<T> result = new ArrayList<>();
-
-    findOverlaps(from, to, result);
-
-    return result;
-  }
-
-  /**
-   * Recursively searches the NCList adding any items that overlap the from-to
-   * range to the result list
-   * 
-   * @param from
-   * @param to
-   * @param result
-   */
-  protected List<T> findOverlaps(long from, long to, List<T> result)
-  {
-
-    // if (OPTION_FIND_ANY)
-    // {
-    // return findAnyOverlaps(from, to, result);
-    // }
-    /*
-     * find the first sublist that might overlap, i.e. 
-     * the first whose end position is >= from
-     */
-    int candidateIndex = findFirstOverlap(from);
-
-    for (int i = candidateIndex; i < subranges.size(); i++)
-    {
-      NCNode<T> candidate = subranges.get(i);
-      if (candidate.getBegin() > to)
-      {
-        /*
-         * we are past the end of our target range
-         */
-        break;
-      }
-      candidate.findOverlaps(from, to, result);
-    }
-    return result;
-  }
-  
-  // /**
-  // * Recursively searches the NCList adding any items that overlap the from-to
-  // * range to the result list
-  // *
-  // * @param from
-  // * @param to
-  // * @param result
-  // */
-  // protected List<T> findAnyOverlaps(long from, long to, List<T> result)
-  // {
-  //
-  // // BH find ANY overlap
-  //
-  // int candidateIndex = findAnyOverlap(subranges, from, to);
-  //
-  // if (candidateIndex < 0)
-  // return result;
-  // for (int i = candidateIndex, n = subranges.size(); i < n; i++)
-  // {
-  // NCNode<T> candidate = subranges.get(i);
-  // if (candidate.getBegin() > to)
-  // {
-  // /*
-  // * we are past the end of our target range
-  // */
-  // break;
-  // }
-  // candidate.findOverlaps(from, to, result);
-  // }
-  //
-  // // BH adds dual-direction check
-  //
-  // for (int i = candidateIndex; --i >= 0;)
-  // {
-  // NCNode<T> candidate = subranges.get(i);
-  // if (candidate.getEnd() < from)
-  // {
-  // break;
-  // }
-  // candidate.findOverlaps(from, to, result);
-  // }
-  // return result;
-  // }
-  //
-  // private int findAnyOverlap(List<NCNode<T>> ranges, long from, long to)
-  // {
-  // int start = 0;
-  // int end = ranges.size() - 1;
-  // while (start <= end)
-  // {
-  // int mid = (start + end) >>> 1;
-  // NCNode<T> r = ranges.get(mid);
-  // if (r.getEnd() >= from)
-  // {
-  // if (r.getBegin() <= to)
-  // return mid;
-  // end = mid - 1;
-  // }
-  // else
-  // {
-  // start = mid + 1;
-  // }
-  // }
-  // return -1;
-  // }
-
-  /**
-   * Search subranges for the first one whose end position is not before the
-   * target range's start position, i.e. the first one that may overlap the
-   * target range. Returns the index in the list of the first such range found,
-   * or the length of the list if none found.
-   * 
-   * @param from
-   * @return
-   */
-  protected int findFirstOverlap(final long from)
-  {
-    return BinarySearcher.findFirst(subranges, (int) from,
-            BinarySearcher.fend);
-  }
-
-  /**
-   * Formats the tree as a bracketed list e.g.
-   * 
-   * <pre>
-   * [1-100 [10-30 [10-20]], 15-30 [20-20]]
-   * </pre>
-   */
-  @Override
-  public String toString()
-  {
-    return subranges.toString();
-  }
-
-  /**
-   * Answers the NCList as an indented list
-   * 
-   * @return
-   */
-  public String prettyPrint()
-  {
-    StringBuilder sb = new StringBuilder(512);
-    int offset = 0;
-    int indent = 2;
-    prettyPrint(sb, offset, indent);
-    sb.append('\n');// System.lineSeparator());
-    return sb.toString();
-  }
-
-  /**
-   * @param sb
-   * @param offset
-   * @param indent
-   */
-  void prettyPrint(StringBuilder sb, int offset, int indent)
-  {
-    boolean first = true;
-    for (NCNode<T> subrange : subranges)
-    {
-      if (!first)
-      {
-        sb.append('\n');// System.lineSeparator());
-      }
-      first = false;
-      subrange.prettyPrint(sb, offset, indent);
-    }
-  }
-
-  /**
-   * Answers true if the store's structure is valid (nesting containment rules
-   * are obeyed), else false. For use in testing and debugging.
-   * 
-   * @return
-   */
-  public boolean isValid()
-  {
-    int count = 0;
-    for (NCNode<T> subrange : subranges)
-    {
-      count += subrange.size();
-    }
-    if (count != size)
-    {
-      return false;
-    }
-    return isValid(Integer.MIN_VALUE, Integer.MAX_VALUE);
-  }
-
-  /**
-   * Answers true if the data held satisfy the rules of construction of an
-   * NCList bounded within the given start-end range, else false.
-   * <p>
-   * Each subrange must lie within start-end (inclusive). Subranges must be
-   * ordered by start position ascending, and within that by end position
-   * descending.
-   * <p>
-   * 
-   * @param start
-   * @param end
-   * @return
-   */
-  boolean isValid(final int start, final int end)
-  {
-    NCNode<T> lastRange = null;
-
-    for (NCNode<T> subrange : subranges)
-    {
-      if (subrange.getBegin() < start)
-      {
-        System.err.println("error in NCList: range " + subrange.toString()
-                + " starts before " + end);
-        return false;
-      }
-      if (subrange.getEnd() > end)
-      {
-        System.err.println("error in NCList: range " + subrange.toString()
-                + " ends after " + end);
-        return false;
-      }
-
-      if (lastRange != null)
-      {
-        if (subrange.getBegin() < lastRange.getBegin())
-        {
-          System.err.println("error in NCList: range " + subrange.toString()
-                  + " starts before " + lastRange.toString());
-          return false;
-        }
-        if (subrange.properlyContainsInterval(lastRange))
-        {
-          System.err.println("error in NCList: range " + subrange.toString()
-                  + " encloses preceding: " + lastRange.toString());
-          return false;
-        }
-        if (lastRange.properlyContainsInterval(subrange))
-        {
-          System.err.println("error in NCList: range " + subrange.toString()
-                  + " enclosed by preceding: " + lastRange.toString());
-          return false;
-        }
-      }
-      lastRange = subrange;
-
-      if (!subrange.isValid())
-      {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Answers the number of intervals stored
-   * 
-   * @return
-   */
-  @Override
-  public int size()
-  {
-    return size;
-  }
-
-  /**
-   * Answers a list of all entries stored, in no guaranteed order. This method
-   * is not synchronized, so is not thread-safe.
-   */
-  public List<T> getEntries()
-  {
-    List<T> result = new ArrayList<>();
-    getEntries(result);
-    return result;
-  }
-
-  /**
-   * Adds all contained entries to the given list
-   * 
-   * @param result
-   */
-  void getEntries(List<T> result)
-  {
-    for (NCNode<T> subrange : subranges)
-    {
-      subrange.getEntries(result);
-    }
-  }
-
-  /**
-   * Removes the first interval <code>I</code>found that is equal to T
-   * (<code>I.equals(T)</code>). Answers true if an interval is removed, false
-   * if no match is found. This method is synchronized so thread-safe.
-   * 
-   * @param entry
-   * @return
-   */
-  public synchronized boolean remove(T entry)
-  {
-    if (entry == null)
-    {
-      return false;
-    }
-    int i = findFirstOverlap(entry.getBegin());
-
-    for (; i < subranges.size(); i++)
-    {
-      NCNode<T> subrange = subranges.get(i);
-      if (subrange.getBegin() > entry.getBegin())
-      {
-        /*
-         * not found
-         */
-        return false;
-      }
-      NCList<T> subRegions = subrange.getSubRegions();
-
-      if (subrange.getRegion().equals(entry))
-      {
-        /*
-         * if the subrange is rooted on this entry, remove it,
-         * and remove and promote its subregions (if any)  
-         */
-        subranges.remove(i);
-        size -= subrange.size();
-        if (subRegions != null)
-        {
-          for (NCNode<T> r : subRegions.subranges)
-          {
-            addNode(r);
-          }
-        }
-        return true;
-      }
-      else
-      {
-        if (subrange.remove(entry))
-        {
-          size--;
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Answers the depth of interval nesting of this object, where 1 means there
-   * are no nested sub-intervals
-   * 
-   * @return
-   */
-  public int getDepth()
-  {
-    int subDepth = 0;
-    for (NCNode<T> subrange : subranges)
-    {
-      subDepth = Math.max(subDepth, subrange.getDepth());
-    }
-
-    return subDepth;
-  }
-
-  /**
-   * Answers an iterator over the contained intervals, with no particular order
-   * guaranteed. The iterator does not support the optional <code>remove</code>
-   * operation (throws <code>UnsupportedOperationException</code> if attempted).
-   */
-  @Override
-  public Iterator<T> iterator()
-  {
-    return new NCListIterator();
-  }
-
-  @Override
-  public synchronized void clear()
-  {
-    subranges.clear();
-    size = 0;
-  }
-
-  public int getWidth()
-  {
-    return subranges.size();
-  }
-}
diff --git a/src/intervalstore/impl/NCListBuilder.java b/src/intervalstore/impl/NCListBuilder.java
deleted file mode 100644 (file)
index d640589..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
-BSD 3-Clause License
-
-Copyright (c) 2018, Mungo Carstairs
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-  this list of conditions and the following disclaimer in the documentation
-  and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-package intervalstore.impl;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import intervalstore.api.IntervalI;
-
-/**
- * A comparator that orders ranges by either start position ascending. If
- * position matches, ordering is by length descending. This provides the
- * canonical ordering of intervals into subranges in order to build a nested
- * containment list.
- * 
- * @author gmcarstairs
- */
-public class NCListBuilder<T extends IntervalI>
-{
-  // class NCListComparator<V extends IntervalI> implements Comparator<V>
-  // {
-  // /**
-  // * Compares two intervals in a way that will sort a list by start position
-  // * ascending, then by length descending. Answers
-  // * <ul>
-  // * <li>a negative value if o1.begin < o2.begin</li>
-  // * <li>else a positive value if o1.begin > o2.begin</li>
-  // * <li>else a negative value if o1.end > o2.end</li>
-  // * <li>else a positive value of o1.end < o2.end</li>
-  // * <li>else zero</li
-  // * </ul>
-  // */
-  // @Override
-  // public int compare(V o1, V o2)
-  // {
-  // int order = Integer.compare(o1.getBegin(), o2.getBegin());
-  // if (order == 0)
-  // {
-  // /*
-  // * if tied on start position, longer length sorts to left
-  // * i.e. the negation of normal ordering by length
-  // */
-  // order = Integer.compare(o2.getEnd(), o1.getEnd());
-  // }
-  // return order;
-  // }
-  // }
-
-  private Comparator<? super IntervalI> comparator = IntervalI.COMPARATOR_BIGENDIAN;// new
-                                                                                    // NCListComparator<>();
-  
-  /**
-   * Default constructor
-   */
-  public NCListBuilder()
-  {
-  }
-
-  /**
-   * Answers a comparator which sorts items of type T by start position
-   * ascending, and within that by end position (length) descending)
-   * 
-   * @return
-   */
-  Comparator<? super IntervalI> getComparator()
-  {
-    return comparator;
-  }
-
-  /**
-   * Sorts and traverses the ranges to identify sublists, whose start intervals
-   * are overlapping or disjoint but not mutually contained. Answers a list of
-   * start-end indices of the sorted list of ranges.
-   * 
-   * @param ranges
-   * @return
-   */
-  List<IntervalI> partitionNestedSublists(List<T> ranges)
-  {
-    List<IntervalI> sublists = new ArrayList<>();
-  
-    /*
-     * sort by start ascending, length descending, so that
-     * contained intervals follow their containing interval
-     */
-    Collections.sort(ranges, comparator);
-  
-    int listStartIndex = 0;
-  
-    IntervalI lastParent = ranges.get(0);
-    boolean first = true;
-  
-    for (int i = 0, n = ranges.size(); i < n; i++)
-    {
-      IntervalI nextInterval = ranges.get(i);
-      if (!first && !lastParent.properlyContainsInterval(nextInterval))
-      {
-        /*
-         * this interval is not properly contained in the parent; 
-         * close off the last sublist
-         */
-        sublists.add(new Range(listStartIndex, i - 1));
-        listStartIndex = i;
-        lastParent = nextInterval;
-      }
-      first = false;
-    }
-  
-    sublists.add(new Range(listStartIndex, ranges.size() - 1));
-    return sublists;
-  }
-}
diff --git a/src/intervalstore/impl/NCNode.java b/src/intervalstore/impl/NCNode.java
deleted file mode 100644 (file)
index a3702f5..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
-BSD 3-Clause License
-
-Copyright (c) 2018, Mungo Carstairs
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-  this list of conditions and the following disclaimer in the documentation
-  and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-package intervalstore.impl;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import intervalstore.api.IntervalI;
-
-/**
- * Each node of the NCList tree consists of a range, and (optionally) the NCList
- * of ranges it encloses
- *
- * @param <T>
- */
-class NCNode<T extends IntervalI> implements IntervalI
-{
-  /**
-   * A depth-first iterator over the intervals stored in the NCNode. The
-   * optional <code>remove</code> operation is not supported.
-   * 
-   * @author gmcarstairs
-   *
-   */
-  private class NCNodeIterator implements Iterator<T>
-  {
-    boolean first = true;
-    Iterator<T> subregionIterator;
-
-    @Override
-    public boolean hasNext()
-    {
-      return first
-              || (subregionIterator != null && subregionIterator.hasNext());
-    }
-
-    /**
-     * Answers the next interval - initially the top level interval for this
-     * node, thereafter the intervals returned by the NCList's iterator
-     */
-    @Override
-    public T next()
-    {
-      if (first)
-      {
-        subregionIterator = subregions == null ? null
-                : subregions.iterator();
-        first = false;
-        return region;
-      }
-      if (subregionIterator == null || !subregionIterator.hasNext())
-      {
-        throw new NoSuchElementException();
-      }
-      return subregionIterator.next();
-    }
-  }
-
-  private T region;
-
-  /*
-   * null, or an object holding contained subregions of this nodes region
-   */
-  private NCList<T> subregions;
-
-  /**
-   * Constructor given a list of ranges. The list not be empty, and should be
-   * ordered so that the first range contains all the others. If not, behaviour
-   * will likely be invalid.
-   * 
-   * @param ranges
-   * @throws IllegalArgumentException
-   *           if the list is empty
-   */
-  NCNode(List<T> ranges)
-  {
-    if (ranges.isEmpty())
-    {
-      throw new IllegalArgumentException("List may not be empty");
-    }
-    region = ranges.get(0);
-
-    if (ranges.size() > 1)
-    {
-      subregions = new NCList<>(ranges.subList(1, ranges.size()));
-    }
-  }
-
-  /**
-   * Constructor given a single range
-   * 
-   * @param range
-   */
-  NCNode(T range)
-  {
-    region = range;
-  }
-
-  @Override
-  public int getBegin()
-  {
-    return region.getBegin();
-  }
-
-  @Override
-  public int getEnd()
-  {
-    return region.getEnd();
-  }
-
-  /**
-   * Formats the node as a bracketed list e.g.
-   * 
-   * <pre>
-   * [1-100 [10-30 [10-20]], 15-30 [20-20]]
-   * </pre>
-   * 
-   * where the format for each interval is as given by <code>T.toString()</code>
-   */
-  @Override
-  public String toString()
-  {
-    StringBuilder sb = new StringBuilder(10 * size());
-    sb.append(region.toString());
-    if (subregions != null)
-    {
-      sb.append(" ").append(subregions.toString());
-    }
-    return sb.toString();
-  }
-
-  void prettyPrint(StringBuilder sb, int offset, int indent)
-  {
-    for (int i = 0; i < offset; i++)
-    {
-      sb.append(" ");
-    }
-    sb.append(region.toString());
-    if (subregions != null)
-    {
-      sb.append('\n');// System.lineSeparator());
-      subregions.prettyPrint(sb, offset + 2, indent);
-    }
-  }
-
-  /**
-   * Add any ranges that overlap the from-to range to the result list
-   * 
-   * @param from
-   * @param to
-   * @param result
-   */
-  void findOverlaps(long from, long to, List<T> result)
-  {
-    if (region.getBegin() <= to && region.getEnd() >= from)
-    {
-      result.add(region);
-      if (subregions != null)
-      {
-        subregions.findOverlaps(from, to, result);
-      }
-    }
-  }
-
-  /**
-   * Add one node to this node's subregions.
-   * 
-   * @param entry
-   * @throws IllegalArgumentException
-   *           if the added node is not contained by the node's start-end range
-   */
-  synchronized void addNode(NCNode<T> entry)
-  {
-    if (!region.containsInterval(entry))
-    {
-      throw new IllegalArgumentException(
-              String.format("adding improper subrange %d-%d to range %d-%d",
-                      entry.getBegin(), entry.getEnd(), region.getBegin(),
-                      region.getEnd()));
-    }
-    if (subregions == null)
-    {
-      subregions = new NCList<>();
-    }
-
-    subregions.addNode(entry);
-  }
-
-  /**
-   * Answers true if the data held satisfy the rules of construction of an
-   * NCList, else false
-   * 
-   * @return
-   */
-  boolean isValid()
-  {
-    /*
-     * we don't handle reverse ranges
-     */
-    if (region != null && region.getBegin() > region.getEnd())
-    {
-      return false;
-    }
-    if (subregions == null)
-    {
-      return true;
-    }
-    if (subregions.isEmpty())
-    {
-      /*
-       * we expect empty subregions to be nulled
-       */
-      return false;
-    }
-    return subregions.isValid(getBegin(), getEnd());
-  }
-
-  /**
-   * Adds all contained entries to the given list
-   * 
-   * @param entries
-   */
-  void getEntries(List<T> entries)
-  {
-    entries.add(region);
-    if (subregions != null)
-    {
-      subregions.getEntries(entries);
-    }
-  }
-
-  /**
-   * Answers true if this object contains the given entry (by object equals
-   * test), else false
-   * 
-   * @param entry
-   * @return
-   */
-  boolean contains(IntervalI entry)
-  {
-    if (entry == null)
-    {
-      return false;
-    }
-    if (entry.equals(region))
-    {
-      return true;
-    }
-    return subregions == null ? false : subregions.contains(entry);
-  }
-
-  /**
-   * Answers the 'root' region modelled by this object
-   * 
-   * @return
-   */
-  T getRegion()
-  {
-    return region;
-  }
-
-  /**
-   * Answers the (possibly null) contained regions within this object
-   * 
-   * @return
-   */
-  NCList<T> getSubRegions()
-  {
-    return subregions;
-  }
-
-  /**
-   * Answers the (deep) size of this node i.e. the number of intervals it models
-   * 
-   * @return
-   */
-  int size()
-  {
-    return subregions == null ? 1 : 1 + subregions.size();
-  }
-
-  /**
-   * Answers the depth of NCNode / NCList nesting in the data tree
-   * 
-   * @return
-   */
-  int getDepth()
-  {
-    return subregions == null ? 1 : 1 + subregions.getDepth();
-  }
-
-  /**
-   * Answers an iterator over the intervals stored in this node. The iterator
-   * does not support the optional <code>remove</code> operation (throws
-   * <code>UnsupportedOperationException</code> if attempted).
-   * 
-   * @return
-   */
-  public Iterator<T> iterator()
-  {
-    return new NCNodeIterator();
-  }
-
-  /**
-   * Removes the first interval found equal to the given entry. Answers true if
-   * a matching interval is found and removed, else false.
-   * 
-   * @param entry
-   * @return
-   */
-  boolean remove(T entry)
-  {
-    if (region.equals(entry))
-    {
-      /*
-       * this case must be handled by NCList, to allow any
-       * children of a deleted interval to be promoted
-       */
-      throw new IllegalArgumentException("NCNode can't remove self");
-    }
-    if (subregions == null)
-    {
-      return false;
-    }
-    if (subregions.remove(entry))
-    {
-      if (subregions.isEmpty())
-      {
-        subregions = null;
-      }
-      return true;
-    }
-    return false;
-  }
-
-  @SuppressWarnings("unchecked")
-  @Override
-  public boolean equals(Object o)
-  {
-    return o != null && o instanceof NCNode
-            && equalsInterval((NCNode<T>) o);
-  }
-
-  @Override
-  public boolean equalsInterval(IntervalI i)
-  {
-    return i != null && getBegin() == i.getBegin()
-            && getEnd() == i.getEnd();
-
-  }
-
-}
diff --git a/src/intervalstore/impl/Range.java b/src/intervalstore/impl/Range.java
deleted file mode 100644 (file)
index c07e793..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-BSD 3-Clause License
-
-Copyright (c) 2018, Mungo Carstairs
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
-  this list of conditions and the following disclaimer in the documentation
-  and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-package intervalstore.impl;
-
-import intervalstore.api.IntervalI;
-
-/**
- * An immutable data bean that models a start-end range
- */
-public class Range implements IntervalI
-{
-
-  // no need for final here; these can be fully mutable as long as
-  // store.revalidate() is run afterwords
-
-  public int start;
-
-  public int end;
-
-
-  @Override
-  public int getBegin()
-  {
-    return start;
-  }
-
-  @Override
-  public int getEnd()
-  {
-    return end;
-  }
-
-  public Range(int i, int j)
-  {
-    start = i;
-    end = j;
-  }
-
-  @Override
-  public String toString()
-  {
-    return String.valueOf(start) + "-" + String.valueOf(end);
-  }
-
-  @Override
-  public int hashCode()
-  {
-    return start * 31 + end;
-  }
-
-  @Override
-  public boolean equals(Object o)
-  {
-    return (o != null && o instanceof Range && equalsInterval((Range) o));
-  }
-
-  @Override
-  public boolean equalsInterval(IntervalI obj)
-  {
-
-    // override equalsInterval, not equals
-    return (obj != null && start == ((Range) obj).start
-            && end == ((Range) obj).end);
-
-  }
-
-  public void setStart(int pos)
-  {
-    start = pos;
-  }
-
-  public void setEnd(int pos)
-  {
-    end = pos;
-  }
-
-
-}
diff --git a/src/intervalstore/nonc/IntervalEndSorter.java b/src/intervalstore/nonc/IntervalEndSorter.java
deleted file mode 100644 (file)
index 282c880..0000000
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package intervalstore.nonc;
-
-import intervalstore.api.IntervalI;
-
-/**
- * A dual pivot quicksort for int[] where the int is a pointer to something for
- * which the value needs to be checked. This class is not used; it was just an
- * idea I was trying. But it is sort of cool, so I am keeping it in the package
- * for possible future use.
- * 
- * Adapted from Java 7 java.util.DualPivotQuicksort -- int[] only. The only
- * difference is that wherever an a[] value is compared, we use val(a[i])
- * instead of a[i] itself. Pretty straightforward. Could be adapted for general
- * use. Why didn't they do this in Java?
- * 
- * val(i) is just a hack here, of course. A more general implementation might
- * use a Function call.
- * 
- * Just thought it was cool that you can do this.
- * 
- * @author Bob Hanson 2019.09.02
- * 
- */
-
-class IntervalEndSorter
-{
-
-  private IntervalI[] intervals;
-
-  private int val(int i)
-  {
-    return intervals[i].getEnd();
-  }
-
-  /*
-   * Tuning parameters.
-   */
-
-  /**
-   * The maximum number of runs in merge sort.
-   */
-  private static final int MAX_RUN_COUNT = 67;
-
-  /**
-   * The maximum length of run in merge sort.
-   */
-  private static final int MAX_RUN_LENGTH = 33;
-
-  /**
-   * If the length of an array to be sorted is less than this constant,
-   * Quicksort is used in preference to merge sort.
-   */
-  private static final int QUICKSORT_THRESHOLD = 286;
-
-  /**
-   * If the length of an array to be sorted is less than this constant,
-   * insertion sort is used in preference to Quicksort.
-   */
-  private static final int INSERTION_SORT_THRESHOLD = 47;
-
-  /*
-   * Sorting methods for seven primitive types.
-   */
-
-  /**
-   * Sorts the specified range of the array using the given workspace array
-   * slice if possible for merging
-   *
-   * @param a
-   *          the array to be sorted
-   * @param left
-   *          the index of the first element, inclusive, to be sorted
-   * @param right
-   *          the index of the last element, inclusive, to be sorted
-   * @param work
-   *          a workspace array (slice)
-   * @param workBase
-   *          origin of usable space in work array
-   * @param workLen
-   *          usable size of work array
-   */
-  void sort(int[] a, IntervalI[] intervals, int len)
-  {
-    this.intervals = intervals;
-
-    int left = 0, right = len - 1;
-    // Use Quicksort on small arrays
-    if (right - left < QUICKSORT_THRESHOLD)
-    {
-      sort(a, left, right, true);
-      return;
-    }
-
-    /*
-     * Index run[i] is the start of i-th run
-     * (ascending or descending sequence).
-     */
-    int[] run = new int[MAX_RUN_COUNT + 1];
-    int count = 0;
-    run[0] = left;
-
-    // Check if the array is nearly sorted
-    for (int k = left; k < right; run[count] = k)
-    {
-      switch (Integer.signum(val(a[k + 1]) - val(a[k])))
-      {
-      case 1:
-        // ascending
-        while (++k <= right && val(a[k - 1]) <= val(a[k]))
-          ;
-        break;
-      case -1:
-        // descending
-        while (++k <= right && val(a[k - 1]) >= val(a[k]))
-          ;
-        for (int lo = run[count] - 1, hi = k; ++lo < --hi;)
-        {
-          int t = a[lo];
-          a[lo] = a[hi];
-          a[hi] = t;
-        }
-        break;
-      default:
-        // equal
-        for (int m = MAX_RUN_LENGTH; ++k <= right
-                && val(a[k - 1]) == val(a[k]);)
-        {
-          if (--m == 0)
-          {
-            sort(a, left, right, true);
-            return;
-          }
-        }
-      }
-
-      /*
-       * The array is not highly structured,
-       * use Quicksort instead of merge sort.
-       */
-      if (++count == MAX_RUN_COUNT)
-      {
-        sort(a, left, right, true);
-        return;
-      }
-    }
-
-    // Check special cases
-    // Implementation note: variable "right" is increased by 1.
-    if (run[count] == right++)
-    { // The last run contains one element
-      run[++count] = right;
-    }
-    else if (count == 1)
-    { // The array is already sorted
-      return;
-    }
-
-    // Determine alternation base for merge
-    byte odd = 0;
-    for (int n = 1; (n <<= 1) < count; odd ^= 1)
-      ;
-
-    // Use or create temporary array b for merging
-    int[] b; // temp array; alternates with a
-    int ao, bo; // array offsets from 'left'
-    int blen = right - left; // space needed for b
-    int[] work = new int[blen];
-    int workBase = 0;
-    if (odd == 0)
-    {
-      System.arraycopy(a, left, work, workBase, blen);
-      b = a;
-      bo = 0;
-      a = work;
-      ao = workBase - left;
-    }
-    else
-    {
-      b = work;
-      ao = 0;
-      bo = workBase - left;
-    }
-
-    // Merging
-    for (int last; count > 1; count = last)
-    {
-      for (int k = (last = 0) + 2; k <= count; k += 2)
-      {
-        int hi = run[k], mi = run[k - 1];
-        for (int i = run[k - 2], p = i, q = mi; i < hi; ++i)
-        {
-          if (q >= hi || p < mi && val(a[p + ao]) <= val(a[q + ao]))
-          {
-            b[i + bo] = a[p++ + ao];
-          }
-          else
-          {
-            b[i + bo] = a[q++ + ao];
-          }
-        }
-        run[++last] = hi;
-      }
-      if ((count & 1) != 0)
-      {
-        for (int i = right, lo = run[count - 1]; --i >= lo; b[i + bo] = a[i
-                + ao])
-          ;
-        run[++last] = right;
-      }
-      int[] t = a;
-      a = b;
-      b = t;
-      int o = ao;
-      ao = bo;
-      bo = o;
-    }
-  }
-
-  /**
-   * Sorts the specified range of the array by Dual-Pivot Quicksort.
-   *
-   * @param a
-   *          the array to be sorted
-   * @param left
-   *          the index of the first element, inclusive, to be sorted
-   * @param right
-   *          the index of the last element, inclusive, to be sorted
-   * @param leftmost
-   *          indicates if this part is the leftmost in the range
-   */
-  private void sort(int[] a, int left, int right, boolean leftmost)
-  {
-    int length = right - left + 1;
-
-    // Use insertion sort on tiny arrays
-    if (length < INSERTION_SORT_THRESHOLD)
-    {
-      if (leftmost)
-      {
-        /*
-         * Traditional (without sentinel) insertion sort,
-         * optimized for server VM, is used in case of
-         * the leftmost part.
-         */
-        for (int i = left, j = i; i < right; j = ++i)
-        {
-          int ai = a[i + 1];
-          while (val(ai) < val(a[j]))
-          {
-            a[j + 1] = a[j];
-            if (j-- == left)
-            {
-              break;
-            }
-          }
-          a[j + 1] = ai;
-        }
-      }
-      else
-      {
-        /*
-         * Skip the longest ascending sequence.
-         */
-        do
-        {
-          if (left >= right)
-          {
-            return;
-          }
-        } while (val(a[++left]) >= val(a[left - 1]));
-
-        /*
-         * Every element from adjoining part plays the role
-         * of sentinel, therefore this allows us to avoid the
-         * left range check on each iteration. Moreover, we use
-         * the more optimized algorithm, so called pair insertion
-         * sort, which is faster (in the context of Quicksort)
-         * than traditional implementation of insertion sort.
-         */
-        for (int k = left; ++left <= right; k = ++left)
-        {
-          int a1 = a[k], a2 = a[left];
-
-          if (val(a1) < val(a2))
-          {
-            a2 = a1;
-            a1 = a[left];
-          }
-          while (val(a1) < val(a[--k]))
-          {
-            a[k + 2] = a[k];
-          }
-          a[++k + 1] = a1;
-
-          while (val(a2) < val(a[--k]))
-          {
-            a[k + 1] = a[k];
-          }
-          a[k + 1] = a2;
-        }
-        int last = a[right];
-
-        while (val(last) < val(a[--right]))
-        {
-          a[right + 1] = a[right];
-        }
-        a[right + 1] = last;
-      }
-      return;
-    }
-
-    // Inexpensive approximation of length / 7
-    int seventh = (length >> 3) + (length >> 6) + 1;
-
-    /*
-     * Sort five evenly spaced elements around (and including) the
-     * center element in the range. These elements will be used for
-     * pivot selection as described below. The choice for spacing
-     * these elements was empirically determined to work well on
-     * a wide variety of inputs.
-     */
-    int e3 = (left + right) >>> 1; // The midpoint
-    int e2 = e3 - seventh;
-    int e1 = e2 - seventh;
-    int e4 = e3 + seventh;
-    int e5 = e4 + seventh;
-
-    // Sort these elements using insertion sort
-    if (val(a[e2]) < val(a[e1]))
-    {
-      int t = a[e2];
-      a[e2] = a[e1];
-      a[e1] = t;
-    }
-
-    if (val(a[e3]) < val(a[e2]))
-    {
-      int t = a[e3];
-      a[e3] = a[e2];
-      a[e2] = t;
-      if (val(t) < val(a[e1]))
-      {
-        a[e2] = a[e1];
-        a[e1] = t;
-      }
-    }
-    if (val(a[e4]) < val(a[e3]))
-    {
-      int t = a[e4];
-      a[e4] = a[e3];
-      a[e3] = t;
-      int vt = val(t);
-      if (vt < val(a[e2]))
-      {
-        a[e3] = a[e2];
-        a[e2] = t;
-        if (vt < val(a[e1]))
-        {
-          a[e2] = a[e1];
-          a[e1] = t;
-        }
-      }
-    }
-    if (val(a[e5]) < val(a[e4]))
-    {
-      int t = a[e5];
-      a[e5] = a[e4];
-      a[e4] = t;
-      int vt = val(t);
-      if (vt < val(a[e3]))
-      {
-        a[e4] = a[e3];
-        a[e3] = t;
-        if (vt < val(a[e2]))
-        {
-          a[e3] = a[e2];
-          a[e2] = t;
-          if (vt < val(a[e1]))
-          {
-            a[e2] = a[e1];
-            a[e1] = t;
-          }
-        }
-      }
-    }
-
-    // Pointers
-    int less = left; // The index of the first element of center part
-    int great = right; // The index before the first element of right part
-
-    if (val(a[e1]) != val(a[e2]) && val(a[e2]) != val(a[e3])
-            && val(a[e3]) != val(a[e4]) && val(a[e4]) != val(a[e5]))
-    {
-      /*
-       * Use the second and fourth of the five sorted elements as pivots.
-       * These values are inexpensive approximations of the first and
-       * second terciles of the array. Note that pivot1 <= pivot2.
-       */
-      int pivot1 = val(a[e2]);
-      int pivot2 = val(a[e4]);
-      int pivot1k = a[e2];
-      int pivot2k = a[e4];
-
-      /*
-       * The first and the last elements to be sorted are moved to the
-       * locations formerly occupied by the pivots. When partitioning
-       * is complete, the pivots are swapped back into their final
-       * positions, and excluded from subsequent sorting.
-       */
-      a[e2] = a[left];
-      a[e4] = a[right];
-
-      /*
-       * Skip elements, which are less or greater than pivot values.
-       */
-      while (val(a[++less]) < pivot1)
-        ;
-      while (val(a[--great]) > pivot2)
-        ;
-
-      /*
-       * Partitioning:
-       *
-       *   left part           center part                   right part
-       * +--------------------------------------------------------------+
-       * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
-       * +--------------------------------------------------------------+
-       *               ^                          ^       ^
-       *               |                          |       |
-       *              less                        k     great
-       *
-       * Invariants:
-       *
-       *              all in (left, less)   < pivot1
-       *    pivot1 <= all in [less, k)     <= pivot2
-       *              all in (great, right) > pivot2
-       *
-       * Pointer k is the first index of ?-part.
-       */
-      outer: for (int k = less - 1; ++k <= great;)
-      {
-        int ak = a[k];
-        if (val(ak) < pivot1)
-        { // Move a[k] to left part
-          a[k] = a[less];
-          /*
-          * Here and below we use "a[i] = b; i++;" instead
-          * of "a[i++] = b;" due to performance issue.
-          */
-          a[less] = ak;
-          ++less;
-        }
-        else if (val(ak) > pivot2)
-        { // Move a[k] to right part
-          while (val(a[great]) > pivot2)
-          {
-            if (great-- == k)
-            {
-              break outer;
-            }
-          }
-          if (val(a[great]) < pivot1)
-          { // a[great] <= pivot2
-            a[k] = a[less];
-            a[less] = a[great];
-            ++less;
-          }
-          else
-          { // pivot1 <= a[great] <= pivot2
-            a[k] = a[great];
-          }
-          /*
-          * Here and below we use "a[i] = b; i--;" instead
-          * of "a[i--] = b;" due to performance issue.
-          */
-          a[great] = ak;
-          --great;
-        }
-      }
-
-      // Swap pivots into their final positions
-      a[left] = a[less - 1];
-      a[less - 1] = pivot1k;
-      a[right] = a[great + 1];
-      a[great + 1] = pivot2k;
-
-      // Sort left and right parts recursively, excluding known pivots
-      sort(a, left, less - 2, leftmost);
-      sort(a, great + 2, right, false);
-
-      /*
-       * If center part is too large (comprises > 4/7 of the array),
-       * swap internal pivot values to ends.
-       */
-      if (less < e1 && e5 < great)
-      {
-        /*
-         * Skip elements, which are equal to pivot values.
-         */
-        while (val(a[less]) == pivot1)
-        {
-          ++less;
-        }
-
-        while (val(a[great]) == pivot2)
-        {
-          --great;
-        }
-
-        /*
-         * Partitioning:
-         *
-         *   left part         center part                  right part
-         * +----------------------------------------------------------+
-         * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
-         * +----------------------------------------------------------+
-         *              ^                        ^       ^
-         *              |                        |       |
-         *             less                      k     great
-         *
-         * Invariants:
-         *
-         *              all in (*,  less) == pivot1
-         *     pivot1 < all in [less,  k)  < pivot2
-         *              all in (great, *) == pivot2
-         *
-         * Pointer k is the first index of ?-part.
-         */
-        outer: for (int k = less - 1; ++k <= great;)
-        {
-          int ak = a[k];
-          if (val(ak) == pivot1)
-          { // Move a[k] to left part
-            a[k] = a[less];
-            a[less] = ak;
-            ++less;
-          }
-          else if (val(ak) == pivot2)
-          { // Move a[k] to right part
-            while (val(a[great]) == pivot2)
-            {
-              if (great-- == k)
-              {
-                break outer;
-              }
-            }
-            if (val(a[great]) == pivot1)
-            { // a[great] < pivot2
-              a[k] = a[less];
-              /*
-              * Even though a[great] equals to pivot1, the
-              * assignment a[less] = pivot1 may be incorrect,
-              * if a[great] and pivot1 are floating-point zeros
-              * of different signs. Therefore in float and
-              * double sorting methods we have to use more
-              * accurate assignment a[less] = a[great].
-              */
-              a[less] = pivot1k;
-              ++less;
-            }
-            else
-            { // pivot1 < a[great] < pivot2
-              a[k] = a[great];
-            }
-            a[great] = ak;
-            --great;
-          }
-        }
-      }
-
-      // Sort center part recursively
-      sort(a, less, great, false);
-
-    }
-    else
-    { // Partitioning with one pivot
-      /*
-       * Use the third of the five sorted elements as pivot.
-       * This value is inexpensive approximation of the median.
-       */
-      int pivot = val(a[e3]);
-
-      /*
-       * Partitioning degenerates to the traditional 3-way
-       * (or "Dutch National Flag") schema:
-       *
-       *   left part    center part              right part
-       * +-------------------------------------------------+
-       * |  < pivot  |   == pivot   |     ?    |  > pivot  |
-       * +-------------------------------------------------+
-       *              ^              ^        ^
-       *              |              |        |
-       *             less            k      great
-       *
-       * Invariants:
-       *
-       *   all in (left, less)   < pivot
-       *   all in [less, k)     == pivot
-       *   all in (great, right) > pivot
-       *
-       * Pointer k is the first index of ?-part.
-       */
-      for (int k = less; k <= great; ++k)
-      {
-        if (val(a[k]) == pivot)
-        {
-          continue;
-        }
-        int ak = a[k];
-        if (val(ak) < pivot)
-        { // Move a[k] to left part
-          a[k] = a[less];
-          a[less] = ak;
-          ++less;
-        }
-        else
-        { // a[k] > pivot - Move a[k] to right part
-          while (val(a[great]) > pivot)
-          {
-            --great;
-          }
-          if (val(a[great]) < pivot)
-          { // a[great] <= pivot
-            a[k] = a[less];
-            a[less] = a[great];
-            ++less;
-          }
-          else
-          { // a[great] == pivot
-            /*
-            * Even though a[great] equals to pivot, the
-            * assignment a[k] = pivot may be incorrect,
-            * if a[great] and pivot are floating-point
-            * zeros of different signs. Therefore in float
-            * and double sorting methods we have to use
-            * more accurate assignment a[k] = a[great].
-            */
-            // So, guess what?
-            //
-            // Actually, we do need a[great] for IntervalStore,
-            // because here, two, the numbers are not necessarily the same item
-            //
-            // a[k] = pivot;
-            a[k] = a[great];
-          }
-          a[great] = ak;
-          --great;
-        }
-      }
-
-      /*
-       * Sort left and right parts recursively.
-       * All elements from center part are equal
-       * and, therefore, already sorted.
-       */
-      sort(a, left, less - 1, leftmost);
-      sort(a, great + 1, right, false);
-    }
-  }
-
-}
index bc9ca83..5c013ad 100644 (file)
@@ -224,8 +224,8 @@ public class IntervalStore<T extends IntervalI>
           Comparator<? super IntervalI> comparator, boolean bigendian)
   {
     icompare = (comparator != null ? comparator
-            : bigendian ? IntervalI.COMPARATOR_BIGENDIAN
-                    : IntervalI.COMPARATOR_LITTLEENDIAN);
+            : bigendian ? IntervalI.COMPARE_BEGIN_ASC_END_DESC
+                    : IntervalI.COMPARE_BEGIN_ASC_END_ASC);
     this.bigendian = bigendian;
 
     if (intervals != null)
@@ -259,7 +259,7 @@ public class IntervalStore<T extends IntervalI>
   }
 
   /**
-   * Adds one interval to the store, allowing duplicates.
+   * Adds one interval to the store, allowing duplicates
    * 
    * @param interval
    */
@@ -320,9 +320,6 @@ public class IntervalStore<T extends IntervalI>
         else
         {
           index = findInterval(interval);
-          // System.out.println("index = " + index + " for " + interval + "\n"
-          // + Arrays.toString(intervals) + "\n"
-          // + Arrays.toString(offsets));
           if (!allowDuplicates && index >= 0)
           {
             return false;
@@ -405,7 +402,7 @@ public class IntervalStore<T extends IntervalI>
       int pt0 = pt;
       while (--pt >= 0 && offsets[pt] == 0)
       {
-        ;
+        
       }
       if (pt < 0)
       {
@@ -484,7 +481,7 @@ public class IntervalStore<T extends IntervalI>
       case 0:
         IntervalI iv = intervals[mid];
         if ((bsIgnore == null || !bsIgnore.get(mid))
-                && iv.equalsInterval(interval))
+                && sameInterval(interval, iv))
         {
           return mid;
           // found one; just scan up and down now, first checking the range, but
@@ -498,7 +495,7 @@ public class IntervalStore<T extends IntervalI>
             break;
           }
           if ((bsIgnore == null || !bsIgnore.get(i))
-                  && iv.equalsInterval(interval))
+                  && sameInterval(interval, iv))
           {
             return i;
           }
@@ -511,7 +508,7 @@ public class IntervalStore<T extends IntervalI>
             return -1 - ++i;
           }
           if ((bsIgnore == null || !bsIgnore.get(i))
-                  && iv.equalsInterval(interval))
+                  && sameInterval(interval, iv))
           {
             return i;
           }
@@ -522,10 +519,21 @@ public class IntervalStore<T extends IntervalI>
     return -1 - start;
   }
 
-  @Override
-  public boolean canCheckForDuplicates()
+  /**
+   * Answers true if the two intervals are equal (as determined by
+   * {@code i1.equals(i2)}, else false
+   * 
+   * @param i1
+   * @param i2
+   * @return
+   */
+  static boolean sameInterval(IntervalI i1, IntervalI i2)
   {
-    return true;
+    /*
+     * for speed, do the fast check for begin/end equality before
+     * the equals check which includes type checking
+     */
+    return i1.equalsInterval(i2) && i1.equals(i2);
   }
 
   /**
@@ -766,21 +774,6 @@ public class IntervalStore<T extends IntervalI>
   }
 
   /**
-   * return the i-th interval in the designated order (bigendian or
-   * littleendian)
-   */
-  @Override
-  public IntervalI get(int i)
-  {
-    if (i < 0 || i >= intervalCount + added)
-    {
-      return null;
-    }
-    ensureFinalized();
-    return intervals[i];
-  }
-
-  /**
    * Return the deepest level of nesting.
    * 
    */
@@ -821,26 +814,6 @@ public class IntervalStore<T extends IntervalI>
   }
 
   /**
-   * Get the number of root-level nests.
-   * 
-   */
-  @Override
-  public int getWidth()
-  {
-    ensureFinalized();
-    // System.out.println(
-    // "ISList w[0]=" + nestCounts[0] + " w[1]=" + nestCounts[1]);
-    return nestCounts[0] + (createUnnested ? nestCounts[1] : 0);
-  }
-
-  @Override
-  public boolean isValid()
-  {
-    ensureFinalized();
-    return true;
-  }
-
-  /**
    * Answers an iterator over the intervals in the store, with no particular
    * ordering guaranteed. The iterator does not support the optional
    * <code>remove</code> operation (throws
@@ -915,17 +888,15 @@ public class IntervalStore<T extends IntervalI>
     {
       sb.append(sep).append(nests[pt + i].toString());
       if (nestCounts[pt + i] > 0)
+      {
         dump(pt + i, sb, sep + "  ");
+      }
     }
   }
 
   @Override
   public synchronized boolean remove(Object o)
   {
-    // if (o == null)
-    // {
-    // throw new NullPointerException();
-    // }
     return (o != null && intervalCount > 0
             && removeInterval((IntervalI) o));
   }
@@ -964,7 +935,7 @@ public class IntervalStore<T extends IntervalI>
         case -1:
           break;
         case 0:
-          if (iv.equalsInterval(interval))
+          if (sameInterval(interval, iv))
           {
             return pt;
           }
@@ -979,9 +950,9 @@ public class IntervalStore<T extends IntervalI>
     else
     {
       int i = intervalCount;
-      while (--i >= 0 && !intervals[i].equalsInterval(interval))
+      while (--i >= 0 && !sameInterval(intervals[i], interval))
       {
-        ;
+        
       }
       return i;
     }
@@ -1067,7 +1038,6 @@ public class IntervalStore<T extends IntervalI>
    * Recreate the key nest arrays.
    * 
    */
-  @Override
   public boolean revalidate()
   {
     isTainted = true;
@@ -1186,7 +1156,6 @@ public class IntervalStore<T extends IntervalI>
     int beginLast2 = beginLast;
 
     // Phase One: Get the temporary container array myContainer.
-
     for (int i = 1; i < intervalCount; i++)
     {
       int pt = i - 1;
index 389439f..1050ee0 100644 (file)
@@ -67,6 +67,7 @@ import intervalstore.api.IntervalStoreI;
 public class IntervalStore0<T extends IntervalI>
         extends AbstractCollection<T> implements IntervalStoreI<T>
 {
+  private static int NOT_CONTAINED = Integer.MIN_VALUE;
 
   /**
    * Search for the last interval that starts before or at the specified from/to
@@ -230,8 +231,8 @@ public class IntervalStore0<T extends IntervalI>
     }
     DO_PRESORT = presort;
     icompare = (comparator != null ? comparator
-            : bigendian ? IntervalI.COMPARATOR_BIGENDIAN
-                    : IntervalI.COMPARATOR_LITTLEENDIAN);
+            : bigendian ? IntervalI.COMPARE_BEGIN_ASC_END_DESC
+                    : IntervalI.COMPARE_BEGIN_ASC_END_ASC);
     this.bigendian = bigendian;
 
     if (DO_PRESORT && intervalCount > 1)
@@ -250,7 +251,7 @@ public class IntervalStore0<T extends IntervalI>
   @Override
   public boolean add(T interval)
   {
-    return add(interval, true);
+    return add(interval, false);
   }
 
   /**
@@ -373,7 +374,7 @@ public class IntervalStore0<T extends IntervalI>
       int pt0 = pt;
       while (--pt >= 0 && offsets[pt] == 0)
       {
-        ;
+        
       }
       if (pt < 0)
       {
@@ -445,7 +446,7 @@ public class IntervalStore0<T extends IntervalI>
       case 0:
         IntervalI iv = intervals[mid];
         if ((bsIgnore == null || !bsIgnore.get(mid))
-                && iv.equalsInterval(interval))
+                && sameInterval(interval, iv))
         {
           return mid;
           // found one; just scan up and down now, first checking the range, but
@@ -459,7 +460,7 @@ public class IntervalStore0<T extends IntervalI>
             break;
           }
           if ((bsIgnore == null || !bsIgnore.get(i))
-                  && iv.equalsInterval(interval))
+                  && sameInterval(interval, iv))
           {
             return i;
           }
@@ -471,7 +472,7 @@ public class IntervalStore0<T extends IntervalI>
             return -1 - ++i;
           }
           if ((bsIgnore == null || !bsIgnore.get(i))
-                  && iv.equalsInterval(interval))
+                  && sameInterval(interval, iv))
           {
             return i;
           }
@@ -482,33 +483,13 @@ public class IntervalStore0<T extends IntervalI>
     return -1 - start;
   }
 
-  // private int binaryInsertionSearch(long from, long to)
-  // {
-  // int matched = intervalCount;
-  // int end = matched - 1;
-  // int start = matched;
-  // if (end < 0 || from > intervals[end].getEnd()
-  // || from < intervals[start = 0].getBegin())
-  // return start;
-  // while (start <= end)
-  // {
-  // int mid = (start + end) >>> 1;
-  // switch (compareRange(intervals[mid], from, to))
-  // {
-  // case 0:
-  // return mid;
-  // case 1:
-  // matched = mid;
-  // end = mid - 1;
-  // continue;
-  // case -1:
-  // start = mid + 1;
-  // continue;
-  // }
-  //
-  // }
-  // return matched;
-  // }
+  boolean sameInterval(IntervalI i1, IntervalI i2)
+  {
+    /*
+     * do the quick test of begin/end first for speed
+     */
+    return i1.equalsInterval(i2) && i1.equals(i2);
+  }
 
   @Override
   public void clear()
@@ -668,17 +649,6 @@ public class IntervalStore0<T extends IntervalI>
     return result;
   }
 
-  @Override
-  public IntervalI get(int i)
-  {
-    if (i < 0 || i >= intervalCount + added)
-    {
-      return null;
-    }
-    ensureFinalized();
-    return intervals[i];
-  }
-
   private int getContainedBy(int index, int begin)
   {
     while (index >= 0)
@@ -692,7 +662,7 @@ public class IntervalStore0<T extends IntervalI>
       }
       index -= Math.abs(offsets[index]);
     }
-    return IntervalI.NOT_CONTAINED;
+    return NOT_CONTAINED;
   }
 
   @Override
@@ -708,7 +678,7 @@ public class IntervalStore0<T extends IntervalI>
     for (int i = 0; i < intervalCount; i++)
     {
       IntervalI element = intervals[i];
-      if (offsets[i] == IntervalI.NOT_CONTAINED)
+      if (offsets[i] == NOT_CONTAINED)
       {
         root = element;
       }
@@ -728,28 +698,6 @@ public class IntervalStore0<T extends IntervalI>
     return maxDepth;
   }
 
-  @Override
-  public int getWidth()
-  {
-    ensureFinalized();
-    int w = 0;
-    for (int i = offsets.length; --i >= 0;)
-    {
-      if (offsets[i] > 0)
-      {
-        w++;
-      }
-    }
-    return w;
-  }
-
-  @Override
-  public boolean isValid()
-  {
-    ensureFinalized();
-    return true;
-  }
-
   /**
    * Answers an iterator over the intervals in the store, with no particular
    * ordering guaranteed. The iterator does not support the optional
@@ -792,7 +740,7 @@ public class IntervalStore0<T extends IntervalI>
       return;
     }
     maxEnd = intervals[0].getEnd();
-    offsets[0] = IntervalI.NOT_CONTAINED;
+    offsets[0] = NOT_CONTAINED;
     if (intervalCount == 1)
     {
       return;
@@ -806,7 +754,7 @@ public class IntervalStore0<T extends IntervalI>
       // System.out.println(sf + " is contained by "
       // + (index < 0 ? null : starts[index]));
 
-      offsets[i] = (index < 0 ? IntervalI.NOT_CONTAINED
+      offsets[i] = (index < 0 ? NOT_CONTAINED
               : isMonotonic ? index - i : i - index);
       isMonotonic = (sf.getEnd() > maxEnd);
       if (isMonotonic)
@@ -888,7 +836,7 @@ public class IntervalStore0<T extends IntervalI>
         case -1:
           break;
         case 0:
-          if (iv.equalsInterval(interval))
+          if (sameInterval(interval, iv))
           {
             return pt;
           }
@@ -903,9 +851,9 @@ public class IntervalStore0<T extends IntervalI>
     else
     {
       int i = intervalCount;
-      while (--i >= 0 && !intervals[i].equalsInterval(interval))
+      while (--i >= 0 && !sameInterval(intervals[i], interval))
       {
-        ;
+        
       }
       return i;
     }
@@ -984,15 +932,6 @@ public class IntervalStore0<T extends IntervalI>
   }
 
   @Override
-  public boolean revalidate()
-  {
-    isTainted = true;
-    isSorted = false;
-    ensureFinalized();
-    return true;
-  }
-
-  @Override
   public int size()
   {
     return intervalCount + added - deleted;
@@ -1045,11 +984,4 @@ public class IntervalStore0<T extends IntervalI>
   {
     return prettyPrint();
   }
-
-  @Override
-  public boolean canCheckForDuplicates()
-  {
-    return true;
-  }
-
 }
index 70dda87..5fe0567 100644 (file)
@@ -41,12 +41,11 @@ public interface AlignmentColsCollectionI extends Iterable<Integer>
   public boolean hasHidden();
 
   /**
-   * Get the visible-column bitset, possibly containing hidden columns (which
-   * may or may not be hidden in the overview).
+   * Get the bitset where a set bit indicates a column to be shown
    * 
    * @return a BitSet
    */
-  public BitSet getOverviewBitSet();
+  public BitSet getShownBitSet();
 
   /**
    * Get the hidden-column bitset, (which may or may not be hidden in the
index 98510e3..22d23bc 100755 (executable)
@@ -59,6 +59,15 @@ public class Alignment implements AlignmentI
 
   private boolean nucleotide = true;
 
+  private List<AlignedCodonFrame> codonFrameList;
+
+  private static final SequenceGroup[] noGroups = new SequenceGroup[0];
+
+  /*
+   * persistent object to hold result of findAllGroups(SequenceI)
+   */
+  private List<SequenceGroup> groupsForSequence = new ArrayList<>();
+
   public boolean hasRNAStructure = false;
 
   public AlignmentAnnotation[] annotations;
@@ -69,8 +78,6 @@ public class Alignment implements AlignmentI
 
   public Hashtable alignmentProperties;
 
-  private List<AlignedCodonFrame> codonFrameList;
-
   private void initAlignment(SequenceI[] seqs)
   {
     groups = Collections.synchronizedList(new ArrayList<SequenceGroup>());
@@ -398,10 +405,6 @@ public class Alignment implements AlignmentI
     return null;
   }
 
-  private static final SequenceGroup[] noGroups = new SequenceGroup[0];
-
-  private ArrayList<SequenceGroup> temp = new ArrayList<>();
-
   /*
    * (non-Javadoc)
    * 
@@ -411,7 +414,6 @@ public class Alignment implements AlignmentI
   @Override
   public SequenceGroup[] findAllGroups(SequenceI s)
   {
-
     synchronized (groups)
     {
       int gSize = groups.size();
@@ -419,7 +421,7 @@ public class Alignment implements AlignmentI
       {
         return noGroups;
       }
-      temp.clear();
+      groupsForSequence.clear();
       for (int i = 0; i < gSize; i++)
       {
         SequenceGroup sg = groups.get(i);
@@ -432,12 +434,12 @@ public class Alignment implements AlignmentI
 
         if (sg.getSequences().contains(s))
         {
-          temp.add(sg);
+          groupsForSequence.add(sg);
         }
       }
     }
-    SequenceGroup[] ret = new SequenceGroup[temp.size()];
-    return temp.toArray(ret);
+    SequenceGroup[] ret = new SequenceGroup[groupsForSequence.size()];
+    return groupsForSequence.toArray(ret);
   }
 
   /**    */
index f3077fa..c65c381 100644 (file)
@@ -67,10 +67,10 @@ public class AllColsCollection implements AlignmentColsCollectionI
   }
 
   /**
-   * return ALL columns, not just the truly visible ones
+   * Returns all columns, including any hidden in the alignment
    */
   @Override
-  public BitSet getOverviewBitSet()
+  public BitSet getShownBitSet()
   {
     if (bsVisible == null)
     {
index bad33d1..47a7ead 100755 (executable)
@@ -118,6 +118,11 @@ public class Sequence extends ASequence implements SequenceI
    */
   private int changeCount;
 
+  /*
+   * cached rgb colours for each position of the aligned sequence (column)
+   */
+  private int[] argb;
+
   /**
    * Creates a new Sequence object.
    * 
@@ -392,10 +397,6 @@ public class Sequence extends ASequence implements SequenceI
     return sequenceFeatureStore.add(sf);
   }
 
-  /**
-   * @param sf
-   *          A known feature of this featureStore
-   */
   @Override
   public void deleteFeature(SequenceFeature sf)
   {
@@ -1616,7 +1617,7 @@ public class Sequence extends ASequence implements SequenceI
       _isNa = Comparison.isNucleotide(this);
     }
     return !_isNa;
-  };
+  }
 
   /*
    * (non-Javadoc)
@@ -1971,15 +1972,6 @@ public class Sequence extends ASequence implements SequenceI
 
     List<SequenceFeature> result = getFeatures().findFeatures(startPos,
             endPos, types);
-    // if (datasetSequence != null)
-    // {
-    // result = datasetSequence.getFeatures().findFeatures(startPos, endPos,
-    // types);
-    // }
-    // else
-    // {
-    // result = sequenceFeatureStore.findFeatures(startPos, endPos, types);
-    // }
 
     /*
      * if end column is gapped, endPos may be to the right, 
@@ -2133,8 +2125,6 @@ public class Sequence extends ASequence implements SequenceI
     return 0;
   }
 
-  private int[] argb;
-
   @Override
   public int getColor(int i)
   {
@@ -2158,12 +2148,10 @@ public class Sequence extends ASequence implements SequenceI
   }
 
   /**
-   * @author Bob Hanson 2019.07.30
-   * 
-   *         allows passing the result ArrayList as a parameter to avoid
-   *         unnecessary construction
-   * @return result (JavaScript) or new ArrayList (Java -- see FeatureRender)
-   * 
+   * Answers a (possibly empty) list of features of the specified type that
+   * overlap the specified column position. If parameter {@code result} is not
+   * null, features are appended to it and the (possibly extended) list is
+   * returned.
    */
   @Override
   public List<SequenceFeature> findFeatures(int column, String type,
@@ -2173,9 +2161,6 @@ public class Sequence extends ASequence implements SequenceI
             result);
   }
 
-  /**
-   * allows early intervention for renderer if this returns false
-   */
   @Override
   public boolean hasFeatures(String type)
   {
index 30e0929..bf0b996 100755 (executable)
@@ -35,8 +35,6 @@ import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.Vector;
 
-import intervalstore.api.IntervalI;
-
 /**
  * A class that models a single contiguous feature on a sequence. If flag
  * 'contactFeature' is true, the start and end positions are interpreted instead
@@ -220,19 +218,10 @@ public class SequenceFeature implements FeatureLocationI
   public boolean equals(Object o)
   {
     return (o != null && (o instanceof SequenceFeature)
-            && equalsInterval((SequenceFeature) o));
+            && equals(((SequenceFeature) o), false));
   }
 
   /**
-   * Having determined that this is in fact a SequenceFeature, now check it for
-   * equivalence. Overridden in CrossRef; used by IntervalStore (possibly).
-   */
-  @Override
-  public boolean equalsInterval(IntervalI sf)
-  {
-    return sf != null && equals((SequenceFeature) sf, false);
-  }
-  /**
    * Overloaded method allows the equality test to optionally ignore the
    * 'Parent' attribute of a feature. This supports avoiding adding many
    * superficially duplicate 'exon' or CDS features to genomic or protein
index 0b26564..ca12c83 100755 (executable)
@@ -386,6 +386,12 @@ public interface SequenceI extends ASequenceI
    */
   public boolean addSequenceFeature(SequenceFeature sf);
 
+  /**
+   * Deletes the feature from the sequence (if found). To be precise, deletes
+   * the first feature {@code f} found where {@code f.equals(sf)}.
+   * 
+   * @param sf
+   */
   public void deleteFeature(SequenceFeature sf);
 
   public void setDatasetSequence(SequenceI seq);
@@ -609,21 +615,18 @@ public interface SequenceI extends ASequenceI
   public void resetColors();
 
   /**
-   * allows passing the result ArrayList as a parameter to avoid unnecessary
-   * construction
-   * 
-   * @author Bob Hanson 2019.07.30
-   * 
-   * 
+   * Answers a (possibly empty) list of features of the specified type that
+   * overlap the specified column position. If parameter {@code result} is not
+   * null, features are appended to it and the (possibly extended) list is
+   * returned.
    */
   List<SequenceFeature> findFeatures(int column, String type,
           List<SequenceFeature> result);
 
   /**
-   * allows early intervention for renderer if false
-   * 
-   * @author Bob Hanson 2019.07.30
+   * Answers true if this store contains at least one feature, else false
    * 
+   * @return
    */
   public boolean hasFeatures(String type);
 
index cd812a1..13709a8 100644 (file)
@@ -64,7 +64,7 @@ public class VisibleColsCollection implements AlignmentColsCollectionI
    * Only the visible columns.
    */
   @Override
-  public BitSet getOverviewBitSet()
+  public BitSet getShownBitSet()
   {
     if (bsVisible == null)
     {
index 75ec45a..4073dd6 100644 (file)
@@ -31,11 +31,12 @@ import java.util.List;
 import java.util.Set;
 
 import intervalstore.api.IntervalStoreI;
+import intervalstore.impl.BinarySearcher;
+import intervalstore.impl.BinarySearcher.Compare;
 
-public abstract class FeatureStore implements FeatureStoreI
+public class FeatureStore
 {
-
-  /**
+  /*
    * track last start for quick insertion of ordered features
    */
   protected int lastStart = -1;
@@ -150,7 +151,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * @param feature
    * @return
    */
-  @Override
   public boolean listContains(List<SequenceFeature> list,
           SequenceFeature feature)
   {
@@ -159,40 +159,26 @@ public abstract class FeatureStore implements FeatureStoreI
       return false;
     }
 
-    return (getEquivalentFeatureIndex(list, feature) >= 0);
-  }
-
-  /**
-   * Binary search for the index (&gt;= 0) of a feature in a list.
-   * 
-   * @param list
-   * @param feature
-   * @return index if found; -1 if not
-   */
-  protected int getEquivalentFeatureIndex(List<SequenceFeature> list,
-          SequenceFeature feature)
-  {
-
     /*
      * locate the first entry in the list which does not precede the feature
      */
     int begin = feature.begin;
-    int pos = findFirstBegin(list, begin);
+    int pos = BinarySearcher.findFirst(list, true, Compare.GE, begin);
     int len = list.size();
     while (pos < len)
     {
       SequenceFeature sf = list.get(pos);
       if (sf.begin > begin)
       {
-        return -1; // no match found
+        return false; // no match found
       }
       if (sf.equals(feature))
       {
-        return pos;
+        return true;
       }
       pos++;
     }
-    return -1;
+    return false;
   }
 
   /**
@@ -248,7 +234,11 @@ public abstract class FeatureStore implements FeatureStoreI
    */
   public FeatureStore(int intervalStoreType)
   {
-    features = getIntervalStore(intervalStoreType);
+    features =
+            // Platform.isJS()
+            // ? new intervalstore.nonc.IntervalStore<>(true)
+            // : new intervalstore.impl.IntervalStore<>();
+            getIntervalStore(intervalStoreType);
     positionalFeatureGroups = new HashSet<>();
     nonPositionalFeatureGroups = new HashSet<>();
     positionalMinScore = Float.NaN;
@@ -262,9 +252,9 @@ public abstract class FeatureStore implements FeatureStoreI
   private IntervalStoreI<SequenceFeature> getIntervalStore(int type)
   {
     switch (type != INTERVAL_STORE_DEFAULT ? type : //
-    Platform.isJS() //
-            ? intervalStoreJSOption
-            : intervalStoreJavaOption)
+            Platform.isJS() //
+                    ? intervalStoreJSOption
+                    : intervalStoreJavaOption)
     {
     default:
     case INTERVAL_STORE_NCLIST_OBJECT:
@@ -301,8 +291,9 @@ public abstract class FeatureStore implements FeatureStoreI
      * insert into list sorted by start (first contact position):
      * binary search the sorted list to find the insertion point
      */
-    contactFeatureStarts.add(
-            findFirstBegin(contactFeatureStarts, feature.begin), feature);
+    int insertAt = BinarySearcher.findFirst(contactFeatureStarts, true,
+            Compare.GE, feature.begin);
+    contactFeatureStarts.add(insertAt, feature);
     /*
      * insert into list sorted by end (second contact position):
      * binary search the sorted list to find the insertion point
@@ -321,23 +312,8 @@ public abstract class FeatureStore implements FeatureStoreI
    * 
    * @param feature
    */
-
-  @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 (feature.isContactFeature())
     {
       if (containsContactFeature(feature))
@@ -353,7 +329,7 @@ public abstract class FeatureStore implements FeatureStoreI
     }
     else if (feature.isNonPositional())
     {
-      if (containsNonPositional(feature))
+      if (containsNonPositionalFeature(feature))
       {
         return false;
       }
@@ -362,9 +338,7 @@ public abstract class FeatureStore implements FeatureStoreI
     }
     else
     {
-      // allow for check with
-      if (checkContainsPositionalFeatureForAdd(feature)
-              || !addPositionalFeature(feature))
+      if (!features.add(feature, false))
       {
         return false;
       }
@@ -423,14 +397,6 @@ 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 boolean addPositionalFeature(SequenceFeature feature);
-
-  /**
    * Adds the feature to the list of non-positional features (with lazy
    * instantiation of the list if it is null), and returns true. The feature
    * group is added to the set of distinct feature groups for non-positional
@@ -460,58 +426,54 @@ public abstract class FeatureStore implements FeatureStoreI
    * @param feature
    * @return
    */
-  @Override
   public boolean contains(SequenceFeature feature)
   {
     if (feature.isNonPositional())
     {
-      return containsNonPositional(feature);
-
+      return containsNonPositionalFeature(feature);
     }
 
     if (feature.isContactFeature())
     {
       return containsContactFeature(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);
+            : features.contains(feature);
   }
 
+  /**
+   * Answers true if this store already contains a contact feature equal to the
+   * given feature (by {@code SequenceFeature.equals()} test), else false
+   * 
+   * @param feature
+   * @return
+   */
   private boolean containsContactFeature(SequenceFeature feature)
   {
     return contactFeatureStarts != null && feature.begin <= lastContactStart
             && listContains(contactFeatureStarts, feature);
   }
 
-  private boolean containsNonPositional(SequenceFeature feature)
+  /**
+   * Answers true if this store already contains a non-positional feature equal
+   * to the given feature (by {@code SequenceFeature.equals()} test), else false
+   * 
+   * @param feature
+   * @return
+   */
+  private boolean containsNonPositionalFeature(SequenceFeature feature)
   {
     return nonPositionalFeatures == null ? false
             : nonPositionalFeatures.contains(feature);
   }
 
-  abstract protected boolean containsFeature(SequenceFeature feature);
-
   /**
    * Deletes the given feature from the store, returning true if it was found
    * (and deleted), else false. This method makes no assumption that the feature
@@ -520,8 +482,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * 
    * @param sf
    */
-
-  @Override
   public synchronized boolean delete(SequenceFeature sf)
   {
     boolean removed = false;
@@ -552,7 +512,7 @@ public abstract class FeatureStore implements FeatureStoreI
      */
     if (!removed && features != null)
     {
-      removed = findAndRemoveNonContactFeature(sf);
+      removed = features.remove(sf);
     }
 
     if (removed)
@@ -563,23 +523,11 @@ public abstract class FeatureStore implements FeatureStoreI
     return removed;
   }
 
-  abstract protected boolean findAndRemoveNonContactFeature(SequenceFeature sf);
-
-  abstract protected void findContactFeatures(long from, long to,
-          List<SequenceFeature> result);
-
-  abstract protected int findFirstBegin(List<SequenceFeature> list,
-          long pos);
-
-  abstract protected int findFirstEnd(List<SequenceFeature> list, long pos);
-
-  @Override
   public List<SequenceFeature> findOverlappingFeatures(long start, long end)
   {
     return findOverlappingFeatures(start, end, null);
   }
 
-  @Override
   public List<SequenceFeature> getContactFeatures()
   {
     return getContactFeatures(new ArrayList<>());
@@ -591,8 +539,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * 
    * @return
    */
-
-  @Override
   public List<SequenceFeature> getContactFeatures(
           List<SequenceFeature> result)
   {
@@ -610,8 +556,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * @param positional
    * @return
    */
-
-  @Override
   public int getFeatureCount(boolean positional)
   {
     if (!positional)
@@ -622,7 +566,6 @@ public abstract class FeatureStore implements FeatureStoreI
 
     return (contactFeatureStarts == null ? 0 : contactFeatureStarts.size())
             + features.size();
-
   }
 
   /**
@@ -633,8 +576,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * @param positionalFeatures
    * @return
    */
-
-  @Override
   public Set<String> getFeatureGroups(boolean positionalFeatures)
   {
     if (positionalFeatures)
@@ -649,7 +590,6 @@ public abstract class FeatureStore implements FeatureStoreI
     }
   }
 
-  @Override
   public Collection<SequenceFeature> getFeatures()
   {
     return features;
@@ -663,8 +603,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * @param group
    * @return
    */
-
-  @Override
   public List<SequenceFeature> getFeaturesForGroup(boolean positional,
           String group)
   {
@@ -700,8 +638,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * @param positional
    * @return
    */
-
-  @Override
   public float getMaximumScore(boolean positional)
   {
     return positional ? positionalMaxScore : nonPositionalMaxScore;
@@ -715,14 +651,11 @@ public abstract class FeatureStore implements FeatureStoreI
    * @param positional
    * @return
    */
-
-  @Override
   public float getMinimumScore(boolean positional)
   {
     return positional ? positionalMinScore : nonPositionalMinScore;
   }
 
-  @Override
   public List<SequenceFeature> getNonPositionalFeatures()
   {
     return getNonPositionalFeatures(new ArrayList<>());
@@ -734,8 +667,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * 
    * @return
    */
-
-  @Override
   public List<SequenceFeature> getNonPositionalFeatures(
           List<SequenceFeature> result)
   {
@@ -746,7 +677,6 @@ public abstract class FeatureStore implements FeatureStoreI
     return result;
   }
 
-  @Override
   public List<SequenceFeature> getPositionalFeatures()
   {
     return getPositionalFeatures(new ArrayList<>());
@@ -757,8 +687,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * 
    * @return
    */
-
-  @Override
   public List<SequenceFeature> getPositionalFeatures(
           List<SequenceFeature> result)
   {
@@ -788,8 +716,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * 
    * @return
    */
-
-  @Override
   public int getTotalFeatureLength()
   {
     return totalExtent;
@@ -800,8 +726,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * 
    * @return
    */
-
-  @Override
   public boolean isEmpty()
   {
     boolean hasFeatures = (contactFeatureStarts != null
@@ -876,8 +800,6 @@ public abstract class FeatureStore implements FeatureStoreI
    * @param shiftBy
    * @return
    */
-
-  @Override
   public synchronized boolean shiftFeatures(int fromPosition, int shiftBy)
   {
     /*
@@ -912,4 +834,163 @@ public abstract class FeatureStore implements FeatureStoreI
     return modified;
   }
 
+  /**
+   * Answers the position (0, 1...) in the list of the first entry whose end
+   * position is not less than {@ pos}. If no such entry is found, answers the
+   * length of the list.
+   * 
+   * @param list
+   * @param pos
+   * @return
+   */
+  protected int findFirstEnd(List<SequenceFeature> list, long pos)
+  {
+    return BinarySearcher.findFirst(list, false, Compare.GE, (int) pos);
+  }
+
+  /**
+   * Adds contact features to the result list where either the second or the
+   * first contact position lies within the target range
+   * 
+   * @param from
+   * @param to
+   * @param result
+   */
+  protected void findContactFeatures(long from, long to,
+          List<SequenceFeature> result)
+  {
+    if (contactFeatureStarts != null)
+    {
+      findContactStartOverlaps(from, to, result);
+      findContactEndOverlaps(from, to, result);
+    }
+  }
+
+  /**
+   * Adds to the result list any contact features whose end (second contact
+   * point), but not start (first contact point), lies in the query from-to
+   * range
+   * 
+   * @param from
+   * @param to
+   * @param result
+   */
+  private void findContactEndOverlaps(long from, long to,
+          List<SequenceFeature> result)
+  {
+    /*
+     * find the first contact feature (if any) 
+     * whose end point is not before the target range
+     */
+    int index = findFirstEnd(contactFeatureEnds, from);
+
+    int n = contactFeatureEnds.size();
+    while (index < n)
+    {
+      SequenceFeature sf = contactFeatureEnds.get(index);
+      if (!sf.isContactFeature())
+      {
+        System.err.println("Error! non-contact feature type " + sf.getType()
+                + " in contact features list");
+        index++;
+        continue;
+      }
+
+      int begin = sf.getBegin();
+      if (begin >= from && begin <= to)
+      {
+        /*
+         * this feature's first contact position lies in the search range
+         * so we don't include it in results a second time
+         */
+        index++;
+        continue;
+      }
+
+      if (sf.getEnd() > to)
+      {
+        /*
+         * this feature (and all following) has end point after the target range
+         */
+        break;
+      }
+
+      /*
+       * feature has end >= from and end <= to
+       * i.e. contact end point lies within overlap search range
+       */
+      result.add(sf);
+      index++;
+    }
+  }
+
+  /**
+   * Adds contact features whose start position lies in the from-to range to the
+   * result list
+   * 
+   * @param from
+   * @param to
+   * @param result
+   */
+  private void findContactStartOverlaps(long from, long to,
+          List<SequenceFeature> result)
+  {
+    int index = BinarySearcher.findFirst(contactFeatureStarts, true,
+            Compare.GE, (int) from);
+
+    while (index < contactFeatureStarts.size())
+    {
+      SequenceFeature sf = contactFeatureStarts.get(index);
+      if (!sf.isContactFeature())
+      {
+        System.err.println("Error! non-contact feature " + sf.toString()
+                + " in contact features list");
+        index++;
+        continue;
+      }
+      if (sf.getBegin() > to)
+      {
+        /*
+         * this feature's start (and all following) follows the target range
+         */
+        break;
+      }
+
+      /*
+       * feature has begin >= from and begin <= to
+       * i.e. contact start point lies within overlap search range
+       */
+      result.add(sf);
+      index++;
+    }
+  }
+
+  /**
+   * 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;
+  }
+
 }
diff --git a/src/jalview/datamodel/features/FeatureStoreI.java b/src/jalview/datamodel/features/FeatureStoreI.java
deleted file mode 100644 (file)
index fb32577..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-package jalview.datamodel.features;
-
-import jalview.datamodel.SequenceFeature;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-public interface FeatureStoreI
-{
-
-  boolean addFeature(SequenceFeature feature);
-
-  boolean contains(SequenceFeature feature);
-
-  boolean delete(SequenceFeature sf);
-
-  List<SequenceFeature> findOverlappingFeatures(long start, long end);
-
-  List<SequenceFeature> findOverlappingFeatures(long start, long end,
-          List<SequenceFeature> result);
-
-  List<SequenceFeature> getContactFeatures();
-
-  List<SequenceFeature> getContactFeatures(List<SequenceFeature> result);
-
-  int getFeatureCount(boolean positional);
-
-  Set<String> getFeatureGroups(boolean positionalFeatures);
-
-  Collection<SequenceFeature> getFeatures();
-
-  List<SequenceFeature> getFeaturesForGroup(boolean positional,
-          String group);
-
-  float getMaximumScore(boolean positional);
-
-  float getMinimumScore(boolean positional);
-
-  List<SequenceFeature> getNonPositionalFeatures();
-
-  List<SequenceFeature> getNonPositionalFeatures(
-          List<SequenceFeature> result);
-
-  List<SequenceFeature> getPositionalFeatures();
-
-  List<SequenceFeature> getPositionalFeatures(List<SequenceFeature> result);
-
-  int getTotalFeatureLength();
-
-  boolean isEmpty();
-
-  boolean shiftFeatures(int fromPosition, int shiftBy);
-
-  boolean listContains(List<SequenceFeature> features,
-          SequenceFeature feature);
-
-}
diff --git a/src/jalview/datamodel/features/FeatureStoreImpl.java b/src/jalview/datamodel/features/FeatureStoreImpl.java
deleted file mode 100644 (file)
index 63ee678..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.datamodel.features;
-
-import jalview.datamodel.SequenceFeature;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import intervalstore.impl.BinarySearcher;
-
-/**
- * A data store for a set of sequence features that supports efficient lookup of
- * features overlapping a given range. Intended for (but not limited to) storage
- * of features for one sequence and feature type.
- * 
- * @author gmcarstairs
- *
- */
-public class FeatureStoreImpl extends FeatureStore
-{
-
-  public FeatureStoreImpl()
-  {
-    super();
-  }
-
-  public FeatureStoreImpl(int option)
-  {
-    super(option);
-  }
-
-  /**
-   * Add a contact feature to the lists that hold them ordered by start (first
-   * contact) and by end (second contact) position, ensuring the lists remain
-   * ordered, and returns true. This method allows duplicate features to be
-   * added, so test before calling to avoid this.
-   * 
-   * @param feature
-   * @return
-   */
-  @Override
-  protected synchronized boolean addContactFeature(SequenceFeature feature)
-  {
-    if (contactFeatureStarts == null)
-    {
-      contactFeatureStarts = new ArrayList<>();
-      contactFeatureEnds = new ArrayList<>();
-    }
-
-    /*
-     * insert into list sorted by start (first contact position):
-     * binary search the sorted list to find the insertion point
-     */
-    int insertPosition = findFirstBegin(contactFeatureStarts,
-            feature.getBegin());
-    contactFeatureStarts.add(insertPosition, feature);
-
-    /*
-     * insert into list sorted by end (second contact position):
-     * binary search the sorted list to find the insertion point
-     */
-    insertPosition = findFirstEnd(contactFeatureEnds,
-            feature.getEnd());
-    contactFeatureEnds.add(insertPosition, feature);
-
-    return true;
-  }
-
-  /**
-   * Adds one feature to the IntervalStore that can manage nested features
-   * (creating the IntervalStore if necessary)
-   */
-  @Override
-  protected synchronized boolean addPositionalFeature(
-          SequenceFeature feature)
-  {
-    return features.add(feature);
-  }
-
-  /**
-   * Adds contact features to the result list where either the second or the
-   * first contact position lies within the target range
-   * 
-   * @param from
-   * @param to
-   * @param result
-   */
-  @Override
-  protected void findContactFeatures(long from, long to,
-          List<SequenceFeature> result)
-  {
-    if (contactFeatureStarts != null)
-    {
-      findContactStartOverlaps(from, to, result);
-      findContactEndOverlaps(from, to, result);
-    }
-  }
-
-  @Override
-  protected boolean containsFeature(SequenceFeature feature)
-  {
-    return features.contains(feature);
-  }
-
-  /**
-   * Adds to the result list any contact features whose end (second contact
-   * point), but not start (first contact point), lies in the query from-to
-   * range
-   * 
-   * @param from
-   * @param to
-   * @param result
-   */
-
-  private void findContactEndOverlaps(long from, long to,
-          List<SequenceFeature> result)
-  {
-    /*
-     * find the first contact feature (if any) 
-     * whose end point is not before the target range
-     */
-    int index = findFirstEnd(contactFeatureEnds, from);
-
-    int n = contactFeatureEnds.size();
-    while (index < n)
-    {
-      SequenceFeature sf = contactFeatureEnds.get(index);
-      if (!sf.isContactFeature())
-      {
-        System.err.println("Error! non-contact feature type " + sf.getType()
-                + " in contact features list");
-        index++;
-        continue;
-      }
-
-      int begin = sf.getBegin();
-      if (begin >= from && begin <= to)
-      {
-        /*
-         * this feature's first contact position lies in the search range
-         * so we don't include it in results a second time
-         */
-        index++;
-        continue;
-      }
-
-      if (sf.getEnd() > to)
-      {
-        /*
-         * this feature (and all following) has end point after the target range
-         */
-        break;
-      }
-
-      /*
-       * feature has end >= from and end <= to
-       * i.e. contact end point lies within overlap search range
-       */
-      result.add(sf);
-      index++;
-    }
-  }
-
-  /**
-   * Adds contact features whose start position lies in the from-to range to the
-   * result list
-   * 
-   * @param from
-   * @param to
-   * @param result
-   */
-
-  private void findContactStartOverlaps(long from, long to,
-          List<SequenceFeature> result)
-  {
-    int index = findFirstBegin(contactFeatureStarts, from);
-
-    while (index < contactFeatureStarts.size())
-    {
-      SequenceFeature sf = contactFeatureStarts.get(index);
-      if (!sf.isContactFeature())
-      {
-        System.err.println("Error! non-contact feature " + sf.toString()
-                + " in contact features list");
-        index++;
-        continue;
-      }
-      if (sf.getBegin() > to)
-      {
-        /*
-         * this feature's start (and all following) follows the target range
-         */
-        break;
-      }
-
-      /*
-       * feature has begin >= from and begin <= to
-       * i.e. contact start point lies within overlap search range
-       */
-      result.add(sf);
-      index++;
-    }
-  }
-
-  /**
-   * 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.
-   * 
-   * @param start
-   *          start position of overlap range (inclusive)
-   * @param end
-   *          end position of overlap range (inclusive)
-   * @param result
-   *          ignored
-   * @return
-   */
-
-  @Override
-  public List<SequenceFeature> findOverlappingFeatures(long start, long end,
-          List<SequenceFeature> result)
-  {
-    result = new ArrayList<>();
-    findContactFeatures(start, end, result);
-    findOverlaps(start, end, result);
-    return result;
-  }
-
-  private void findOverlaps(long start, long end,
-          List<SequenceFeature> result)
-  {
-    result.addAll(features
-            .findOverlaps(start, end));
-  }
-
-  @Override
-  protected int findFirstBegin(List<SequenceFeature> list, long pos)
-  {
-    return BinarySearcher.findFirst(list, (int) pos,
-            BinarySearcher.fbegin);
-  }
-
-  @Override
-  protected int findFirstEnd(List<SequenceFeature> list, long pos)
-  {
-    return BinarySearcher.findFirst(list, (int) pos, BinarySearcher.fend);
-  }
-
-  @Override
-  protected boolean findAndRemoveNonContactFeature(SequenceFeature sf)
-  {
-    return features.remove(sf);
-  }
-
-}
diff --git a/src/jalview/datamodel/features/FeatureStoreJS.java b/src/jalview/datamodel/features/FeatureStoreJS.java
deleted file mode 100644 (file)
index 05adeb1..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview is distributed in the hope that it will be useful, but 
- * WITHOUT ANY WARRANTY; without even the implied warranty 
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
- * PURPOSE.  See the GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.datamodel.features;
-
-import jalview.datamodel.SequenceFeature;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * An adaption of FeatureStore that is efficient and lightweight, accelerating
- * processing speed in JavaScript.
- * 
- * It could be used in Java as well, with significant acceleration, but all this
- * is so fast anyway that it probably will not be noticed in Java to speed it up
- * by a factor of two or three. So for now, at least, this implementation is
- * just in JavaScript. The flag for this is in SequenceFeatures.
- * 
- * This implementation uses the IntervalStore developed by Bob Hanson, found at
- * https://github.com/BobHanson/IntervalStoreJ, forked from the one developed by
- * Mungo Carstairs at https://github.com/bartongroup/IntervalStoreJ.
- * 
- * See the discussion folder at https://github.com/BobHanson/IntervalStoreJ for
- * details.
- * 
- * @author gmcarstairs
- * @author Bob Hanson 2019.08.03-2019.08.16
- *
- */
-public class FeatureStoreJS extends FeatureStore
-{
-
-  
-  public FeatureStoreJS()
-  {
-    super();
-  }
-
-  public FeatureStoreJS(int option)
-  {
-    super(option);
-  }
-
-  /**
-   * Add a contact feature to the lists that hold them ordered by start (first
-   * contact) and by end (second contact) position, ensuring the lists remain
-   * ordered. This method allows duplicate features to be added, so test before
-   * calling to avoid this.
-   * 
-   * @param feature
-   * @return true
-   */
-  @Override
-  protected synchronized boolean addContactFeature(SequenceFeature feature)
-  {
-    if (contactFeatureStarts == null)
-    {
-      contactFeatureStarts = new ArrayList<>();
-      contactFeatureEnds = new ArrayList<>();
-    }
-    contactFeatureStarts.add(
-            findFirstBegin(contactFeatureStarts, feature.begin), feature);
-    contactFeatureEnds.add(findFirstEnd(contactFeatureEnds, feature.end),
-            feature);
-    return true;
-  }
-
-  /**
-   * Add a feature to the IntervalStore, not allowing for duplicates.
-   *
-   *
-   * @return false if could not add it (late check for duplicate)
-   */
-  @Override
-  protected synchronized boolean addPositionalFeature(
-          SequenceFeature feature)
-  {
-    return features.add(feature, false);
-  }
-
-  /**
-   * Initial check in FeatureStore.add(feature) that in other implementations
-   * does a containment check, but in this implementation just returns false to
-   * indicate that we should continue. This implementation will do this check as
-   * part of the add() method for greater efficiency (one binary search instead
-   * of two).
-   * 
-   * @return false -- meaning "maybe not contained; continue adding"
-   */
-  @Override
-  protected boolean checkContainsPositionalFeatureForAdd(
-          SequenceFeature feature)
-  {
-    return false;
-  }
-
-  /**
-   * Check to see if a feature (or its equivalent based on
-   * IntervalI.equalsInterval) is already in this store. This method should be
-   * avoided except when necessary, as it involves a binary search with identity
-   * check.
-   * 
-   * @return true if this feature or its equivalent (based on equalsInterval) is
-   *         present already in the collection.
-   */
-  @Override
-  protected boolean containsFeature(SequenceFeature feature)
-  {
-    return features.contains(feature);
-  }
-
-  @Override
-  protected boolean findAndRemoveNonContactFeature(SequenceFeature sf)
-  {
-    return features.remove(sf);
-  }
-
-  /**
-   * Add contact features to the result list where either the second or the
-   * first contact position lies within the target range, inclusively.
-   * 
-   * @param from
-   * @param to
-   * @param result
-   */
-  @Override
-  protected void findContactFeatures(long from, long to,
-          List<SequenceFeature> result)
-  {
-    getContactStartOverlaps(from, to, result);
-    getContactEndOverlaps(from, to, result);
-  }
-
-  /**
-   * Locate the first feature start in a standard ArrayList that is at or after
-   * this position.
-   * 
-   */
-
-  @Override
-  protected int findFirstBegin(List<SequenceFeature> list, long pos)
-  {
-    int matched = list.size();
-    int end = matched - 1;
-    int start = (end < 0 || list.get(end).begin < pos ? matched : 0);
-    while (start <= end)
-    {
-      int mid = (start + end) / 2;
-      if (list.get(mid).begin >= pos)
-      {
-        matched = mid;
-        end = mid - 1;
-      }
-      else
-      {
-        start = mid + 1;
-      }
-    }
-    return matched;
-  }
-
-  /**
-   * Locate the feature end in a standard ArrayList that is after or at this
-   * position.
-   * 
-   */
-
-  @Override
-  protected int findFirstEnd(List<SequenceFeature> list, long pos)
-  {
-    int matched = list.size();
-    int end = matched - 1;
-    int start = 0;
-    while (start <= end)
-    {
-      int mid = (start + end) / 2;
-      if (list.get(mid).end >= pos)
-      {
-        matched = mid;
-        end = mid - 1;
-      }
-      else
-      {
-        start = mid + 1;
-      }
-    }
-    return matched;
-  }
-
-  /**
-   * Returns a (possibly empty) list of features whose extent overlaps the given
-   * range. The returned list is ordered as follows:
-   * 
-   * (1) ContactFeature starts
-   * 
-   * (2) ContactFeature ends (that are not also starts)
-   * 
-   * (3) noncontact SequenceFeatures, in reverse start order
-   * 
-   * (This last reverse order is for efficiency in processing only.)
-   * 
-   * 
-   * 
-   * @param start
-   *          start position of overlap range (inclusive)
-   * @param end
-   *          end position of overlap range (inclusive)
-   * 
-   * @param result
-   *          optional result list; for highest efficiency, provide this
-   *          parameter
-   * @return result same as result parameter, or a new ArrayList if that is null
-   */
-
-  @Override
-  public List<SequenceFeature> findOverlappingFeatures(long start, long end,
-          List<SequenceFeature> result)
-  {
-    if (result == null)
-    {
-      result = new ArrayList<>();
-    }
-    if (contactFeatureStarts != null)
-    {
-      if (start == end)
-      {
-        getContactPointStarts(contactFeatureStarts, start, result);
-        getContactPointEnds(contactFeatureEnds, end, result);
-      }
-      else
-      {
-        findContactFeatures(start, end, result);
-      }
-    }
-    if (features.size() > 0)
-    {
-      features.findOverlaps(start, end, result);
-    }
-    return result;
-  }
-
-  /**
-   * Adds to the result list any contact features having end (second contact
-   * point), but not start (first contact point), in the query from-to range
-   * 
-   * @param from
-   * @param to
-   * @param result
-   */
-
-  private void getContactEndOverlaps(long from, long to,
-          List<SequenceFeature> result)
-  {
-    // find the first contact feature (if any)
-    // with end point not before the target range
-
-    for (int i = findFirstEnd(contactFeatureEnds,
-            from), n = contactFeatureEnds.size(); i < n; i++)
-    {
-      SequenceFeature sf = contactFeatureEnds.get(i);
-      if (sf.begin >= from && sf.begin <= to)
-      {
-        // this feature's first contact position lies in the search range
-        // so we don't include it in results a second time
-        continue;
-      }
-
-      if (sf.end > to)
-      {
-        // this feature (and all following) has end point after the target range
-        break;
-      }
-
-      // feature has end >= from and end <= to
-      // i.e. contact end point lies within overlap search range
-      result.add(sf);
-    }
-  }
-
-  /**
-   * Binary search for contact start or end matching a specific position. This
-   * efficient search was designed specifically for rapid return for the
-   * OverviewPanel. It's implementation sped processing of that panel by 2300%.
-   * 
-   * @param l
-   * @param pos
-   * @param result
-   * @param isStart
-   * 
-   * @author Bob Hanson 2019.07.30
-   */
-  private void getContactPointStarts(List<SequenceFeature> l, long pos,
-          List<SequenceFeature> result)
-  {
-    int low = 0;
-    int high = l.size() - 1;
-    while (low <= high)
-    {
-      int mid = (low + high) >>> 1;
-      SequenceFeature f = l.get(mid);
-      switch (Long.signum(f.begin - pos))
-      {
-      case -1:
-        low = mid + 1;
-        continue;
-      case 1:
-        high = mid - 1;
-        continue;
-      case 0:
-        int m = mid;
-        result.add(f);
-        // could be "5" in 12345556788 ?
-        while (++mid <= high && (f = l.get(mid)) != null && f.begin == pos)
-        {
-          result.add(f);
-        }
-        while (--m >= low && (f = l.get(m)) != null && f.begin == pos)
-        {
-          result.add(f);
-        }
-        return;
-      }
-    }
-  }
-
-  private void getContactPointEnds(List<SequenceFeature> l, long pos,
-          List<SequenceFeature> result)
-  {
-    int low = 0;
-    int high = l.size() - 1;
-    while (low <= high)
-    {
-      int mid = (low + high) >>> 1;
-      SequenceFeature f = l.get(mid);
-      switch (Long.signum(f.end - pos))
-      {
-      case -1:
-        low = mid + 1;
-        continue;
-      case 1:
-        high = mid - 1;
-        continue;
-      case 0:
-        int m = mid;
-        if (f.begin != f.end)
-        {
-          result.add(f);
-        }
-        // could be "5" in 12345556788 ?
-        while (++mid <= high && (f = l.get(mid)) != null
-                && f.end == pos)
-        {
-          if (f.begin != f.end)
-          {
-            result.add(f);
-          }
-        }
-        while (--m >= low && (f = l.get(m)) != null
-                && f.end == pos)
-        {
-          if (f.begin != f.end)
-          {
-            result.add(f);
-          }
-        }
-        return;
-      }
-    }
-  }
-
-  /**
-   * Adds contact features whose start position lies in the from-to range to the
-   * result list
-   * 
-   * @param from
-   * @param to
-   * @param result
-   */
-
-  private void getContactStartOverlaps(long from, long to,
-          List<SequenceFeature> result)
-  {
-    for (int i = findFirstBegin(contactFeatureStarts,
-            from), n = contactFeatureStarts.size(); i < n; i++)
-    {
-      SequenceFeature sf = contactFeatureStarts.get(i);
-      if (sf.begin > to)
-      {
-        break;
-      }
-      result.add(sf);
-    }
-  }
-}
index 6c83013..e747d5f 100644 (file)
@@ -23,10 +23,10 @@ package jalview.datamodel.features;
 import jalview.datamodel.SequenceFeature;
 import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyI;
-import jalview.util.Platform;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -46,12 +46,11 @@ import intervalstore.api.IntervalI;
  */
 public class SequenceFeatures implements SequenceFeaturesI
 {
-
   /*
    * map from feature type to structured store of features for that type
    * null types are permitted (but not a good idea!)
    */
-  private Map<String, FeatureStoreI> featureStore;
+  private Map<String, FeatureStore> featureStore;
 
   /**
    * Constructor
@@ -63,7 +62,7 @@ public class SequenceFeatures implements SequenceFeaturesI
      * ? wrap as a synchronized map for add and delete operations
      */
     // featureStore = Collections
-    // .synchronizedSortedMap(new TreeMap<String, FeatureStoreI>());
+    // .synchronizedSortedMap(new TreeMap<String, FeatureStore>());
     featureStore = new TreeMap<>();
   }
 
@@ -97,19 +96,11 @@ public class SequenceFeatures implements SequenceFeaturesI
 
     if (featureStore.get(type) == null)
     {
-      featureStore.put(type, newFeatureStore());
+      featureStore.put(type, new FeatureStore());
     }
     return featureStore.get(type).addFeature(sf);
   }
 
-  private FeatureStoreI newFeatureStore()
-  {
-    return (//
-    Platform.isJS()//
-            ? new FeatureStoreJS()
-            : new FeatureStoreImpl());
-  }
-
   /**
    * {@inheritDoc}
    */
@@ -118,13 +109,9 @@ public class SequenceFeatures implements SequenceFeaturesI
           String... type)
   {
     List<SequenceFeature> result = new ArrayList<>();
-    for (FeatureStoreI featureSet : varargToTypes(type))
+    for (FeatureStore featureSet : varargToTypes(type))
     {
-      // System.err.println("SF findFeature " + System.currentTimeMillis()
-      // + " " + from + " " + to + " "
-      // + featureSet.getPositionalFeatures().get(0).type);
-      //
-      result.addAll(featureSet.findOverlappingFeatures(from, to, null));
+      featureSet.findOverlappingFeatures(from, to, result);
     }
     return result;
   }
@@ -176,7 +163,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   {
     int result = 0;
 
-    for (FeatureStoreI featureSet : varargToTypes(type))
+    for (FeatureStore featureSet : varargToTypes(type))
     {
       result += featureSet.getFeatureCount(positional);
     }
@@ -191,7 +178,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   {
     int result = 0;
 
-    for (FeatureStoreI featureSet : varargToTypes(type))
+    for (FeatureStore featureSet : varargToTypes(type))
     {
       result += featureSet.getTotalFeatureLength();
     }
@@ -206,7 +193,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   {
     List<SequenceFeature> result = new ArrayList<>();
 
-    for (FeatureStoreI featureSet : varargToTypes(type))
+    for (FeatureStore featureSet : varargToTypes(type))
     {
       featureSet.getPositionalFeatures(result);
     }
@@ -220,7 +207,7 @@ public class SequenceFeatures implements SequenceFeaturesI
    * @param type
    * @return
    */
-  protected Iterable<FeatureStoreI> varargToTypes(String... type)
+  protected Iterable<FeatureStore> varargToTypes(String... type)
   {
     if (type == null || type.length == 0)
     {
@@ -230,9 +217,9 @@ public class SequenceFeatures implements SequenceFeaturesI
       return featureStore.values();
     }
 
-    List<FeatureStoreI> types = new ArrayList<>();
+    List<FeatureStore> types = new ArrayList<>();
     List<String> args = Arrays.asList(type);
-    for (Entry<String, FeatureStoreI> featureType : featureStore.entrySet())
+    for (Entry<String, FeatureStore> featureType : featureStore.entrySet())
     {
       if (args.contains(featureType.getKey()))
       {
@@ -250,7 +237,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   {
     List<SequenceFeature> result = new ArrayList<>();
 
-    for (FeatureStoreI featureSet : varargToTypes(type))
+    for (FeatureStore featureSet : varargToTypes(type))
     {
       featureSet.getContactFeatures(result);
     }
@@ -265,7 +252,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   {
     List<SequenceFeature> result = new ArrayList<>();
 
-    for (FeatureStoreI featureSet : varargToTypes(type))
+    for (FeatureStore featureSet : varargToTypes(type))
     {
       featureSet.getNonPositionalFeatures(result);
     }
@@ -278,7 +265,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   @Override
   public boolean delete(SequenceFeature sf)
   {
-    for (FeatureStoreI featureSet : featureStore.values())
+    for (FeatureStore featureSet : featureStore.values())
     {
       if (featureSet.delete(sf))
       {
@@ -294,7 +281,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   @Override
   public boolean hasFeatures()
   {
-    for (FeatureStoreI featureSet : featureStore.values())
+    for (FeatureStore featureSet : featureStore.values())
     {
       if (!featureSet.isEmpty())
       {
@@ -313,7 +300,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   {
     Set<String> groups = new HashSet<>();
 
-    for (FeatureStoreI featureSet : varargToTypes(type))
+    for (FeatureStore featureSet : varargToTypes(type))
     {
       groups.addAll(featureSet.getFeatureGroups(positionalFeatures));
     }
@@ -330,7 +317,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   {
     Set<String> result = new HashSet<>();
 
-    for (Entry<String, FeatureStoreI> featureType : featureStore.entrySet())
+    for (Entry<String, FeatureStore> featureType : featureStore.entrySet())
     {
       Set<String> featureGroups = featureType.getValue()
               .getFeatureGroups(positionalFeatures);
@@ -357,7 +344,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   public Set<String> getFeatureTypes(String... soTerm)
   {
     Set<String> types = new HashSet<>();
-    for (Entry<String, FeatureStoreI> entry : featureStore.entrySet())
+    for (Entry<String, FeatureStore> entry : featureStore.entrySet())
     {
       String type = entry.getKey();
       if (!entry.getValue().isEmpty() && isOntologyTerm(type, soTerm))
@@ -427,7 +414,9 @@ public class SequenceFeatures implements SequenceFeaturesI
   public static void sortFeatures(List<? extends IntervalI> features,
           final boolean forwardStrand)
   {
-    IntervalI.sortIntervals(features, forwardStrand);
+    Collections.sort(features,
+            forwardStrand ? IntervalI.COMPARE_BEGIN_ASC
+                    : IntervalI.COMPARE_END_DESC);
   }
 
   /**
@@ -446,7 +435,7 @@ public class SequenceFeatures implements SequenceFeaturesI
           String group, String... type)
   {
     List<SequenceFeature> result = new ArrayList<>();
-    for (FeatureStoreI featureSet : varargToTypes(type))
+    for (FeatureStore featureSet : varargToTypes(type))
     {
       if (featureSet.getFeatureGroups(positional).contains(group))
       {
@@ -463,7 +452,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   public boolean shiftFeatures(int fromPosition, int shiftBy)
   {
     boolean modified = false;
-    for (FeatureStoreI fs : featureStore.values())
+    for (FeatureStore fs : featureStore.values())
     {
       modified |= fs.shiftFeatures(fromPosition, shiftBy);
     }
@@ -479,58 +468,14 @@ public class SequenceFeatures implements SequenceFeaturesI
     featureStore.clear();
   }
 
-  /**
-   * Simplified find for features associated with a given position.
-   * 
-   * JavaScript set to not use IntervalI, but easily testable by setting false
-   * to true in javadoc
-   * 
-   * FeatureRenderer has checked already that featureStore does contain type.
-   * 
-   * @author Bob Hanson 2019.07.30
-   */
   @Override
   public List<SequenceFeature> findFeatures(int pos, String type,
           List<SequenceFeature> list)
   {
-    FeatureStoreI fs = featureStore.get(type);
+    FeatureStore fs = featureStore.get(type);
     return fs.findOverlappingFeatures(pos, pos, list);
   }
 
-  // Chrome; developer console closed
-
-  // BH 2019.08.01 useIntervalStore true, redraw false:
-  // Platform: timer mark 13.848 0.367 overviewrender 16000 pixels row:14
-  // Platform: timer mark 15.391 0.39 overviewrender 16000 pixels row:14
-  // Platform: timer mark 16.498 0.39 overviewrender 16000 pixels row:14
-  // Platform: timer mark 17.596 0.401 overviewrender 16000 pixels row:14
-  // Platform: timer mark 18.738 0.363 overviewrender 16000 pixels row:14
-  // Platform: timer mark 19.659 0.358 overviewrender 16000 pixels row:14
-  // Platform: timer mark 20.737 0.359 overviewrender 16000 pixels row:14
-  // Platform: timer mark 21.797 0.391 overviewrender 16000 pixels row:14
-  // Platform: timer mark 22.851 0.361 overviewrender 16000 pixels row:14
-  // Platform: timer mark 24.019 0.395 overviewrender 16000 pixels row:14
-
-  // BH 2019.08.01 useIntervalStore false, redraw false:
-  // Platform: timer mark 19.011 0.181 overviewrender 16000 pixels row:14
-  // Platform: timer mark 20.311 0.183 overviewrender 16000 pixels row:14
-  // Platform: timer mark 21.368 0.175 overviewrender 16000 pixels row:14
-  // Platform: timer mark 22.347 0.178 overviewrender 16000 pixels row:14
-  // Platform: timer mark 23.605 0.216 overviewrender 16000 pixels row:14
-  // Platform: timer mark 24.836 0.191 overviewrender 16000 pixels row:14
-  // Platform: timer mark 26.016 0.181 overviewrender 16000 pixels row:14
-  // Platform: timer mark 27.278 0.178 overviewrender 16000 pixels row:14
-  // Platform: timer mark 28.158 0.181 overviewrender 16000 pixels row:14
-  // Platform: timer mark 29.227 0.196 overviewrender 16000 pixels row:14
-  // Platform: timer mark 30.1 0.171 overviewrender 16000 pixels row:14
-  // Platform: timer mark 31.684 0.196 overviewrender 16000 pixels row:14
-  // Platform: timer mark 32.779 0.18 overviewrender 16000 pixels row:14
-  // Platform: timer mark 52.355 0.185 overviewrender 16000 pixels row:14
-  // Platform: timer mark 53.829 0.186 overviewrender 16000 pixels row:14
-
-  /**
-   * @author Bob Hanson 2019.08.01
-   */
   @Override
   public boolean hasFeatures(String type)
   {
index deed751..fe5e927 100644 (file)
@@ -230,21 +230,20 @@ public interface SequenceFeaturesI
   void deleteAll();
 
   /**
-   * Point-specific parameter return for JavaScript
+   * Answers a (possibly empty) list of features of the specified type that
+   * overlap the specified column position. If parameter {@code result} is not
+   * null, features are appended to it and the (possibly extended) list is
+   * returned.
    * 
    * @param pos
    * @param type
    * @param result
-   * @return result (JavaScript) or new ArrayList (Java -- see FeatureRender)
-   * @author Bob Hanson 2019.07.30
+   * @return
    */
   List<SequenceFeature> findFeatures(int pos, String type, List<SequenceFeature> result);
 
   /**
-   * @author Bob Hanson 2019.08.01
-   * 
-   * @param type
-   * @return true if this type is in featureStore
+   * Answers true if there are any features of the given type, else false
    */
   boolean hasFeatures(String type);
 }
index 2dd6ebb..e4c4365 100644 (file)
@@ -27,9 +27,7 @@ import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.io.gff.SequenceOntologyI;
 import jalview.util.JSONUtils;
-import jalview.util.Platform;
 
-import java.io.BufferedReader;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -95,10 +93,7 @@ class EnsemblFeatures extends EnsemblRestClient
     List<String> queries = new ArrayList<>();
     queries.add(query);
     SequenceI seq = parseFeaturesJson(queries);
-    if (seq == null)
-       return null;
     return new Alignment(new SequenceI[] { seq });
-
   }
 
   /**
index c3350a5..873fdac 100644 (file)
@@ -254,7 +254,7 @@ public class OverviewRenderer
     WritableRaster raster = miniMe.getRaster();
     DataBufferInt db = (DataBufferInt) raster.getDataBuffer();
     pixels = db.getBankData()[0];
-    bscol = cols.getOverviewBitSet();
+    bscol = cols.getShownBitSet();
     if (skippingColumns)
     {
       columnsToShow = calcColumnsToShow();
index a98f3b3..e0d6696 100644 (file)
@@ -29,6 +29,13 @@ import java.awt.Color;
 
 public class OverviewResColourFinder extends ResidueColourFinder
 {
+  public static final Color OVERVIEW_DEFAULT_GAP = Color.lightGray;
+
+  public static final Color OVERVIEW_DEFAULT_LEGACY_GAP = Color.white;
+
+  public static final Color OVERVIEW_DEFAULT_HIDDEN = Color.darkGray
+          .darker();
+
   final int GAP_COLOUR; // default colour to use at gaps
 
   final int RESIDUE_COLOUR; // default colour to use at residues
@@ -37,13 +44,6 @@ public class OverviewResColourFinder extends ResidueColourFinder
 
   boolean useLegacy = false;
 
-  public static final Color OVERVIEW_DEFAULT_GAP = Color.lightGray;
-
-  public static final Color OVERVIEW_DEFAULT_LEGACY_GAP = Color.white;
-
-  public static final Color OVERVIEW_DEFAULT_HIDDEN = Color.darkGray
-          .darker();
-
   /**
    * Constructor without colour settings (used by applet)
    */
@@ -130,9 +130,9 @@ public class OverviewResColourFinder extends ResidueColourFinder
 
     // if there's a FeatureColourFinder we might override the residue colour
     // here with feature colouring
-    return seq.setColor(i,
-            finder == null || finder.noFeaturesDisplayed() ? col
-                    : finder.findFeatureColourInt(col, seq, i));
+    col = finder == null || finder.noFeaturesDisplayed() ? col
+            : finder.findFeatureColourInt(col, seq, i);
+    return seq.setColor(i, col);
   }
 
   /**
index 8da880a..a2ce35b 100644 (file)
@@ -120,11 +120,6 @@ public class FeatureColourFinder
   public int findFeatureColourInt(int defaultColour, SequenceI seq,
           int column)
   {
-    // if (noFeaturesDisplayed())
-    // {
-    // return defaultColour;
-    // }
-
     Graphics g = null;
 
     /*
index 9988076..c1bccb8 100644 (file)
@@ -42,6 +42,13 @@ public class FeatureRenderer extends FeatureRendererModel
   private static final AlphaComposite NO_TRANSPARENCY = AlphaComposite
           .getInstance(AlphaComposite.SRC_OVER, 1.0f);
 
+  /*
+   * persistent list used by JalviewJS; not threadsafe for Java
+   */
+  private List<SequenceFeature> overlaps = (Platform.isJS()
+          ? new ArrayList<>()
+          : null);
+
   /**
    * Constructor given a viewport
    * 
@@ -223,13 +230,6 @@ public class FeatureRenderer extends FeatureRendererModel
   @Override
   public Color findFeatureColour(SequenceI seq, int column, Graphics g)
   {
-    // BH 2019.08.01
-    // this is already checked in FeatureColorFinder
-    // if (!av.isShowSequenceFeatures())
-    // {
-    // return null;
-    // }
-
     // column is 'base 1' but getCharAt is an array index (ie from 0)
     if (Comparison.isGap(seq.getCharAt(column - 1)))
     {
@@ -266,8 +266,7 @@ public class FeatureRenderer extends FeatureRendererModel
    * applies), or null if no feature is drawn in the range given.
    * 
    * @param g
-   *          the graphics context to draw on (may be null only if t == 1 from
-   *          colourOnly==true)
+   *          the graphics context to draw on (null if no transparency applies)
    * @param seq
    * @param start
    *          start column
@@ -284,7 +283,6 @@ public class FeatureRenderer extends FeatureRendererModel
           final SequenceI seq, int start, int end, int y1,
           boolean colourOnly)
   {
-    // from SeqCanvas and OverviewRender
     /*
      * if columns are all gapped, or sequence has no features, nothing to do
      */
@@ -300,8 +298,7 @@ public class FeatureRenderer extends FeatureRendererModel
 
     updateFeatures();
 
-    if (transparency != 1f) // g cannot be null here if trans == 1f - BH // && g
-                            // != null)
+    if (transparency != 1f)
     {
       ((Graphics2D) g).setComposite(
               AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
@@ -439,10 +436,6 @@ public class FeatureRenderer extends FeatureRendererModel
     findAllFeatures();
   }
 
-  private List<SequenceFeature> overlaps = (Platform.isJS()
-          ? new ArrayList<>()
-          : null);
-
   /**
    * Returns the sequence feature colour rendered at the given column position,
    * or null if none found. The feature of highest render order (i.e. on top) is
@@ -454,12 +447,6 @@ public class FeatureRenderer extends FeatureRendererModel
    * colour for features enclosing a gapped column. Check for gap before calling
    * if different behaviour is wanted.
    * 
-   * BH 2019.07.30
-   * 
-   * Adds a result ArrayList to parameters in order to avoid an unnecessary
-   * construction of that for every pixel checked.
-   * 
-   * 
    * @param seq
    * @param column
    *          (1..)
@@ -484,6 +471,10 @@ public class FeatureRenderer extends FeatureRendererModel
         continue;
       }
 
+      /*
+       * field overlaps is used by JalviewJS to avoid object creation;
+       * not thread-safe for Java (Javascript is single-threaded)
+       */
       if (overlaps != null)
       {
         overlaps.clear();
diff --git a/test/intervalstore/nonc/IntervalStoreTest.java b/test/intervalstore/nonc/IntervalStoreTest.java
new file mode 100644 (file)
index 0000000..7b96e39
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+BSD 3-Clause License
+
+Copyright (c) 2018, Mungo Carstairs
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package intervalstore.nonc;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class IntervalStoreTest
+{
+  @Test(groups = "Functional")
+  public void testFindOverlaps_nonNested()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    SimpleFeature sf1 = add(store, 10, 20);
+    // same range different description
+    SimpleFeature sf2 = new SimpleFeature(10, 20, "desc");
+    store.add(sf2);
+    SimpleFeature sf3 = add(store, 15, 25);
+    SimpleFeature sf4 = add(store, 20, 35);
+
+    assertEquals(store.size(), 4);
+    List<SimpleFeature> overlaps = store.findOverlaps(1, 9);
+    assertTrue(overlaps.isEmpty());
+
+    overlaps = store.findOverlaps(8, 10);
+    assertEquals(overlaps.size(), 2);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+
+    overlaps = store.findOverlaps(12, 16);
+    assertEquals(overlaps.size(), 3);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+    assertTrue(overlaps.contains(sf3));
+
+    overlaps = store.findOverlaps(33, 33);
+    assertEquals(overlaps.size(), 1);
+    assertTrue(overlaps.contains(sf4));
+
+    /*
+     * ensure edge cases are covered
+     */
+    overlaps = store.findOverlaps(35, 40);
+    assertEquals(overlaps.size(), 1);
+    assertTrue(overlaps.contains(sf4));
+    assertTrue(store.findOverlaps(36, 100).isEmpty());
+    assertTrue(store.findOverlaps(1, 9).isEmpty());
+  }
+
+  @Test(groups = "Functional")
+  public void testFindOverlaps_nested()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    SimpleFeature sf1 = add(store, 10, 50);
+    SimpleFeature sf2 = add(store, 10, 40);
+    SimpleFeature sf3 = add(store, 20, 30);
+    // feature at same location but different description
+    SimpleFeature sf4 = new SimpleFeature(20, 30, "different desc");
+    store.add(sf4);
+    SimpleFeature sf5 = add(store, 35, 36);
+
+    List<SimpleFeature> overlaps = store.findOverlaps(1, 9);
+    assertTrue(overlaps.isEmpty());
+
+    overlaps = store.findOverlaps(10, 15);
+    assertEquals(overlaps.size(), 2);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+
+    overlaps = store.findOverlaps(45, 60);
+    assertEquals(overlaps.size(), 1);
+    assertTrue(overlaps.contains(sf1));
+
+    overlaps = store.findOverlaps(32, 38);
+    assertEquals(overlaps.size(), 3);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+    assertTrue(overlaps.contains(sf5));
+
+    overlaps = store.findOverlaps(15, 25);
+    assertEquals(overlaps.size(), 4);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+    assertTrue(overlaps.contains(sf3));
+    assertTrue(overlaps.contains(sf4));
+  }
+
+  @Test(groups = "Functional")
+  public void testFindOverlaps_mixed()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    SimpleFeature sf1 = add(store, 10, 50);
+    SimpleFeature sf2 = add(store, 1, 15);
+    SimpleFeature sf3 = add(store, 20, 30);
+    SimpleFeature sf4 = add(store, 40, 100);
+    SimpleFeature sf5 = add(store, 60, 100);
+    SimpleFeature sf6 = add(store, 70, 70);
+
+    List<SimpleFeature> overlaps = store.findOverlaps(200, 200);
+    assertTrue(overlaps.isEmpty());
+
+    overlaps = store.findOverlaps(1, 9);
+    assertEquals(overlaps.size(), 1);
+    assertTrue(overlaps.contains(sf2));
+
+    overlaps = store.findOverlaps(5, 18);
+    assertEquals(overlaps.size(), 2);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+
+    overlaps = store.findOverlaps(30, 40);
+    assertEquals(overlaps.size(), 3);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf3));
+    assertTrue(overlaps.contains(sf4));
+
+    overlaps = store.findOverlaps(80, 90);
+    assertEquals(overlaps.size(), 2);
+    assertTrue(overlaps.contains(sf4));
+    assertTrue(overlaps.contains(sf5));
+
+    overlaps = store.findOverlaps(68, 70);
+    assertEquals(overlaps.size(), 3);
+    assertTrue(overlaps.contains(sf4));
+    assertTrue(overlaps.contains(sf5));
+    assertTrue(overlaps.contains(sf6));
+  }
+
+  /**
+   * Helper method to add a feature with type "desc"
+   * 
+   * @param store
+   * @param from
+   * @param to
+   * @return
+   */
+  SimpleFeature add(IntervalStore<SimpleFeature> store, int from,
+          int to)
+  {
+    SimpleFeature sf1 = new SimpleFeature(from, to, "desc");
+    store.add(sf1);
+    return sf1;
+  }
+
+  @Test(groups = "Functional")
+  public void testRemove()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    SimpleFeature sf1 = add(store, 10, 20);
+    assertTrue(store.contains(sf1));
+
+    try
+    {
+      store.remove("what is this?");
+    } catch (ClassCastException e)
+    {
+      // expected;
+    }
+    assertFalse(store.remove(null));
+
+    /*
+     * simple deletion
+     */
+    assertTrue(store.remove(sf1));
+    assertTrue(store.isEmpty());
+
+    SimpleFeature sf2 = add(store, 0, 0);
+    SimpleFeature sf2a = add(store, 30, 40);
+    assertTrue(store.contains(sf2));
+    assertFalse(store.remove(sf1));
+    assertTrue(store.remove(sf2));
+    assertTrue(store.remove(sf2a));
+    assertTrue(store.isEmpty());
+
+    /*
+     * nested feature deletion
+     */
+    SimpleFeature sf4 = add(store, 20, 30);
+    SimpleFeature sf5 = add(store, 22, 26); // to NCList
+    SimpleFeature sf6 = add(store, 23, 24); // child of sf5
+    SimpleFeature sf7 = add(store, 25, 25); // sibling of sf6
+    SimpleFeature sf8 = add(store, 24, 24); // child of sf6
+    SimpleFeature sf9 = add(store, 23, 23); // child of sf6
+    assertEquals(store.size(), 6);
+
+    // delete a node with children - they take its place
+    assertTrue(store.remove(sf6)); // sf8, sf9 should become children of sf5
+    assertEquals(store.size(), 5);
+    assertFalse(store.contains(sf6));
+
+    // delete a node with no children
+    assertTrue(store.remove(sf7));
+    assertEquals(store.size(), 4);
+    assertFalse(store.contains(sf7));
+
+    // delete root of NCList
+    assertTrue(store.remove(sf5));
+    assertEquals(store.size(), 3);
+    assertFalse(store.contains(sf5));
+
+    // continue the killing fields
+    assertTrue(store.remove(sf4));
+    assertEquals(store.size(), 2);
+    assertFalse(store.contains(sf4));
+
+    assertTrue(store.remove(sf9));
+    assertEquals(store.size(), 1);
+    assertFalse(store.contains(sf9));
+
+    assertTrue(store.remove(sf8));
+    assertTrue(store.isEmpty());
+  }
+
+  /**
+   * A helper method to test whether a list contains a specific object (by
+   * object identity, not equality test as used by List.contains())
+   * 
+   * @param list
+   * @param o
+   * @return
+   */
+  private static boolean containsObject(List<? extends Object> list,
+          Object o)
+  {
+    for (Object i : list)
+    {
+      if (i == o)
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Test(groups = "Functional")
+  public void testAdd()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+
+    assertFalse(store.add(null));
+
+    SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
+    SimpleFeature sf2 = new SimpleFeature(10, 20, "Cath");
+
+    assertTrue(store.add(sf1));
+    assertEquals(store.size(), 1);
+
+    /*
+     * contains should return true for the same or an identical feature
+     */
+    assertTrue(store.contains(sf1));
+    assertTrue(store.contains(sf2));
+
+    /*
+     * duplicates are accepted
+     */
+    assertTrue(store.add(sf2));
+    assertEquals(store.size(), 2);
+
+    SimpleFeature sf3 = new SimpleFeature(0, 0, "Cath");
+    assertTrue(store.add(sf3));
+    assertEquals(store.size(), 3);
+  }
+
+  @Test(groups = "Functional")
+  public void testAdd_noDuplicates()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+
+    SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
+    SimpleFeature sf2 = new SimpleFeature(10, 20, "Cath");
+    assertTrue(sf1.equals(sf2));
+    assertTrue(store.add(sf1));
+    assertEquals(store.size(), 1);
+    assertFalse(store.add(sf2, false));
+    assertEquals(store.size(), 1);
+    assertTrue(store.contains(sf1));
+    assertTrue(store.contains(sf2)); // because sf1.equals(sf2) !
+  }
+
+  @Test(groups = "Functional")
+  public void testIsEmpty()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    assertTrue(store.isEmpty());
+    assertEquals(store.size(), 0);
+
+    /*
+     * non-nested feature
+     */
+    SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
+    store.add(sf1);
+    assertFalse(store.isEmpty());
+    assertEquals(store.size(), 1);
+    store.remove(sf1);
+    assertTrue(store.isEmpty());
+    assertEquals(store.size(), 0);
+
+    sf1 = new SimpleFeature(0, 0, "Cath");
+    store.add(sf1);
+    assertFalse(store.isEmpty());
+    assertEquals(store.size(), 1);
+    store.remove(sf1);
+    assertTrue(store.isEmpty());
+    assertEquals(store.size(), 0);
+
+    /*
+     * sf2, sf3 added as nested features
+     */
+    sf1 = new SimpleFeature(19, 49, "Cath");
+    SimpleFeature sf2 = new SimpleFeature(20, 40, "Cath");
+    SimpleFeature sf3 = new SimpleFeature(25, 35, "Cath");
+    store.add(sf1);
+    assertEquals(store.size(), 1);
+    store.add(sf2);
+    assertEquals(store.size(), 2);
+    store.add(sf3);
+    assertEquals(store.size(), 3);
+    assertTrue(store.remove(sf1));
+    assertEquals(store.size(), 2);
+
+    assertFalse(store.isEmpty());
+    assertTrue(store.remove(sf2));
+    assertEquals(store.size(), 1);
+    assertFalse(store.isEmpty());
+    assertTrue(store.remove(sf3));
+    assertEquals(store.size(), 0);
+    assertTrue(store.isEmpty()); // all gone
+  }
+
+  @Test(groups = "Functional")
+  public void testRemove_readd()
+  {
+    /*
+     * add a feature and a nested feature
+     */
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    SimpleFeature sf1 = add(store, 10, 20);
+    // sf2 is nested in sf1 so will be stored in nestedFeatures
+    SimpleFeature sf2 = add(store, 12, 14);
+    assertEquals(store.size(), 2);
+    assertTrue(store.contains(sf1));
+    assertTrue(store.contains(sf2));
+
+    /*
+     * delete the first feature
+     */
+    assertTrue(store.remove(sf1));
+    assertFalse(store.contains(sf1));
+    assertTrue(store.contains(sf2));
+
+    /*
+     * re-add the 'nested' feature; it is now duplicated
+     */
+    store.add(sf2);
+    assertEquals(store.size(), 2);
+    assertTrue(store.contains(sf2));
+  }
+
+  @Test(groups = "Functional")
+  public void testContains()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    SimpleFeature sf1 = new SimpleFeature(10, 20, "Cath");
+    SimpleFeature sf2 = new SimpleFeature(10, 20, "Pfam");
+
+    store.add(sf1);
+    assertTrue(store.contains(sf1));
+    assertTrue(store.contains(new SimpleFeature(sf1))); // identical feature
+    assertFalse(store.contains(sf2)); // different description
+
+    /*
+     * add a nested feature
+     */
+    SimpleFeature sf3 = new SimpleFeature(12, 16, "Cath");
+    store.add(sf3);
+    assertTrue(store.contains(sf3));
+    assertTrue(store.contains(new SimpleFeature(sf3)));
+
+    /*
+     * delete the outer (enclosing, non-nested) feature
+     */
+    store.remove(sf1);
+    assertFalse(store.contains(sf1));
+    assertTrue(store.contains(sf3));
+
+    assertFalse(store.contains(null));
+    try
+    {
+      assertFalse(store.contains("junk"));
+    } catch (ClassCastException e)
+    {
+      // expected;
+    }
+  }
+
+  @Test(groups = "Functional")
+  public void testFindOverlaps_resultsArg_mixed()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    SimpleFeature sf1 = add(store, 10, 50);
+    SimpleFeature sf2 = add(store, 1, 15);
+    SimpleFeature sf3 = add(store, 20, 30);
+    SimpleFeature sf4 = add(store, 40, 100);
+    SimpleFeature sf5 = add(store, 60, 100);
+    SimpleFeature sf6 = add(store, 70, 70);
+  
+    List<SimpleFeature> overlaps = new ArrayList<>();
+    List<SimpleFeature> overlaps2 = store.findOverlaps(200, 200, overlaps);
+    assertSame(overlaps, overlaps2);
+    assertTrue(overlaps.isEmpty());
+  
+    overlaps.clear();
+    store.findOverlaps(1, 9, overlaps);
+    assertEquals(overlaps.size(), 1);
+    assertTrue(overlaps.contains(sf2));
+  
+    overlaps.clear();
+    store.findOverlaps(5, 18, overlaps);
+    assertEquals(overlaps.size(), 2);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+  
+    overlaps.clear();
+    store.findOverlaps(30, 40, overlaps);
+    assertEquals(overlaps.size(), 3);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf3));
+    assertTrue(overlaps.contains(sf4));
+  
+    overlaps.clear();
+    store.findOverlaps(80, 90, overlaps);
+    assertEquals(overlaps.size(), 2);
+    assertTrue(overlaps.contains(sf4));
+    assertTrue(overlaps.contains(sf5));
+  
+    overlaps.clear();
+    store.findOverlaps(68, 70, overlaps);
+    assertEquals(overlaps.size(), 3);
+    assertTrue(overlaps.contains(sf4));
+    assertTrue(overlaps.contains(sf5));
+    assertTrue(overlaps.contains(sf6));
+
+    /*
+     * and without clearing the list first
+     * note that sf4 is included twice, as an
+     * overlap of 68-70 and also of 30-40
+     */
+    store.findOverlaps(30, 40, overlaps);
+    assertEquals(overlaps.size(), 6);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf3));
+    assertTrue(overlaps.contains(sf4));
+    assertTrue(overlaps.contains(sf5));
+    assertTrue(overlaps.contains(sf6));
+    assertSame(sf4, overlaps.get(0));
+    assertSame(sf4, overlaps.get(4));
+  }
+
+  @Test(groups = "Functional")
+  public void testFindOverlaps_resultsArg_nested()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    SimpleFeature sf1 = add(store, 10, 50);
+    SimpleFeature sf2 = add(store, 10, 40);
+    SimpleFeature sf3 = add(store, 20, 30);
+    // feature at same location but different description
+    SimpleFeature sf4 = new SimpleFeature(20, 30, "different desc");
+    store.add(sf4);
+    SimpleFeature sf5 = add(store, 35, 36);
+  
+    List<SimpleFeature> overlaps = new ArrayList<>();
+    store.findOverlaps(1, 9, overlaps);
+    assertTrue(overlaps.isEmpty());
+  
+    store.findOverlaps(10, 15, overlaps);
+    assertEquals(overlaps.size(), 2);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+  
+    overlaps.clear();
+    store.findOverlaps(45, 60, overlaps);
+    assertEquals(overlaps.size(), 1);
+    assertTrue(overlaps.contains(sf1));
+  
+    overlaps.clear();
+    store.findOverlaps(32, 38, overlaps);
+    assertEquals(overlaps.size(), 3);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+    assertTrue(overlaps.contains(sf5));
+  
+    overlaps.clear();
+    store.findOverlaps(15, 25, overlaps);
+    assertEquals(overlaps.size(), 4);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+    assertTrue(overlaps.contains(sf3));
+    assertTrue(overlaps.contains(sf4));
+  }
+
+  @Test(groups = "Functional")
+  public void testFindOverlaps_resultsArg_nonNested()
+  {
+    IntervalStore<SimpleFeature> store = new IntervalStore<>();
+    SimpleFeature sf1 = add(store, 10, 20);
+    // same range different description
+    SimpleFeature sf2 = new SimpleFeature(10, 20, "desc");
+    store.add(sf2);
+    SimpleFeature sf3 = add(store, 15, 25);
+    SimpleFeature sf4 = add(store, 20, 35);
+  
+    assertEquals(store.size(), 4);
+    List<SimpleFeature> overlaps = new ArrayList<>();
+    store.findOverlaps(1, 9, overlaps);
+    assertTrue(overlaps.isEmpty());
+  
+    store.findOverlaps(8, 10, overlaps);
+    assertEquals(overlaps.size(), 2);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+  
+    overlaps.clear();
+    store.findOverlaps(12, 16, overlaps);
+    assertEquals(overlaps.size(), 3);
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
+    assertTrue(overlaps.contains(sf3));
+  
+    overlaps.clear();
+    store.findOverlaps(33, 33, overlaps);
+    assertEquals(overlaps.size(), 1);
+    assertTrue(overlaps.contains(sf4));
+  
+    /*
+     * ensure edge cases are covered
+     */
+    overlaps.clear();
+    store.findOverlaps(35, 40, overlaps);
+    assertEquals(overlaps.size(), 1);
+    assertTrue(overlaps.contains(sf4));
+
+    overlaps.clear();
+    assertTrue(store.findOverlaps(36, 100, overlaps).isEmpty());
+    assertTrue(store.findOverlaps(1, 9, overlaps).isEmpty());
+  }
+}
similarity index 74%
rename from src/intervalstore/impl/SimpleFeature.java
rename to test/intervalstore/nonc/SimpleFeature.java
index be1db97..d10d90a 100644 (file)
@@ -29,18 +29,20 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
-package intervalstore.impl;
+package intervalstore.nonc;
 
 import intervalstore.api.IntervalI;
 
 /**
  * A simplified feature instance sufficient for unit test purposes
  */
-public class SimpleFeature extends Range
+public class SimpleFeature implements IntervalI
 {
+  final private int begin;
 
-  private String description;
+  final private int end;
 
+  private String description;
 
   /**
    * Constructor
@@ -51,7 +53,8 @@ public class SimpleFeature extends Range
    */
   public SimpleFeature(int from, int to, String desc)
   {
-    super(from, to);
+    begin = from;
+    end = to;
     description = desc;
   }
 
@@ -62,48 +65,59 @@ public class SimpleFeature extends Range
    */
   public SimpleFeature(SimpleFeature sf1)
   {
-    this(sf1.start, sf1.end, sf1.description);
+    this(sf1.begin, sf1.end, sf1.description);
   }
 
-  public String getDescription()
+  @Override
+  public int getBegin()
   {
-    return description;
+    return begin;
   }
 
   @Override
-  public int hashCode()
+  public int getEnd()
   {
-    return start + 37 * end
-            + (description == null ? 0 : description.hashCode());
+    return end;
+  }
+
+  public String getDescription()
+  {
+    return description;
   }
 
   @Override
-  public boolean equals(Object o)
+  public int hashCode()
   {
-    return (o != null && o instanceof SimpleFeature
-            && equalsInterval((SimpleFeature) o));
+    return begin + 37 * end
+            + (description == null ? 0 : description.hashCode());
   }
 
   /**
    * Equals method that requires two instances to have the same description, as
-   * well as start and end position. Does not do a test for null
+   * well as start and end position.
    */
   @Override
-  public boolean equalsInterval(IntervalI o)
+  public boolean equals(Object obj)
   {
-    // must override equalsInterval, not equals
-    return (o != null && start == ((SimpleFeature) o).start
-            && end == ((SimpleFeature) o).end)
-            && (description == null
-                    ? ((SimpleFeature) o).description == null
-                    : description.equals(((SimpleFeature) o).description));
+    if (obj != null && obj instanceof SimpleFeature)
+    {
+      SimpleFeature o = (SimpleFeature) obj;
+      if (this.begin == o.begin && this.end == o.end)
+      {
+        if (this.description == null)
+        {
+          return o.description == null;
+        }
+        return this.description.equals(o.description);
+      }
+    }
+    return false;
   }
 
   @Override
   public String toString()
   {
-    return start + ":" + end + ":" + description;
+    return begin + ":" + end + ":" + description;
   }
 
-
 }
index ac80298..489ac38 100644 (file)
@@ -21,7 +21,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testFindFeatures_nonNested()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     fs.addFeature(new SequenceFeature("", "", 10, 20, Float.NaN,
             null));
     // same range different description
@@ -49,15 +49,15 @@ public class FeatureStoreJSTest
     assertEquals(overlaps.get(0).getEnd(), 35);
   }
 
-  private FeatureStoreI newFeatureStore()
+  private FeatureStore newFeatureStore()
   {
-    return new FeatureStoreJS(intervalStoreOption);
+    return new FeatureStore(intervalStoreOption);
   }
 
   @Test(groups = "Functional")
   public void testFindFeatures_nested()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = addFeature(fs, 10, 50);
     SequenceFeature sf2 = addFeature(fs, 10, 40);
     SequenceFeature sf3 = addFeature(fs, 20, 30);
@@ -95,7 +95,7 @@ public class FeatureStoreJSTest
 
   private void testFind()
   {
-    FeatureStoreI fs1 = newFeatureStore();
+    FeatureStore fs1 = newFeatureStore();
 
     SequenceFeature sf = addFeature(fs1, 1, 3000);
 
@@ -128,7 +128,7 @@ public class FeatureStoreJSTest
   {
     testFind();
 
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = addFeature(fs, 10, 50);
     SequenceFeature sf2 = addFeature(fs, 1, 15);
     SequenceFeature sf3 = addFeature(fs, 20, 30);
@@ -174,7 +174,7 @@ public class FeatureStoreJSTest
    * @param to
    * @return
    */
-  SequenceFeature addFeature(FeatureStoreI fs, int from, int to)
+  SequenceFeature addFeature(FeatureStore fs, int from, int to)
   {
     SequenceFeature sf1 = new SequenceFeature("", "", from, to, Float.NaN,
             null);
@@ -185,7 +185,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testFindFeatures_contactFeatures()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     SequenceFeature sf = new SequenceFeature("disulphide bond", "bond", 10,
             20, Float.NaN, null);
@@ -228,7 +228,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testGetPositionalFeatures()
   {
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
     store.addFeature(sf1);
@@ -275,7 +275,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testDelete()
   {
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = addFeature(store, 10, 20);
     assertTrue(store.getPositionalFeatures().contains(sf1));
 
@@ -347,7 +347,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testAddFeature()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
             Float.NaN, null);
@@ -398,7 +398,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testIsEmpty()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertTrue(fs.isEmpty());
     assertEquals(fs.getFeatureCount(true), 0);
 
@@ -464,7 +464,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testGetFeatureGroups()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertTrue(fs.getFeatureGroups(true).isEmpty());
     assertTrue(fs.getFeatureGroups(false).isEmpty());
 
@@ -531,7 +531,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testGetTotalFeatureLength()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertEquals(fs.getTotalFeatureLength(), 0);
 
     addFeature(fs, 10, 20); // 11
@@ -607,7 +607,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testGetMinimumScore_getMaximumScore()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertEquals(fs.getMinimumScore(true), Float.NaN); // positional
     assertEquals(fs.getMaximumScore(true), Float.NaN);
     assertEquals(fs.getMinimumScore(false), Float.NaN); // non-positional
@@ -679,7 +679,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testListContains()
   {
-    FeatureStoreI featureStore = newFeatureStore();
+    FeatureStore featureStore = newFeatureStore();
     assertFalse(featureStore.listContains(null, null));
     List<SequenceFeature> features = new ArrayList<>();
     assertFalse(featureStore.listContains(features, null));
@@ -703,7 +703,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testGetFeaturesForGroup()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     /*
      * with no features
@@ -761,7 +761,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testShiftFeatures()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertFalse(fs.shiftFeatures(0, 1)); // nothing to do
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
@@ -848,7 +848,7 @@ public class FeatureStoreJSTest
     /*
      * add a feature and a nested feature
      */
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = addFeature(store, 10, 20);
     // sf2 is nested in sf1 so will be stored in nestedFeatures
     SequenceFeature sf2 = addFeature(store, 12, 14);
@@ -879,7 +879,7 @@ public class FeatureStoreJSTest
   @Test(groups = "Functional")
   public void testContains()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
             Float.NaN, "group1");
     SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20,
index 5d2ca3d..efcef68 100644 (file)
@@ -15,18 +15,15 @@ import org.testng.annotations.Test;
 
 public class FeatureStoreJavaTest
 {
-
-  private int intervalStoreOption = FeatureStore.intervalStoreJavaOption;
-
-  private FeatureStoreI newFeatureStore()
+  private FeatureStore newFeatureStore()
   {
-    return new FeatureStoreImpl(intervalStoreOption);
+    return new FeatureStore();
   }
 
   @Test(groups = "Functional")
   public void testFindFeatures_nonNested()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     fs.addFeature(new SequenceFeature("", "", 10, 20, Float.NaN,
             null));
     // same range different description
@@ -56,7 +53,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testFindFeatures_nested()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = addFeature(fs, 10, 50);
     SequenceFeature sf2 = addFeature(fs, 10, 40);
     SequenceFeature sf3 = addFeature(fs, 20, 30);
@@ -95,7 +92,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testFindFeatures_mixed()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = addFeature(fs, 10, 50);
     SequenceFeature sf2 = addFeature(fs, 1, 15);
     SequenceFeature sf3 = addFeature(fs, 20, 30);
@@ -141,7 +138,7 @@ public class FeatureStoreJavaTest
    * @param to
    * @return
    */
-  SequenceFeature addFeature(FeatureStoreI fs, int from, int to)
+  SequenceFeature addFeature(FeatureStore fs, int from, int to)
   {
     SequenceFeature sf1 = new SequenceFeature("", "", from, to, Float.NaN,
             null);
@@ -152,7 +149,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testFindFeatures_contactFeatures()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     SequenceFeature sf = new SequenceFeature("disulphide bond", "bond", 10,
             20, Float.NaN, null);
@@ -195,7 +192,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testGetPositionalFeatures()
   {
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
     store.addFeature(sf1);
@@ -242,7 +239,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testDelete()
   {
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = addFeature(store, 10, 20);
     assertTrue(store.getPositionalFeatures().contains(sf1));
 
@@ -314,7 +311,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testAddFeature()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
             Float.NaN, null);
@@ -365,7 +362,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testIsEmpty()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertTrue(fs.isEmpty());
     assertEquals(fs.getFeatureCount(true), 0);
 
@@ -431,7 +428,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testGetFeatureGroups()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertTrue(fs.getFeatureGroups(true).isEmpty());
     assertTrue(fs.getFeatureGroups(false).isEmpty());
 
@@ -498,7 +495,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testGetTotalFeatureLength()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertEquals(fs.getTotalFeatureLength(), 0);
 
     addFeature(fs, 10, 20); // 11
@@ -574,7 +571,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testGetMinimumScore_getMaximumScore()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertEquals(fs.getMinimumScore(true), Float.NaN); // positional
     assertEquals(fs.getMaximumScore(true), Float.NaN);
     assertEquals(fs.getMinimumScore(false), Float.NaN); // non-positional
@@ -646,7 +643,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testListContains()
   {
-    FeatureStoreI featureStore = newFeatureStore();
+    FeatureStore featureStore = newFeatureStore();
     assertFalse(featureStore.listContains(null, null));
     List<SequenceFeature> features = new ArrayList<>();
     assertFalse(featureStore.listContains(features, null));
@@ -670,7 +667,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testGetFeaturesForGroup()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     /*
      * with no features
@@ -728,7 +725,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testShiftFeatures()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertFalse(fs.shiftFeatures(0, 1)); // nothing to do
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
@@ -815,7 +812,7 @@ public class FeatureStoreJavaTest
     /*
      * add a feature and a nested feature
      */
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = addFeature(store, 10, 20);
     // sf2 is nested in sf1 so will be stored in nestedFeatures
     SequenceFeature sf2 = addFeature(store, 12, 14);
@@ -846,7 +843,7 @@ public class FeatureStoreJavaTest
   @Test(groups = "Functional")
   public void testContains()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
             Float.NaN, "group1");
     SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20,
index 25fdbb2..c1cd6d7 100644 (file)
@@ -16,46 +16,50 @@ import org.testng.annotations.Test;
 public class FeatureStoreLinkedTest
 {
 
-  private FeatureStoreI newFeatureStore()
+  private FeatureStore newFeatureStore()
   {
-    return new FeatureStoreImpl(
+    return new FeatureStore(
             FeatureStore.INTERVAL_STORE_LINKED_LIST_PRESORT);
   }
 
   @Test(groups = "Functional")
   public void testFindFeatures_nonNested()
   {
-    FeatureStoreI fs = newFeatureStore();
-    fs.addFeature(new SequenceFeature("", "", 10, 20, Float.NaN,
-            null));
+    FeatureStore fs = newFeatureStore();
+    SequenceFeature sf0 = new SequenceFeature("", "", 10, 20, Float.NaN,
+            null);
+    fs.addFeature(sf0);
     // same range different description
-    fs.addFeature(new SequenceFeature("", "desc", 10, 20, Float.NaN, null));
-    fs.addFeature(new SequenceFeature("", "", 15, 25, Float.NaN, null));
-    fs.addFeature(new SequenceFeature("", "", 20, 35, Float.NaN, null));
+    SequenceFeature sf1 = new SequenceFeature("", "desc", 10, 20, Float.NaN, null);
+    fs.addFeature(sf1);
+    SequenceFeature sf2 = new SequenceFeature("", "", 15, 25, Float.NaN, null);
+    fs.addFeature(sf2);
+    SequenceFeature sf3 = new SequenceFeature("", "", 20, 35, Float.NaN, null);
+    fs.addFeature(sf3);
 
     List<SequenceFeature> overlaps = fs.findOverlappingFeatures(1, 9);
     assertTrue(overlaps.isEmpty());
 
     overlaps = fs.findOverlappingFeatures(8, 10);
     assertEquals(overlaps.size(), 2);
-    assertEquals(overlaps.get(0).getEnd(), 20);
-    assertEquals(overlaps.get(1).getEnd(), 20);
+    assertTrue(overlaps.contains(sf0));
+    assertTrue(overlaps.contains(sf1));
 
     overlaps = fs.findOverlappingFeatures(12, 16);
     assertEquals(overlaps.size(), 3);
-    assertEquals(overlaps.get(0).getEnd(), 20);
-    assertEquals(overlaps.get(1).getEnd(), 20);
-    assertEquals(overlaps.get(2).getEnd(), 25);
+    assertTrue(overlaps.contains(sf0));
+    assertTrue(overlaps.contains(sf1));
+    assertTrue(overlaps.contains(sf2));
 
     overlaps = fs.findOverlappingFeatures(33, 33);
     assertEquals(overlaps.size(), 1);
-    assertEquals(overlaps.get(0).getEnd(), 35);
+    assertTrue(overlaps.contains(sf3));
   }
 
   @Test(groups = "Functional")
   public void testFindFeatures_nested()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = addFeature(fs, 10, 50);
     SequenceFeature sf2 = addFeature(fs, 10, 40);
     SequenceFeature sf3 = addFeature(fs, 20, 30);
@@ -94,7 +98,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testFindFeatures_mixed()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = addFeature(fs, 10, 50);
     SequenceFeature sf2 = addFeature(fs, 1, 15);
     SequenceFeature sf3 = addFeature(fs, 20, 30);
@@ -140,7 +144,7 @@ public class FeatureStoreLinkedTest
    * @param to
    * @return
    */
-  SequenceFeature addFeature(FeatureStoreI fs, int from, int to)
+  SequenceFeature addFeature(FeatureStore fs, int from, int to)
   {
     SequenceFeature sf1 = new SequenceFeature("", "", from, to, Float.NaN,
             null);
@@ -151,7 +155,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testFindFeatures_contactFeatures()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     SequenceFeature sf = new SequenceFeature("disulphide bond", "bond", 10,
             20, Float.NaN, null);
@@ -194,7 +198,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testGetPositionalFeatures()
   {
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
     store.addFeature(sf1);
@@ -241,7 +245,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testDelete()
   {
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = addFeature(store, 10, 20);
     assertTrue(store.getPositionalFeatures().contains(sf1));
 
@@ -321,7 +325,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testAddFeature()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
             Float.NaN, null);
@@ -372,7 +376,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testIsEmpty()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertTrue(fs.isEmpty());
     assertEquals(fs.getFeatureCount(true), 0);
 
@@ -438,7 +442,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testGetFeatureGroups()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertTrue(fs.getFeatureGroups(true).isEmpty());
     assertTrue(fs.getFeatureGroups(false).isEmpty());
 
@@ -505,7 +509,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testGetTotalFeatureLength()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertEquals(fs.getTotalFeatureLength(), 0);
 
     addFeature(fs, 10, 20); // 11
@@ -581,7 +585,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testGetMinimumScore_getMaximumScore()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertEquals(fs.getMinimumScore(true), Float.NaN); // positional
     assertEquals(fs.getMaximumScore(true), Float.NaN);
     assertEquals(fs.getMinimumScore(false), Float.NaN); // non-positional
@@ -653,7 +657,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testListContains()
   {
-    FeatureStoreI featureStore = newFeatureStore();
+    FeatureStore featureStore = newFeatureStore();
     assertFalse(featureStore.listContains(null, null));
     List<SequenceFeature> features = new ArrayList<>();
     assertFalse(featureStore.listContains(features, null));
@@ -677,7 +681,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testGetFeaturesForGroup()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     /*
      * with no features
@@ -735,7 +739,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testShiftFeatures()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertFalse(fs.shiftFeatures(0, 1)); // nothing to do
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
@@ -822,7 +826,7 @@ public class FeatureStoreLinkedTest
     /*
      * add a feature and a nested feature
      */
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = addFeature(store, 10, 20);
     // sf2 is nested in sf1 so will be stored in nestedFeatures
     SequenceFeature sf2 = addFeature(store, 12, 14);
@@ -853,7 +857,7 @@ public class FeatureStoreLinkedTest
   @Test(groups = "Functional")
   public void testContains()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
             Float.NaN, "group1");
     SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20,
index 2b9198a..c7598d4 100644 (file)
@@ -16,16 +16,16 @@ import org.testng.annotations.Test;
 public class FeatureStoreNCListBufferTest
 {
 
-  private FeatureStoreI newFeatureStore()
+  private FeatureStore newFeatureStore()
   {
-    return new FeatureStoreImpl(
+    return new FeatureStore(
             FeatureStore.INTERVAL_STORE_NCLIST_BUFFER_PRESORT);
   }
 
   @Test(groups = "Functional")
   public void testFindFeatures_nonNested()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     fs.addFeature(new SequenceFeature("", "", 10, 20, Float.NaN,
             null));
     // same range different description
@@ -55,7 +55,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testFindFeatures_nested()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = addFeature(fs, 10, 50);
     SequenceFeature sf2 = addFeature(fs, 10, 40);
     SequenceFeature sf3 = addFeature(fs, 20, 30);
@@ -94,7 +94,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testFindFeatures_mixed()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = addFeature(fs, 10, 50);
     SequenceFeature sf2 = addFeature(fs, 1, 15);
     SequenceFeature sf3 = addFeature(fs, 20, 30);
@@ -140,7 +140,7 @@ public class FeatureStoreNCListBufferTest
    * @param to
    * @return
    */
-  SequenceFeature addFeature(FeatureStoreI fs, int from, int to)
+  SequenceFeature addFeature(FeatureStore fs, int from, int to)
   {
     SequenceFeature sf1 = new SequenceFeature("", "", from, to, Float.NaN,
             null);
@@ -151,7 +151,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testFindFeatures_contactFeatures()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     SequenceFeature sf = new SequenceFeature("disulphide bond", "bond", 10,
             20, Float.NaN, null);
@@ -194,7 +194,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testGetPositionalFeatures()
   {
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = new SequenceFeature("Metal", "desc", 10, 20,
             Float.NaN, null);
     store.addFeature(sf1);
@@ -241,7 +241,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testDelete()
   {
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = addFeature(store, 10, 20);
     assertTrue(store.getPositionalFeatures().contains(sf1));
 
@@ -321,7 +321,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testAddFeature()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
             Float.NaN, null);
@@ -372,7 +372,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testIsEmpty()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertTrue(fs.isEmpty());
     assertEquals(fs.getFeatureCount(true), 0);
 
@@ -438,7 +438,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testGetFeatureGroups()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertTrue(fs.getFeatureGroups(true).isEmpty());
     assertTrue(fs.getFeatureGroups(false).isEmpty());
 
@@ -505,7 +505,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testGetTotalFeatureLength()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertEquals(fs.getTotalFeatureLength(), 0);
 
     addFeature(fs, 10, 20); // 11
@@ -581,7 +581,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testGetMinimumScore_getMaximumScore()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertEquals(fs.getMinimumScore(true), Float.NaN); // positional
     assertEquals(fs.getMaximumScore(true), Float.NaN);
     assertEquals(fs.getMinimumScore(false), Float.NaN); // non-positional
@@ -653,7 +653,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testListContains()
   {
-    FeatureStoreI featureStore = newFeatureStore();
+    FeatureStore featureStore = newFeatureStore();
     assertFalse(featureStore.listContains(null, null));
     List<SequenceFeature> features = new ArrayList<>();
     assertFalse(featureStore.listContains(features, null));
@@ -677,7 +677,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testGetFeaturesForGroup()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
 
     /*
      * with no features
@@ -735,7 +735,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testShiftFeatures()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     assertFalse(fs.shiftFeatures(0, 1)); // nothing to do
 
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 2, 5, 0f, null);
@@ -822,7 +822,7 @@ public class FeatureStoreNCListBufferTest
     /*
      * add a feature and a nested feature
      */
-    FeatureStoreI store = newFeatureStore();
+    FeatureStore store = newFeatureStore();
     SequenceFeature sf1 = addFeature(store, 10, 20);
     // sf2 is nested in sf1 so will be stored in nestedFeatures
     SequenceFeature sf2 = addFeature(store, 12, 14);
@@ -853,7 +853,7 @@ public class FeatureStoreNCListBufferTest
   @Test(groups = "Functional")
   public void testContains()
   {
-    FeatureStoreI fs = newFeatureStore();
+    FeatureStore fs = newFeatureStore();
     SequenceFeature sf1 = new SequenceFeature("Cath", "", 10, 20,
             Float.NaN, "group1");
     SequenceFeature sf2 = new SequenceFeature("Cath", "", 10, 20,
index 30b1402..29e76bb 100644 (file)
@@ -889,11 +889,11 @@ public class SequenceFeaturesTest
      * no type specified - get all types stored
      * they are returned in keyset (alphabetical) order
      */
-    Map<String, FeatureStoreI> featureStores = (Map<String, FeatureStoreI>) PA
+    Map<String, FeatureStore> featureStores = (Map<String, FeatureStore>) PA
             .getValue(sf, "featureStore");
 
-    Iterable<FeatureStoreI> types = sf.varargToTypes();
-    Iterator<FeatureStoreI> iterator = types.iterator();
+    Iterable<FeatureStore> types = sf.varargToTypes();
+    Iterator<FeatureStore> iterator = types.iterator();
     assertTrue(iterator.hasNext());
     assertSame(iterator.next(), featureStores.get("Cath"));
     assertTrue(iterator.hasNext());