| /* |
| * Copyright 2012-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.collect; |
| |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Iterators; |
| |
| import java.util.Iterator; |
| import java.util.NoSuchElementException; |
| |
| /** |
| * {@link Iterable} of an array object that does not make a copy of the array. |
| * <p> |
| * Designed to be used when it is too expensive to copy an array to a {@link java.util.List} and use |
| * the list as an {@link Iterable} instead. |
| */ |
| public class ArrayIterable<T> implements Iterable<T> { |
| |
| private final T[] array; |
| private final int startIndex; |
| private final int endIndex; |
| |
| /** |
| * @param startIndex inclusive |
| * @param endIndex exclusive |
| */ |
| private ArrayIterable(T[] array, int startIndex, int endIndex) { |
| // No precondition checks here: they have already been performed in the of() method. |
| this.array = array; |
| this.startIndex = startIndex; |
| this.endIndex = endIndex; |
| } |
| |
| public static <T> Iterable<T> of(T[] array) { |
| return of(array, /* startIndex */ 0, /* endIndex */ array.length); |
| } |
| |
| public static <T> Iterable<T> of(final T[] array, final int startIndex, int endIndex) { |
| Preconditions.checkNotNull(array); |
| Preconditions.checkPositionIndexes(startIndex, endIndex, array.length); |
| |
| // Special-case the empty Iterator with a singleton value. |
| if (startIndex >= endIndex) { |
| // Note that Collections.emptyIterator().remove() throws an IllegalStateException. We prefer |
| // that remove() throws an UnsupportedOperationException for an empty Iterator, so we use |
| // ImmutableList instead. |
| return ImmutableList.<T>of(); |
| } else if (endIndex - startIndex == 1) { |
| return new Iterable<T>() { |
| @Override |
| public Iterator<T> iterator() { |
| // This always looks up the element in the array in case the user modifies the contents of |
| // the array outside of this method. That would probably be a bad thing for the user to |
| // do, but this ensures that the behavior is consistent with ArrayIterable. |
| return Iterators.singletonIterator(array[startIndex]); |
| } |
| }; |
| } else { |
| return new ArrayIterable<T>(array, startIndex, endIndex); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") // (Iterator<T>) ImmutableList.of() |
| @Override |
| public Iterator<T> iterator() { |
| |
| return new Iterator<T>() { |
| |
| private int index = startIndex; |
| |
| @Override |
| public boolean hasNext() { |
| return index < endIndex; |
| } |
| |
| @Override |
| public T next() { |
| if (hasNext()) { |
| T element = array[index]; |
| index++; |
| return element; |
| } else { |
| throw new NoSuchElementException(); |
| } |
| } |
| |
| @Override |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| }; |
| } |
| |
| } |