| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package accord.primitives; |
| |
| import accord.api.RoutingKey; |
| import accord.utils.IndexedFoldToLong; |
| import accord.utils.IndexedTriFold; |
| import net.nicoulaj.compilecommand.annotations.Inline; |
| |
| import javax.annotation.Nonnull; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.function.Predicate; |
| import java.util.stream.Stream; |
| |
| import com.google.common.collect.ImmutableMap; |
| |
| import static accord.primitives.AbstractRanges.UnionMode.MERGE_OVERLAPPING; |
| import static accord.primitives.Routables.Slice.Overlapping; |
| |
| public class Ranges extends AbstractRanges implements Iterable<Range>, Seekables<Range, Ranges>, Unseekables<Range>, Participants<Range> |
| { |
| public static final Ranges EMPTY = new Ranges(new Range[0]); |
| |
| private Ranges(@Nonnull Range[] ranges) |
| { |
| super(ranges); |
| } |
| |
| public static Ranges of(Range... ranges) |
| { |
| return AbstractRanges.of(Ranges::ofSortedAndDeoverlappedUnchecked, ranges); |
| } |
| |
| public static Ranges ofSorted(Range... ranges) |
| { |
| return AbstractRanges.deoverlapSorted(Ranges::ofSortedAndDeoverlappedUnchecked, ranges, ranges.length, MERGE_OVERLAPPING); |
| } |
| |
| public static Ranges ofSortedAndDeoverlapped(Range... ranges) |
| { |
| return AbstractRanges.ofSortedAndDeoverlapped(Ranges::ofSortedAndDeoverlappedUnchecked, ranges); |
| } |
| |
| static Ranges ofSortedAndDeoverlappedUnchecked(Range... ranges) |
| { |
| if (ranges.length == 0) |
| return EMPTY; |
| |
| return new Ranges(ranges); |
| } |
| |
| public static Ranges single(Range range) |
| { |
| return new Ranges(new Range[]{range}); |
| } |
| |
| public Ranges select(int[] indexes) |
| { |
| Range[] selection = new Range[indexes.length]; |
| for (int i=0; i<indexes.length; i++) |
| selection[i] = ranges[indexes[i]]; |
| return ofSortedAndDeoverlapped(Ranges::ofSortedAndDeoverlappedUnchecked, selection); |
| } |
| |
| public Stream<Range> stream() |
| { |
| return Stream.of(ranges); |
| } |
| |
| @Override |
| public final Ranges slice(Ranges ranges) |
| { |
| return slice(ranges, Overlapping); |
| } |
| |
| @Override |
| public final Ranges slice(Ranges ranges, Slice slice) |
| { |
| return slice(ranges, slice, this, null, (i1, i2, rs) -> i1.ranges == rs ? i1 : Ranges.ofSortedAndDeoverlapped(rs)); |
| } |
| |
| public Ranges intersecting(Routables<?> keysOrRanges) |
| { |
| return intersecting(this, keysOrRanges, this, (i1, i2, rs) -> i2.ranges == rs ? i2 : new Ranges(rs)); |
| } |
| |
| @Override |
| public Ranges with(Unseekables<Range> with) |
| { |
| return with((AbstractRanges) with); |
| } |
| |
| @Override |
| public Participants<Range> with(Participants<Range> with) |
| { |
| return with((AbstractRanges) with); |
| } |
| |
| @Override |
| public Ranges with(Ranges that) |
| { |
| return union(MERGE_OVERLAPPING, that); |
| } |
| |
| public Ranges with(AbstractRanges that) |
| { |
| return union(MERGE_OVERLAPPING, that); |
| } |
| |
| @Override |
| public Unseekables<Range> with(RoutingKey withKey) |
| { |
| if (contains(withKey)) |
| return this; |
| |
| return with(Ranges.of(withKey.asRange())); |
| } |
| |
| @Override |
| public UnseekablesKind kind() |
| { |
| return UnseekablesKind.RoutingRanges; |
| } |
| |
| @Override |
| public Ranges toParticipants() |
| { |
| return this; |
| } |
| |
| @Override |
| public Ranges toRanges() |
| { |
| return this; |
| } |
| |
| @Override |
| public FullRangeRoute toRoute(RoutingKey homeKey) |
| { |
| if (!contains(homeKey)) |
| { |
| Range[] ranges = with(Ranges.of(homeKey.asRange())).ranges; |
| return new FullRangeRoute(homeKey, false, ranges); |
| } |
| return new FullRangeRoute(homeKey, true, ranges); |
| } |
| |
| public Ranges union(UnionMode mode, Ranges that) |
| { |
| return union(mode, this, that, this, that, (left, right, ranges) -> { |
| if (ranges == left.ranges) return left; |
| if (ranges == right.ranges) return right; |
| return Ranges.ofSortedAndDeoverlapped(ranges); |
| }); |
| } |
| |
| public Ranges union(UnionMode mode, AbstractRanges that) |
| { |
| return union(mode, this, that, this, that, (left, right, ranges) -> { |
| if (ranges == left.ranges) return left; |
| return Ranges.ofSortedAndDeoverlapped(ranges); |
| }); |
| } |
| |
| public Ranges mergeTouching() |
| { |
| return mergeTouching(this, Ranges::ofSortedAndDeoverlapped); |
| } |
| |
| public Map<Boolean, Ranges> partitioningBy(Predicate<? super Range> test) |
| { |
| if (isEmpty()) |
| return Collections.emptyMap(); |
| List<Range> trues = new ArrayList<>(); |
| List<Range> falses = new ArrayList<>(); |
| for (Range range : this) |
| (test.test(range) ? trues : falses).add(range); |
| if (trues.isEmpty()) return ImmutableMap.of(Boolean.FALSE, this); |
| if (falses.isEmpty()) return ImmutableMap.of(Boolean.TRUE, this); |
| return ImmutableMap.of(Boolean.TRUE, Ranges.ofSortedAndDeoverlapped(trues.toArray(new Range[0])), |
| Boolean.FALSE, Ranges.ofSortedAndDeoverlapped(falses.toArray(new Range[0]))); |
| } |
| |
| @Inline |
| public final long foldl(Ranges intersect, IndexedFoldToLong<Range> fold, long param, long accumulator, long terminalValue) |
| { |
| return Routables.foldl(this, intersect, fold, param, accumulator, terminalValue); |
| } |
| |
| @Inline |
| public final <P1, P2, V> V foldl(Ranges intersect, IndexedTriFold<P1, P2, Range, V> fold, P1 p1, P2 p2, V accumulator) |
| { |
| return Routables.foldl(this, intersect, fold, p1, p2, accumulator, i -> false); |
| } |
| } |