X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2FHiddenColumns.java;h=2d43f025f7bc6746b216f37d9aee2feb13330bb1;hb=033962da90469745dd6639a1346ecbcbe2ed071f;hp=fd4a9b5493f56348c130af1cb92eeec99695d007;hpb=ecdbc96815298ac853543640881ef8d2384b48a1;p=jalview.git diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index fd4a9b5..2d43f02 100644 --- a/src/jalview/datamodel/HiddenColumns.java +++ b/src/jalview/datamodel/HiddenColumns.java @@ -66,9 +66,6 @@ public class HiddenColumns { private static final int HASH_MULTIPLIER = 31; - private static final int NUMCOLUMNS_RESET = -1; // value of numColumns if it - // needs to be recalculated - private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock(); /* @@ -78,7 +75,8 @@ public class HiddenColumns private HiddenColumnsCursor cursor = new HiddenColumnsCursor(); /* - * cache of the number of hidden columns + * cache of the number of hidden columns: must be kept up to date by methods + * which add or remove hidden columns */ private int numColumns = 0; @@ -171,8 +169,7 @@ public class HiddenColumns if (!hiddenColumns.isEmpty()) { // set up cursor reset values - HiddenCursorPosition cursorPos = cursor.findRegionForColumn(start, - false); + HiddenCursorPosition cursorPos = cursor.findRegionForColumn(start, false); regionindex = cursorPos.getRegionIndex(); if (regionindex > 0) @@ -185,13 +182,13 @@ public class HiddenColumns } } - /* - * new range follows everything else; check first to avoid looping over whole hiddenColumns collection - */ + // new range follows everything else; check first to avoid looping over + // whole hiddenColumns collection if (hiddenColumns.isEmpty() || start > hiddenColumns.get(hiddenColumns.size() - 1)[1]) { hiddenColumns.add(new int[] { start, end }); + numColumns += end - start + 1; } else { @@ -214,10 +211,6 @@ public class HiddenColumns // a lot of reprocessing in large alignments cursor = new HiddenColumnsCursor(hiddenColumns, previndex, prevHiddenCount); - - // reset the number of columns so they will be recounted - resetNumColumns(); - } finally { LOCK.writeLock().unlock(); @@ -247,6 +240,7 @@ public class HiddenColumns * insert discontiguous preceding range */ hiddenColumns.add(i, new int[] { start, end }); + numColumns += end - start + 1; added = true; } else if (end <= region[1]) @@ -255,7 +249,10 @@ public class HiddenColumns * new range overlaps existing, or is contiguous preceding it - adjust * start column */ + int oldstart = region[0]; region[0] = Math.min(region[0], start); + numColumns += oldstart - region[0]; // new columns are between old and + // adjusted starts added = true; } else if (start <= region[1] + 1) @@ -264,32 +261,55 @@ public class HiddenColumns * 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); + insertRangeAtOverlap(i, start, end, region); + added = true; + } + return added; + } - /* - * also update or remove any subsequent ranges - * that are overlapped - */ - while (i < hiddenColumns.size() - 1) + /** + * Insert a range whose start position overlaps an existing region and/or is + * contiguous to the right of the region + * + * @param i + * index to insert at + * @param start + * start of range to insert + * @param end + * end of range to insert + * @param region + * the overlapped/continued region + */ + private void insertRangeAtOverlap(int i, int start, int end, int[] region) + { + int oldstart = region[0]; + int oldend = region[1]; + region[0] = Math.min(region[0], start); + region[1] = Math.max(region[1], end); + + numColumns += oldstart - region[0]; + + /* + * also update or remove any subsequent ranges + * that are overlapped + */ + int endi = i; + while (endi < hiddenColumns.size() - 1) + { + int[] nextRegion = hiddenColumns.get(endi + 1); + if (nextRegion[0] > end + 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); - - // in theory hiddenColumns.subList(i + 1, i + 2).clear() is faster than - // hiddenColumns.remove(i+1) but benchmarking results a bit ambivalent - hiddenColumns.remove(i + 1); + /* + * gap to next hidden range - no more to update + */ + break; } - added = true; + numColumns -= nextRegion[1] - nextRegion[0] + 1; + region[1] = Math.max(nextRegion[1], end); + endi++; } - return added; + numColumns += region[1] - oldend; + hiddenColumns.subList(i + 1, endi + 1).clear(); } /** @@ -307,7 +327,7 @@ public class HiddenColumns hideColumns(r[0], r[1]); } cursor = new HiddenColumnsCursor(hiddenColumns); - resetNumColumns(); + } finally { LOCK.writeLock().unlock(); @@ -332,7 +352,7 @@ public class HiddenColumns } hiddenColumns.clear(); cursor = new HiddenColumnsCursor(hiddenColumns); - resetNumColumns(); + numColumns = 0; } finally { @@ -373,16 +393,7 @@ public class HiddenColumns } int colsToRemove = region[1] - region[0] + 1; hiddenColumns.remove(regionIndex); - - if (hiddenColumns.isEmpty()) - { - resetNumColumns(); - } - else - { - numColumns -= colsToRemove; - } - cursor.updateForDeletedRegion(hiddenColumns); + numColumns -= colsToRemove; } } } @@ -438,39 +449,7 @@ public class HiddenColumns */ public int getSize() { - try - { - LOCK.readLock().lock(); - - if (numColumns == NUMCOLUMNS_RESET) - { - // numColumns is out of date, so recalculate - int size = 0; - - for (int[] range : hiddenColumns) - { - size += range[1] - range[0] + 1; - } - - numColumns = size; - } - - return numColumns; - } finally - { - LOCK.readLock().unlock(); - } - } - - /** - * Reset numColumns so that it gets recalculated. Currently the code does not - * recalculate numColumns on hide/reveal as it requires a full sweep of the - * hidden columns collection / smarter updating. Placeholder here if later on - * a recalculation is added. - */ - private void resetNumColumns() - { - numColumns = NUMCOLUMNS_RESET; + return numColumns; } /** @@ -490,6 +469,10 @@ public class HiddenColumns } } + /** + * Answers true if obj is an instance of HiddenColumns, and holds the same + * array of start-end column ranges as this, else answers false + */ @Override public boolean equals(Object obj) { @@ -703,16 +686,19 @@ public class HiddenColumns { LOCK.readLock().lock(); - int regionindex = cursor.findRegionForColumn(column, false) - .getRegionIndex(); - if (regionindex > -1 && regionindex < hiddenColumns.size()) + if (!hiddenColumns.isEmpty()) { - int[] region = hiddenColumns.get(regionindex); - // already know that column <= region[1] as cursor returns containing - // region or region to right - if (column >= region[0]) + int regionindex = cursor.findRegionForColumn(column, false) + .getRegionIndex(); + if (regionindex > -1 && regionindex < hiddenColumns.size()) { - return false; + int[] region = hiddenColumns.get(regionindex); + // already know that column <= region[1] as cursor returns containing + // region or region to right + if (column >= region[0]) + { + return false; + } } } return true; @@ -790,18 +776,41 @@ public class HiddenColumns */ public void hideColumns(BitSet inserts) { + hideColumns(inserts, 0, inserts.length() - 1); + } + + /** + * Hide columns corresponding to the marked bits, within the range + * [start,end]. Entries in tohide which are outside [start,end] are ignored. + * + * @param tohide + * columns mapped to bits starting from zero + * @param start + * start of range to hide columns within + * @param end + * end of range to hide columns within + */ + private void hideColumns(BitSet tohide, int start, int end) + { try { LOCK.writeLock().lock(); - for (int firstSet = inserts - .nextSetBit(0), lastSet = 0; firstSet >= 0; firstSet = inserts + for (int firstSet = tohide + .nextSetBit(start), lastSet = start; firstSet >= start + && lastSet <= end; firstSet = tohide .nextSetBit(lastSet)) { - lastSet = inserts.nextClearBit(firstSet); - hideColumns(firstSet, lastSet - 1); + lastSet = tohide.nextClearBit(firstSet); + if (lastSet <= end) + { + hideColumns(firstSet, lastSet - 1); + } + else if (firstSet <= end) + { + hideColumns(firstSet, end); + } } cursor = new HiddenColumnsCursor(hiddenColumns); - resetNumColumns(); } finally { LOCK.writeLock().unlock(); @@ -811,6 +820,7 @@ public class HiddenColumns /** * Hide columns corresponding to the marked bits, within the range * [start,end]. Entries in tohide which are outside [start,end] are ignored. + * NB Existing entries in [start,end] are cleared. * * @param tohide * columns mapped to bits starting from zero @@ -819,19 +829,10 @@ public class HiddenColumns * @param end * end of range to hide columns within */ - public void hideColumns(BitSet tohide, int start, int end) + public void clearAndHideColumns(BitSet tohide, int start, int end) { clearHiddenColumnsInRange(start, end); - - // make sure only bits between start and end are set - if (!tohide.isEmpty()) - { - tohide.clear(0, start); - tohide.clear(Math.min(end + 1, tohide.length() + 1), - tohide.length() + 1); - } - - hideColumns(tohide); + hideColumns(tohide, start, end); } /** @@ -852,7 +853,6 @@ public class HiddenColumns { HiddenCursorPosition pos = cursor.findRegionForColumn(start, false); int index = pos.getRegionIndex(); - int startindex = index; // first index in hiddenColumns to remove if (index != -1 && index != hiddenColumns.size()) { @@ -862,30 +862,35 @@ public class HiddenColumns if (region[0] < start && region[1] >= start) { // region contains start, truncate so that it ends just before start + numColumns -= region[1] - start + 1; region[1] = start - 1; - startindex++; + index++; } - } - pos = cursor.findRegionForColumn(end, false); - index = pos.getRegionIndex(); - int endindex = index - 1; // last index in hiddenColumns to remove - - if (index != -1 && index != hiddenColumns.size()) - { - // regionIndex is the region which either contains end - // or lies to the right of end - int[] region = hiddenColumns.get(index); - if (region[0] <= end && region[1] > end) + int endi = index; + while (endi < hiddenColumns.size()) { - // region contains end, truncate so that it starts just after end - region[0] = end + 1; + region = hiddenColumns.get(endi); + + if (region[1] > end) + { + if (region[0] <= end) + { + // region contains end, truncate so it starts just after end + numColumns -= end - region[0] + 1; + region[0] = end + 1; + } + break; + } + + numColumns -= region[1] - region[0] + 1; + endi++; } + hiddenColumns.subList(index, endi).clear(); + } - hiddenColumns.subList(startindex, endindex + 1).clear(); cursor = new HiddenColumnsCursor(hiddenColumns); - resetNumColumns(); } } finally { @@ -1007,7 +1012,7 @@ public class HiddenColumns try { LOCK.readLock().lock(); - return new HiddenColsIterator(hiddenColumns); + return new RangeIterator(hiddenColumns); } finally { LOCK.readLock().unlock(); @@ -1028,7 +1033,7 @@ public class HiddenColumns try { LOCK.readLock().lock(); - return new HiddenColsIterator(start, end, hiddenColumns); + return new RangeIterator(start, end, hiddenColumns); } finally { LOCK.readLock().unlock(); @@ -1044,7 +1049,7 @@ public class HiddenColumns * @param end * position to end at (inclusive, visible column position) */ - public Iterator getBoundedStartIterator(int start, int end) + public Iterator getStartRegionIterator(int start, int end) { try { @@ -1061,7 +1066,7 @@ public class HiddenColumns HiddenCursorPosition pos = cursor .findRegionForColumn(absoluteStart - 1, false); - return new BoundedStartRegionIterator(pos, start, end, + return new StartRegionIterator(pos, start, end, hiddenColumns); } finally { @@ -1083,7 +1088,8 @@ public class HiddenColumns try { LOCK.readLock().lock(); - return new VisibleColsIterator(start, end, hiddenColumns); + return new RangeElementsIterator( + new VisibleContigsIterator(start, end + 1, hiddenColumns)); } finally { LOCK.readLock().unlock();