// 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.LinkedHashSet; 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} or {@code Label}. */ @Immutable public final class ResolvedTargets { 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 ResolvedTargets failed() { return (ResolvedTargets) FAILED_RESULT; } @SuppressWarnings("unchecked") public static ResolvedTargets empty() { return (ResolvedTargets) EMPTY_RESULT; } public static ResolvedTargets of(T target) { return new ResolvedTargets<>(ImmutableSet.of(target), false); } private final boolean hasError; private final ImmutableSet targets; private final ImmutableSet filteredTargets; public ResolvedTargets(Set targets, Set filteredTargets, boolean hasError) { this.targets = ImmutableSet.copyOf(targets); this.filteredTargets = ImmutableSet.copyOf(filteredTargets); this.hasError = hasError; } public ResolvedTargets(Set 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 getTargets() { return targets; } public ImmutableSet getFilteredTargets() { return filteredTargets; } /** * Returns a builder using concurrent sets, as long as you don't call filter. */ public static ResolvedTargets.Builder concurrentBuilder() { return new ResolvedTargets.Builder<>( Sets.newConcurrentHashSet(), Sets.newConcurrentHashSet()); } public static ResolvedTargets.Builder builder() { return new ResolvedTargets.Builder<>(); } public static final class Builder { private Set targets; private Set filteredTargets; private volatile boolean hasError = false; private Builder() { this(new LinkedHashSet<>(), new LinkedHashSet<>()); } private Builder(Set targets, Set filteredTargets) { this.targets = targets; this.filteredTargets = filteredTargets; } public ResolvedTargets build() { return new ResolvedTargets<>(targets, filteredTargets, hasError); } public Builder merge(ResolvedTargets other) { removeAll(other.filteredTargets); addAll(other.targets); if (other.hasError) { hasError = true; } return this; } public Builder add(T target) { targets.add(target); filteredTargets.remove(target); return this; } public Builder addAll(Collection targets) { this.targets.addAll(targets); this.filteredTargets.removeAll(targets); return this; } public void remove(T target) { targets.remove(target); filteredTargets.add(target); } public Builder removeAll(Collection targets) { this.filteredTargets.addAll(targets); this.targets.removeAll(targets); return this; } public Builder filter(Predicate predicate) { Set oldTargets = targets; targets = Sets.newLinkedHashSet(); for (T target : oldTargets) { if (predicate.apply(target)) { add(target); } else { remove(target); } } return this; } public Builder setError() { this.hasError = true; return this; } public Builder mergeError(boolean hasError) { this.hasError |= hasError; return this; } public boolean isEmpty() { return targets.isEmpty(); } } }