Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,59 +7,41 @@

/**
* Contiguous range of long values, inclusive of start and end.
* Valid ranges must have start and end values between 0 and Long.MAX_VALUE-1 inclusive,
* with start less than or equal to end. This ensures that the size() method can correctly
* represent any valid range with a long value without risk of overflow.
* Valid ranges must have start and end values between 0 and Long.MAX_VALUE-1
* inclusive, with start less than or equal to end. This ensures that the size()
* method can correctly represent any valid range with a long value without risk
* of overflow.
*/
public record LongRange(long start, long end) implements Comparable<LongRange> {

/** Comparator for comparing LongRange objects by their start and end values. */
public static final Comparator<LongRange> COMPARATOR =
Comparator.comparingLong(LongRange::start).thenComparingLong(LongRange::end);

/**
* Creates a new LongRange with the specified start and end values.
*
* @param start the start value of the range (inclusive), must be between 0 and Long.MAX_VALUE-1
* @param end the end value of the range (inclusive), must be between 0 and Long.MAX_VALUE-1
* @throws IllegalArgumentException if start or end is negative or greater than Long.MAX_VALUE-1,
* or if start is greater than end
* @param start the start value of the range (inclusive), must be between 0
* and Long.MAX_VALUE-1
* @param end the end value of the range (inclusive), must be between 0 and
* Long.MAX_VALUE-1
* @throws IllegalArgumentException if start or end is negative or greater
* than Long.MAX_VALUE-1, or if start is greater than end
*/
public LongRange {
// Special case: allow both start and end to be -1 for clean state initialization
if (!(start == -1 && end == -1)) {
if (start < 0) {
throw new IllegalArgumentException("Range start must be non-negative: " + start);
}
if (end < 0) {
throw new IllegalArgumentException("Range end must be non-negative: " + end);
}
if (start > end) {
throw new IllegalArgumentException(
"Range start must be less than or equal to end: " + start + " > " + end);
}
if (end > Long.MAX_VALUE - 1) {
throw new IllegalArgumentException("Range end must be less than or equal to Long.MAX_VALUE-1: " + end);
}
if (start < 0) {
throw new IllegalArgumentException("LongRange start: %d must not be negative".formatted(start));
}
if (end < 0) {
throw new IllegalArgumentException("LongRange end: %d must not be negative".formatted(end));
}
if (end > Long.MAX_VALUE - 1) {
throw new IllegalArgumentException(
"LongRange end: %d must not be greater than Long.MAX_VALUE-1".formatted(end));
}
if (start > end) {
throw new IllegalArgumentException(
"LongRange start: %d must not be greater than end: %d".formatted(start, end));
}
}

/**
* Gets the start value of the range, inclusive.
*
* @return the start value of the range
*/
public long start() {
return start;
}

/**
* Gets the end value of the range, inclusive.
*
* @return the end value of the range
*/
public long end() {
return end;
}

/**
Expand All @@ -68,25 +50,34 @@ public long end() {
* @param value the value to check
* @return true if the range contains the value, false otherwise
*/
public boolean contains(long value) {
public boolean contains(final long value) {
return value >= start && value <= end;
}

/**
* Checks if the range contains another range specified by start and end values.
* Checks if the range contains another range specified by start and end
* values.
*
* @param start the start value of the range to check
* @param end the end value of the range to check
* @return true if the range contains the specified range, false otherwise
*/
public boolean contains(long start, long end) {
return start >= this.start && end <= this.end;
public boolean contains(final long start, final long end) {
if (start > end) {
// if the caller supplies invalid values, responsibility falls on
// them, we must return a response that makes sense based on input,
// in this case false, as no range can start after it ends
return false;
} else {
return start >= this.start && end <= this.end;
}
}

/**
* Gets the size of the range.
*
* @return the size of the range (number of elements), computed as end - start + 1
* @return the size of the range (number of elements),
* computed as end - start + 1
*/
public long size() {
return end - start + 1;
Expand All @@ -98,7 +89,7 @@ public long size() {
* @param other the other range to check
* @return true if the ranges overlap, false otherwise
*/
public boolean overlaps(LongRange other) {
public boolean overlaps(final LongRange other) {
return !(end < other.start() || start > other.end());
}

Expand All @@ -118,7 +109,7 @@ public boolean isAdjacent(LongRange other) {
* @param other the other range to merge with
* @return a new ImmutableLongRange representing the merged range
*/
public LongRange merge(LongRange other) {
public LongRange merge(final LongRange other) {
return new LongRange(Math.min(start, other.start()), Math.max(end, other.end()));
}

Expand All @@ -135,11 +126,11 @@ public LongStream stream() {
* Compares this range to another range.
*
* @param o the other range to compare to
* @return a negative integer, zero, or a positive integer as this range is less than, equal to, or greater than
* the specified range
* @return a negative integer, zero, or a positive integer as this range is
* less than, equal to, or greater than the specified range
*/
@Override
public int compareTo(@NonNull LongRange o) {
public int compareTo(@NonNull final LongRange o) {
return COMPARATOR.compare(this, o);
}

Expand All @@ -148,6 +139,7 @@ public int compareTo(@NonNull LongRange o) {
*
* @return a string representation of the range in the format "start->end"
*/
@NonNull
@Override
public String toString() {
return start + "->" + end;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,8 @@ void testConstructor() {
assertEquals(10, range3.start());
assertEquals(10, range3.end());

// Test special case for clean state initialization
final LongRange cleanStateRange = new LongRange(-1, -1);
assertEquals(-1, cleanStateRange.start());
assertEquals(-1, cleanStateRange.end());

// Test validation failures
assertThrows(IllegalArgumentException.class, () -> new LongRange(-1, -1));
assertThrows(IllegalArgumentException.class, () -> new LongRange(-1, 5));
assertThrows(IllegalArgumentException.class, () -> new LongRange(5, -1));
assertThrows(IllegalArgumentException.class, () -> new LongRange(6, 5));
Expand Down
Loading