JAL-2759 improvements to speed up synchronisation; caching of size
[jalview.git] / src / jalview / datamodel / HiddenColumns.java
index 3710829..0a4d04b 100644 (file)
@@ -34,6 +34,8 @@ public class HiddenColumns
 
   private HiddenColumnsCursor cursor = new HiddenColumnsCursor();
 
+  private int numColumns = 0;
+
   /*
    * list of hidden column [start, end] ranges; the list is maintained in
    * ascending start column order
@@ -99,6 +101,7 @@ public class HiddenColumns
       if (copy != null)
       {
         hiddenColumns = new ArrayList<>();
+        numColumns = 0;
         Iterator<int[]> it = copy.getBoundedIterator(start, end);
         while (it.hasNext())
         {
@@ -110,6 +113,7 @@ public class HiddenColumns
             hiddenColumns.add(
                     new int[]
             { region[0] - offset, region[1] - offset });
+            numColumns += region[1] - region[0] + 1;
           }
         }
         cursor.resetCursor(hiddenColumns);
@@ -167,17 +171,24 @@ public class HiddenColumns
     try
     {
       LOCK.readLock().lock();
-      int size = 0;
-      if (hiddenColumns != null)
+
+      if (numColumns == 0 && hiddenColumns != null)
       {
-        Iterator<int[]> it = hiddenColumns.iterator();
-        while (it.hasNext())
+        // numColumns is out of date, so recalculate
+        int size = 0;
+        if (hiddenColumns != null)
         {
-          int[] range = it.next();
-          size += range[1] - range[0] + 1;
+          Iterator<int[]> it = hiddenColumns.iterator();
+          while (it.hasNext())
+          {
+            int[] range = it.next();
+            size += range[1] - range[0] + 1;
+          }
         }
+        numColumns = size;
       }
-      return size;
+
+      return numColumns;
     } finally
     {
       LOCK.readLock().unlock();
@@ -266,18 +277,7 @@ public class HiddenColumns
 
       if (hiddenColumns != null)
       {
-        result += cursor.getHiddenOffset(column);
-
-        /*   
-        Iterator<int[]> it = hiddenColumns.iterator();
-        while (it.hasNext())
-        {
-          int[] region = it.next();
-          if (result >= region[0])
-          {
-            result += region[1] - region[0] + 1;
-          }
-        }*/
+        result += cursor.getHiddenOffset(column).getHiddenSoFar();
       }
 
       return result;
@@ -302,43 +302,39 @@ public class HiddenColumns
     {
       LOCK.readLock().lock();
       int result = hiddenColumn;
-      int[] region = null;
+
       if (hiddenColumns != null)
       {
-        Iterator<int[]> it = new RegionsIterator(0,
-                hiddenColumn, hiddenColumns, cursor);
-        while (it.hasNext())
-        {
-          region = it.next();
-          if (hiddenColumn > region[1])
-          {
-            result -= region[1] + 1 - region[0];
-          }
-        }
-
-        if (region != null && hiddenColumn >= region[0]
-                && hiddenColumn <= region[1])
+        HiddenCursorPosition cursorPos = cursor
+                .findRegionForColumn(hiddenColumn);
+        int index = cursorPos.getRegionIndex();
+        int hiddenBeforeCol = cursorPos.getHiddenSoFar();
+    
+        // just subtract hidden cols count - this works fine if column is
+        // visible
+        result = hiddenColumn - hiddenBeforeCol;
+    
+        // now check in case column is hidden - it will be in the returned
+        // hidden region
+        if (index < hiddenColumns.size())
         {
-          // Here the hidden column is within a region, so
-          // we want to return the position of region[0]-1, adjusted for any
-          // 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.
-
-          // However, if the region begins at 0 we cannot return region[0]-1
-          // just return 0
-          if (region[0] == 0)
-          {
-            return 0;
-          }
-          else
+          int[] region = hiddenColumns.get(index);
+          if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
           {
-            return result - (hiddenColumn - region[0] + 1);
+            // actually col is hidden, return region[0]-1
+            // unless region[0]==0 in which case return 0
+            if (region[0] == 0)
+            {
+              result = 0;
+            }
+            else
+            {
+              result = region[0] - 1 - hiddenBeforeCol;
+            }
           }
         }
       }
+
       return result; // return the shifted position after removing hidden
                      // columns.
     } finally
@@ -404,7 +400,8 @@ public class HiddenColumns
    * hidden columns. In otherwords, the next hidden column.
    * 
    * @param alPos
-   *          the (visible) alignmentPosition to find the next hidden column for
+   *          the absolute (visible) alignmentPosition to find the next hidden
+   *          column for
    */
   public int getHiddenBoundaryRight(int alPos)
   {
@@ -413,14 +410,22 @@ public class HiddenColumns
       LOCK.readLock().lock();
       if (hiddenColumns != null)
       {
-        Iterator<int[]> it = hiddenColumns.iterator();
-        while (it.hasNext())
+        int index = cursor.findRegionForColumn(alPos).getRegionIndex();
+        if (index < hiddenColumns.size())
         {
-          int[] region = it.next();
+          int[] region = hiddenColumns.get(index);
           if (alPos < region[0])
           {
             return region[0];
           }
+          else if ((alPos <= region[1])
+                  && (index + 1 < hiddenColumns.size()))
+          {
+            // alPos is within a hidden region, return the next one
+            // if there is one
+            region = hiddenColumns.get(index + 1);
+            return region[0];
+          }
         }
       }
       return alPos;
@@ -435,8 +440,8 @@ public class HiddenColumns
    * hidden columns. In otherwords, the previous hidden column.
    * 
    * @param alPos
-   *          the (visible) alignmentPosition to find the previous hidden column
-   *          for
+   *          the absolute (visible) alignmentPosition to find the previous
+   *          hidden column for
    */
   public int getHiddenBoundaryLeft(int alPos)
   {
@@ -444,17 +449,16 @@ public class HiddenColumns
     {
       LOCK.readLock().lock();
 
-      Iterator<int[]> it = new ReverseRegionsIterator(0, alPos,
-              hiddenColumns);
-      while (it.hasNext())
+      if (hiddenColumns != null)
       {
-        int[] region = it.next();
-        if (alPos > region[1])
+        int index = cursor.findRegionForColumn(alPos).getRegionIndex();
+
+        if (index > 0)
         {
+          int[] region = hiddenColumns.get(index - 1);
           return region[1];
         }
       }
-
       return alPos;
     } finally
     {
@@ -514,6 +518,9 @@ public class HiddenColumns
       if (!wasAlreadyLocked)
       {
         cursor.resetCursor(hiddenColumns);
+
+        // reset the number of columns so they will be recounted
+        numColumns = 0;
       }
     } finally
     {
@@ -602,18 +609,17 @@ public class HiddenColumns
     {
       LOCK.readLock().lock();
 
-      Iterator<int[]> it = new RegionsIterator(column, column,
-              hiddenColumns, cursor);
-      while (it.hasNext())
+      int regionindex = cursor.findRegionForColumn(column).getRegionIndex();
+      if (regionindex > -1 && regionindex < hiddenColumns.size())
       {
-        int[] region = it.next();
+        int[] region = hiddenColumns.get(regionindex);
         if (column >= region[0] && column <= region[1])
         {
           return false;
         }
       }
-
       return true;
+
     } finally
     {
       LOCK.readLock().unlock();
@@ -907,6 +913,7 @@ public class HiddenColumns
         hideColumns(r[0], r[1]);
       }
       cursor.resetCursor(hiddenColumns);
+      numColumns = 0;
     } finally
     {
       LOCK.writeLock().unlock();
@@ -934,6 +941,7 @@ public class HiddenColumns
         }
         hiddenColumns = null;
         cursor.resetCursor(hiddenColumns);
+        numColumns = 0;
       }
     } finally
     {
@@ -952,31 +960,40 @@ public class HiddenColumns
     try
     {
       LOCK.writeLock().lock();
-      Iterator<int[]> it = new RegionsIterator(start, start, hiddenColumns,
-              cursor);
-      while (it.hasNext())
+
+      if (hiddenColumns != null)
       {
-        int[] region = it.next();
-        if (start == region[0])
+        int regionIndex = cursor.findRegionForColumn(start)
+                .getRegionIndex();
+
+        if (regionIndex != -1 && regionIndex != hiddenColumns.size())
         {
-          for (int j = region[0]; j < region[1] + 1; j++)
+          // regionIndex is the region which either contains start
+          // or lies to the right of start
+          int[] region = hiddenColumns.get(regionIndex);
+          if (start == region[0])
           {
-            sel.addElement(j);
+            for (int j = region[0]; j < region[1] + 1; j++)
+            {
+              sel.addElement(j);
+            }
+            int colsToRemove = region[1] - region[0] + 1;
+            hiddenColumns.remove(regionIndex);
+
+            if (hiddenColumns.isEmpty())
+            {
+              hiddenColumns = null;
+              numColumns = 0;
+            }
+            else
+            {
+              numColumns -= colsToRemove;
+            }
+            cursor.updateForDeletedRegion(hiddenColumns);
+
           }
-          it.remove();
-          break;
-        }
-        else if (start < region[0])
-        {
-          break; // passed all possible matching regions
         }
       }
-
-      if (hiddenColumns.size() == 0)
-      {
-        hiddenColumns = null;
-      }
-      cursor.resetCursor(hiddenColumns);
     } finally
     {
       LOCK.writeLock().unlock();
@@ -1082,6 +1099,7 @@ public class HiddenColumns
       }
       hiddenColumns = newhidden;
       cursor.resetCursor(hiddenColumns);
+      numColumns = 0;
     } finally
     {
       LOCK.writeLock().unlock();
@@ -1186,6 +1204,7 @@ public class HiddenColumns
         hideColumns(firstSet, lastSet - 1);
       }
       cursor.resetCursor(hiddenColumns);
+      numColumns = 0;
     } finally
     {
       LOCK.writeLock().unlock();
@@ -1289,18 +1308,36 @@ public class HiddenColumns
       int adjres = adjustForHiddenColumns(res);
 
       int[] reveal = null;
-      Iterator<int[]> it = new RegionsIterator(adjres - 2,
-              adjres + 2, hiddenColumns, cursor);
-      while (it.hasNext())
+
+      if (hiddenColumns != null)
       {
-        int[] region = it.next();
-        if (adjres + 1 == region[0] || adjres - 1 == region[1])
+        // look for a region ending just before adjres
+        int regionindex = cursor.findRegionForColumn(adjres - 1)
+                .getRegionIndex();
+        if (regionindex < hiddenColumns.size()
+                && hiddenColumns.get(regionindex)[1] == adjres - 1)
         {
-          reveal = region;
-          break;
+          reveal = hiddenColumns.get(regionindex);
+        }
+        // check if the region ends just after adjres
+        else if (regionindex < hiddenColumns.size()
+                && hiddenColumns.get(regionindex)[0] == adjres + 1)
+        {
+          reveal = hiddenColumns.get(regionindex);
+        }
+        // or try the next region
+        else
+        {
+          regionindex++;
+          if (regionindex < hiddenColumns.size()
+                  && hiddenColumns.get(regionindex)[0] == adjres + 1)
+          {
+            reveal = hiddenColumns.get(regionindex);
+          }
         }
       }
       return reveal;
+
     } finally
     {
       LOCK.readLock().unlock();
@@ -1527,7 +1564,7 @@ public class HiddenColumns
 
             i++;
           }
-          if (visSoFar < end - start)
+          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