blob: 3702276c915f59c017fc209a48ddbe062cda69e4 [file] [log] [blame]
package accord.topology;
import accord.api.Key;
import accord.api.KeyRange;
import accord.txn.Keys;
import com.google.common.base.Preconditions;
import com.google.common.collect.Iterators;
import java.util.*;
public class KeyRanges implements Iterable<KeyRange>
{
public static final KeyRanges EMPTY = new KeyRanges(new KeyRange[0]);
// TODO: fix raw parameterized use
private final KeyRange[] ranges;
public KeyRanges(KeyRange[] ranges)
{
Preconditions.checkNotNull(ranges);
this.ranges = ranges;
}
public KeyRanges(List<KeyRange> ranges)
{
this(ranges.toArray(KeyRange[]::new));
}
@Override
public String toString()
{
return Arrays.toString(ranges);
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KeyRanges ranges1 = (KeyRanges) o;
return Arrays.equals(ranges, ranges1.ranges);
}
@Override
public int hashCode()
{
return Arrays.hashCode(ranges);
}
@Override
public Iterator<KeyRange> iterator()
{
return Iterators.forArray(ranges);
}
public int rangeIndexForKey(int lowerBound, int upperBound, Key key)
{
return Arrays.binarySearch(ranges, lowerBound, upperBound, key,
(r, k) -> -((KeyRange) r).compareKey((Key) k));
}
public int rangeIndexForKey(Key key)
{
return rangeIndexForKey(0, ranges.length, key);
}
public int size()
{
return ranges.length;
}
public KeyRange get(int i)
{
return ranges[i];
}
public boolean isEmpty()
{
return size() == 0;
}
public KeyRanges select(int[] indexes)
{
KeyRange[] selection = new KeyRange[indexes.length];
for (int i=0; i<indexes.length; i++)
selection[i] = ranges[indexes[i]];
return new KeyRanges(selection);
}
public boolean intersects(Keys keys)
{
for (int i=0; i<ranges.length; i++)
if (ranges[i].intersects(keys))
return true;
return false;
}
/**
* Subtracts the given set of key ranges from this
* @param that
* @return
*/
public KeyRanges difference(KeyRanges that)
{
List<KeyRange> result = new ArrayList<>(this.size() + that.size());
int thatIdx = 0;
for (int thisIdx=0; thisIdx<this.size(); thisIdx++)
{
KeyRange thisRange = this.ranges[thisIdx];
while (thatIdx < that.size())
{
KeyRange thatRange = that.ranges[thatIdx];
int cmp = thisRange.compareIntersecting(thatRange);
if (cmp > 0)
{
thatIdx++;
continue;
}
if (cmp < 0) break;
int scmp = thisRange.start().compareTo(thatRange.start());
int ecmp = thisRange.end().compareTo(thatRange.end());
if (scmp < 0)
result.add(thisRange.subRange(thisRange.start(), thatRange.start()));
if (ecmp <= 0)
{
thisRange = null;
break;
}
else
{
thisRange = thisRange.subRange(thatRange.end(), thisRange.end());
thatIdx++;
}
}
if (thisRange != null)
result.add(thisRange);
}
return new KeyRanges(result.toArray(KeyRange[]::new));
}
/**
* Adds a set of non-overlapping ranges
*/
public KeyRanges union(KeyRanges that)
{
KeyRange[] combined = new KeyRange[this.ranges.length + that.ranges.length];
System.arraycopy(this.ranges, 0, combined, 0, this.ranges.length);
System.arraycopy(that.ranges, 0, combined, this.ranges.length, that.ranges.length);
Arrays.sort(combined, Comparator.comparing(KeyRange::start));
for (int i=1; i<combined.length; i++)
Preconditions.checkArgument(combined[i].compareIntersecting(combined[i -1]) != 0);
return new KeyRanges(combined);
}
public KeyRanges union(KeyRange range)
{
return union(new KeyRanges(new KeyRange[]{range}));
}
public KeyRanges mergeTouching()
{
if (ranges.length == 0)
return this;
List<KeyRange> result = new ArrayList<>(ranges.length);
KeyRange current = ranges[0];
for (int i=1; i<ranges.length; i++)
{
KeyRange merged = current.tryMerge(ranges[i]);
if (merged != null)
{
current = merged;
}
else
{
result.add(current);
current = ranges[i];
}
}
result.add(current);
return new KeyRanges(result.toArray(KeyRange[]::new));
}
}