+
+ class BoundedVisRegionIterator implements Iterator<int[]>
+ {
+ private int start; // start position to iterate from
+
+ private int end; // end position to iterate to
+
+ // current region in visColumns
+ private int[] currentRegion;
+
+ // current index in visColumns
+ private int currentPosition = 0;
+
+ private List<int[]> vcontigs = null;
+
+ /**
+ * Construct an iterator over visibleColumn regions bounded at
+ * [lowerBound,upperBound]
+ *
+ * @param lowerBound
+ * lower bound to iterate from
+ * @param upperBound
+ * upper bound to iterate to
+ * @param useCopyCols
+ * whether to make a local copy for iteration (set to true if
+ * calling from outwith the HiddenColumns class)
+ */
+ BoundedVisRegionIterator(int lowerBound, int upperBound,
+ boolean useCopy)
+ {
+ try
+ {
+ start = lowerBound;
+ end = upperBound;
+
+ if (useCopy)
+ {
+ // assume that if useCopy is false the calling code has locked
+ // hiddenColumns
+ LOCK.readLock().lock();
+ }
+
+ int visStart = start;
+
+ if (hiddenColumns != null)
+ {
+ vcontigs = new ArrayList<>(hiddenColumns.size() + 1);
+
+ // navigate to start, keeping count of hidden columns
+ int i = 0;
+ int[] region = null;
+ while ((i < hiddenColumns.size())
+ && (hiddenColumns.get(i)[0] <= start))
+ {
+ i++;
+ }
+ // if there was a hidden region before (i>=1), and it ended after
+ // start
+ // and before end, adjust visStart to be just after that region
+ if (i > 0)
+ {
+ region = hiddenColumns.get(i - 1);
+ if ((region[1] > start) && (region[1] < end))
+ {
+ visStart = region[1] + 1;
+ }
+ else if (region[1] >= end)
+ {
+ // previous hidden region covers whole range [start,end]
+ // early exit - vcontigs is empty
+ return;
+ }
+ }
+
+ // iterate from start to end, adding start positions of each
+ // hidden region. Positions are visible columns count, not absolute
+ while (i < hiddenColumns.size()
+ && (hiddenColumns.get(i)[0] < end))
+ {
+ region = hiddenColumns.get(i);
+ int[] prevVisibleRegion = new int[] { visStart, region[0] - 1 };
+ vcontigs.add(prevVisibleRegion);
+ visStart = region[1] + 1;
+ i++;
+ }
+ // add on a final visible region if needed
+ if (visStart <= end)
+ {
+ int[] lastRegion = new int[] { visStart, end };
+ vcontigs.add(lastRegion);
+ }
+ }
+ else
+ {
+ vcontigs = new ArrayList<>();
+ int[] lastRegion = new int[] { start, end };
+ vcontigs.add(lastRegion);
+ }
+ } finally
+ {
+ if (useCopy)
+ {
+ LOCK.readLock().unlock();
+ }
+ }
+ }
+
+ @Override
+ public boolean hasNext()
+ {
+ return (currentPosition < vcontigs.size());
+ }
+
+ @Override
+ public int[] next()
+ {
+ currentRegion = vcontigs.get(currentPosition);
+ currentPosition++;
+ return currentRegion;
+ }
+ }