blob: 3778a7629b76684b6f30a069a2cadf2ff9f158a5 [file] [log] [blame]
/**********************************************************************
* Copyright (c) 2018, 2019 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.tracecompass.tmf.core.model.timegraph;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.tmf.core.model.filters.SelectionTimeQueryFilter;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
/**
* Implements timegraph state filtering support. This interface provide default
* method to provide the inputs and do the filtering.
*
* @author Jean-Christian Kouame
* @since 4.0
*/
public interface ITimeGraphStateFilter {
/**
* Filter the time graph state and add it to the state list
*
* @param stateList
* The timegraph state list
* @param timeGraphState
* The current timegraph state
* @param key
* The timegraph entry model id
* @param predicates
* The predicates used to filter the timegraph state. It is a map of
* predicate by property. The value of the property is an integer
* representing a bitmask associated to that property. The status of
* each property will be set for the timegraph state according to the
* associated predicate test result.
* @param monitor
* The progress monitor
* @deprecated Use the {@link #applyFilterAndAddState(List, ITimeGraphState, Long, Multimap, Map, IProgressMonitor)} instead
*/
@Deprecated
default void addToStateList(List<ITimeGraphState> stateList, ITimeGraphState timeGraphState, Long key, Map<Integer, Predicate<Map<String, String>>> predicates, @Nullable IProgressMonitor monitor) {
if (!predicates.isEmpty()) {
// Get the filter external input data
long startTime = timeGraphState.getStartTime();
SelectionTimeQueryFilter filter = new SelectionTimeQueryFilter(Collections.singletonList(startTime), Collections.singleton(Objects.requireNonNull(key)));
Map<@NonNull String, @NonNull String> input = getFilterInput(filter, monitor);
input.putAll(timeGraphState.computeData());
// Test each predicates and set the status of the property associated to the
// predicate
for (Map.Entry<Integer, Predicate<Map<String, String>>> mapEntry : predicates.entrySet()) {
Predicate<Map<String, String>> value = Objects.requireNonNull(mapEntry.getValue());
boolean status = value.test(input);
Integer property = Objects.requireNonNull(mapEntry.getKey());
if (property == IFilterProperty.DIMMED || property == IFilterProperty.EXCLUDE) {
timeGraphState.setProperty(property, !status);
} else {
timeGraphState.setProperty(property, status);
}
}
}
if (timeGraphState.isPropertyActive(IFilterProperty.EXCLUDE)) {
TimeGraphState timeGraphState2 = new TimeGraphState(timeGraphState.getStartTime(), timeGraphState.getDuration(), Integer.MIN_VALUE);
timeGraphState2.setActiveProperties(timeGraphState.getActiveProperties());
stateList.add(timeGraphState2);
} else {
stateList.add(timeGraphState);
}
}
/**
* Filter the time graph state and add it to the state list.
*
* @param stateList
* The timegraph state list
* @param timeGraphState
* The current timegraph state
* @param entryId
* The timegraph entry model id
* @param predicates
* The predicates used to filter the timegraph state. It is a map
* of predicate by property. The value of the property is an
* integer representing a bitmask associated to that property.
* The status of each property will be set for the timegraph
* state according to the associated predicate test result.
* @param monitor
* The progress monitor
* @since 5.0
*/
default void applyFilterAndAddState(List<ITimeGraphState> stateList, ITimeGraphState timeGraphState, Long entryId, Map<Integer, Predicate<Multimap<String, Object>>> predicates, @Nullable IProgressMonitor monitor) {
applyFilterAndAddState(stateList, timeGraphState, entryId, predicates, null, monitor);
}
/**
* Filter the time graph state and add it to the state list.
* <p>
* If a list of times is specified, all states that intersect a time in the
* list are included. States that do not intersect any time (e.g. in gap)
* are only included if they are neither dimmed nor excluded, and a maximum
* of one state per gap is included. The method must be called in
* chronological order of states, otherwise the result is unspecified.
*
* @param stateList
* The timegraph state list
* @param timeGraphState
* The current timegraph state
* @param entryId
* The timegraph entry model id
* @param predicates
* The predicates used to filter the timegraph state. It is a map
* of predicate by property. The value of the property is an
* integer representing a bitmask associated to that property.
* The status of each property will be set for the timegraph
* state according to the associated predicate test result.
* @param times
* The list of times that should be included in the state list.
* If set to <code>null</code>, all matching states should be
* included.
* @param monitor
* The progress monitor
* @since 5.2
*/
default void applyFilterAndAddState(List<ITimeGraphState> stateList, ITimeGraphState timeGraphState, Long entryId, Map<Integer, Predicate<Multimap<String, Object>>> predicates, @Nullable List<Long> times, @Nullable IProgressMonitor monitor) {
long startTime = timeGraphState.getStartTime();
long endTime = timeGraphState.getStartTime() + timeGraphState.getDuration();
// Discard all additional states in same gap after first match
if (times != null && !stateList.isEmpty()) {
ITimeGraphState lastState = Iterables.getLast(stateList);
long lastStart = lastState.getStartTime();
long lastEnd = lastStart + lastState.getDuration();
int index = Collections.binarySearch(times, lastStart);
if (index < 0) {
index = -index - 1;
if (index >= times.size()) {
// Skip all after the last query time
return;
}
if (lastEnd < times.get(index) && endTime <= times.get(index)) {
// If last state was in gap, skip all others in same gap
return;
}
}
}
if (!predicates.isEmpty()) {
// Get the filter external input data
Multimap<@NonNull String, @NonNull Object> input = HashMultimap.create();
input.putAll(getFilterData(entryId, startTime, monitor));
input.putAll(timeGraphState.getMetadata());
// Test each predicates and set the status of the property
// associated to the predicate
for (Map.Entry<Integer, Predicate<Multimap<String, Object>>> mapEntry : predicates.entrySet()) {
Predicate<Multimap<String, Object>> value = Objects.requireNonNull(mapEntry.getValue());
boolean status = value.test(input);
Integer property = Objects.requireNonNull(mapEntry.getKey());
if (property == IFilterProperty.DIMMED || property == IFilterProperty.EXCLUDE) {
timeGraphState.setProperty(property, !status);
} else {
timeGraphState.setProperty(property, status);
}
}
}
if (times != null && (timeGraphState.getActiveProperties() & (IFilterProperty.DIMMED | IFilterProperty.EXCLUDE)) != 0) {
// Do not include state in gap if it is dimmed or excluded
int index = Collections.binarySearch(times, startTime);
if (index < 0) {
index = -index - 1;
if (index >= times.size() || (endTime < times.get(index))) {
return;
}
}
}
if (timeGraphState.isPropertyActive(IFilterProperty.EXCLUDE)) {
// Replace excluded state with a null state
TimeGraphState timeGraphState2 = new TimeGraphState(timeGraphState.getStartTime(), timeGraphState.getDuration(), Integer.MIN_VALUE);
timeGraphState2.setActiveProperties(timeGraphState.getActiveProperties());
stateList.add(timeGraphState2);
} else {
stateList.add(timeGraphState);
}
}
/**
* Get input data used for filtering
*
* @param filter
* The selection time query filter
* @param monitor
* The progress monitor
* @return The map of input data
* @deprecated Use the {@link #getFilterData(long, long, IProgressMonitor)} instead
*/
@Deprecated
default Map<String, String> getFilterInput(SelectionTimeQueryFilter filter, @Nullable IProgressMonitor monitor) {
return new HashMap<>();
}
/**
* Get input data used for filtering
*
* @param entryId
* The ID of the entry
* @param time
* The time at which to get data
* @param monitor
* The progress monitor
* @return The map of input data
* @since 5.0
*/
default Multimap<String, Object> getFilterData(long entryId, long time, @Nullable IProgressMonitor monitor) {
return ImmutableMultimap.of();
}
/**
* Merge multiple multimaps into one. The resulting map is not immutable so
* callers can fill it with additional data.
*
* @param maps
* The maps to merge
* @return A multimap that is the result of the merge of the maps in
* arguments
* @since 5.0
*/
@SafeVarargs
static Multimap<String, Object> mergeMultimaps(Multimap<String, Object>... maps) {
Multimap<@NonNull String, @NonNull Object> data = HashMultimap.create();
for (Multimap<String, Object> multimap : maps) {
data.putAll(multimap);
}
return data;
}
}