public SkipScanFilter(List<List<KeyRange>> slots, RowKeySchema schema) {
   int maxKeyLength = getTerminatorCount(schema);
   for (List<KeyRange> slot : slots) {
     int maxSlotLength = 0;
     for (KeyRange range : slot) {
       int maxRangeLength = Math.max(range.getLowerRange().length, range.getUpperRange().length);
       if (maxSlotLength < maxRangeLength) {
         maxSlotLength = maxRangeLength;
       }
     }
     maxKeyLength += maxSlotLength;
   }
   init(slots, schema, maxKeyLength);
 }
 private boolean intersect(
     byte[] lowerInclusiveKey, byte[] upperExclusiveKey, List<List<KeyRange>> newSlots) {
   boolean lowerUnbound = (lowerInclusiveKey.length == 0);
   Arrays.fill(position, 0);
   isDone = false;
   int startPos = 0;
   int lastSlot = slots.size() - 1;
   if (!lowerUnbound) {
     // Find the position of the first slot of the lower range
     ptr.set(lowerInclusiveKey);
     schema.first(ptr, 0, ValueBitSet.EMPTY_VALUE_BITSET);
     startPos = ScanUtil.searchClosestKeyRangeWithUpperHigherThanPtr(slots.get(0), ptr, 0);
     // Lower range is past last upper range of first slot, so cannot possibly be in range
     if (startPos >= slots.get(0).size()) {
       return false;
     }
   }
   boolean upperUnbound = (upperExclusiveKey.length == 0);
   int endPos = slots.get(0).size() - 1;
   if (!upperUnbound) {
     // Find the position of the first slot of the upper range
     ptr.set(upperExclusiveKey);
     schema.first(ptr, 0, ValueBitSet.EMPTY_VALUE_BITSET);
     endPos = ScanUtil.searchClosestKeyRangeWithUpperHigherThanPtr(slots.get(0), ptr, startPos);
     // Upper range lower than first lower range of first slot, so cannot possibly be in range
     if (endPos == 0
         && Bytes.compareTo(upperExclusiveKey, slots.get(0).get(0).getLowerRange()) <= 0) {
       return false;
     }
     // Past last position, so we can include everything from the start position
     if (endPos >= slots.get(0).size()) {
       upperUnbound = true;
       endPos = slots.get(0).size() - 1;
     }
   }
   if (!lowerUnbound) {
     position[0] = startPos;
     navigate(lowerInclusiveKey, 0, lowerInclusiveKey.length, Terminate.AFTER);
     if (filterAllRemaining()) {
       return false;
     }
   }
   if (upperUnbound) {
     if (newSlots != null) {
       newSlots.add(slots.get(0).subList(startPos, endPos + 1));
       newSlots.addAll(slots.subList(1, slots.size()));
     }
     return true;
   }
   int[] lowerPosition = Arrays.copyOf(position, position.length);
   // Navigate to the upperExclusiveKey, but not past it
   ReturnCode endCode = navigate(upperExclusiveKey, 0, upperExclusiveKey.length, Terminate.AT);
   if (endCode == ReturnCode.INCLUDE) {
     setStartKey();
     // If the upperExclusiveKey is equal to the start key, we've gone one position too far, since
     // our upper key is exclusive. In that case, go to the previous key
     if (Bytes.compareTo(
                 startKey, 0, startKeyLength, upperExclusiveKey, 0, upperExclusiveKey.length)
             == 0
         && (previousPosition(lastSlot) < 0 || position[0] < lowerPosition[0])) {
       // If by backing up one position we have an empty range, then return
       return false;
     }
   } else if (endCode == ReturnCode.SEEK_NEXT_USING_HINT) {
     // The upperExclusive key is smaller than the slots stored in the position. Check if it's the
     // same position
     // as the slots for lowerInclusive. If so, there is no intersection.
     if (Arrays.equals(lowerPosition, position)) {
       return false;
     }
   }
   // Copy inclusive all positions
   for (int i = 0; i <= lastSlot; i++) {
     List<KeyRange> newRanges =
         slots.get(i).subList(lowerPosition[i], Math.min(position[i] + 1, slots.get(i).size()));
     if (newRanges.isEmpty()) {
       return false;
     }
     if (newSlots != null) {
       newSlots.add(newRanges);
     }
     if (position[i] > lowerPosition[i]) {
       if (newSlots != null) {
         newSlots.addAll(slots.subList(i + 1, slots.size()));
       }
       break;
     }
   }
   return true;
 }