/******************************************************************************* * Copyright (c) 2017 École Polytechnique de Montréal * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html ******************************************************************************/ package org.eclipse.tracecompass.internal.provisional.datastore.core.condition; import java.util.Collection; import java.util.Collections; import java.util.Set; import java.util.TreeSet; import java.util.function.Predicate; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.internal.datastore.core.condition.ContinuousRangeCondition; import org.eclipse.tracecompass.internal.datastore.core.condition.DiscreteRangeCondition; /** * Describe conditions such as ranges or sets. These conditions are used for * example to abstract queries on history trees. * * New RangeCondition objects can be generated by using the * {@link #forContinuousRange} and {@link #fromCollection} factory methods. * * @author Loïc Prieur-Drevon * * @param <E> * Comparable type that extends Number, typically an Integer or a * Long * @noimplement Accessor interface */ public interface RangeCondition<@NonNull E extends Comparable<E>> extends Predicate<E> { /** * Get the lower bound of this range * * @return the lowest acceptable value for this condition. */ @NonNull E min(); /** * Get the upper bound of this range * * @return the highest acceptable value for this condition. */ @NonNull E max(); /** * Test whether a value is within this specific range boundaries. If the * range is continuous, it will return <code>true</code> if the value is * between the lower and upper bounds. If the range is discrete, it will * return <code>true</code> if the requested element is one of the elements * in the discrete range. * * @param element * value that we want to test * @return true if element is contained in this condition's set or range */ @Override boolean test(@NonNull E element); /** * Determine if the current range intersects a ranged bounded by the values * in parameter * * @param low * interval's lower bound * @param high * interval's upper bound * @return true if this element intersects the range's condition or any of * the set's elements */ boolean intersects(@NonNull E low, @NonNull E high); /** * Reduce the Condition to elements or the range within bounds from and to. * <code>null</code> is returned if the resulting condition is empty. * * @param from * lower bound for the condition reduction. * @param to * upper bound for the condition reduction. * @return the reduced condition or <code>null</code> if the reduced * condition does not contain any element */ @Nullable RangeCondition<E> subCondition(@NonNull E from, @NonNull E to); /** * Get a condition of a single element. * * @param elem The single element * @return The corresponding range condition */ static <E extends Comparable<E>> RangeCondition<E> singleton(E elem) { return new DiscreteRangeCondition<>(Collections.singleton(elem)); } /** * Get a range condition representing a continuous time range. * * @param bound1 * The first bound * @param bound2 * The second bound. It's fine for bound2 to be > or < than * bound1. * @return The corresponding range condition */ static <E extends Comparable<E>> RangeCondition<E> forContinuousRange( E bound1, E bound2) { return new ContinuousRangeCondition<>(bound1, bound2); } /** * Get a range condition representing distinct elements within a range. * * @param collection * A collection of individual elements * @return The corresponding range condition */ static <E extends Comparable<E>> RangeCondition<E> fromCollection( Collection<E> collection) { return new DiscreteRangeCondition<>(collection); } /** * Utility method to generate a range condition of discrete elements, by * providing a min, a max, and a "step" between each elements. Note that * "max" will be included in the condition. * * For example, specifying (min=1, max=10, step=2) will return a condition * representing [1, 3, 5, 7, 9, 10]. * * @param min * The minimum value * @param max * The maximum value. Should be greater than or equal to min * @param step * The step between each element * @return The corresponding range condition */ static RangeCondition<Long> forDiscreteRange(long min, long max, long step) { if (max < min || step < 0) { throw new IllegalArgumentException("Invalid range: max should be < min and step >= 0 (max: " + max + ", min:" + min + ", step: " + step + ')'); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ } /* * If resolution is 0, adjust increment to return consecutive number */ long increment = Math.max(step, 1L); Set<Long> times = new TreeSet<>(); for (long t = min; t < max; t += increment) { times.add(t); } times.add(max); return fromCollection(times); } }