package jalview.datamodel;
import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
public class HiddenColumnsCursor
{
// absolute position of first hidden column
private int firstColumn;
- // index of last visited region
- private int regionIndex;
-
- // number of hidden columns before last visited region
- private int hiddenSoFar;
-
private List<int[]> hiddenColumns;
+ // AtomicReference to hold the current region index and hidden column count
+ // Could be done with synchronisation but benchmarking shows this way is 2x
+ // faster
+ private final AtomicReference<HiddenCursorPosition> cursorPos = new AtomicReference<>(
+ new HiddenCursorPosition(0, 0, 0));
+
protected HiddenColumnsCursor()
{
}
/**
- * Set the cursor to a position
+ * Reset the cursor with a new hidden columns collection. Calls to resetCursor
+ * should be made from within a writeLock in the HiddenColumns class - since
+ * changes to the hiddenColumns collection require a writeLock the lock should
+ * already exist.
*
* @param hiddenCols
*/
protected void resetCursor(List<int[]> hiddenCols)
{
- synchronized (this)
+ hiddenColumns = hiddenCols;
+ if ((hiddenCols != null) && (!hiddenCols.isEmpty()))
{
- hiddenColumns = hiddenCols;
- if ((hiddenCols != null) && (!hiddenCols.isEmpty()))
- {
- firstColumn = hiddenColumns.get(0)[0];
- regionIndex = 0;
- hiddenSoFar = 0;
- }
+ firstColumn = hiddenColumns.get(0)[0];
+ HiddenCursorPosition oldpos = cursorPos.get();
+ HiddenCursorPosition newpos = new HiddenCursorPosition(0, 0, 0);
+ cursorPos.compareAndSet(oldpos, newpos);
}
}
/**
* Delete the region the cursor is currently at. Avoids having to reset the
* cursor just because we deleted a region.
+ *
+ * Calls to updateForDeletedRegion should be made from within a writeLock in
+ * the HiddenColumns class - since changes to the hiddenColumns collection
+ * require a writeLock the lock should already exist.
*
* @param hiddenCols
*/
// nothing changes; otherwise
// we deleted the last region (index=hiddenCols.size()-1)
// or the index was at the end of the alignment (index=hiddenCols.size())
- if (regionIndex >= hiddenColumns.size() - 1)
+ HiddenCursorPosition oldpos = cursorPos.get();
+
+ int index = oldpos.getRegionIndex();
+ if (index >= hiddenColumns.size() - 1)
{
// deleted last region, index is now end of alignment
- regionIndex = hiddenCols.size();
+ index = hiddenCols.size();
}
- }
-
- hiddenColumns = hiddenCols;
- }
- protected void updateCursor(int index, int hiddenCount)
- {
- synchronized (this)
- {
- regionIndex = index;
- hiddenSoFar = hiddenCount;
+ // update the cursor position
+ HiddenCursorPosition newpos = new HiddenCursorPosition(index,
+ oldpos.getHiddenSoFar(), oldpos.getNumColumns());
+ cursorPos.compareAndSet(oldpos, newpos);
}
+ hiddenColumns = hiddenCols;
}
- protected synchronized int getIndex()
- {
- return regionIndex;
- }
-
- protected synchronized int getHiddenSoFar()
- {
- return hiddenSoFar;
- }
-
-
/**
* Get the index of the region that column is within (if column is hidden) or
* which is to the right of column (if column is visible). If no hidden
* absolute position of a column in the alignment
* @return region index
*/
- protected int findRegionForColumn(int column)
+ protected HiddenCursorPosition findRegionForColumn(int column)
{
if (hiddenColumns == null)
{
- return -1;
+ return null;
}
- int index = regionIndex;
- int hiddenCount = hiddenSoFar;
+ HiddenCursorPosition oldpos = cursorPos.get();
+ int index = oldpos.getRegionIndex();
+ int hiddenCount = oldpos.getHiddenSoFar();
if (index == hiddenColumns.size())
{
}
}
}
- updateCursor(index, hiddenCount);
- return index;
+ HiddenCursorPosition newpos = new HiddenCursorPosition(index,
+ hiddenCount, oldpos.getNumColumns());
+ cursorPos.compareAndSet(oldpos, newpos);
+ return newpos;
}
/**
* index of column in visible alignment
* @return
*/
- protected int getHiddenOffset(int column)
+ protected HiddenCursorPosition getHiddenOffset(int column)
{
if (hiddenColumns == null)
{
- return -1;
+ return null;
}
- int index = getIndex();
- int hiddenCount = getHiddenSoFar();
+ HiddenCursorPosition oldpos = cursorPos.get();
+ int index = oldpos.getRegionIndex();
+ int hiddenCount = oldpos.getHiddenSoFar();
if (column < firstColumn)
{
}
}
- updateCursor(index, hiddenCount);
- return hiddenCount;
+
+ HiddenCursorPosition newpos = new HiddenCursorPosition(index,
+ hiddenCount, oldpos.getNumColumns());
+ cursorPos.compareAndSet(oldpos, newpos);
+ return newpos;
}
}