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}