1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections4.iterators;
18
19 import java.lang.reflect.Array;
20 import java.util.ListIterator;
21 import java.util.NoSuchElementException;
22
23 import org.apache.commons.collections4.ResettableListIterator;
24
25 /**
26 * Implements a {@link ListIterator} over an array.
27 * <p>
28 * The array can be either an array of object or of primitives. If you know
29 * that you have an object array, the {@link ObjectArrayListIterator}
30 * class is a better choice, as it will perform better.
31 * </p>
32 * <p>
33 * This iterator does not support {@link #add(Object)} or {@link #remove()}, as the array
34 * cannot be changed in size. The {@link #set(Object)} method is supported however.
35 * </p>
36 *
37 * @param <E> The type of elements returned by this iterator.
38 * @see org.apache.commons.collections4.iterators.ArrayIterator
39 * @see java.util.Iterator
40 * @see java.util.ListIterator
41 * @since 3.0
42 */
43 public class ArrayListIterator<E> extends ArrayIterator<E>
44 implements ResettableListIterator<E> {
45
46 /**
47 * Holds the index of the last item returned by a call to {@code next()}
48 * or {@code previous()}. This is set to {@code -1} if neither method
49 * has yet been invoked. {@code lastItemIndex} is used to implement
50 * the {@link #set} method.
51 */
52 private int lastItemIndex = -1;
53
54 /**
55 * Constructs an ArrayListIterator that will iterate over the values in the
56 * specified array.
57 *
58 * @param array The array to iterate over
59 * @throws IllegalArgumentException if {@code array} is not an array.
60 * @throws NullPointerException if {@code array} is {@code null}
61 */
62 public ArrayListIterator(final Object array) {
63 super(array);
64 }
65
66 /**
67 * Constructs an ArrayListIterator that will iterate over the values in the
68 * specified array from a specific start index.
69 *
70 * @param array The array to iterate over
71 * @param startIndex The index to start iterating at
72 * @throws IllegalArgumentException if {@code array} is not an array.
73 * @throws NullPointerException if {@code array} is {@code null}
74 * @throws IndexOutOfBoundsException if the start index is out of bounds
75 */
76 public ArrayListIterator(final Object array, final int startIndex) {
77 super(array, startIndex);
78 }
79
80 /**
81 * Constructs an ArrayListIterator that will iterate over a range of values
82 * in the specified array.
83 *
84 * @param array The array to iterate over
85 * @param startIndex The index to start iterating at
86 * @param endIndex The index (exclusive) to finish iterating at
87 * @throws IllegalArgumentException if {@code array} is not an array.
88 * @throws IndexOutOfBoundsException if the start or end index is out of bounds
89 * @throws IllegalArgumentException if end index is before the start
90 * @throws NullPointerException if {@code array} is {@code null}
91 */
92 public ArrayListIterator(final Object array, final int startIndex, final int endIndex) {
93 super(array, startIndex, endIndex);
94 }
95
96 /**
97 * This iterator does not support modification of its backing collection, and so will
98 * always throw an {@link UnsupportedOperationException} when this method is invoked.
99 *
100 * @param o The element to add
101 * @throws UnsupportedOperationException always thrown.
102 * @see java.util.ListIterator#set
103 */
104 @Override
105 public void add(final Object o) {
106 throw new UnsupportedOperationException("add() method is not supported");
107 }
108
109 /**
110 * Returns true if there are previous elements to return from the array.
111 *
112 * @return true if there is a previous element to return
113 */
114 @Override
115 public boolean hasPrevious() {
116 return index > startIndex;
117 }
118
119 /**
120 * Gets the next element from the array.
121 *
122 * @return The next element
123 * @throws NoSuchElementException if there is no next element
124 */
125 @Override
126 @SuppressWarnings("unchecked")
127 public E next() {
128 if (!hasNext()) {
129 throw new NoSuchElementException();
130 }
131 lastItemIndex = index;
132 return (E) Array.get(array, index++);
133 }
134
135 /**
136 * Gets the next index to be retrieved.
137 *
138 * @return The index of the item to be retrieved next
139 */
140 @Override
141 public int nextIndex() {
142 return index - startIndex;
143 }
144
145 /**
146 * Gets the previous element from the array.
147 *
148 * @return The previous element
149 * @throws NoSuchElementException if there is no previous element
150 */
151 @Override
152 @SuppressWarnings("unchecked")
153 public E previous() {
154 if (!hasPrevious()) {
155 throw new NoSuchElementException();
156 }
157 lastItemIndex = --index;
158 return (E) Array.get(array, index);
159 }
160
161 /**
162 * Gets the index of the item to be retrieved if {@link #previous()} is called.
163 *
164 * @return The index of the item to be retrieved next
165 */
166 @Override
167 public int previousIndex() {
168 return index - startIndex - 1;
169 }
170
171 /**
172 * Resets the iterator back to the start index.
173 */
174 @Override
175 public void reset() {
176 super.reset();
177 lastItemIndex = -1;
178 }
179
180 /**
181 * Sets the element under the cursor.
182 * <p>
183 * This method sets the element that was returned by the last call
184 * to {@link #next()} of {@link #previous()}.
185 * </p>
186 * <p>
187 * <strong>Note:</strong> {@link ListIterator} implementations that support
188 * {@code add()} and {@code remove()} only allow {@code set()} to be called
189 * once per call to {@code next()} or {@code previous} (see the {@link ListIterator}
190 * Javadoc for more details). Since this implementation does
191 * not support {@code add()} or {@code remove()}, {@code set()} may be
192 * called as often as desired.
193 * </p>
194 *
195 * @param o The element to set
196 * @throws IllegalStateException if {@link #next()} or {@link #previous()} has not been called
197 * before {@link #set(Object)}
198 * @see java.util.ListIterator#set
199 */
200 @Override
201 public void set(final Object o) {
202 if (lastItemIndex == -1) {
203 throw new IllegalStateException("must call next() or previous() before a call to set()");
204 }
205
206 Array.set(array, lastItemIndex, o);
207 }
208
209 }