JAL-2759 cursor option for BoundedStartRegionIterator
authorkiramt <k.mourao@dundee.ac.uk>
Mon, 20 Nov 2017 14:25:39 +0000 (14:25 +0000)
committerkiramt <k.mourao@dundee.ac.uk>
Mon, 20 Nov 2017 14:25:39 +0000 (14:25 +0000)
src/jalview/datamodel/BoundedStartRegionIterator.java
src/jalview/datamodel/HiddenColumns.java
src/jalview/datamodel/HiddenColumnsCursor.java
src/jalview/datamodel/HiddenCursorPosition.java
src/jalview/datamodel/VisibleContigsIterator.java

index 831e906..d68eeeb 100644 (file)
@@ -72,6 +72,68 @@ public class BoundedStartRegionIterator implements Iterator<Integer>
 
   }
 
+  /**
+   * Construct an iterator over hiddenColums bounded at [lowerBound,upperBound]
+   * 
+   * @param pos
+   *          a hidden cursor position to start from - may be null
+   * @param lowerBound
+   *          lower bound to iterate from - will be ignored if pos != null
+   * @param upperBound
+   *          upper bound to iterate to
+   * @param hiddenColumns
+   *          the hidden columns collection to use
+   */
+  BoundedStartRegionIterator(HiddenCursorPosition pos, int lowerBound,
+          int upperBound, List<int[]> hiddenColumns)
+  {
+    start = lowerBound;
+    end = upperBound;
+
+    if (hiddenColumns != null)
+    {
+      positions = new ArrayList<>(hiddenColumns.size());
+
+      // navigate to start, keeping count of hidden columns
+      int i = 0;
+      int hiddenSoFar = 0;
+      
+      if (pos != null)
+      {
+        // use the cursor position provided
+        i = pos.getRegionIndex();
+        hiddenSoFar = pos.getHiddenSoFar();
+      }
+      else
+      {
+        // navigate to start
+        while ((i < hiddenColumns.size())
+                && (hiddenColumns.get(i)[0] < start + hiddenSoFar))
+        {
+          int[] region = hiddenColumns.get(i);
+          hiddenSoFar += region[1] - region[0] + 1;
+          i++;
+        }
+      }
+
+      // iterate from start to end, adding start positions of each
+      // hidden region. Positions are visible columns count, not absolute
+      while (i < hiddenColumns.size()
+              && (hiddenColumns.get(i)[0] <= end + hiddenSoFar))
+      {
+        int[] region = hiddenColumns.get(i);
+        positions.add(region[0] - hiddenSoFar);
+        hiddenSoFar += region[1] - region[0] + 1;
+        i++;
+      }
+    }
+    else
+    {
+      positions = new ArrayList<>();
+    }
+
+  }
+
   @Override
   public boolean hasNext()
   {
index 48cfb42..a81d3bd 100644 (file)
@@ -1420,7 +1420,20 @@ public class HiddenColumns
     try
     {
       LOCK.readLock().lock();
-      return new BoundedStartRegionIterator(start, end, hiddenColumns);
+
+      // get absolute position of column in alignment
+      int absoluteStart = adjustForHiddenColumns(start);
+
+      // Get cursor position and supply it to the iterator:
+      // Since we want visible region start, we look for a cursor for the
+      // (absoluteStart-1), then if absoluteStart is the start of a visible
+      // region we'll get the cursor pointing to the region before, which is
+      // what we want
+      HiddenCursorPosition pos = cursor
+              .findRegionForColumn(absoluteStart - 1);
+
+      return new BoundedStartRegionIterator(pos, start, end,
+              hiddenColumns);
     } finally
     {
       LOCK.readLock().unlock();
@@ -1453,9 +1466,9 @@ public class HiddenColumns
    * boundaries
    * 
    * @param start
-   *          (first column inclusive from 0)
+   *          first column, inclusive from 0, absolute value
    * @param end
-   *          (last column - not inclusive)
+   *          last column - not inclusive, absolute value
    */
   public Iterator<int[]> getVisContigsIterator(int start, int end)
   {
@@ -1484,172 +1497,23 @@ public class HiddenColumns
   public Iterator<int[]> getVisibleBlocksIterator(int start, int end,
           boolean useVisibleCoords)
   {
+    int adjstart = start;
+    int adjend = end;
     if (useVisibleCoords)
     {
-      // TODO
-      // we should really just convert start and end here with
-      // adjustForHiddenColumns
-      // and then create a VisibleContigsIterator
-      // but without a cursor this will be horribly slow in some situations
-      // ... so until then...
-      // return new VisibleBlocksVisBoundsIterator(start, end, true);
-      try
-      {
-        LOCK.readLock().lock();
-        int adjstart = adjustForHiddenColumns(start);
-        int adjend = adjustForHiddenColumns(end);
-        return new VisibleContigsIterator(adjstart, adjend + 1,
-                hiddenColumns);
-      } finally
-      {
-        LOCK.readLock().unlock();
-      }
+      adjstart = adjustForHiddenColumns(start);
+      adjend = adjustForHiddenColumns(end);
     }
-    else
-    {
-      try
-      {
-        LOCK.readLock().lock();
-        return new VisibleContigsIterator(start, end + 1, hiddenColumns);
-      } finally
-      {
-        LOCK.readLock().unlock();
-      }
-    }
-  }
-
-  /**
-   * An iterator which iterates over visible regions in a range. The range is
-   * specified in terms of visible column positions. Provides a special
-   * "endsAtHidden" indicator to allow callers to determine if the final visible
-   * column is adjacent to a hidden region.
-   */
-  public class VisibleBlocksVisBoundsIterator implements Iterator<int[]>
-  {
-    private List<int[]> vcontigs = new ArrayList<>();
-
-    private int currentPosition = 0;
-
-    private boolean endsAtHidden = false;
-
-    /**
-     * Constructor for iterator over visible regions in a range.
-     * 
-     * @param start
-     *          start position in terms of visible column position
-     * @param end
-     *          end position in terms of visible column position
-     * @param usecopy
-     *          whether to use a local copy of hidden columns
-     */
-    VisibleBlocksVisBoundsIterator(int start, int end, boolean usecopy)
-    {
-      /* actually this implementation always uses a local copy but this may change in future */
-      try
-      {
-        if (usecopy)
-        {
-          LOCK.readLock().lock();
-        }
-
-        if (hiddenColumns != null && hiddenColumns.size() > 0)
-        {
-          int blockStart = start;
-          int blockEnd = end;
-          int hiddenSoFar = 0;
-          int visSoFar = 0;
-
-          // iterate until a region begins within (start,end]
-          int i = 0;
-          while ((i < hiddenColumns.size())
-                  && (hiddenColumns.get(i)[0] <= blockStart + hiddenSoFar))
-          {
-            hiddenSoFar += hiddenColumns.get(i)[1] - hiddenColumns.get(i)[0]
-                    + 1;
-            i++;
-          }
-
-          blockStart += hiddenSoFar; // convert start to absolute position
-          blockEnd += hiddenSoFar; // convert end to absolute position
-
-          // iterate from start to end, adding each visible region. Positions
-          // are
-          // absolute, and all hidden regions which overlap [start,end] are
-          // used.
-          while (i < hiddenColumns.size()
-                  && (hiddenColumns.get(i)[0] <= blockEnd))
-          {
-            int[] region = hiddenColumns.get(i);
-
-            // end position of this visible region is either just before the
-            // start of the next hidden region, or the absolute position of
-            // 'end', whichever is lowest
-            blockEnd = Math.min(blockEnd, region[0] - 1);
-
-            vcontigs.add(new int[] { blockStart, blockEnd });
 
-            visSoFar += blockEnd - blockStart + 1;
-
-            // next visible region starts after this hidden region
-            blockStart = region[1] + 1;
-
-            hiddenSoFar += region[1] - region[0] + 1;
-
-            // reset blockEnd to absolute position of 'end', assuming we've now
-            // passed all hidden regions before end
-            blockEnd = end + hiddenSoFar;
-
-            i++;
-          }
-          if (visSoFar < end - start + 1)
-          {
-            // the number of visible columns we've accounted for is less than
-            // the number specified by end-start; work out the end position of
-            // the last visible region
-            blockEnd = blockStart + end - start - visSoFar;
-            vcontigs.add(new int[] { blockStart, blockEnd });
-
-            // if the last visible region ends at the next hidden region, set
-            // endsAtHidden=true
-            if (i < hiddenColumns.size()
-                    && hiddenColumns.get(i)[0] - 1 == blockEnd)
-            {
-              endsAtHidden = true;
-            }
-          }
-        }
-        else
-        {
-          // there are no hidden columns, return a single visible contig
-          vcontigs.add(new int[] { start, end });
-          endsAtHidden = false;
-        }
-      } finally
-      {
-        if (usecopy)
-        {
-          LOCK.readLock().unlock();
-        }
-      }
-    }
-
-    @Override
-    public boolean hasNext()
-    {
-      return (currentPosition < vcontigs.size());
-    }
-
-    @Override
-    public int[] next()
+    try
     {
-      int[] result = vcontigs.get(currentPosition);
-      currentPosition++;
-      return result;
-    }
+      LOCK.readLock().lock();
 
-    public boolean endsAtHidden()
+      return new VisibleContigsIterator(adjstart, adjend + 1,
+              hiddenColumns);
+    } finally
     {
-      return endsAtHidden;
+      LOCK.readLock().unlock();
     }
   }
 }
index 3284504..a002232 100644 (file)
@@ -34,7 +34,7 @@ public class HiddenColumnsCursor
   // Could be done with synchronisation but benchmarking shows this way is 2x
   // faster
   private final AtomicReference<HiddenCursorPosition> cursorPos = new AtomicReference<>(
-          new HiddenCursorPosition(0, 0, 0));
+          new HiddenCursorPosition(0, 0));
 
   protected HiddenColumnsCursor()
   {
@@ -56,7 +56,7 @@ public class HiddenColumnsCursor
     {
       firstColumn = hiddenColumns.get(0)[0];
       HiddenCursorPosition oldpos = cursorPos.get();
-      HiddenCursorPosition newpos = new HiddenCursorPosition(0, 0, 0);
+      HiddenCursorPosition newpos = new HiddenCursorPosition(0, 0);
       cursorPos.compareAndSet(oldpos, newpos);
     }
   }
@@ -91,7 +91,7 @@ public class HiddenColumnsCursor
 
       // update the cursor position
       HiddenCursorPosition newpos = new HiddenCursorPosition(index,
-              oldpos.getHiddenSoFar(), oldpos.getNumColumns());
+              oldpos.getHiddenSoFar());
       cursorPos.compareAndSet(oldpos, newpos);
     }
     hiddenColumns = hiddenCols;
@@ -170,7 +170,7 @@ public class HiddenColumnsCursor
       }
     }
     HiddenCursorPosition newpos = new HiddenCursorPosition(index,
-            hiddenCount, oldpos.getNumColumns());
+            hiddenCount);
     cursorPos.compareAndSet(oldpos, newpos);
     return newpos;
   }
@@ -225,7 +225,7 @@ public class HiddenColumnsCursor
     }
 
     HiddenCursorPosition newpos = new HiddenCursorPosition(index,
-            hiddenCount, oldpos.getNumColumns());
+            hiddenCount);
     cursorPos.compareAndSet(oldpos, newpos);
     return newpos;
   }
index 606a7c5..3c0b17a 100644 (file)
@@ -7,14 +7,11 @@ public class HiddenCursorPosition
 
   // number of hidden columns before last visited region
   private int hiddenSoFar;
-  
-  private int numColumns;
 
-  public HiddenCursorPosition(int index, int hiddencount, int colscount)
+  public HiddenCursorPosition(int index, int hiddencount)
   {
     regionIndex = index;
     hiddenSoFar = hiddencount;
-    numColumns = colscount;
   }
 
   public int getRegionIndex()
@@ -26,9 +23,4 @@ public class HiddenCursorPosition
   {
     return hiddenSoFar;
   }
-  
-  public int getNumColumns()
-  {
-    return numColumns;
-  }
 }
index ff060ac..d98121a 100644 (file)
@@ -5,7 +5,9 @@ import java.util.Iterator;
 import java.util.List;
 
 /**
- * An iterator which iterates over visible regions in a range.
+ * An iterator which iterates over visible regions in a range. Provides a
+ * special "endsAtHidden" indicator to allow callers to determine if the final
+ * visible column is adjacent to a hidden region.
  */
 public class VisibleContigsIterator implements Iterator<int[]>
 {