package org.torrent.internal.util;
import java.io.Serializable;
/**
* This class represents an interval.
*
* @author dante
*
*/
public final class Range implements Serializable {
private static final long serialVersionUID = 1L;
private final long start, length;
/**
* Creates a range with the given parameters
*
* @param start
* the beginning of the range
* @param length
* the length of the range
* @return a range
*/
public static Range getRangeByLength(long start, long length) {
Validator.isTrue(length >= 0, "Invalid length: " + length);
return new Range(start, length);
}
/**
* Creates the smallest possible range containing the given numbers.
*
* @param number1
* number to be within the range
* @param number2
* number to be within the range
* @return
*/
public static Range getRangeByNumbers(long number1, long number2) {
long s = Math.min(number1, number2);
return new Range(s, Math.max(number1, number2) - s + 1);
}
private Range(long start, long length) {
assert length >= 0;
this.start = start;
this.length = length;
}
/**
* @param range
* @return true if the given range is contained within this range
*/
public boolean contains(Range range) {
return getStart() <= range.getStart() && getEnd() >= range.getEnd();
}
/**
* @param pos
* @return true if the given point is contained within this range
*/
public boolean contains(long pos) {
return getStart() <= pos && getEnd() >= pos;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Range) {
Range r = (Range) obj;
return getStart() == r.getStart() && getLength() == r.getLength();
}
return false;
}
/**
* @return the last index contained in this range
*/
public long getEnd() {
return start + length - 1;
}
/**
* @return the length of this range
*/
public long getLength() {
return length;
}
/**
* @return the first index contained in this range
*/
public long getStart() {
return start;
}
@Override
public int hashCode() {
return (int) ((getStart() * 13) & (getEnd() * 137));
}
/**
* Creates a range which contains only the indices contained in the
* intersection of this range and the given range.
*
* @param range
* the range to intersect with
* @return the intersected range or null if the ranges don't overlap
*/
public Range intersection(Range range) {
if (!intersects(range)) {
return null;
}
return getRangeByNumbers(Math.max(getStart(), range.getStart()), Math
.min(getEnd(), range.getEnd()));
}
/**
* Returns the number of indices which are in this range and the given
* range.
*
* @param r
* @return 0 if the ranges don't overlap, the length of the intersection
* between them otherwise
*/
public long intersectionLength(Range r) {
if (!intersects(r)) {
return 0;
}
return Math.min(getEnd(), r.getEnd())
- Math.max(getStart(), r.getStart()) + 1;
}
/**
* @param range
* the range to intersect test with
* @return true if the ranges overlap
*/
public boolean intersects(Range range) {
return getStart() <= range.getEnd() && getEnd() >= range.getStart();
}
@Override
public String toString() {
return "[" + getStart() + " - " + getEnd() + "]";
}
}