JAL-2674 finish with iterators for now
authorkiramt <k.mourao@dundee.ac.uk>
Fri, 29 Sep 2017 13:22:30 +0000 (14:22 +0100)
committerkiramt <k.mourao@dundee.ac.uk>
Fri, 29 Sep 2017 13:22:30 +0000 (14:22 +0100)
src/jalview/analysis/Dna.java
src/jalview/datamodel/HiddenColumns.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/VamsasApplication.java
test/jalview/analysis/DnaTest.java
test/jalview/datamodel/HiddenColumnsTest.java

index c3408bd..a6fe541 100644 (file)
@@ -44,6 +44,7 @@ import jalview.util.ShiftList;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
 
 public class Dna
@@ -60,7 +61,7 @@ public class Dna
 
   private final String[] seqstring;
 
-  private final List<int[]> contigs;
+  private final Iterator<int[]> contigs;
 
   private final char gapChar;
 
@@ -91,7 +92,7 @@ public class Dna
    * @param viewport
    * @param visibleContigs
    */
-  public Dna(AlignViewportI viewport, List<int[]> visibleContigs)
+  public Dna(AlignViewportI viewport, Iterator<int[]> visibleContigs)
   {
     this.selection = Arrays.asList(viewport.getSequenceSelection());
     this.seqstring = viewport.getViewAsString(true);
@@ -396,11 +397,12 @@ public class Dna
     ShiftList vismapping = new ShiftList(); // map from viscontigs to seqstring
     // intervals
     int vc = 0;
-    int[] scontigs = new int[contigs.size() * 2];
+
     int npos = 0;
     int[] lastregion = null;
-    for (int[] region : contigs)
+    while (contigs.hasNext())
     {
+      int[] region = contigs.next();
       if (lastregion == null)
       {
         vismapping.addShift(npos, region[0]);
@@ -411,7 +413,14 @@ public class Dna
         vismapping.addShift(npos, region[0] - lastregion[1] + 1);
       }
       lastregion = region;
+      vc++;
+    }
 
+    int[] scontigs = new int[vc];
+    vc = 0;
+    while (contigs.hasNext())
+    {
+      int[] region = contigs.next();
       scontigs[vc] = region[0];
       scontigs[vc + 1] = region[1];
       vc++;
index c77fb7b..5554be0 100644 (file)
@@ -714,70 +714,6 @@ public class HiddenColumns
     return copy;
   }
 
-  /**
-   * return all visible segments between the given start and end boundaries
-   * 
-   * @param start
-   *          (first column inclusive from 0)
-   * @param end
-   *          (last column - not inclusive)
-   * @return List<int[]> {[i_start, i_end], ..} where intervals lie in
-   *         start<=i_start<=i_end<end
-   */
-  public List<int[]> getVisibleContigs(int start, int end)
-  {
-    try
-    {
-      LOCK.readLock().lock();
-      List<int[]> vcontigs = new ArrayList<>();
-      if (hiddenColumns != null && hiddenColumns.size() > 0)
-      {
-        int vstart = start;
-        int hideStart;
-        int hideEnd;
-
-        for (int[] region : hiddenColumns)
-        {
-          hideStart = region[0];
-          hideEnd = region[1];
-
-          // navigate to start
-          if (hideEnd < vstart)
-          {
-            continue;
-          }
-          if (hideStart > vstart)
-          {
-            int[] contig = new int[] { vstart, hideStart - 1 };
-            vcontigs.add(contig);
-          }
-          vstart = hideEnd + 1;
-
-          // exit if we're past the end
-          if (vstart >= end)
-          {
-            break;
-          }
-        }
-
-        if (vstart < end)
-        {
-          int[] contig = new int[] { vstart, end - 1 };
-          vcontigs.add(contig);
-        }
-      }
-      else
-      {
-        int[] contig = new int[] { start, end - 1 };
-        vcontigs.add(contig);
-      }
-      return vcontigs;
-    } finally
-    {
-      LOCK.readLock().unlock();
-    }
-  }
-
   public String[] getVisibleSequenceStrings(int start, int end,
           SequenceI[] seqs)
   {
@@ -794,30 +730,18 @@ public class HiddenColumns
 
           int blockStart = start;
           int blockEnd = end;
-          int hideStart;
-          int hideEnd;
 
-          for (int[] region : hiddenColumns)
+          Iterator<int[]> regions = new BoundedHiddenColsIterator(start,
+                  end, false);
+          while (regions.hasNext())
           {
-            hideStart = region[0];
-            hideEnd = region[1];
-
-            if (hideStart < start)
-            {
-              continue;
-            }
-
-            blockStart = Math.min(blockStart, hideEnd + 1);
-            blockEnd = Math.min(blockEnd, hideStart);
-
-            if (blockStart > blockEnd)
-            {
-              break;
-            }
+            int[] region = regions.next();
+            blockStart = Math.min(blockStart, region[1] + 1);
+            blockEnd = Math.min(blockEnd, region[0]);
 
             visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
 
-            blockStart = hideEnd + 1;
+            blockStart = region[1] + 1;
             blockEnd = end;
           }
 
@@ -962,95 +886,91 @@ public class HiddenColumns
     try
     {
       LOCK.readLock().lock();
-      if (alignmentAnnotation.annotations == null)
-      {
-        return;
-      }
-      if (start == end && end == -1)
-      {
-        start = 0;
-        end = alignmentAnnotation.annotations.length;
-      }
-      if (hiddenColumns != null && hiddenColumns.size() > 0)
-      {
-        // then mangle the alignmentAnnotation annotation array
-        Vector<Annotation[]> annels = new Vector<>();
-        Annotation[] els = null;
-        int blockStart = start;
-        int blockEnd = end;
-        int hideStart;
-        int hideEnd;
-        int w = 0;
-
-        for (int[] region : hiddenColumns)
-        {
-          hideStart = region[0];
-          hideEnd = region[1];
 
-          if (hideStart < start)
-          {
-            continue;
-          }
-
-          blockStart = Math.min(blockStart, hideEnd + 1);
-          blockEnd = Math.min(blockEnd, hideStart);
-
-          if (blockStart > blockEnd)
-          {
-            break;
-          }
+      int startFrom = start;
+      int endAt = end;
 
-          els = new Annotation[blockEnd - blockStart];
-          annels.addElement(els);
-          System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
-                  0, els.length);
-          w += els.length;
-          blockStart = hideEnd + 1;
-          blockEnd = end;
+      if (alignmentAnnotation.annotations != null)
+      {
+        if (start == end && end == -1)
+        {
+          startFrom = 0;
+          endAt = alignmentAnnotation.annotations.length;
         }
-
-        if (end > blockStart)
+        if (hiddenColumns != null && hiddenColumns.size() > 0)
         {
-          els = new Annotation[end - blockStart + 1];
-          annels.addElement(els);
-          if ((els.length
-                  + blockStart) <= alignmentAnnotation.annotations.length)
-          {
-            // copy just the visible segment of the annotation row
-            System.arraycopy(alignmentAnnotation.annotations, blockStart,
-                    els, 0, els.length);
-          }
-          else
-          {
-            // copy to the end of the annotation row
-            System.arraycopy(alignmentAnnotation.annotations, blockStart,
-                    els, 0,
-                    (alignmentAnnotation.annotations.length - blockStart));
-          }
-          w += els.length;
+          removeHiddenAnnotation(startFrom, endAt, alignmentAnnotation);
         }
-        if (w == 0)
+        else
         {
-          return;
+          alignmentAnnotation.restrict(startFrom, endAt);
         }
+      }
+    } finally
+    {
+      LOCK.readLock().unlock();
+    }
+  }
 
-        alignmentAnnotation.annotations = new Annotation[w];
-        w = 0;
+  private void removeHiddenAnnotation(int start, int end,
+          AlignmentAnnotation alignmentAnnotation)
+  {
+    // mangle the alignmentAnnotation annotation array
+    Vector<Annotation[]> annels = new Vector<>();
+    Annotation[] els = null;
+    int blockStart = start;
+    int blockEnd = end;
+    int w = 0;
+
+    Iterator<int[]> regions = new BoundedHiddenColsIterator(start, end,
+            false);
+    while (regions.hasNext())
+    {
+      int[] region = regions.next();
+      blockStart = Math.min(blockStart, region[1] + 1);
+      blockEnd = Math.min(blockEnd, region[0]);
 
-        for (Annotation[] chnk : annels)
-        {
-          System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
-                  chnk.length);
-          w += chnk.length;
-        }
+      els = new Annotation[blockEnd - blockStart];
+      annels.addElement(els);
+      System.arraycopy(alignmentAnnotation.annotations, blockStart, els, 0,
+              els.length);
+      w += els.length;
+
+      blockStart = region[1] + 1;
+      blockEnd = end;
+    }
+
+    if (end > blockStart)
+    {
+      els = new Annotation[end - blockStart + 1];
+      annels.addElement(els);
+      if ((els.length
+              + blockStart) <= alignmentAnnotation.annotations.length)
+      {
+        // copy just the visible segment of the annotation row
+        System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
+                0, els.length);
       }
       else
       {
-        alignmentAnnotation.restrict(start, end);
+        // copy to the end of the annotation row
+        System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
+                0, (alignmentAnnotation.annotations.length - blockStart));
       }
-    } finally
+      w += els.length;
+    }
+
+    if (w != 0)
     {
-      LOCK.readLock().unlock();
+      alignmentAnnotation.annotations = new Annotation[w];
+
+      w = 0;
+      for (Annotation[] chnk : annels)
+      {
+        System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
+                chnk.length);
+        w += chnk.length;
+      }
     }
   }
 
@@ -1481,6 +1401,9 @@ public class HiddenColumns
     }
   }
 
+  /**
+   * Return an iterator over the hidden regions
+   */
   public Iterator<int[]> iterator()
   {
     if (hiddenColumns != null)
@@ -1494,28 +1417,66 @@ public class HiddenColumns
     }
   }
 
+  /**
+   * Return a bounded iterator over the hidden regions
+   * 
+   * @param start
+   *          position to start from (inclusive, absolute column position)
+   * @param end
+   *          position to end at (inclusive, absolute column position)
+   * @return
+   */
   public Iterator<int[]> getBoundedIterator(int start, int end)
   {
     return new BoundedHiddenColsIterator(start, end, true);
   }
 
+  /**
+   * Return a bounded iterator over the *visible* start positions of hidden
+   * regions
+   * 
+   * @param start
+   *          position to start from (inclusive, visible column position)
+   * @param end
+   *          position to end at (inclusive, visible column position)
+   */
   public Iterator<Integer> getBoundedStartIterator(int start, int end)
   {
     return new BoundedStartRegionIterator(start, end, true);
   }
 
+  /**
+   * Return an iterator over visible columns between the given start and end
+   * boundaries
+   * 
+   * @param start
+   *          first column (inclusive)
+   * @param end
+   *          last column (inclusive)
+   */
   public Iterator<Integer> getVisibleColsIterator(int start, int end)
   {
     return new VisibleColsIterator(start, end, true);
   }
 
   /**
-   * An iterator which iterates over hidden column regions in a range.
+   * return an iterator over visible segments between the given start and end
+   * boundaries
    * 
-   * @author kmourao
-   *
+   * @param start
+   *          (first column inclusive from 0)
+   * @param end
+   *          (last column - not inclusive)
    */
-  class BoundedHiddenColsIterator implements Iterator<int[]>
+  public Iterator<int[]> getVisContigsIterator(int start, int end)
+  {
+    return new VisibleContigsIterator(start, end, true);
+  }
+
+  /**
+   * An iterator which iterates over hidden column regions in a range.
+   */
+  private class BoundedHiddenColsIterator implements Iterator<int[]>
   {
     private int start; // start position to iterate from
 
@@ -1616,12 +1577,17 @@ public class HiddenColumns
     }
   }
 
-  class BoundedStartRegionIterator implements Iterator<Integer>
+  /**
+   * An iterator which iterates over visible start positions of hidden column
+   * regions in a range.
+   */
+  private class BoundedStartRegionIterator implements Iterator<Integer>
   {
+    // start position to iterate from
+    private int start;
 
-    private int start; // start position to iterate from
-
-    private int end; // end position to iterate to
+    // end position to iterate to
+    private int end;
 
     // current index in hiddenColumns
     private int currentPosition = 0;
@@ -1701,6 +1667,11 @@ public class HiddenColumns
       return (currentPosition < positions.size());
     }
 
+    /**
+     * Get next hidden region start position
+     * 
+     * @return the start position in *visible* coordinates
+     */
     @Override
     public Integer next()
     {
@@ -1710,7 +1681,7 @@ public class HiddenColumns
     }
   }
 
-  public class VisibleColsIterator implements Iterator<Integer>
+  private class VisibleColsIterator implements Iterator<Integer>
   {
     private int last;
 
@@ -1722,7 +1693,7 @@ public class HiddenColumns
 
     private int lasthiddenregion;
 
-    public VisibleColsIterator(int firstcol, int lastcol, boolean useCopy)
+    VisibleColsIterator(int firstcol, int lastcol, boolean useCopy)
     {
       last = lastcol;
       current = firstcol;
@@ -1838,4 +1809,87 @@ public class HiddenColumns
       throw new UnsupportedOperationException();
     }
   }
+
+  /**
+   * An iterator which iterates over visible regions in a range.
+   */
+  private class VisibleContigsIterator implements Iterator<int[]>
+  {
+    private List<int[]> vcontigs = new ArrayList<>();
+
+    private int currentPosition = 0;
+
+    VisibleContigsIterator(int start, int end, boolean usecopy)
+    {
+      try
+      {
+        if (usecopy)
+        {
+          LOCK.readLock().lock();
+        }
+
+        if (hiddenColumns != null && hiddenColumns.size() > 0)
+        {
+          int vstart = start;
+          int hideStart;
+          int hideEnd;
+
+          for (int[] region : hiddenColumns)
+          {
+            hideStart = region[0];
+            hideEnd = region[1];
+
+            // navigate to start
+            if (hideEnd < vstart)
+            {
+              continue;
+            }
+            if (hideStart > vstart)
+            {
+              int[] contig = new int[] { vstart, hideStart - 1 };
+              vcontigs.add(contig);
+            }
+            vstart = hideEnd + 1;
+
+            // exit if we're past the end
+            if (vstart >= end)
+            {
+              break;
+            }
+          }
+
+          if (vstart < end)
+          {
+            int[] contig = new int[] { vstart, end - 1 };
+            vcontigs.add(contig);
+          }
+        }
+        else
+        {
+          int[] contig = new int[] { start, end - 1 };
+          vcontigs.add(contig);
+        }
+      } finally
+      {
+        if (usecopy)
+        {
+          LOCK.readLock().unlock();
+        }
+      }
+    }
+
+    @Override
+    public boolean hasNext()
+    {
+      return (currentPosition < vcontigs.size());
+    }
+
+    @Override
+    public int[] next()
+    {
+      int[] result = vcontigs.get(currentPosition);
+      currentPosition++;
+      return result;
+    }
+  }
 }
index 657f8f3..86dcbca 100644 (file)
@@ -60,6 +60,7 @@ import java.awt.FontMetrics;
 import java.awt.Rectangle;
 import java.util.ArrayList;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Vector;
 
@@ -476,10 +477,10 @@ public class AlignViewport extends AlignmentViewport
    *          area
    * @return
    */
-  public List<int[]> getViewAsVisibleContigs(boolean selectedRegionOnly)
+  public Iterator<int[]> getViewAsVisibleContigs(boolean selectedRegionOnly)
   {
-    List<int[]> viscontigs = null;
-    int start = 0, end = 0;
+    int start = 0;
+    int end = 0;
     if (selectedRegionOnly && selectionGroup != null)
     {
       start = selectionGroup.getStartRes();
@@ -489,8 +490,7 @@ public class AlignViewport extends AlignmentViewport
     {
       end = alignment.getWidth();
     }
-    viscontigs = alignment.getHiddenColumns().getVisibleContigs(start, end);
-    return viscontigs;
+    return (alignment.getHiddenColumns().getVisContigsIterator(start, end));
   }
 
   /**
index 3bf7c24..ac72e93 100644 (file)
@@ -42,7 +42,6 @@ import java.io.IOException;
 import java.util.Hashtable;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
-import java.util.List;
 
 import javax.swing.JInternalFrame;
 
@@ -1075,15 +1074,15 @@ public class VamsasApplication implements SelectionSource, VamsasSource
                   }
                   else
                   {
-                    // int[] intervals = colsel.getVisibleContigs(
-                    // seqsel.getStartRes(), seqsel.getEndRes() + 1);
-                    List<int[]> intervals = hidden.getVisibleContigs(
-                            seqsel.getStartRes(), seqsel.getEndRes() + 1);
-                    for (int[] region : intervals)
+                    Iterator<int[]> intervals = hidden
+                            .getVisContigsIterator(seqsel.getStartRes(),
+                                    seqsel.getEndRes() + 1);
+                    while (intervals.hasNext())
                     {
+                      int[] region = intervals.next();
                       Seg s = new Seg();
-                      s.setStart(region[0] + 1); // vamsas indices begin at
-                      // 1, not zero.
+                      s.setStart(region[0] + 1); // vamsas indices begin at 1,
+                                                 // not zero.
                       s.setEnd(region[1] + 1);
                       s.setInclusive(true);
                       range.addSeg(s);
index 96ac0c3..1ed846a 100644 (file)
@@ -38,8 +38,7 @@ import jalview.io.FileFormat;
 import jalview.io.FormatAdapter;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Iterator;
 
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -137,9 +136,7 @@ public class DnaTest
             FileFormat.Fasta);
     HiddenColumns cs = new HiddenColumns();
     AlignViewportI av = new AlignViewport(alf, cs);
-    int[] contig = new int[] { 0, alf.getWidth() - 1 };
-    List<int[]> contigs = new ArrayList<>();
-    contigs.add(contig);
+    Iterator<int[]> contigs = cs.getVisContigsIterator(0, alf.getWidth());
     Dna dna = new Dna(av, contigs);
     AlignmentI translated = dna.translateCdna();
     assertNotNull("Couldn't do a full width translation of test data.",
@@ -168,7 +165,8 @@ public class DnaTest
         cs.hideColumns(0, ipos - 1);
       }
       cs.hideColumns(ipos + vwidth, alf.getWidth());
-      List<int[]> vcontigs = cs.getVisibleContigs(0, alf.getWidth());
+      Iterator<int[]> vcontigs = cs.getVisContigsIterator(0,
+              alf.getWidth());
       AlignViewportI av = new AlignViewport(alf, cs);
       Dna dna = new Dna(av, vcontigs);
       AlignmentI transAlf = dna.translateCdna();
@@ -195,9 +193,7 @@ public class DnaTest
             DataSourceType.PASTE, FileFormat.Fasta);
     HiddenColumns cs = new HiddenColumns();
     AlignViewportI av = new AlignViewport(alf, cs);
-    int[] contig = new int[] { 0, alf.getWidth() - 1 };
-    List<int[]> contigs = new ArrayList<>();
-    contigs.add(contig);
+    Iterator<int[]> contigs = cs.getVisContigsIterator(0, alf.getWidth());
     Dna dna = new Dna(av, contigs);
     AlignmentI translated = dna.translateCdna();
     String aa = translated.getSequenceAt(0).getSequenceAsString();
@@ -221,9 +217,7 @@ public class DnaTest
     cs.hideColumns(24, 35); // hide codons 9-12
     cs.hideColumns(177, 191); // hide codons 60-64
     AlignViewportI av = new AlignViewport(alf, cs);
-    int[] contig = new int[] { 0, alf.getWidth() - 1 };
-    List<int[]> contigs = new ArrayList<>();
-    contigs.add(contig);
+    Iterator<int[]> contigs = cs.getVisContigsIterator(0, alf.getWidth());
     Dna dna = new Dna(av, contigs);
     AlignmentI translated = dna.translateCdna();
     String aa = translated.getSequenceAt(0).getSequenceAsString();
@@ -309,9 +303,7 @@ public class DnaTest
             .generate(12, 8, 97, 5, 5);
     HiddenColumns cs = new HiddenColumns();
     AlignViewportI av = new AlignViewport(cdna, cs);
-    int[] contig = new int[] { 0, cdna.getWidth() - 1 };
-    List<int[]> contigs = new ArrayList<>();
-    contigs.add(contig);
+    Iterator<int[]> contigs = cs.getVisContigsIterator(0, cdna.getWidth());
     Dna dna = new Dna(av, contigs);
     AlignmentI translated = dna.translateCdna();
 
@@ -327,9 +319,7 @@ public class DnaTest
     }
     AlignmentI cdnaReordered = new Alignment(sorted);
     av = new AlignViewport(cdnaReordered, cs);
-    contig = new int[] { 0, cdna.getWidth() - 1 };
-    contigs = new ArrayList<>();
-    contigs.add(contig);
+    contigs = cs.getVisContigsIterator(0, cdna.getWidth());
     dna = new Dna(av, contigs);
     AlignmentI translated2 = dna.translateCdna();
 
@@ -561,9 +551,7 @@ public class DnaTest
 
     HiddenColumns cs = new HiddenColumns();
     AlignViewportI av = new AlignViewport(al, cs);
-    int[] contig = new int[] { 0, al.getWidth() - 1 };
-    List<int[]> contigs = new ArrayList<>();
-    contigs.add(contig);
+    Iterator<int[]> contigs = cs.getVisContigsIterator(0, al.getWidth());
     Dna testee = new Dna(av, contigs);
     AlignmentI reversed = testee.reverseCdna(false);
     assertEquals(1, reversed.getHeight());
index 142762b..a3d4623 100644 (file)
@@ -184,12 +184,14 @@ public class HiddenColumnsTest
   }
 
   @Test(groups = { "Functional" })
-  public void testGetVisibleContigs()
+  public void testVisibleContigsIterator()
   {
     HiddenColumns cs = new HiddenColumns();
 
-    List<int[]> visible = cs.getVisibleContigs(3, 10);
-    assertEquals("[3, 9]", Arrays.toString(visible.get(0)));
+    Iterator<int[]> visible = cs.getVisContigsIterator(3, 10);
+    int[] region = visible.next();
+    assertEquals("[3, 9]", Arrays.toString(region));
+    assertFalse(visible.hasNext());
 
     cs.hideColumns(3, 6);
     cs.hideColumns(8, 9);
@@ -198,30 +200,44 @@ public class HiddenColumnsTest
     // Test both ends visible region
 
     // start position is inclusive, end position exclusive
-    visible = cs.getVisibleContigs(1, 13);
-    assertEquals("[1, 2]", Arrays.toString(visible.get(0)));
-    assertEquals("[7, 7]", Arrays.toString(visible.get(1)));
-    assertEquals("[10, 11]", Arrays.toString(visible.get(2)));
+    visible = cs.getVisContigsIterator(1, 13);
+    region = visible.next();
+    assertEquals("[1, 2]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[7, 7]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[10, 11]", Arrays.toString(region));
+    assertFalse(visible.hasNext());
 
     // Test start hidden, end visible
-    visible = cs.getVisibleContigs(4, 14);
-    assertEquals("[7, 7]", Arrays.toString(visible.get(0)));
-    assertEquals("[10, 11]", Arrays.toString(visible.get(1)));
-    assertEquals("[13, 13]", Arrays.toString(visible.get(2)));
+    visible = cs.getVisContigsIterator(4, 14);
+    region = visible.next();
+    assertEquals("[7, 7]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[10, 11]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[13, 13]", Arrays.toString(region));
+    assertFalse(visible.hasNext());
 
     // Test start hidden, end hidden
-    visible = cs.getVisibleContigs(3, 10);
-    assertEquals("[7, 7]", Arrays.toString(visible.get(0)));
+    visible = cs.getVisContigsIterator(3, 10);
+    region = visible.next();
+    assertEquals("[7, 7]", Arrays.toString(region));
+    assertFalse(visible.hasNext());
 
     // Test start visible, end hidden
-    visible = cs.getVisibleContigs(0, 13);
-    assertEquals("[0, 2]", Arrays.toString(visible.get(0)));
-    assertEquals("[7, 7]", Arrays.toString(visible.get(1)));
-    assertEquals("[10, 11]", Arrays.toString(visible.get(2)));
+    visible = cs.getVisContigsIterator(0, 13);
+    region = visible.next();
+    assertEquals("[0, 2]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[7, 7]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[10, 11]", Arrays.toString(region));
+    assertFalse(visible.hasNext());
 
     // Test empty result
-    visible = cs.getVisibleContigs(4, 6);
-    assertEquals(0, visible.size());
+    visible = cs.getVisContigsIterator(4, 6);
+    assertFalse(visible.hasNext());
   }
 
   @Test(groups = { "Functional" })
@@ -976,18 +992,22 @@ public class HiddenColumnsTest
             false);
 
     // confirm that original contigs are as expected
-    List<int[]> visible = hidden.getVisibleContigs(0, 25);
-    assertEquals("[0, 14]", Arrays.toString(visible.get(0)));
-    assertEquals("[18, 24]", Arrays.toString(visible.get(1)));
+    Iterator<int[]> visible = hidden.getVisContigsIterator(0, 25);
+    int[] region = visible.next();
+    assertEquals("[0, 14]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[18, 24]", Arrays.toString(region));
 
     // propagate insertions
     HiddenColumns result = HiddenColumns.propagateInsertions(profileseq, al,
             view);
 
     // confirm that the contigs have changed to account for the gaps
-    visible = result.getVisibleContigs(0, 25);
-    assertEquals("[0, 10]", Arrays.toString(visible.get(0)));
-    assertEquals("[14, 24]", Arrays.toString(visible.get(1)));
+    visible = result.getVisContigsIterator(0, 25);
+    region = visible.next();
+    assertEquals("[0, 10]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[14, 24]", Arrays.toString(region));
 
     // confirm the alignment has been changed so that the other sequences have
     // gaps inserted where the columns are hidden
@@ -1030,18 +1050,24 @@ public class HiddenColumnsTest
             false);
 
     // confirm that original contigs are as expected
-    List<int[]> visible = hidden.getVisibleContigs(0, 20);
-    assertEquals("[0, 6]", Arrays.toString(visible.get(0)));
-    assertEquals("[11, 19]", Arrays.toString(visible.get(1)));
+    Iterator<int[]> visible = hidden.getVisContigsIterator(0, 20);
+    int[] region = visible.next();
+    assertEquals("[0, 6]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[11, 19]", Arrays.toString(region));
+    assertFalse(visible.hasNext());
 
     // propagate insertions
     HiddenColumns result = HiddenColumns.propagateInsertions(profileseq, al,
             view);
 
     // confirm that the contigs have changed to account for the gaps
-    visible = result.getVisibleContigs(0, 20);
-    assertEquals("[0, 4]", Arrays.toString(visible.get(0)));
-    assertEquals("[7, 19]", Arrays.toString(visible.get(1)));
+    visible = result.getVisContigsIterator(0, 20);
+    region = visible.next();
+    assertEquals("[0, 4]", Arrays.toString(region));
+    region = visible.next();
+    assertEquals("[7, 19]", Arrays.toString(region));
+    assertFalse(visible.hasNext());
 
     // confirm the alignment has been changed so that the other sequences have
     // gaps inserted where the columns are hidden