001/*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect;
018
019import static com.google.common.base.Preconditions.checkState;
020
021import com.google.common.annotations.GwtCompatible;
022import com.google.errorprone.annotations.CanIgnoreReturnValue;
023import java.util.NoSuchElementException;
024
025/**
026 * This class provides a skeletal implementation of the {@code Iterator} interface, to make this
027 * interface easier to implement for certain types of data sources.
028 *
029 * <p>{@code Iterator} requires its implementations to support querying the end-of-data status
030 * without changing the iterator's state, using the {@link #hasNext} method. But many data sources,
031 * such as {@link java.io.Reader#read()}, do not expose this information; the only way to discover
032 * whether there is any data left is by trying to retrieve it. These types of data sources are
033 * ordinarily difficult to write iterators for. But using this class, one must implement only the
034 * {@link #computeNext} method, and invoke the {@link #endOfData} method when appropriate.
035 *
036 * <p>Another example is an iterator that skips over null elements in a backing iterator. This could
037 * be implemented as:
038 *
039 * <pre>{@code
040 * public static Iterator<String> skipNulls(final Iterator<String> in) {
041 *   return new AbstractIterator<String>() {
042 *     protected String computeNext() {
043 *       while (in.hasNext()) {
044 *         String s = in.next();
045 *         if (s != null) {
046 *           return s;
047 *         }
048 *       }
049 *       return endOfData();
050 *     }
051 *   };
052 * }
053 * }</pre>
054 *
055 * <p>This class supports iterators that include null elements.
056 *
057 * @author Kevin Bourrillion
058 * @since 2.0
059 */
060// When making changes to this class, please also update the copy at
061// com.google.common.base.AbstractIterator
062@GwtCompatible
063public abstract class AbstractIterator<T> extends UnmodifiableIterator<T> {
064  private State state = State.NOT_READY;
065
066  /** Constructor for use by subclasses. */
067  protected AbstractIterator() {}
068
069  private enum State {
070    /** We have computed the next element and haven't returned it yet. */
071    READY,
072
073    /** We haven't yet computed or have already returned the element. */
074    NOT_READY,
075
076    /** We have reached the end of the data and are finished. */
077    DONE,
078
079    /** We've suffered an exception and are kaput. */
080    FAILED,
081  }
082
083  private T next;
084
085  /**
086   * Returns the next element. <b>Note:</b> the implementation must call {@link #endOfData()} when
087   * there are no elements left in the iteration. Failure to do so could result in an infinite loop.
088   *
089   * <p>The initial invocation of {@link #hasNext()} or {@link #next()} calls this method, as does
090   * the first invocation of {@code hasNext} or {@code next} following each successful call to
091   * {@code next}. Once the implementation either invokes {@code endOfData} or throws an exception,
092   * {@code computeNext} is guaranteed to never be called again.
093   *
094   * <p>If this method throws an exception, it will propagate outward to the {@code hasNext} or
095   * {@code next} invocation that invoked this method. Any further attempts to use the iterator will
096   * result in an {@link IllegalStateException}.
097   *
098   * <p>The implementation of this method may not invoke the {@code hasNext}, {@code next}, or
099   * {@link #peek()} methods on this instance; if it does, an {@code IllegalStateException} will
100   * result.
101   *
102   * @return the next element if there was one. If {@code endOfData} was called during execution,
103   *     the return value will be ignored.
104   * @throws RuntimeException if any unrecoverable error happens. This exception will propagate
105   *     outward to the {@code hasNext()}, {@code next()}, or {@code peek()} invocation that invoked
106   *     this method. Any further attempts to use the iterator will result in an {@link
107   *     IllegalStateException}.
108   */
109  protected abstract T computeNext();
110
111  /**
112   * Implementations of {@link #computeNext} <b>must</b> invoke this method when there are no
113   * elements left in the iteration.
114   *
115   * @return {@code null}; a convenience so your {@code computeNext} implementation can use the
116   *     simple statement {@code return endOfData();}
117   */
118  @CanIgnoreReturnValue
119  protected final T endOfData() {
120    state = State.DONE;
121    return null;
122  }
123
124  @CanIgnoreReturnValue // TODO(kak): Should we remove this? Some people are using it to prefetch?
125  @Override
126  public final boolean hasNext() {
127    checkState(state != State.FAILED);
128    switch (state) {
129      case DONE:
130        return false;
131      case READY:
132        return true;
133      default:
134    }
135    return tryToComputeNext();
136  }
137
138  private boolean tryToComputeNext() {
139    state = State.FAILED; // temporary pessimism
140    next = computeNext();
141    if (state != State.DONE) {
142      state = State.READY;
143      return true;
144    }
145    return false;
146  }
147
148  @CanIgnoreReturnValue // TODO(kak): Should we remove this?
149  @Override
150  public final T next() {
151    if (!hasNext()) {
152      throw new NoSuchElementException();
153    }
154    state = State.NOT_READY;
155    T result = next;
156    next = null;
157    return result;
158  }
159
160  /**
161   * Returns the next element in the iteration without advancing the iteration, according to the
162   * contract of {@link PeekingIterator#peek()}.
163   *
164   * <p>Implementations of {@code AbstractIterator} that wish to expose this functionality should
165   * implement {@code PeekingIterator}.
166   */
167  public final T peek() {
168    if (!hasNext()) {
169      throw new NoSuchElementException();
170    }
171    return next;
172  }
173}