/******************************************************************************* * Copyright (c) 2016 Ericsson * * 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.analysis.os.linux.ui.views.resources; import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent; import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry; /** * Aggregate TimeEvent iterator, this takes multiple streams of events and * merges them into one single time event stream * * @author Matthew Khouzam * @since 2.0 */ public class AggregateEventIterator implements Iterator<@NonNull ITimeEvent> { private final List<org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.resources.CachingIterator> fIterators = new ArrayList<>(); private final Comparator<ITimeEvent> fComparator; /** * Constructor * * @param contributors * the entries to aggregate * @param comparator * The comparator to sort time events */ public AggregateEventIterator(@NonNull List<ITimeGraphEntry> contributors, Comparator<ITimeEvent> comparator) { this(contributors, Long.MIN_VALUE, Long.MAX_VALUE, 1, comparator); } /** * Constructor with a time range * * @param contributors * the entries to aggregate * @param startTime * start time in nanoseconds * @param endTime * stop time in nanoseconds * @param duration * duration of one pixel in nanoseconds * @param comparator * The comparator to sort time events */ public AggregateEventIterator(@NonNull List<ITimeGraphEntry> contributors, long startTime, long endTime, long duration, Comparator<ITimeEvent> comparator) { fComparator = comparator; contributors.forEach(timeGraphEntry -> { final Iterator<@NonNull ITimeEvent> timeEventsIterator = timeGraphEntry.getTimeEventsIterator(startTime, endTime, duration); if (timeEventsIterator != null) { CachingIterator iterator = new CachingIterator(timeEventsIterator, comparator); if (iterator.hasNext()) { fIterators.add(iterator); } } }); } @Override public boolean hasNext() { return !fIterators.isEmpty(); } @Override public @NonNull ITimeEvent next() { final List<org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.resources.CachingIterator> iterators = fIterators; if (iterators.isEmpty()) { throw new NoSuchElementException("Aggregate iterator is empty"); //$NON-NLS-1$ } ITimeEvent winner = iterators.get(0).peek(); long trimTime = winner.getTime() + winner.getDuration(); for (int i = 1; i < iterators.size(); i++) { CachingIterator iterator = iterators.get(i); ITimeEvent candidate = iterator.peek(); if (candidate.getTime() < winner.getTime()) { trimTime = Math.min(winner.getTime(), candidate.getTime() + candidate.getDuration()); winner = candidate; } else if (candidate.getTime() == winner.getTime()) { trimTime = Math.min(trimTime, candidate.getTime() + candidate.getDuration()); if (fComparator.compare(candidate, winner) < 0) { winner = candidate; } } else { trimTime = Math.min(trimTime, candidate.getTime()); } } /* Trim the next event before the trim time, if necessary. */ final ITimeEvent next = (trimTime < (winner.getDuration() + winner.getTime())) ? winner.splitBefore(trimTime) : winner; /* Trim all remaining events after the trim time, if necessary. */ Iterator<CachingIterator> iteratorIterator = iterators.iterator(); while (iteratorIterator.hasNext()) { CachingIterator iterator = iteratorIterator.next(); iterator.trim(trimTime); /* Remove empty iterators from the list */ if (!iterator.hasNext()) { iteratorIterator.remove(); } } return checkNotNull(next); } }