X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2FHiddenColumns.java;h=fb1961eca932ae4bfbf359e2841fb392e67e0f09;hb=a3c835f0495ade5c3ae7968dd9727c03710d870b;hp=41bd16bd1394cb6017e44abefbf1eb6c1e8e6fd8;hpb=b2aa974228b87c7aefc1f637fcae8ca30a920c80;p=jalview.git diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index 41bd16b..fb1961e 100644 --- a/src/jalview/datamodel/HiddenColumns.java +++ b/src/jalview/datamodel/HiddenColumns.java @@ -25,7 +25,6 @@ import java.util.BitSet; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; -import java.util.Vector; import java.util.concurrent.locks.ReentrantReadWriteLock; public class HiddenColumns @@ -61,7 +60,12 @@ public class HiddenColumns { if (copy.hiddenColumns != null) { - hiddenColumns = copy.copyHiddenRegionsToArrayList(0); + hiddenColumns = new ArrayList<>(); + Iterator it = copy.iterator(); + while (it.hasNext()) + { + hiddenColumns.add(it.next()); + } } } } finally @@ -129,7 +133,7 @@ public class HiddenColumns { LOCK.readLock().lock(); StringBuilder regionBuilder = new StringBuilder(); - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); while (it.hasNext()) { int[] range = it.next(); @@ -158,7 +162,7 @@ public class HiddenColumns { LOCK.readLock().lock(); int size = 0; - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); while (it.hasNext()) { int[] range = it.next(); @@ -220,7 +224,7 @@ public class HiddenColumns return false; } - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); Iterator thatit = that.iterator(); while (it.hasNext()) { @@ -252,7 +256,7 @@ public class HiddenColumns LOCK.readLock().lock(); int result = column; - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); while (it.hasNext()) { int[] region = it.next(); @@ -287,7 +291,7 @@ public class HiddenColumns int[] region = null; if (hiddenColumns != null) { - Iterator it = new LocalBoundedHiddenColsIterator(0, + Iterator it = new RegionsIterator(0, hiddenColumn); while (it.hasNext()) { @@ -306,8 +310,8 @@ public class HiddenColumns // earlier hidden columns. // Calculate the difference between the actual hidden col position // and region[0]-1, and then subtract from result to convert result - // from - // the adjusted hiddenColumn value to the adjusted region[0]-1 value + // from the adjusted hiddenColumn value to the adjusted region[0]-1 + // value. // However, if the region begins at 0 we cannot return region[0]-1 // just return 0 @@ -344,64 +348,48 @@ public class HiddenColumns { try { - LOCK.readLock().lock(); int distance = visibleDistance; // in case startColumn is in a hidden region, move it to the left int start = adjustForHiddenColumns(findColumnPosition(startColumn)); - // get index of hidden region to left of start - int index = getHiddenIndexLeft(start); - if (index == -1) - { - // no hidden regions to left of startColumn - return start - distance; - } - - // walk backwards through the alignment subtracting the counts of visible - // columns from distance - int[] region; - int gap = 0; - int nextstart = start; + Iterator it = new ReverseRegionsIterator(0, start); - while ((index > -1) && (distance - gap > 0)) + while (it.hasNext() && (distance > 0)) { - // subtract the gap to right of region from distance - distance -= gap; - start = nextstart; - - // calculate the next gap - region = hiddenColumns.get(index); - gap = start - region[1]; + int[] region = it.next(); - // set start to just to left of current region - nextstart = region[0] - 1; - index--; + if (start > region[1]) + { + // subtract the gap to right of region from distance + if (start - region[1] <= distance) + { + distance -= start - region[1]; + start = region[0] - 1; + } + else + { + start = start - distance; + distance = 0; + } + } } - if (distance - gap > 0) - { - // fell out of loop because there are no more hidden regions - distance -= gap; - return nextstart - distance; - } return start - distance; + } finally { LOCK.readLock().unlock(); } - } - - /** * This method returns the rightmost limit of a region of an alignment with * hidden columns. In otherwords, the next hidden column. * - * @param index - * int + * @param alPos + * the (visible) alignmentPosition to find the next hidden column for */ public int getHiddenBoundaryRight(int alPos) { @@ -410,33 +398,30 @@ public class HiddenColumns LOCK.readLock().lock(); if (hiddenColumns != null) { - int index = 0; - do + Iterator it = new RegionsIterator(); + while (it.hasNext()) { - int[] region = hiddenColumns.get(index); + int[] region = it.next(); if (alPos < region[0]) { return region[0]; } - - index++; - } while (index < hiddenColumns.size()); + } } - return alPos; } finally { LOCK.readLock().unlock(); } - } /** * This method returns the leftmost limit of a region of an alignment with * hidden columns. In otherwords, the previous hidden column. * - * @param index - * int + * @param alPos + * the (visible) alignmentPosition to find the previous hidden column + * for */ public int getHiddenBoundaryLeft(int alPos) { @@ -444,19 +429,14 @@ public class HiddenColumns { LOCK.readLock().lock(); - if (hiddenColumns != null) + Iterator it = new ReverseRegionsIterator(0, alPos); + while (it.hasNext()) { - int index = hiddenColumns.size() - 1; - do + int[] region = it.next(); + if (alPos > region[1]) { - int[] region = hiddenColumns.get(index); - if (alPos > region[1]) - { - return region[1]; - } - - index--; - } while (index > -1); + return region[1]; + } } return alPos; @@ -467,47 +447,12 @@ public class HiddenColumns } /** - * This method returns the index of the hidden region to the left of a column - * position. If the column is in a hidden region it returns the index of the - * region to the left. If there is no hidden region to the left it returns -1. - * - * @param pos - * int - */ - private int getHiddenIndexLeft(int pos) - { - try - { - - LOCK.readLock().lock(); - if (hiddenColumns != null) - { - int index = hiddenColumns.size() - 1; - do - { - int[] region = hiddenColumns.get(index); - if (pos > region[1]) - { - return index; - } - - index--; - } while (index > -1); - } - - return -1; - } finally - { - LOCK.readLock().unlock(); - } - - } - - /** - * Adds the specified column range to the hidden columns + * Adds the specified column range to the hidden columns collection * * @param start + * start of range to add (absolute position in alignment) * @param end + * end of range to add (absolute position in alignment) */ public void hideColumns(int start, int end) { @@ -547,53 +492,7 @@ public class HiddenColumns boolean added = false; for (int i = 0; !added && i < hiddenColumns.size(); i++) { - int[] region = hiddenColumns.get(i); - - if (end < region[0] - 1) - { - /* - * insert discontiguous preceding range - */ - hiddenColumns.add(i, new int[] { start, end }); - added = true; - } - else if (end <= region[1]) - { - /* - * new range overlaps existing, or is contiguous preceding it - adjust - * start column - */ - region[0] = Math.min(region[0], start); - added = true; - } - else if (start <= region[1] + 1) - { - /* - * new range overlaps existing, or is contiguous following it - adjust - * start and end columns - */ - region[0] = Math.min(region[0], start); - region[1] = Math.max(region[1], end); - - /* - * also update or remove any subsequent ranges - * that are overlapped - */ - while (i < hiddenColumns.size() - 1) - { - int[] nextRegion = hiddenColumns.get(i + 1); - if (nextRegion[0] > end + 1) - { - /* - * gap to next hidden range - no more to update - */ - break; - } - region[1] = Math.max(nextRegion[1], end); - hiddenColumns.remove(i + 1); - } - added = true; - } + added = insertRangeAtRegion(i, start, end); } // for } } finally @@ -605,13 +504,73 @@ public class HiddenColumns } } + private boolean insertRangeAtRegion(int i, int start, int end) + { + boolean added = false; + + int[] region = hiddenColumns.get(i); + if (end < region[0] - 1) + { + /* + * insert discontiguous preceding range + */ + hiddenColumns.add(i, new int[] { start, end }); + added = true; + } + else if (end <= region[1]) + { + /* + * new range overlaps existing, or is contiguous preceding it - adjust + * start column + */ + region[0] = Math.min(region[0], start); + added = true; + } + else if (start <= region[1] + 1) + { + /* + * new range overlaps existing, or is contiguous following it - adjust + * start and end columns + */ + region[0] = Math.min(region[0], start); + region[1] = Math.max(region[1], end); + + /* + * also update or remove any subsequent ranges + * that are overlapped + */ + while (i < hiddenColumns.size() - 1) + { + int[] nextRegion = hiddenColumns.get(i + 1); + if (nextRegion[0] > end + 1) + { + /* + * gap to next hidden range - no more to update + */ + break; + } + region[1] = Math.max(nextRegion[1], end); + hiddenColumns.remove(i + 1); + } + added = true; + } + return added; + } + + /** + * Answers if a column in the alignment is visible + * + * @param column + * absolute position of column in the alignment + * @return true if column is visible + */ public boolean isVisible(int column) { try { LOCK.readLock().lock(); - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); while (it.hasNext()) { int[] region = it.next(); @@ -628,31 +587,17 @@ public class HiddenColumns } } - private ArrayList copyHiddenRegionsToArrayList(int startIndex) - { - int size = 0; - if (hiddenColumns != null) - { - size = hiddenColumns.size(); - } - ArrayList copy = new ArrayList<>(size); - - for (int i = startIndex, j = size; i < j; i++) - { - int[] rh; - int[] cp; - rh = hiddenColumns.get(i); - if (rh != null) - { - cp = new int[rh.length]; - System.arraycopy(rh, 0, cp, 0, rh.length); - copy.add(cp); - } - } - - return copy; - } - + /** + * Get the visible sections of a set of sequences + * + * @param start + * sequence position to start from + * @param end + * sequence position to end at + * @param seqs + * an array of sequences + * @return an array of strings encoding the visible parts of each sequence + */ public String[] getVisibleSequenceStrings(int start, int end, SequenceI[] seqs) { @@ -725,7 +670,7 @@ public class HiddenColumns // Simply walk along the sequence whilst watching for hidden column // boundaries - Iterator regions = new LocalBoundedHiddenColsIterator(); + Iterator regions = new RegionsIterator(); int hideStart = seq.getLength(); int hideEnd = -1; int visPrev = 0; @@ -825,7 +770,7 @@ public class HiddenColumns AlignmentAnnotation alignmentAnnotation) { // mangle the alignmentAnnotation annotation array - Vector annels = new Vector<>(); + ArrayList annels = new ArrayList<>(); Annotation[] els = null; int w = 0; @@ -860,7 +805,7 @@ public class HiddenColumns } els = new Annotation[annotationLength]; - annels.addElement(els); + annels.add(els); System.arraycopy(alignmentAnnotation.annotations, block[0], els, 0, copylength); w += annotationLength; @@ -942,7 +887,7 @@ public class HiddenColumns try { LOCK.writeLock().lock(); - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); while (it.hasNext()) { int[] region = it.next(); @@ -970,7 +915,7 @@ public class HiddenColumns try { LOCK.writeLock().lock(); - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); while (it.hasNext()) { int[] region = it.next(); @@ -1064,7 +1009,7 @@ public class HiddenColumns // of // preceding visible gaps // update hidden columns at the same time - Iterator regions = new LocalBoundedHiddenColsIterator(); + Iterator regions = new RegionsIterator(); ArrayList newhidden = new ArrayList<>(); int numGapsBefore = 0; @@ -1169,7 +1114,7 @@ public class HiddenColumns { LOCK.readLock().lock(); int hashCode = 1; - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); while (it.hasNext()) { int[] hidden = it.next(); @@ -1221,7 +1166,7 @@ public class HiddenColumns { return; } - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); while (it.hasNext()) { int[] range = it.next(); @@ -1257,7 +1202,7 @@ public class HiddenColumns return new int[] { startPos, endPos }; } - Iterator it = new LocalBoundedHiddenColsIterator(); + Iterator it = new RegionsIterator(); while (it.hasNext()) { int[] range = it.next(); @@ -1305,7 +1250,7 @@ public class HiddenColumns int adjres = adjustForHiddenColumns(res); int[] reveal = null; - Iterator it = new LocalBoundedHiddenColsIterator(adjres - 2, + Iterator it = new RegionsIterator(adjres - 2, adjres + 2); while (it.hasNext()) { @@ -1421,14 +1366,17 @@ public class HiddenColumns /** * A local iterator which iterates over hidden column regions in a range. - * Works with the actual hidden columns collection (so locking before use may - * be required). + * Intended for use ONLY within the HiddenColumns class, because it works + * directly with the hiddenColumns collection without locking (callers should + * lock hiddenColumns). */ - private class LocalBoundedHiddenColsIterator implements Iterator + private class RegionsIterator implements Iterator { - private int start; // start position to iterate from + // start position to iterate from + private int start; - private int end; // end position to iterate to + // end position to iterate to + private int end; // current index in hiddenColumns private int currentPosition = 0; @@ -1436,20 +1384,24 @@ public class HiddenColumns // current column in hiddenColumns private int[] nextRegion = null; - LocalBoundedHiddenColsIterator(int lowerBound, int upperBound) + // Constructor with bounds + RegionsIterator(int lowerBound, int upperBound) { init(lowerBound, upperBound); } - LocalBoundedHiddenColsIterator() + // Unbounded constructor + RegionsIterator() { if (hiddenColumns != null) { + // iterator over full hiddenColumns collection int last = hiddenColumns.get(hiddenColumns.size() - 1)[1]; init(0, last); } else { + // empty iterator init(0, 0); } } @@ -1462,9 +1414,6 @@ public class HiddenColumns * lower bound to iterate from * @param upperBound * upper bound to iterate to - * @param useCopyCols - * whether to make a local copy of hiddenColumns for iteration (set - * to true if calling from outwith the HiddenColumns class) */ private void init(int lowerBound, int upperBound) { @@ -1513,14 +1462,98 @@ public class HiddenColumns } /** + * A local iterator which reverse iterates over hidden column regions in a + * range. Intended for use ONLY within the HiddenColumns class, because it + * works directly with the hiddenColumns collection without locking (callers + * should lock hiddenColumns). + */ + private class ReverseRegionsIterator implements Iterator + { + // start position to iterate to + private int start; + + // end position to iterate from + private int end; + + // current index in hiddenColumns + private int currentPosition = 0; + + // current column in hiddenColumns + private int[] nextRegion = null; + + // Constructor with bounds + ReverseRegionsIterator(int lowerBound, int upperBound) + { + init(lowerBound, upperBound); + } + + /** + * Construct an iterator over hiddenColums bounded at + * [lowerBound,upperBound] + * + * @param lowerBound + * lower bound to iterate to + * @param upperBound + * upper bound to iterate from + */ + private void init(int lowerBound, int upperBound) + { + start = lowerBound; + end = upperBound; + + if (hiddenColumns != null) + { + // iterate until a region overlaps with [start,end] + currentPosition = hiddenColumns.size() - 1; + while (currentPosition >= 0 + && hiddenColumns.get(currentPosition)[1] > end) + { + currentPosition--; + } + if (currentPosition >= 0) + { + nextRegion = hiddenColumns.get(currentPosition); + } + } + } + + @Override + public boolean hasNext() + { + return (hiddenColumns != null) && (nextRegion != null) + && (nextRegion[1] >= start); + } + + @Override + public int[] next() + { + int[] region = nextRegion; + currentPosition--; + if (currentPosition >= 0) + { + nextRegion = hiddenColumns.get(currentPosition); + } + else + { + nextRegion = null; + } + return region; + } + + } + + /** * An iterator which iterates over hidden column regions in a range. Works - * with a copy of the hidden columns collection. + * with a copy of the hidden columns collection. Intended to be used by + * callers OUTSIDE of HiddenColumns. */ private class BoundedHiddenColsIterator implements Iterator { - private int start; // start position to iterate from + // start position to iterate from + private int start; - private int end; // end position to iterate to + // end position to iterate to + private int end; // current index in hiddenColumns private int currentPosition = 0; @@ -1531,6 +1564,9 @@ public class HiddenColumns // local copy or reference to hiddenColumns private List localHidden; + /** + * Unbounded constructor + */ BoundedHiddenColsIterator() { if (hiddenColumns != null)