
ru.progrm_jarvis.javacommons.range.Range Maven / Gradle / Ivy
package ru.progrm_jarvis.javacommons.range;
import lombok.NonNull;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import ru.progrm_jarvis.javacommons.collection.Iterables;
import ru.progrm_jarvis.javacommons.ownership.annotation.Own;
import ru.progrm_jarvis.javacommons.ownership.annotation.Ref;
import java.util.*;
import java.util.function.Predicate;
/**
* Range limiting some value.
*
* @param type of value limited by this range.
*/
@FunctionalInterface
public interface Range extends Predicate {
/**
* Checks if the given value is in range.
*
* @param value value checked for inclusion in this range
* @return {@code true} if the range includes the given value and {@code false} otherwise
*/
default boolean includes(final T value) {
return test(value);
}
/* ************************************************* Modifiers ************************************************* */
@Override
default @NotNull Range negate() {
return value -> !includes(value);
}
/* ************************************************ Combinators ************************************************ */
@Override
default @NotNull Range and(final @NonNull Predicate super T> other) {
return value -> includes(value) && other.test(value);
}
@Override
default @NotNull Range or(final @NonNull Predicate super T> other) {
return value -> includes(value) || other.test(value);
}
/* ************************************************* Factories ************************************************* */
/**
* Creates a range [-∞ ; +∞].
*
* @param type of range's elements
* @return created range
*/
static @NotNull Range any() {
return value -> true;
}
/**
* Creates a range ∅.
*
* @param type of range's elements
* @return created range
*/
static @NotNull Range none() {
return value -> false;
}
/**
* Creates a range {{@code null}}.
*
* @param type of range's elements
* @return created range
*/
static @NotNull Range onlyNull() {
return Objects::isNull;
}
/**
* Creates a range {{@code value}}.
*
* @param value the only value contained by the range
* @param type of range's elements
* @return created range
*/
static @NotNull Range only(final @Ref T value) {
return value == null ? onlyNull() : value::equals;
}
/**
* Creates a range {x: x ∈ {@code values}}.
*
* @param values the only values contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code values}
*/
@SafeVarargs
static @NotNull Range only(final @Own T @Own @NonNull ... values) {
Arrays.sort(values);
return value -> Arrays.binarySearch(values, value) >= 0;
}
/**
* Creates a range {x: x ∈ {@code values}}.
*
* @param values the only values contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code values}
*/
static @NotNull Range only(final @Ref @NonNull Collection values) {
return values::contains;
}
/**
* Creates a range {x: x ∈ {@code values}}.
*
* @param values the only values contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code values} not preserving order
*/
@SafeVarargs
static @NotNull Range onlyCopy(final @Own T @Ref @NonNull ... values) {
return only(Arrays.copyOf(values, values.length));
}
/**
* Creates a range {x: x ∈ {@code values}}.
*
* @param values the only values contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code values} not preserving order
*/
static @NotNull Range onlyCopy(final @Ref @NonNull Collection values) {
return only(new HashSet<>(values));
}
/**
* Creates a range {x: x ∈ {@code values}}.
*
* @param values the only values contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code values} preserving order
*/
static @NotNull Range onlyCopyOrdered(final @Ref @NonNull Collection values) {
return only(new ArrayList<>(values));
}
/**
* Creates a range ¬{{@code null}}.
*
* @param type of range's elements
* @return created range
*/
static @NotNull Range exceptNull() {
return Objects::nonNull;
}
/**
* Creates a range ¬{{@code value}}.
*
* @param value the only value not contained by the range
* @param type of range's elements
* @return created range
*/
static @NotNull Range except(final @Ref T value) {
return value == null ? exceptNull() : tested -> !value.equals(tested);
}
/**
* Creates a range {x: x ∉ {@code values}}.
*
* @param values the only values not contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code values}
*/
@SafeVarargs
static @NotNull Range except(final @Own T @Own @NonNull ... values) {
Arrays.sort(values);
return value -> Arrays.binarySearch(values, value) < 0;
}
/**
* Creates a range {x: x ∉ {@code values}}.
*
* @param values the only values not contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code values}
*/
static @NotNull Range except(final @Ref @NonNull Collection values) {
return value -> !values.contains(value);
}
/**
* Creates a range {x: x ∉ {@code values}}.
*
* @param values the only values not contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code values} not preserving order
*/
@SafeVarargs
static @NotNull Range exceptCopy(final @Own T @Own @NonNull ... values) {
return except(Arrays.copyOf(values, values.length));
}
/**
* Creates a range {x: x ∉ {@code values}}.
*
* @param values the only values not contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code values} not preserving order
*/
static @NotNull Range exceptCopy(final @Ref @NonNull Collection values) {
return except(new HashSet<>(values));
}
/**
* Creates a range {x: x ∉ {@code values}}.
*
* @param values the only values not contained by the range
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code values} preserving order
*/
static @NotNull Range exceptCopyOrdered(final @Ref @NonNull Collection values) {
return except(new ArrayList<>(values));
}
/* ************************************************* Intervals ************************************************* */
/**
* Creates a range ({@code lowerBound}; +∞).
*
* @param lowerBound lower exclusive bound of the range
* @param type of range's elements
* @return created range
*/
static > @NotNull Range greater(final @Ref @NonNull T lowerBound) {
return value -> lowerBound.compareTo(value) < 0;
}
/**
* Creates a range [{@code lowerBound}; +∞).
*
* @param lowerBound lower inclusive bound of the range
* @param type of range's elements
* @return created range
*/
static > @NotNull Range greaterOrEqual(final @Ref @NonNull T lowerBound) {
return value -> lowerBound.compareTo(value) <= 0;
}
/**
* Creates a range (∞; {@code upperBound}).
*
* @param upperBound upper inclusive bound of the range
* @param type of range's elements
* @return created range
*/
static > @NotNull Range less(final @Ref @NonNull T upperBound) {
return value -> upperBound.compareTo(value) > 0;
}
/**
* Creates a range (∞; {@code upperBound}].
*
* @param upperBound upper exclusive bound of the range
* @param type of range's elements
* @return created range
*/
static > @NotNull Range lessOrEqual(final @Ref @NonNull T upperBound) {
return value -> upperBound.compareTo(value) >= 0;
}
/**
* Creates a range ({@code lowerBound}; {@code upperBound}).
*
* @param lowerBound lower exclusive bound of the range
* @param upperBound upper exclusive bound of the range
* @param type of range's elements
* @return created range
*/
static > @NotNull Range between(final @Ref @NonNull T lowerBound,
final @Ref @NonNull T upperBound) {
return value -> lowerBound.compareTo(value) < 0 && upperBound.compareTo(value) > 0;
}
/**
* Creates a range [{@code lowerBound}; {@code upperBound}].
*
* @param lowerBound lower inclusive bound of the range
* @param upperBound upper inclusive bound of the range
* @param type of range's elements
* @return created range
*/
static > @NotNull Range betweenOrEqual(final @Ref @NonNull T lowerBound,
final @Ref @NonNull T upperBound) {
return value -> lowerBound.compareTo(value) <= 0 && upperBound.compareTo(value) >= 0;
}
/**
* Creates a range ({@code lowerBound}; {@code upperBound}].
*
* @param lowerBound lower exclusive bound of the range
* @param upperBound upper inclusive bound of the range
* @param type of range's elements
* @return created range
*/
static > @NotNull Range fromExclusiveTo(final @Ref @NonNull T lowerBound,
final @Ref @NonNull T upperBound) {
return value -> lowerBound.compareTo(value) < 0 && upperBound.compareTo(value) >= 0;
}
/**
* Creates a range [{@code lowerBound}; {@code upperBound}).
*
* @param lowerBound lower inclusive bound of the range
* @param upperBound upper exclusive bound of the range
* @param type of range's elements
* @return created range
*/
static > @NotNull Range fromToExclusive(final @Ref @NonNull T lowerBound,
final @Ref @NonNull T upperBound) {
return value -> lowerBound.compareTo(value) <= 0 && upperBound.compareTo(value) > 0;
}
/* ************************************************** Joiners ************************************************** */
/**
* Creates a range {x: ∃ range ∈ ranges: x ∈ range}.
*
* @param ranges matched disjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code ranges}
*/
@SafeVarargs
static @NotNull Range anyOf(final @Ref @NotNull Range @NonNull ... ranges) {
return value -> {
for (val range : ranges) if (range.includes(value)) return true;
return false;
};
}
/**
* Creates a range {x: ∃ range ∈ ranges: x ∈ range}.
*
* @param ranges matched disjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code ranges}
*/
static @NotNull Range anyOf(final @Ref @NonNull Iterable<@NotNull Range> ranges) {
return value -> {
for (val range : ranges) if (range.includes(value)) return true;
return false;
};
}
/**
* Creates a range {x: ∃ range ∈ ranges: x ∈ range}.
*
* @param ranges matched disjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code ranges} preserving order
*/
@SafeVarargs
static @NotNull Range anyOfCopy(final @Ref @NotNull Range @NonNull ... ranges) {
return anyOf(Arrays.copyOf(ranges, ranges.length));
}
/**
* Creates a range {x: ∃ range ∈ ranges: x ∈ range}.
*
* @param ranges matched disjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code ranges} not preserving order
*/
static @NotNull Range anyOfCopy(final @Ref @NonNull Iterable<@NotNull Range> ranges) {
return anyOf(Iterables.toSet(ranges));
}
/**
* Creates a range {x: ∃ range ∈ ranges: x ∈ range}.
*
* @param ranges matched disjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code ranges} preserving order
*/
static @NotNull Range anyOfCopyOrdered(final @Ref @NonNull Iterable<@NotNull Range> ranges) {
return anyOf(Iterables.toList(ranges));
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∈ range}.
*
* @param ranges matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code ranges}
*/
@SafeVarargs
static @NotNull Range allOf(final @Ref @NotNull Range @NonNull ... ranges) {
return value -> {
for (val range : ranges) if (!range.includes(value)) return false;
return true;
};
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∈ range}.
*
* @param ranges matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code ranges}
*/
static @NotNull Range allOf(final @Ref @NonNull Iterable<@NotNull Range> ranges) {
return value -> {
for (val range : ranges) if (!range.includes(value)) return false;
return true;
};
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∈ range}.
*
* @param ranges matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code ranges} preserving order
*/
@SafeVarargs
static @NotNull Range allOfCopy(final @Ref @NotNull Range @NonNull ... ranges) {
return allOf(Arrays.copyOf(ranges, ranges.length));
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∈ range}.
*
* @param ranges matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code ranges} not preserving order
*/
static @NotNull Range allOfCopy(final @Ref @NonNull Iterable<@NotNull Range> ranges) {
return allOf(Iterables.toSet(ranges));
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∈ range}.
*
* @param ranges matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code ranges} preserving order
*/
static @NotNull Range allOfCopyOrdered(final @Ref @NonNull Iterable<@NotNull Range> ranges) {
return allOf(Iterables.toList(ranges));
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∉ range}.
*
* @param ranges not matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code ranges}
*/
@SafeVarargs
static @NotNull Range noneOf(final @Ref @NotNull Range @NonNull ... ranges) {
return value -> {
for (val range : ranges) if (range.includes(value)) return false;
return true;
};
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∉ range}.
*
* @param ranges not matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this takes ownership over {@code ranges}
*/
static @NotNull Range noneOf(final @Ref @NonNull Iterable<@NotNull Range> ranges) {
return value -> {
for (val range : ranges) if (range.includes(value)) return false;
return true;
};
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∉ range}.
*
* @param ranges not matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code ranges} preserving order
*/
@SafeVarargs
static @NotNull Range noneOfCopy(final @Ref @NotNull Range @NonNull ... ranges) {
return noneOf(Arrays.copyOf(ranges, ranges.length));
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∉ range}.
*
* @param ranges not matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code ranges} not preserving order
*/
static @NotNull Range noneOfCopy(final @Ref @NonNull Iterable<@NotNull Range> ranges) {
return noneOf(Iterables.toSet(ranges));
}
/**
* Creates a range {x: ∀ range ∈ ranges, x ∉ range}.
*
* @param ranges not matched conjunctive ranges
* @param type of range's elements
* @return created range
*
* @apiNote this copies {@code ranges} preserving order
*/
static @NotNull Range noneOfCopyOrdered(final @Ref @NonNull Iterable<@NotNull Range> ranges) {
return noneOf(Iterables.toList(ranges));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy