    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</code> is an {@link java.util.ListIterator} over a single
    025 * object instance.
    026 *
    027 * @since 2.1
    028 */
    029public class SingletonListIterator<E> implements ResettableListIterator<E> {
    030
    031    private boolean beforeFirst = true;
    032    private boolean nextCalled = false;
    033    private boolean removed = false;
    034    private E object;
    035
    036    /**
    037     * Constructs a new <code>SingletonListIterator</code>.
    038     *
    039     * @param object  the single object to return from the iterator
    040     */
    041    public SingletonListIterator(final E object) {
    042        super();
    043        this.object = object;
    044    }
    045
    046    /**
    047     * Is another object available from the iterator?
    048     * <p>
    049     * This returns true if the single object hasn't been returned yet.
    050     *
    051     * @return true if the single object hasn't been returned yet
    052     */
    053    @Override
    054    public boolean hasNext() {
    055        return beforeFirst && !removed;
    056    }
    057
    058    /**
    059     * Is a previous object available from the iterator?
    060     * <p>
    061     * This returns true if the single object has been returned.
    062     *
    063     * @return true if the single object has been returned
    064     */
    065    @Override
    066    public boolean hasPrevious() {
    067        return !beforeFirst && !removed;
    068    }
    069
    070    /**
    071     * Returns the index of the element that would be returned by a subsequent
    072     * call to {@code next}.
    073     *
    074     * @return 0 or 1 depending on current state.
    075     */
    076    @Override
    077    public int nextIndex() {
    078        return beforeFirst ? 0 : 1;
    079    }
    080
    081    /**
    082     * Returns the index of the element that would be returned by a subsequent
    083     * call to {@code previous}. A return value of -1 indicates that the iterator is currently at
    084     * the start.
    085     *
    086     * @return 0 or -1 depending on current state.
    087     */
    088    @Override
    089    public int previousIndex() {
    090        return beforeFirst ? -1 : 0;
    091    }
    092
    093    /**
    094     * Get the next object from the iterator.
    095     * <p>
    096     * This returns the single object if it hasn't been returned yet.
    097     *
    098     * @return the single object
    099     * @throws NoSuchElementException if the single object has already
    100     *    been returned
    101     */
    102    @Override
    103    public E next() {
    104        if (!beforeFirst || removed) {
    105            throw new NoSuchElementException();
    106        }
    107        beforeFirst = false;
    108        nextCalled = true;
    109        return object;
    110    }
    111
    112    /**
    113     * Get the previous object from the iterator.
    114     * <p>
    115     * This returns the single object if it has been returned.
    116     *
    117     * @return the single object
    118     * @throws NoSuchElementException if the single object has not already
    119     *    been returned
    120     */
    121    @Override
    122    public E previous() {
    123        if (beforeFirst || removed) {
    124            throw new NoSuchElementException();
    125        }
    126        beforeFirst = true;
    127        return object;
    128    }
    129
    130    /**
    131     * Remove the object from this iterator.
    132     * @throws IllegalStateException if the {@code next} or {@code previous}
    133     *        method has not yet been called, or the {@code remove} method
    134     *        has already been called after the last call to {@code next}
    135     *        or {@code previous}.
    136     */
    137    @Override
    138    public void remove() {
    139        if(!nextCalled || removed) {
    140            throw new IllegalStateException();
    141        }
    142        object = null;
    143        removed = true;
    144    }
    145
    146    /**
    147     * Add always throws {@link UnsupportedOperationException}.
    148     *
    149     * @param obj  the object to add
    150     * @throws UnsupportedOperationException always
    151     */
    152    @Override
    153    public void add(final E obj) {
    154        throw new UnsupportedOperationException("add() is not supported by this iterator");
    155    }
    156
    157    /**
    158     * Set sets the value of the singleton.
    159     *
    160     * @param obj  the object to set
    161     * @throws IllegalStateException if {@code next} has not been called
    162     *          or the object has been removed
    163     */
    164    @Override
    165    public void set(final E obj) {
    166        if (!nextCalled || removed) {
    167            throw new IllegalStateException();
    168        }
    169        this.object = obj;
    170    }
    171
    172    /**
    173     * Reset the iterator back to the start.
    174     */
    175    @Override
    176    public void reset() {
    177        beforeFirst = true;
    178        nextCalled = false;
    179    }
    180
    181}