// Copyright 2014 The Bazel Authors. All rights reserved. // // Licensed 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 com.google.devtools.build.lib.cmdline; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import java.util.Collection; import java.util.Set; import javax.annotation.concurrent.Immutable; /** * Contains the result of the target pattern evaluation. This is a specialized container class for * the result of target pattern resolution. There is no restriction on the element type, but it will * usually be {@code Target}. */ @Immutable public final class ResolvedTargets<T> { private static final ResolvedTargets<?> FAILED_RESULT = new ResolvedTargets<>(ImmutableSet.of(), ImmutableSet.of(), true); private static final ResolvedTargets<?> EMPTY_RESULT = new ResolvedTargets<>(ImmutableSet.of(), ImmutableSet.of(), false); @SuppressWarnings("unchecked") public static <T> ResolvedTargets<T> failed() { return (ResolvedTargets<T>) FAILED_RESULT; } @SuppressWarnings("unchecked") public static <T> ResolvedTargets<T> empty() { return (ResolvedTargets<T>) EMPTY_RESULT; } public static <T> ResolvedTargets<T> of(T target) { return new ResolvedTargets<>(ImmutableSet.<T>of(target), false); } private final boolean hasError; private final ImmutableSet<T> targets; private final ImmutableSet<T> filteredTargets; public ResolvedTargets(Set<T> targets, Set<T> filteredTargets, boolean hasError) { this.targets = ImmutableSet.copyOf(targets); this.filteredTargets = ImmutableSet.copyOf(filteredTargets); this.hasError = hasError; } public ResolvedTargets(Set<T> targets, boolean hasError) { this.targets = ImmutableSet.copyOf(targets); this.filteredTargets = ImmutableSet.of(); this.hasError = hasError; } @Override public String toString() { return "ResolvedTargets(" + targets + ", filtered=" + filteredTargets + ", hasError=" + hasError + ")"; } public boolean hasError() { return hasError; } public ImmutableSet<T> getTargets() { return targets; } public ImmutableSet<T> getFilteredTargets() { return filteredTargets; } /** * Returns a builder using concurrent sets, as long as you don't call filter. */ public static <T> ResolvedTargets.Builder<T> concurrentBuilder() { return new ResolvedTargets.Builder<>( Sets.<T>newConcurrentHashSet(), Sets.<T>newConcurrentHashSet()); } public static <T> ResolvedTargets.Builder<T> builder() { return new ResolvedTargets.Builder<>(); } public static final class Builder<T> { private Set<T> targets; private Set<T> filteredTargets; private volatile boolean hasError = false; private Builder() { this(Sets.<T>newLinkedHashSet(), Sets.<T>newLinkedHashSet()); } private Builder(Set<T> targets, Set<T> filteredTargets) { this.targets = targets; this.filteredTargets = filteredTargets; } public ResolvedTargets<T> build() { return new ResolvedTargets<>(targets, filteredTargets, hasError); } public Builder<T> merge(ResolvedTargets<T> other) { removeAll(other.filteredTargets); addAll(other.targets); if (other.hasError) { hasError = true; } return this; } public Builder<T> add(T target) { targets.add(target); filteredTargets.remove(target); return this; } public Builder<T> addAll(Collection<T> targets) { this.targets.addAll(targets); this.filteredTargets.removeAll(targets); return this; } public void remove(T target) { targets.remove(target); filteredTargets.add(target); } public Builder<T> removeAll(Collection<T> targets) { this.filteredTargets.addAll(targets); this.targets.removeAll(targets); return this; } public Builder<T> filter(Predicate<T> predicate) { Set<T> oldTargets = targets; targets = Sets.newLinkedHashSet(); for (T target : oldTargets) { if (predicate.apply(target)) { add(target); } else { remove(target); } } return this; } public Builder<T> setError() { this.hasError = true; return this; } public Builder<T> mergeError(boolean hasError) { this.hasError |= hasError; return this; } public boolean isEmpty() { return targets.isEmpty(); } } }