package org.aksw.jena_sparql_api.utils; import java.util.Collection; import java.util.Map.Entry; import java.util.Set; import java.util.function.BiFunction; import java.util.stream.Collectors; import com.google.common.collect.DiscreteDomain; import com.google.common.collect.Range; public class RangeUtils { public static final Range<Long> rangeStartingWithZero = Range.atLeast(0l); /** * Convert a range relative within another one to an absolute range * * @param outer * @param relative * @param domain * @param addition * @return */ public static <C extends Comparable<C>> Range<C> makeAbsolute(Range<C> outer, Range<C> relative, DiscreteDomain<C> domain, BiFunction<C, Long, C> addition) { long distance = domain.distance(outer.lowerEndpoint(), relative.lowerEndpoint()); Range<C> shifted = RangeUtils.shift(relative, distance, domain, addition); Range<C> result = shifted.intersection(outer); return result; } public static <C extends Comparable<C>> Range<C> shift(Range<C> range, long distance, DiscreteDomain<C> domain) { BiFunction<C, Long, C> addition = (item, d) -> { C result = item; if(d >= 0) { for(int i = 0; i < d; ++i) { result = domain.next(item); } } else { for(int i = 0; i < -d; ++i) { result = domain.previous(item); } } return result; }; Range<C> result = shift(range, distance, domain, addition); return result; } public static <C extends Comparable<C>> Range<C> shift(Range<C> rawRange, long distance, DiscreteDomain<C> domain, BiFunction<C, Long, C> addition) { Range<C> range = rawRange.canonical(domain); Range<C> result; if(range.hasLowerBound()) { C oldLower = range.lowerEndpoint(); C newLower = addition.apply(oldLower, distance); if(range.hasUpperBound()) { C oldUpper = range.upperEndpoint(); C newUpper = addition.apply(oldUpper, distance); result = Range.closedOpen(newLower, newUpper); } else { result = Range.atLeast(oldLower); } } else { throw new IllegalArgumentException("Cannot displace a range without lower bound"); } return result; } public static <K extends Comparable<K>, V> Set<Entry<Range<K>, V>> getIntersectingRanges(Range<K> r, Collection<Entry<Range<K>, V>> ranges) { Set<Entry<Range<K>, V>> result = ranges.stream() .filter(e -> !r.intersection(e.getKey()).isEmpty()) .collect(Collectors.toSet()); return result; } //public static NavigableMap<T extends Comparable> getOverlapping items public static Range<Long> startFromZero(Range<Long> range) { Range<Long> result = range.intersection(rangeStartingWithZero); return result; } public static PageInfo<Long> computeRange(Range<Long> range, long pageSize) { // Example: If pageSize=100 and offset = 130, then we will adjust the offset to 100, and use a subOffset of 30 long o = range.hasLowerBound() ? range.lowerEndpoint() : 0; long subOffset = o % pageSize; o -= subOffset; // Adjust the limit to a page boundary; the original limit becomes the subLimit // And we will extend the new limit to the page boundary again. // Example: If pageSize=100 and limit = 130, then we adjust the new limit to 200 Range<Long> outerRange; Range<Long> innerRange; if(range.hasUpperBound()) { long limit = range.upperEndpoint() - range.lowerEndpoint(); long l = limit; long mod = l % pageSize; long extra = mod != 0 ? pageSize - mod : 0; l += extra; outerRange = Range.closedOpen(o, o + l); innerRange = Range.closedOpen(subOffset, limit); } else { outerRange = Range.atLeast(o); innerRange = Range.atLeast(subOffset); } PageInfo<Long> result = new PageInfo<>(outerRange, innerRange); return result; } }