blob: 5f4c8186820979f1b83340df0aebe0c6a1ccc36b [file] [log] [blame]
// 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<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(new LinkedHashSet<>(), new LinkedHashSet<>());
}
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();
}
}
}