All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.inject.internal.util.Iterators Maven / Gradle / Ivy

There is a newer version: 7.0.0
Show newest version
/*
 * Copyright (C) 2007 Google 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.google.inject.internal.util;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;

/**
 * This class contains static utility methods that operate on or return objects
 * of type {@code Iterator}. Also see the parallel implementations in {@link
 * Iterables}.
 *
 * @author Kevin Bourrillion
 * @author Scott Bonneau
 */
public final class Iterators {
  private Iterators() {}

  static final Iterator EMPTY_ITERATOR
      = new UnmodifiableIterator() {
        public boolean hasNext() {
          return false;
        }
        public Object next() {
          throw new NoSuchElementException();
        }
      };


  /** Returns the empty {@code Iterator}. */
  // Casting to any type is safe since there are no actual elements.
  @SuppressWarnings("unchecked")
  public static  UnmodifiableIterator emptyIterator() {
    return (UnmodifiableIterator) EMPTY_ITERATOR;
  }

  private static final ListIterator EMPTY_LIST_ITERATOR =
      new ListIterator() {
        public boolean hasNext() {
          return false;
        }
        public boolean hasPrevious() {
          return false;
        }
        public int nextIndex() {
          return 0;
        }
        public int previousIndex() {
          return -1;
        }
        public Object next() {
          throw new NoSuchElementException();
        }
        public Object previous() {
          throw new NoSuchElementException();
        }
        public void set(Object o) {
          throw new UnsupportedOperationException();
        }
        public void add(Object o) {
          throw new UnsupportedOperationException();
        }
        public void remove() {
          throw new UnsupportedOperationException();
        }
      };

  /** Returns the empty {@code ListIterator}. */
  // Casting to any type is safe since there are no actual elements.
  @SuppressWarnings("unchecked")
  public static  ListIterator emptyListIterator() {
    return (ListIterator) EMPTY_LIST_ITERATOR;
  }

  /** Returns an unmodifiable view of {@code iterator}. */
  public static  UnmodifiableIterator unmodifiableIterator(
      final Iterator iterator) {
    Preconditions.checkNotNull(iterator);
    return new UnmodifiableIterator() {
      public boolean hasNext() {
        return iterator.hasNext();
      }
      public T next() {
        return iterator.next();
      }
    };
  }


  /**
   * Returns a string representation of {@code iterator}, with the format
   * {@code [e1, e2, ..., en]}. The iterator will be left exhausted: its
   * {@code hasNext()} method will return {@code false}.
   */
  public static String toString(Iterator iterator) {
    if (!iterator.hasNext()) {
      return "[]";
    }
    StringBuilder builder = new StringBuilder();
    builder.append('[').append(iterator.next());
    while (iterator.hasNext()) {
      builder.append(", ").append(iterator.next());
    }
    return builder.append(']').toString();
  }

  /**
   * Returns the single element contained in {@code iterator}.
   *
   * @throws NoSuchElementException if the iterator is empty
   * @throws IllegalArgumentException if the iterator contains multiple
   *     elements.  The state of the iterator is unspecified.
   */
  public static  T getOnlyElement(Iterator iterator) {
    T first = iterator.next();
    if (!iterator.hasNext()) {
      return first;
    }

    StringBuilder sb = new StringBuilder();
    sb.append("expected one element but was: <" + first);
    for (int i = 0; i < 4 && iterator.hasNext(); i++) {
      sb.append(", " + iterator.next());
    }
    if (iterator.hasNext()) {
      sb.append(", ...");
    }
    sb.append(">");

    throw new IllegalArgumentException(sb.toString());
  }

  /**
   * Combines multiple iterators into a single iterator. The returned iterator
   * iterates across the elements of each iterator in {@code inputs}. The input
   * iterators are not polled until necessary.
   *
   * 

The returned iterator supports {@code remove()} when the corresponding * input iterator supports it. The methods of the returned iterator may throw * {@code NullPointerException} if any of the input iterators are null. */ public static Iterator concat( final Iterator> inputs) { Preconditions.checkNotNull(inputs); return new Iterator() { Iterator current = emptyIterator(); Iterator removeFrom; public boolean hasNext() { while (!current.hasNext() && inputs.hasNext()) { current = inputs.next(); } return current.hasNext(); } public T next() { if (!hasNext()) { throw new NoSuchElementException(); } removeFrom = current; return current.next(); } public void remove() { Preconditions.checkState(removeFrom != null, "no calls to next() since last call to remove()"); removeFrom.remove(); removeFrom = null; } }; } /** * Returns an iterator that applies {@code function} to each element of {@code * fromIterator}. * *

The returned iterator supports {@code remove()} if the provided iterator * does. After a successful {@code remove()} call, {@code fromIterator} no * longer contains the corresponding element. */ public static Iterator transform(final Iterator fromIterator, final Function function) { Preconditions.checkNotNull(fromIterator); Preconditions.checkNotNull(function); return new Iterator() { public boolean hasNext() { return fromIterator.hasNext(); } public T next() { F from = fromIterator.next(); return function.apply(from); } public void remove() { fromIterator.remove(); } }; } // Methods only in Iterators, not in Iterables /** * Returns an iterator containing the elements of {@code array} in order. The * returned iterator is a view of the array; subsequent changes to the array * will be reflected in the iterator. * *

Note: It is often preferable to represent your data using a * collection type, for example using {@link Arrays#asList(Object[])}, making * this method unnecessary. */ public static UnmodifiableIterator forArray(final T... array) { // optimized. benchmarks at nearly 2x of the straightforward impl return new UnmodifiableIterator() { final int length = array.length; int i = 0; public boolean hasNext() { return i < length; } public T next() { try { // 'return array[i++];' almost works T t = array[i]; i++; return t; } catch (ArrayIndexOutOfBoundsException e) { throw new NoSuchElementException(); } } }; } /** * Returns an iterator containing the elements in the specified range of * {@code array} in order. The returned iterator is a view of the array; * subsequent changes to the array will be reflected in the iterator. * * @param array array to read elements out of * @param offset index of first array element to retrieve * @param length number of elements in iteration * * @throws IndexOutOfBoundsException if {@code offset} is negative, * {@code length} is negative, or {@code offset + length > array.length} */ public static UnmodifiableIterator forArray( final T[] array, final int offset, final int length) { Preconditions.checkArgument(length >= 0); final int end = offset + length; // Technically we should give a slightly more descriptive error on overflow Preconditions.checkPositionIndexes(offset, end, array.length); // If length == 0 is a common enough case, we could return emptyIterator(). return new UnmodifiableIterator() { int i = offset; public boolean hasNext() { return i < end; } public T next() { if (!hasNext()) { throw new NoSuchElementException(); } return array[i++]; } }; } /** * Returns an iterator containing only {@code value}. */ public static UnmodifiableIterator singletonIterator( @Nullable final T value) { return new UnmodifiableIterator() { boolean done; public boolean hasNext() { return !done; } public T next() { if (done) { throw new NoSuchElementException(); } done = true; return value; } }; } /** * Adapts an {@code Iterator} to the {@code Enumeration} interface. * * @see Collections#enumeration(Collection) */ public static Enumeration asEnumeration(final Iterator iterator) { Preconditions.checkNotNull(iterator); return new Enumeration() { public boolean hasMoreElements() { return iterator.hasNext(); } public T nextElement() { return iterator.next(); } }; } }