/* * Copyright 2014-present Facebook, Inc. * * 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.facebook.buck.util; import com.facebook.buck.model.Pair; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; public class MoreIterables { private MoreIterables() {} private static <T> ImmutableList<Iterator<T>> iterators(Iterable<T> inputs[]) { ImmutableList.Builder<Iterator<T>> iterators = ImmutableList.builder(); for (Iterable<T> input : inputs) { iterators.add(input.iterator()); } return iterators.build(); } /** * Combine the given iterables by peeling off items one at a time from each of the input iterables * until any one of the iterables are exhausted. */ @SafeVarargs public static <T> Iterable<T> zipAndConcat(Iterable<T>... inputs) { // If no inputs were seen, just return an empty list. if (inputs.length == 0) { return ImmutableList.of(); } ImmutableList.Builder<T> result = ImmutableList.builder(); ImmutableList<Iterator<T>> iterators = iterators(inputs); // Keep grabbing rounds from the input iterators until we've exhausted one // of them, then return. List<T> round = Lists.newArrayListWithCapacity(inputs.length); while (true) { for (Iterator<T> iterator : iterators) { if (!iterator.hasNext()) { return result.build(); } round.add(iterator.next()); } result.addAll(round); round.clear(); } } /** * Returns a deduped version of toDedup and keeps the order of elements If a key is contained more * than once (that is, there are multiple elements e1, e2... en, such that ei.equals(ej)) then the * last one will be kept in the ordering */ public static <T> Set<T> dedupKeepLast(Iterable<T> toDedup) { Set<T> dedupedSet = new LinkedHashSet<>(); for (T t : toDedup) { if (dedupedSet.contains(t)) { dedupedSet.remove(t); } dedupedSet.add(t); } return dedupedSet; } /** * @return a new {@link Iterable} containing pairs of the original items along with the index of * the current item. */ public static <T> Iterable<Pair<Integer, T>> enumerate(Iterable<T> items) { return () -> new Iterator<Pair<Integer, T>>() { private int index = 0; private final Iterator<T> delegate = items.iterator(); @Override public boolean hasNext() { return delegate.hasNext(); } @Override public Pair<Integer, T> next() { return new Pair<>(index++, delegate.next()); } }; } }