package com.onthegomap.planetiler.collection; import com.google.common.collect.Range; import com.google.common.collect.TreeRangeSet; import java.util.Iterator; import java.util.PrimitiveIterator; import javax.annotation.concurrent.NotThreadSafe; /** * A set of ints backed by a {@link TreeRangeSet} to efficiently represent large continuous ranges. *

* This makes iterating through tile coordinates inside ocean polygons significantly faster. */ @SuppressWarnings("UnstableApiUsage") @NotThreadSafe public class IntRangeSet implements Iterable { private final TreeRangeSet rangeSet = TreeRangeSet.create(); /** Mutates and returns this range set, adding all elements in {@code other} to it. */ public IntRangeSet addAll(IntRangeSet other) { rangeSet.addAll(other.rangeSet); return this; } /** Mutates and returns this range set, removing all elements in {@code other} from it. */ public IntRangeSet removeAll(IntRangeSet other) { rangeSet.removeAll(other.rangeSet); return this; } @Override public PrimitiveIterator.OfInt iterator() { return new Iter(rangeSet.asRanges().iterator()); } /** Mutates and returns this range set, with range {@code a} to {@code b} (inclusive) added. */ public IntRangeSet add(int a, int b) { rangeSet.add(Range.closedOpen(a, b + 1)); return this; } /** Mutates and returns this range set, with {@code a} removed. */ public IntRangeSet remove(int a) { rangeSet.remove(Range.closedOpen(a, a + 1)); return this; } public boolean contains(int y) { return rangeSet.contains(y); } /** Mutates and returns this range set to remove all elements not in {@code other} */ public IntRangeSet intersect(IntRangeSet other) { rangeSet.removeAll(other.rangeSet.complement()); return this; } /** Iterate through all ints in this range */ private static class Iter implements PrimitiveIterator.OfInt { private final Iterator> rangeIter; Range range; int cur; boolean hasNext = true; private Iter(Iterator> rangeIter) { this.rangeIter = rangeIter; advance(); } private void advance() { while (true) { if (range != null && cur < range.upperEndpoint() - 1) { cur++; return; } else if (rangeIter.hasNext()) { range = rangeIter.next(); cur = range.lowerEndpoint() - 1; } else { hasNext = false; return; } } } @Override public int nextInt() { int result = cur; advance(); return result; } @Override public boolean hasNext() { return hasNext; } } }