// 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.collect; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * An immutable chain of immutable Iterables. * *

This class is defined for the sole purpose of being able to check for immutability (using * instanceof). Otherwise, we could use a plain Iterable (as returned by {@code * Iterables.concat()}). * * @see CollectionUtils#checkImmutable(Iterable) */ public final class IterablesChain implements Iterable { public static Iterable concat(Iterable a, Iterable b) { return IterablesChain.builder().add(a).add(b).build(); } private final Iterable chain; IterablesChain(Iterable chain) { this.chain = chain; } @Override public Iterator iterator() { return chain.iterator(); } public static Builder builder() { return new Builder<>(); } @Override public String toString() { return "[" + Joiner.on(", ").join(this) + "]"; } /** Builder for IterablesChain. */ public static class Builder { private List> iterables = new ArrayList<>(); private Builder() {} /** * Adds an immutable iterable to the end of the chain. * *

If the iterable can not be confirmed to be immutable, a runtime error is thrown. */ public Builder add(Iterable iterable) { CollectionUtils.checkImmutable(iterable); // Avoid unnecessarily expanding a NestedSet. boolean isEmpty = iterable instanceof NestedSet ? ((NestedSet) iterable).isEmpty() : Iterables.isEmpty(iterable); if (!isEmpty) { iterables.add(iterable); } return this; } /** Adds a single element to the chain. */ public Builder addElement(T element) { iterables.add(ImmutableList.of(element)); return this; } /** Returns true if the chain is empty. */ public boolean isEmpty() { return iterables.isEmpty(); } /** Builds an iterable that iterates through all elements in this chain. */ @SuppressWarnings("unchecked") public Iterable build() { int size = iterables.size(); if (size == 0) { return ImmutableList.of(); } else if (size == 1) { // cast is type safe since Iterable doesn't allow mutation return (Iterable) iterables.get(0); } return new IterablesChain<>(Iterables.concat(ImmutableList.copyOf(iterables))); } } }