// Copyright 2015 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.query2.engine; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.MapMaker; import com.google.devtools.build.lib.collect.CompactHashSet; import java.util.Collections; import java.util.Set; /** Several query utilities to make easier to work with query callbacks and uniquifiers. */ public final class QueryUtil { private QueryUtil() { } /** A {@link Callback} that can aggregate all the partial results into one set. */ public interface AggregateAllCallback extends Callback { Set getResult(); } /** A {@link OutputFormatterCallback} that can aggregate all the partial results into one set. */ public abstract static class AggregateAllOutputFormatterCallback extends OutputFormatterCallback implements AggregateAllCallback { } private static class AggregateAllOutputFormatterCallbackImpl extends AggregateAllOutputFormatterCallback { private final Set result = CompactHashSet.create(); @Override public final void processOutput(Iterable partialResult) { Iterables.addAll(result, partialResult); } @Override public Set getResult() { return result; } } /** * Returns a fresh {@link AggregateAllOutputFormatterCallback} that can aggregate all the partial * results into one set. * *

Intended to be used by top-level evaluation of {@link QueryExpression}s; contrast with * {@link #newAggregateAllCallback}. */ public static AggregateAllOutputFormatterCallback newAggregateAllOutputFormatterCallback() { return new AggregateAllOutputFormatterCallbackImpl<>(); } /** * Returns a fresh {@link AggregateAllCallback}. * *

Intended to be used by {@link QueryExpression} implementations; contrast with * {@link #newAggregateAllOutputFormatterCallback}. */ public static AggregateAllCallback newAggregateAllCallback() { return new AggregateAllOutputFormatterCallbackImpl<>(); } /** * Fully evaluate a {@code QueryExpression} and return a set with all the results. * *

Should only be used by QueryExpressions when it is the only way of achieving correctness. */ public static Set evalAll( QueryEnvironment env, VariableContext context, QueryExpression expr) throws QueryException, InterruptedException { AggregateAllCallback callback = newAggregateAllCallback(); env.eval(expr, context, callback); return callback.getResult(); } /** A trivial {@link Uniquifier} base class. */ public abstract static class AbstractUniquifier extends AbstractUniquifierBase { private final CompactHashSet alreadySeen = CompactHashSet.create(); @Override public final boolean unique(T element) { return alreadySeen.add(extractKey(element)); } /** * Extracts an unique key that can be used to dedupe the given {@code element}. * *

Depending on the choice of {@code K}, this enables potential memory optimizations. */ protected abstract K extractKey(T element); } /** A trivial {@link ThreadSafeUniquifier} base class. */ public abstract static class AbstractThreadSafeUniquifier extends AbstractUniquifierBase implements ThreadSafeUniquifier { private final Set alreadySeen; protected AbstractThreadSafeUniquifier(int concurrencyLevel) { this.alreadySeen = Collections.newSetFromMap( new MapMaker().concurrencyLevel(concurrencyLevel).makeMap()); } @Override public final boolean unique(T element) { return alreadySeen.add(extractKey(element)); } /** * Extracts an unique key that can be used to dedupe the given {@code element}. * *

Depending on the choice of {@code K}, this enables potential memory optimizations. */ protected abstract K extractKey(T element); } private abstract static class AbstractUniquifierBase implements Uniquifier { @Override public final ImmutableList unique(Iterable newElements) { ImmutableList.Builder result = ImmutableList.builder(); for (T element : newElements) { if (unique(element)) { result.add(element); } } return result.build(); } } }