/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.common.util.iterable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.stream.Stream; import java.util.stream.StreamSupport; public class Iterables { public Iterables() { } public static <T> Iterable<T> concat(Iterable<T>... inputs) { Objects.requireNonNull(inputs); return new ConcatenatedIterable(inputs); } static class ConcatenatedIterable<T> implements Iterable<T> { private final Iterable<T>[] inputs; ConcatenatedIterable(Iterable<T>[] inputs) { this.inputs = Arrays.copyOf(inputs, inputs.length); } @Override public Iterator<T> iterator() { return Stream .of(inputs) .map(it -> StreamSupport.stream(it.spliterator(), false)) .reduce(Stream::concat) .orElseGet(Stream::empty).iterator(); } } /** Flattens the two level {@code Iterable} into a single {@code Iterable}. Note that this pre-caches the values from the outer {@code * Iterable}, but not the values from the inner one. */ public static <T> Iterable<T> flatten(Iterable<? extends Iterable<T>> inputs) { Objects.requireNonNull(inputs); return new FlattenedIterables<>(inputs); } static class FlattenedIterables<T> implements Iterable<T> { private final Iterable<? extends Iterable<T>> inputs; FlattenedIterables(Iterable<? extends Iterable<T>> inputs) { List<Iterable<T>> list = new ArrayList<>(); for (Iterable<T> iterable : inputs) { list.add(iterable); } this.inputs = list; } @Override public Iterator<T> iterator() { return StreamSupport .stream(inputs.spliterator(), false) .flatMap(s -> StreamSupport.stream(s.spliterator(), false)).iterator(); } } public static boolean allElementsAreEqual(Iterable<?> left, Iterable<?> right) { Objects.requireNonNull(left); Objects.requireNonNull(right); if (left instanceof Collection && right instanceof Collection) { Collection collection1 = (Collection) left; Collection collection2 = (Collection) right; if (collection1.size() != collection2.size()) { return false; } } Iterator<?> leftIt = left.iterator(); Iterator<?> rightIt = right.iterator(); while (true) { if (leftIt.hasNext()) { if (!rightIt.hasNext()) { return false; } Object o1 = leftIt.next(); Object o2 = rightIt.next(); if (Objects.equals(o1, o2)) { continue; } return false; } return !rightIt.hasNext(); } } public static <T> T getFirst(Iterable<T> collection, T defaultValue) { Objects.requireNonNull(collection); Iterator<T> iterator = collection.iterator(); return iterator.hasNext() ? iterator.next() : defaultValue; } public static <T> T get(Iterable<T> iterable, int position) { Objects.requireNonNull(iterable); if (position < 0) { throw new IllegalArgumentException("position >= 0"); } if (iterable instanceof List) { List<T> list = (List<T>)iterable; if (position >= list.size()) { throw new IndexOutOfBoundsException(Integer.toString(position)); } return list.get(position); } else { Iterator<T> it = iterable.iterator(); for (int index = 0; index < position; index++) { if (!it.hasNext()) { throw new IndexOutOfBoundsException(Integer.toString(position)); } it.next(); } if (!it.hasNext()) { throw new IndexOutOfBoundsException(Integer.toString(position)); } return it.next(); } } }