Skip to content

Commit

Permalink
Empty Range now actually empty not infinity.
Browse files Browse the repository at this point in the history
  • Loading branch information
nstdio committed Oct 2, 2022
1 parent 7bbd20c commit f113814
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 12 deletions.
Expand Up @@ -12,7 +12,7 @@

/**
* Represents the range/interval with two bounds. Abstraction follows the semantics of the mathematical interval. The
* range can be unbounded or open from the left or/and unbounded from the right. The range supports half-open or closed
* range can be unbounded, empty or open from the left or/and unbounded from the right. The range supports half-open or closed
* bounds on both sides.
*
* <p>
Expand Down Expand Up @@ -68,7 +68,7 @@ private Range(T lower, T upper, int mask, Class<T> clazz) {
this.mask = mask;
this.clazz = clazz;

if (isBounded() && lower.compareTo(upper) > 0) {
if (isBounded() && lower != null && upper != null && lower.compareTo(upper) > 0) {
throw new IllegalArgumentException("The lower bound is greater then upper!");
}
}
Expand Down Expand Up @@ -250,6 +250,28 @@ public static <T extends Comparable<? super T>> Range<T> infinite(Class<T> cls)
return new Range<>(null, null, LOWER_INFINITE | UPPER_INFINITE, cls);
}

/**
* Creates the empty range. In other words the range that contains no points.
* <p>
* The mathematical equivalent will be:
* <pre>{@code
* (a, a) = ∅
* }</pre>
*
* @param cls The range class, never null.
* @param <R> The type of bounds.
*
* @return The empty range.
*/
public static <R extends Comparable<? super R>> Range<R> emptyRange(Class<R> cls) {
return new Range<>(
null,
null,
LOWER_EXCLUSIVE | UPPER_EXCLUSIVE,
cls
);
}

public static <T extends Comparable<? super T>> Range<T> ofString(String str, Function<String, T> converter, Class<T> clazz) {
if(str.equals(EMPTY)) {
return emptyRange(clazz);
Expand Down Expand Up @@ -561,6 +583,10 @@ public T upper() {
* @return Whether {@code point} in this range or not.
*/
public boolean contains(T point) {
if (isEmpty()) {
return false;
}

boolean l = hasLowerBound();
boolean u = hasUpperBound();

Expand Down Expand Up @@ -596,7 +622,30 @@ public boolean contains(T point) {
* @return Whether {@code range} in this range or not.
*/
public boolean contains(Range<T> range) {
return (!range.hasLowerBound() || contains(range.lower)) && (!range.hasUpperBound() || contains(range.upper));
return !isEmpty() && (!range.hasLowerBound() || contains(range.lower)) && (!range.hasUpperBound() || contains(range.upper));
}

/**
* Determines whether this range is empty or not.
* <p>
* For example:
* <pre>{@code
* assertFalse(integerRange("empty").contains(1))
* }</pre>
*
* @return Whether {@code range} in this range or not.
*/
public boolean isEmpty() {
boolean boundedExclusive = isBounded()
&& hasMask(LOWER_EXCLUSIVE)
&& hasMask(UPPER_EXCLUSIVE);

return boundedExclusive && hasEqualBounds();
}

private boolean hasEqualBounds() {
return lower == null && upper == null
|| lower != null && upper != null && lower.compareTo(upper) == 0;
}

public String asString() {
Expand Down Expand Up @@ -624,13 +673,4 @@ private Function<T, String> boundToString() {
Class<T> getClazz() {
return clazz;
}

public static <R extends Comparable<? super R>> Range<R> emptyRange(Class<R> clazz) {
return new Range<>(
null,
null,
LOWER_INFINITE|UPPER_INFINITE,
clazz
);
}
}
Expand Up @@ -5,8 +5,15 @@
import static com.vladmihalcea.hibernate.type.range.Range.integerRange;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import java.time.LocalDate;

/**
* @author Edgar Asatryan
Expand Down Expand Up @@ -36,6 +43,9 @@ public void ofStringTest() {

assertThat(integerRange("(-5,5]").isUpperBoundClosed(), is(true));
assertThat(integerRange("(-5,5]").isLowerBoundClosed(), is(false));
assertThat(integerRange("(,)").contains(integerRange("empty")), is(true));

assertThat(integerRange("empty").contains(integerRange("(,)")), is(false));
}

@Test
Expand Down Expand Up @@ -74,4 +84,52 @@ public void zonedDateTimeTest() {
assertNotNull(Range.zonedDateTimeRange("[2019-03-27 16:33:10.123456+05:30,)"));
assertNotNull(Range.zonedDateTimeRange("[2019-03-27 16:33:10.123456-06,infinity)"));
}


@Test
public void emptyInfinityEquality() {
assertEquals(integerRange("empty"), integerRange("empty"));
assertEquals(integerRange("(infinity,infinity)"), integerRange("(infinity,infinity)"));
assertEquals(integerRange("(,)"), integerRange("(infinity,infinity)"));
assertEquals(integerRange("(infinity,infinity)"), integerRange("(,)"));

assertNotEquals(integerRange("empty"), integerRange("(infinity,infinity)"));
assertNotEquals(integerRange("empty"), integerRange("(,)"));
assertNotEquals(integerRange("empty"), integerRange("(5,5)"));
}

@Test
public void emptyRangeWithEmptyKeyword() {
Range<LocalDate> empty = Range.localDateRange("empty");

assertTrue(empty.isEmpty());

assertFalse(empty.contains(LocalDate.MIN));
assertFalse(empty.contains((LocalDate) null));
assertFalse(empty.contains(LocalDate.now()));
assertFalse(empty.contains(LocalDate.MAX));

assertNull(empty.upper());
assertNull(empty.lower());
}

@Test
public void emptyRangeWithValues() {
Range<LocalDate> empty = Range.localDateRange("(2019-03-27,2019-03-27)");

assertTrue(empty.isEmpty());
assertFalse(empty.contains(LocalDate.MIN));
assertFalse(empty.contains(LocalDate.now()));
assertFalse(empty.contains(LocalDate.MAX));

assertTrue(integerRange("(5,5)").isEmpty());
}

@Test
public void notEmptyWithValues() {
assertFalse(integerRange("(5,)").isEmpty());
assertFalse(integerRange("(5,5]").isEmpty());
assertFalse(integerRange("(,5)").isEmpty());
assertFalse(integerRange("(,)").isEmpty());
}
}

0 comments on commit f113814

Please sign in to comment.