X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2FHiddenColumns.java;h=2d43f025f7bc6746b216f37d9aee2feb13330bb1;hb=caa5930cf71ef14a4af891f2c17aa4a6e0f72bcf;hp=9a8669f0b863aa9d8c4c96eb4f048969d22990c1;hpb=9e064d395de4746f14106c1c296bc94696a6190e;p=jalview.git diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index 9a8669f..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,7 +169,7 @@ public class HiddenColumns if (!hiddenColumns.isEmpty()) { // set up cursor reset values - HiddenCursorPosition cursorPos = cursor.findRegionForColumn(start); + HiddenCursorPosition cursorPos = cursor.findRegionForColumn(start, false); regionindex = cursorPos.getRegionIndex(); if (regionindex > 0) @@ -184,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 { @@ -213,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(); @@ -246,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]) @@ -254,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) @@ -263,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(); } /** @@ -306,7 +327,7 @@ public class HiddenColumns hideColumns(r[0], r[1]); } cursor = new HiddenColumnsCursor(hiddenColumns); - resetNumColumns(); + } finally { LOCK.writeLock().unlock(); @@ -331,7 +352,7 @@ public class HiddenColumns } hiddenColumns.clear(); cursor = new HiddenColumnsCursor(hiddenColumns); - resetNumColumns(); + numColumns = 0; } finally { @@ -356,7 +377,7 @@ public class HiddenColumns if (!hiddenColumns.isEmpty()) { - int regionIndex = cursor.findRegionForColumn(start) + int regionIndex = cursor.findRegionForColumn(start, false) .getRegionIndex(); if (regionIndex != -1 && regionIndex != hiddenColumns.size()) @@ -372,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; } } } @@ -437,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; } /** @@ -489,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) { @@ -544,7 +528,8 @@ public class HiddenColumns if (!hiddenColumns.isEmpty()) { - result += cursor.findRegionForVisColumn(column).getHiddenSoFar(); + result += cursor.findRegionForColumn(column, true) + .getHiddenSoFar(); } return result; @@ -574,7 +559,7 @@ public class HiddenColumns if (!hiddenColumns.isEmpty()) { HiddenCursorPosition cursorPos = cursor - .findRegionForColumn(hiddenColumn); + .findRegionForColumn(hiddenColumn, false); int index = cursorPos.getRegionIndex(); int hiddenBeforeCol = cursorPos.getHiddenSoFar(); @@ -656,7 +641,8 @@ public class HiddenColumns LOCK.readLock().lock(); if (!hiddenColumns.isEmpty()) { - int index = cursor.findRegionForColumn(alPos).getRegionIndex(); + int index = cursor.findRegionForColumn(alPos, false) + .getRegionIndex(); if (left && index > 0) { @@ -700,15 +686,19 @@ public class HiddenColumns { LOCK.readLock().lock(); - int regionindex = cursor.findRegionForColumn(column).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; @@ -786,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(); @@ -807,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 @@ -815,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); } /** @@ -846,9 +851,8 @@ public class HiddenColumns if (!hiddenColumns.isEmpty()) { - HiddenCursorPosition pos = cursor.findRegionForColumn(start); + 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()) { @@ -858,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); - 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 { @@ -973,7 +982,7 @@ public class HiddenColumns if (!hiddenColumns.isEmpty()) { // look for a region ending just before adjres - int regionindex = cursor.findRegionForColumn(adjres - 1) + int regionindex = cursor.findRegionForColumn(adjres - 1, false) .getRegionIndex(); if (regionindex < hiddenColumns.size() && hiddenColumns.get(regionindex)[1] == adjres - 1) @@ -1003,7 +1012,7 @@ public class HiddenColumns try { LOCK.readLock().lock(); - return new HiddenColsIterator(hiddenColumns); + return new RangeIterator(hiddenColumns); } finally { LOCK.readLock().unlock(); @@ -1024,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(); @@ -1040,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 { @@ -1055,9 +1064,9 @@ public class HiddenColumns // region we'll get the cursor pointing to the region before, which is // what we want HiddenCursorPosition pos = cursor - .findRegionForColumn(absoluteStart - 1); + .findRegionForColumn(absoluteStart - 1, false); - return new BoundedStartRegionIterator(pos, start, end, + return new StartRegionIterator(pos, start, end, hiddenColumns); } finally { @@ -1079,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();