From bdb7e11f6bad25d24bbdc0f2f509fc8ae2f485bb Mon Sep 17 00:00:00 2001 From: kiramt Date: Mon, 20 Nov 2017 14:25:39 +0000 Subject: [PATCH] JAL-2759 cursor option for BoundedStartRegionIterator --- .../datamodel/BoundedStartRegionIterator.java | 62 +++++++ src/jalview/datamodel/HiddenColumns.java | 188 +++----------------- src/jalview/datamodel/HiddenColumnsCursor.java | 10 +- src/jalview/datamodel/HiddenCursorPosition.java | 10 +- src/jalview/datamodel/VisibleContigsIterator.java | 4 +- 5 files changed, 97 insertions(+), 177 deletions(-) diff --git a/src/jalview/datamodel/BoundedStartRegionIterator.java b/src/jalview/datamodel/BoundedStartRegionIterator.java index 831e906..d68eeeb 100644 --- a/src/jalview/datamodel/BoundedStartRegionIterator.java +++ b/src/jalview/datamodel/BoundedStartRegionIterator.java @@ -72,6 +72,68 @@ public class BoundedStartRegionIterator implements Iterator } + /** + * 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 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() { diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index 48cfb42..a81d3bd 100644 --- a/src/jalview/datamodel/HiddenColumns.java +++ b/src/jalview/datamodel/HiddenColumns.java @@ -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 getVisContigsIterator(int start, int end) { @@ -1484,172 +1497,23 @@ public class HiddenColumns public Iterator 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 - { - private List 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(); } } } diff --git a/src/jalview/datamodel/HiddenColumnsCursor.java b/src/jalview/datamodel/HiddenColumnsCursor.java index 3284504..a002232 100644 --- a/src/jalview/datamodel/HiddenColumnsCursor.java +++ b/src/jalview/datamodel/HiddenColumnsCursor.java @@ -34,7 +34,7 @@ public class HiddenColumnsCursor // Could be done with synchronisation but benchmarking shows this way is 2x // faster private final AtomicReference 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; } diff --git a/src/jalview/datamodel/HiddenCursorPosition.java b/src/jalview/datamodel/HiddenCursorPosition.java index 606a7c5..3c0b17a 100644 --- a/src/jalview/datamodel/HiddenCursorPosition.java +++ b/src/jalview/datamodel/HiddenCursorPosition.java @@ -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; - } } diff --git a/src/jalview/datamodel/VisibleContigsIterator.java b/src/jalview/datamodel/VisibleContigsIterator.java index ff060ac..d98121a 100644 --- a/src/jalview/datamodel/VisibleContigsIterator.java +++ b/src/jalview/datamodel/VisibleContigsIterator.java @@ -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 { -- 1.7.10.2