    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.collections4.iterators;
    018
    019import java.util.NoSuchElementException;
    020
    021import org.apache.commons.collections4.ResettableListIterator;
    022
    023/**
    024 * {@code SingletonIterator} is an {@link java.util.ListIterator} over a single
    025 * object instance.
    026 *
    027 * @param <E> the type of elements returned by this iterator.
    028 * @since 2.1
    029 */
    030public class SingletonListIterator<E> implements ResettableListIterator<E> {
    031
    032    private boolean beforeFirst = true;
    033    private boolean nextCalled;
    034    private boolean removed;
    035    private E object;
    036
    037    /**
    038     * Constructs a new {@code SingletonListIterator}.
    039     *
    040     * @param object  the single object to return from the iterator
    041     */
    042    public SingletonListIterator(final E object) {
    043        this.object = object;
    044    }
    045
    046    /**
    047     * Add always throws {@link UnsupportedOperationException}.
    048     *
    049     * @param obj  the object to add
    050     * @throws UnsupportedOperationException always
    051     */
    052    @Override
    053    public void add(final E obj) {
    054        throw new UnsupportedOperationException("add() is not supported by this iterator");
    055    }
    056
    057    /**
    058     * Is another object available from the iterator?
    059     * <p>
    060     * This returns true if the single object hasn't been returned yet.
    061     *
    062     * @return true if the single object hasn't been returned yet
    063     */
    064    @Override
    065    public boolean hasNext() {
    066        return beforeFirst && !removed;
    067    }
    068
    069    /**
    070     * Is a previous object available from the iterator?
    071     * <p>
    072     * This returns true if the single object has been returned.
    073     *
    074     * @return true if the single object has been returned
    075     */
    076    @Override
    077    public boolean hasPrevious() {
    078        return !beforeFirst && !removed;
    079    }
    080
    081    /**
    082     * Gets the next object from the iterator.
    083     * <p>
    084     * This returns the single object if it hasn't been returned yet.
    085     *
    086     * @return the single object
    087     * @throws NoSuchElementException if the single object has already
    088     *    been returned
    089     */
    090    @Override
    091    public E next() {
    092        if (!beforeFirst || removed) {
    093            throw new NoSuchElementException();
    094        }
    095        beforeFirst = false;
    096        nextCalled = true;
    097        return object;
    098    }
    099
    100    /**
    101     * Returns the index of the element that would be returned by a subsequent
    102     * call to {@code next}.
    103     *
    104     * @return 0 or 1 depending on current state.
    105     */
    106    @Override
    107    public int nextIndex() {
    108        return beforeFirst ? 0 : 1;
    109    }
    110
    111    /**
    112     * Gets the previous object from the iterator.
    113     * <p>
    114     * This returns the single object if it has been returned.
    115     *
    116     * @return the single object
    117     * @throws NoSuchElementException if the single object has not already
    118     *    been returned
    119     */
    120    @Override
    121    public E previous() {
    122        if (beforeFirst || removed) {
    123            throw new NoSuchElementException();
    124        }
    125        beforeFirst = true;
    126        return object;
    127    }
    128
    129    /**
    130     * Returns the index of the element that would be returned by a subsequent
    131     * call to {@code previous}. A return value of -1 indicates that the iterator is currently at
    132     * the start.
    133     *
    134     * @return 0 or -1 depending on current state.
    135     */
    136    @Override
    137    public int previousIndex() {
    138        return beforeFirst ? -1 : 0;
    139    }
    140
    141    /**
    142     * Remove the object from this iterator.
    143     * @throws IllegalStateException if the {@code next} or {@code previous}
    144     *        method has not yet been called, or the {@code remove} method
    145     *        has already been called after the last call to {@code next}
    146     *        or {@code previous}.
    147     */
    148    @Override
    149    public void remove() {
    150        if (!nextCalled || removed) {
    151            throw new IllegalStateException();
    152        }
    153        object = null;
    154        removed = true;
    155    }
    156
    157    /**
    158     * Reset the iterator back to the start.
    159     */
    160    @Override
    161    public void reset() {
    162        beforeFirst = true;
    163        nextCalled = false;
    164    }
    165
    166    /**
    167     * Sets sets the value of the singleton.
    168     *
    169     * @param obj  the object to set
    170     * @throws IllegalStateException if {@code next} has not been called
    171     *          or the object has been removed
    172     */
    173    @Override
    174    public void set(final E obj) {
    175        if (!nextCalled || removed) {
    176            throw new IllegalStateException();
    177        }
    178        this.object = obj;
    179    }
    180
    181}