+ public static class SegmentStoreWithRange<E extends ISegment> implements Iterable<E> {
+ /**
+ * Constant used in the {@link #getElement(long)} method to return the
+ * last element of the store
+ */
+ public static final long LAST = Long.MIN_VALUE;
+ private final ISegmentStore<E> fSegmentStore;
+ private final TmfTimeRange fRange;
+
+ private @Nullable Comparator<ISegment> fComparator = null;
+ private @Nullable Iterable<E> fIterable = null;
+ private @Nullable Predicate<E> fPredicate = null;
+
+ private long fLastReadPos = -1;
+ private @Nullable Iterator<E> fIterator = null;
+
+ /**
+ * Constructor
+ *
+ * @param segStore
+ * The segment store
+ * @param range
+ * The time range to get for this segment store
+ */
+ public SegmentStoreWithRange(ISegmentStore<E> segStore, TmfTimeRange range) {
+ fSegmentStore = segStore;
+ fRange = range;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param segStore
+ * The segment store
+ * @param range
+ * The time range to get for this segment store
+ * @param predicate
+ * An extra predicate to further filter the segments
+ */
+ public SegmentStoreWithRange(ISegmentStore<E> segStore, TmfTimeRange range, Predicate<E> predicate) {
+ fSegmentStore = segStore;
+ fRange = range;
+ fPredicate = predicate;
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return NonNullUtils.checkNotNull(getIterable().iterator());
+ }
+
+ /**
+ * Set the comparator for this store
+ *
+ * @param comparator
+ * The comparator to use for this store
+ */
+ public void setComparator(Comparator<ISegment> comparator) {
+ fComparator = comparator;
+ fIterable = null;
+ resetIterator();
+ }
+
+ /**
+ * Get the iterable to iterate over this segment store
+ *
+ * @return The iterable object to iterate through the segment store
+ */
+ private Iterable<E> getIterable() {
+ Iterable<E> iterable = fIterable;
+ if (iterable == null) {
+ Comparator<ISegment> comparator = fComparator;
+ Predicate<? super E> predicate = fPredicate;
+ if (comparator != null) {
+ iterable = fSegmentStore.getIntersectingElements(fRange.getStartTime().toNanos(), fRange.getEndTime().toNanos(), comparator);
+ } else {
+ iterable = fSegmentStore.getIntersectingElements(fRange.getStartTime().toNanos(), fRange.getEndTime().toNanos());
+ }
+ if (predicate != null) {
+ iterable = Iterables.filter(iterable, input -> predicate.test(input));
+ }
+ fIterable = iterable;
+ }
+ return iterable;
+ }
+
+ private Iterator<? extends @NonNull ISegment> resetIterator() {
+ Iterator<E> iterator = NonNullUtils.checkNotNull(getIterable().iterator());
+ fIterator = iterator;
+ fLastReadPos = -1;
+ return iterator;
+ }
+
+ /**
+ * Get the element at position index. If the index is {@link #LAST}, it
+ * will return the last element from the end of the iterator, if a
+ * comparator was specified, otherwise it will return the first event.
+ * This method with {@link #LAST} is meant to be used with sorted
+ * stores.
+ *
+ * @param index
+ * The index of the requested element. If index is
+ * {@link #LAST} it will return the last element, at the end
+ * of the iterator.
+ * @return The segment at position index or <code>null</code> if it is
+ * not available
+ */
+ public @Nullable ISegment getElement(long index) {
+ long idx = index;
+ // Special code path if we are looking for an element from the end there is a comparator
+ if (index == LAST) {
+ Comparator<@NonNull ISegment> comparator = fComparator;
+ if (comparator != null) {
+ return getLastElement(comparator);
+ }
+ // No comparator, so impossible the easily get last element,
+ // just return the first as it is random anyway
+ idx = 0;
+ }
+ Iterable<? extends @NonNull ISegment> iterable = fIterable;
+ if (iterable instanceof List<?> && idx <= Integer.MAX_VALUE) {
+ return Iterables.get(iterable, (int) idx, null);
+ }
+ Iterator<? extends @NonNull ISegment> iterator = fIterator;
+ if (iterator == null || idx <= fLastReadPos) {
+ iterator = resetIterator();
+ }
+ ISegment segment = null;
+ while (fLastReadPos < idx && iterator.hasNext()) {
+ fLastReadPos++;
+ segment = NonNullUtils.checkNotNull(iterator.next());
+ }
+ if (fLastReadPos == idx) {
+ return segment;
+ }
+ return null;
+ }
+
+ private @Nullable ISegment getLastElement(Comparator<@NonNull ISegment> comparator) {
+ Iterable<? extends ISegment> baseIterable = fIterable;
+ if (baseIterable instanceof List<?>) {
+ return Iterables.getLast(baseIterable, null);
+ }
+ // Not a trivial get, so get an iterable for the reverse comparator
+ // and fetch first element
+ Predicate<? super E> predicate = fPredicate;
+ Iterable<E> iterable = fSegmentStore.getIntersectingElements(fRange.getStartTime().toNanos(), fRange.getEndTime().toNanos(), comparator.reversed());
+ if (predicate != null) {
+ iterable = Iterables.filter(iterable, input -> predicate.test(input));
+ }
+ // FIXME: The cast turns an error into a warning for this null
+ // value, but it is completely unnecessary otherwise
+ return Iterables.getFirst((Iterable<? extends ISegment>) iterable, null);
+ }
+
+ /**
+ * Get the number of segments
+ *
+ * TODO: Try to live without this method, this is not lazy enough
+ *
+ * @return The number of segment in the current iterable
+ */
+ public long getSegmentCount() {
+ return Iterables.size(getIterable());
+ }
+ }