001    /*
002     *  Copyright 2001-2010 Stephen Colebourne
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    package org.joda.primitives.list.impl;
017    
018    import java.util.Collection;
019    import java.util.ConcurrentModificationException;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.NoSuchElementException;
023    
024    import org.joda.primitives.CharUtils;
025    import org.joda.primitives.collection.impl.AbstractCharCollection;
026    import org.joda.primitives.iterator.CharIterator;
027    import org.joda.primitives.list.CharList;
028    import org.joda.primitives.listiterator.CharListIterator;
029    
030    /**
031     * Abstract base class for lists of primitive <code>char</code> elements.
032     * <p>
033     * This class implements {@link java.util.Collection Collection} allowing
034     * seamless integration with other APIs.
035     * <p>
036     * The <code>get(int)</code> and <code>size()</code> methods must be
037     * implemented by subclases.
038     * To make the subclass modifiable, the <code>add(int, char)</code>,
039     * <code>removeIndex(int)</code> and set(int, char) must also be implemented.
040     * Subclasses may override other methods to increase efficiency.
041     *
042     * @author Stephen Colebourne
043     * @author Rodney Waldhoff
044     * @author Jason Tiscione
045     * @version CODE GENERATED
046     * @since 1.0
047     */
048    public abstract class AbstractCharList extends AbstractCharCollection implements CharList {
049        // This file is CODE GENERATED. Do not change manually.
050    
051        /**
052         * Constructor.
053         */
054        protected AbstractCharList() {
055            super();
056        }
057    
058        // CharList methods
059        //-----------------------------------------------------------------------
060        /**
061         * Gets an iterator over this list.
062         *
063         * @return an iterator over this list, not null
064         */
065        public CharListIterator iterator() {
066            return listIterator(0);
067        }
068    
069        /**
070         * Gets a list iterator over this list.
071         * <p>
072         * This implementation uses <code>charListIterator(int)</code>.
073         *
074         * @return an iterator over this list, not null
075         */
076        public CharListIterator listIterator() {
077            return listIterator(0);
078        }
079    
080        /**
081         * Gets a list iterator over this list from a start index.
082         *
083         * @param index  the index to start from
084         * @return an iterator over this list, not null
085         * @throws IndexOutOfBoundsException if the index is invalid
086         */
087        public CharListIterator listIterator(int index) {
088            checkIndex(index);
089            return new PListIterator(this, index);
090        }
091    
092        /**
093         * Gets the first primitive value.
094         *
095         * @return value at index zero
096         * @throws IndexOutOfBoundsException if the size is zero
097         */
098        public char firstChar() {
099            return getChar(0);
100        }
101    
102        /**
103         * Gets the last primitive value.
104         *
105         * @return value at index <code>size() - 1</code>
106         * @throws IndexOutOfBoundsException if the size is zero
107         */
108        public char lastChar() {
109            return getChar(size() - 1);
110        }
111    
112        /**
113         * Checks whether this collection contains a specified primitive value.
114         * <p>
115         * This implementation uses <code>getChar(int)</code>.
116         *
117         * @param value  the value to search for
118         * @return <code>true</code> if the value is found
119         */
120        public boolean contains(char value) {
121            for (int i = 0, isize = size(); i < isize; i++) {
122                if (getChar(i) == value) {
123                    return true;
124                }
125            }
126            return false;
127        }
128    
129        /**
130         * Gets the first index of the specified primitive value.
131         * <p>
132         * This implementation uses <code>indexof(char, int)</code>.
133         *
134         * @param value  the value to search for
135         * @return the zero-based index, or <code>-1</code> if not found
136         */
137        public int indexOf(char value) {
138            return indexOf(value, 0);
139        }
140    
141        /**
142         * Gets the first index of the specified primitive value from an index.
143         * <p>
144         * This method follows the conventions of <code>String</code> in that a
145         * negative index is treated as zero, and an index greater than the list
146         * size will simply return <code>-1</code>.
147         * <p>
148         * This implementation uses <code>get(int)</code>.
149         *
150         * @param value  the value to search for
151         * @param fromIndexInclusive  the index to start searching from, inclusive
152         * @return the zero-based index, or <code>-1</code> if not found
153         */
154        public int indexOf(char value, int fromIndexInclusive) {
155            if (fromIndexInclusive < 0) {
156                fromIndexInclusive = 0;
157            }
158            for (int i = fromIndexInclusive, isize = size(); i < isize; i++) {
159                if (getChar(i) == value) {
160                    return i;
161                }
162            }
163            return -1;
164        }
165    
166        /**
167         * Gets the last index of the specified primitive value.
168         * <p>
169         * This implementation uses <code>lastIndexof(char, int)</code>.
170         *
171         * @param value  the value to search for
172         * @return the zero-based index, or <code>-1</code> if not found
173         */
174        public int lastIndexOf(char value) {
175            return lastIndexOf(value, size());
176        }
177    
178        /**
179         * Gets the first index of the specified primitive value from an index.
180         * <p>
181         * This method follows the conventions of <code>String</code> in that an
182         * index greater than the list size will start searching at the list size,
183         * and a negative index simply returns <code>-1</code>.
184         * <p>
185         * This implementation uses <code>get(int)</code>.
186         *
187         * @param value  the value to search for
188         * @param fromIndexInclusive  the index to start searching from, inclusive
189         * @return the zero-based index, or <code>-1</code> if not found
190         */
191        public int lastIndexOf(char value, int fromIndexInclusive) {
192            if (fromIndexInclusive >= size()) {
193                fromIndexInclusive = size() - 1;
194            }
195            for (int i = fromIndexInclusive; i >= 0; i--) {
196                if (getChar(i) == value) {
197                    return i;
198                }
199            }
200            return -1;
201        }
202    
203        /**
204         * Gets the contents of the list as a String.
205         *
206         * @return the list contents
207         */
208        public String toStringContents() {
209            return new String(toCharArray());
210        }
211    
212        /**
213         * Gets a range of elements as an array.
214         *
215         * @param fromIndexInclusive  the index to start from, inclusive
216         * @param toIndexExclusive  the index to end at, exclusive
217         * @return a new array containing a copy of the range of elements, not null
218         * @throws IndexOutOfBoundsException if either index is invalid
219         */
220        public char[] toCharArray(int fromIndexInclusive, int toIndexExclusive) {
221            checkRange(fromIndexInclusive, toIndexExclusive);
222            
223            if (fromIndexInclusive == toIndexExclusive) {
224                return CharUtils.EMPTY_CHAR_ARRAY;
225            }
226            int size = toIndexExclusive - fromIndexInclusive;
227            char[] result = new char[size];
228            arrayCopy(fromIndexInclusive, result, 0, size);
229            return result;
230        }
231    
232        /**
233         * Gets a range view of part of this list.
234         * <p>
235         * This method allows operations to work on a range within the greater list.
236         * Changes made to the either object will affect the other.
237         *
238         * @param fromIndexInclusive  the index to start from, inclusive
239         * @param toIndexExclusive  the index to end at, exclusive
240         * @return a new CharList for the subList, not null
241         * @throws IndexOutOfBoundsException if either index is invalid
242         */
243        public CharList subList(int fromIndexInclusive, int toIndexExclusive) {
244            return null; // TODO
245        }
246    
247        /**
248         * Clears the listof all elements (optional operation).
249         * <p>
250         * This implementation uses <code>removeRange(int, int)</code>.
251         *
252         * @throws UnsupportedOperationException if method not supported by this collection
253         */
254        public void clear() {
255            removeRange(0, size());
256        }
257    
258        /**
259         * Adds a primitive value to this collection (optional operation).
260         * <p>
261         * This implementation uses <code>add(int, char)</code>.
262         *
263         * @param value  the value to add to this collection
264         * @return <code>true</code> if this collection was modified by this method call
265         * @throws IllegalArgumentException if value is rejected by this collection
266         * @throws UnsupportedOperationException if not supported by this collection
267         */
268        public boolean add(char value) {
269            checkAddModifiable();
270            return add(size(), value);
271        }
272    
273        /**
274         * Adds a primitive value to this list at an index (optional operation).
275         * <p>
276         * This implementation throws UnsupportedOperationException.
277         *
278         * @param index  the index to add at
279         * @param value  the value to add to this collection
280         * @return <code>true</code> if this list was modified by this method call
281         * @throws IndexOutOfBoundsException if the index is invalid
282         * @throws IllegalArgumentException if value is rejected by this collection
283         * @throws UnsupportedOperationException if not supported by this collection
284         */
285        public boolean add(int index, char value) {
286            throw new UnsupportedOperationException("List does not support add");
287        }
288    
289        /**
290         * Adds an array of primitive values to this list at an index (optional operation).
291         * <p>
292         * This implementation uses <code>addAll(int, char)</code>.
293         *
294         * @param values  the values to add to this collection, null treated as empty array
295         * @return <code>true</code> if this list was modified by this method call
296         * @throws IndexOutOfBoundsException if the index is invalid
297         * @throws IllegalArgumentException if value is rejected by this collection
298         * @throws UnsupportedOperationException if not supported by this collection
299         */
300        public boolean addAll(char[] values) {
301            checkAddModifiable();
302            return addAll(size(), values);
303        }
304    
305        /**
306         * Adds an array of primitive values to this list at an index (optional operation).
307         * <p>
308         * This method is optional, throwing an UnsupportedOperationException if the
309         * collection cannot be added to.
310         *
311         * @param index  the index to add at
312         * @param values  the values to add to this collection, null treated as empty array
313         * @return <code>true</code> if this list was modified by this method call
314         * @throws IndexOutOfBoundsException if the index is invalid
315         * @throws IllegalArgumentException if value is rejected by this collection
316         * @throws UnsupportedOperationException if not supported by this collection
317         */
318        public boolean addAll(int index, char[] values) {
319            checkAddModifiable();
320            checkIndex(index);
321            boolean changed = false;
322            if (values != null) {
323                for (int i = 0; i < values.length; i++) {
324                    changed |= add(index + i, values[i]);
325                }
326            }
327            return changed;
328        }
329    
330        /**
331         * Removes a primitive value by index from the list (optional operation).
332         * <p>
333         * This implementation throws UnsupportedOperationException.
334         *
335         * @param index  the index to remove from
336         * @return the primitive value previously at this index
337         * @throws IndexOutOfBoundsException if the index is invalid
338         * @throws UnsupportedOperationException if not supported by this collection
339         */
340        public char removeCharAt(int index) {
341            throw new UnsupportedOperationException("List does not support remove");
342        }
343    
344        /**
345         * Removes the first occurrence of a primitive value from the list (optional operation).
346         * <p>
347         * This implementation uses <code>get(int)</code> and <code>removeCharAt(int)</code>.
348         *
349         * @param value  the value to remove
350         * @return the primitive value previously at this index
351         * @throws UnsupportedOperationException if not supported by this collection
352         */
353        public boolean removeChar(char value) {
354            checkRemoveModifiable();
355            for (int i = 0, isize = size(); i < isize; i++) {
356                if (getChar(i) == value) {
357                    removeCharAt(i);
358                    return true;
359                }
360            }
361            return false;
362        }
363    
364        /**
365         * Removes a range of values from the list (optional operation).
366         * <p>
367         * This implementation uses <code>removeCharAt(int)</code>.
368         *
369         * @param fromIndexInclusive  the start of the range to remove, inclusive
370         * @param toIndexExclusive  the end of the range to remove, exclusive
371         * @return <code>true</code> if the collection was modified
372         * @throws IndexOutOfBoundsException if the index is invalid
373         * @throws UnsupportedOperationException if remove is not supported
374         */
375        public boolean removeRange(int fromIndexInclusive, int toIndexExclusive) {
376            checkRemoveModifiable();
377            checkRange(fromIndexInclusive, toIndexExclusive);
378            if (fromIndexInclusive == toIndexExclusive) {
379                return false;
380            }
381            for (int i = size() - 1; i >= 0; i--) {
382                removeCharAt(i);
383            }
384            return true;
385        }
386    
387        /**
388         * Sets the primitive value at a specified index.
389         * <p>
390         * This implementation throws UnsupportedOperationException.
391         *
392         * @param index  the index to set
393         * @param value  the value to store
394         * @return the previous value at the index
395         * @throws IndexOutOfBoundsException if the index is invalid
396         * @throws IllegalArgumentException if value is rejected by this collection
397         * @throws UnsupportedOperationException if not supported by this collection
398         */
399        public char set(int index, char value) {
400            throw new UnsupportedOperationException("List does not support set");
401        }
402    
403        // List methods
404        //-----------------------------------------------------------------------
405        /**
406         * Gets the <code>Character</code> value at the specified index.
407         *
408         * @param index  the index to get from
409         * @return value at the index
410         * @throws IndexOutOfBoundsException if the index is invalid
411         */
412        public Character get(int index) {
413            return CharUtils.toObject(getChar(index));
414        }
415    
416        /**
417         * Gets the first <code>Character</code> value.
418         *
419         * @return value at index zero or null if the size is zero
420         */
421        public Character first() {
422            if (size() == 0) {
423                return null;
424            }
425            return get(0);
426        }
427    
428        /**
429         * Gets the last <code>Character</code> value.
430         *
431         * @return value at index <code>size() - 1</code> or null if the size is zero
432         */
433        public Character last() {
434            if (size() == 0) {
435                return null;
436            }
437            return get(size() - 1);
438        }
439    
440        /**
441         * Gets the first index of the specified <code>Character</code> value.
442         *
443         * @param value  the value to search for
444         * @return the zero-based index, or <code>-1</code> if not found
445         * @throws NullPointerException if the value if null
446         * @throws ClassCastException if the object is not <code>Character</code>
447         */
448        public int indexOf(Object value) {
449            return indexOf(CharUtils.toPrimitive(value));
450        }
451    
452        /**
453         * Gets the first index of the specified <code>Character</code> value from an index.
454         * <p>
455         * This method follows the conventions of <code>String</code> in that a
456         * negative index is treated as zero, and an index greater than the list
457         * size will simply return <code>-1</code>.
458         *
459         * @param value  the value to search for
460         * @param fromIndexInclusive  the index to start searching from, inclusive
461         * @return the zero-based index, or <code>-1</code> if not found
462         * @throws NullPointerException if the value if null
463         * @throws ClassCastException if the object is not <code>Character</code>
464         */
465        public int indexOf(Object value, int fromIndexInclusive) {
466            return indexOf(CharUtils.toPrimitive(value), fromIndexInclusive);
467        }
468    
469        /**
470         * Gets the last index of the specified <code>Character</code> value.
471         *
472         * @param value  the value to search for
473         * @return the zero-based index, or <code>-1</code> if not found
474         * @throws NullPointerException if the value if null
475         * @throws ClassCastException if the object is not <code>Character</code>
476         */
477        public int lastIndexOf(Object value) {
478            return lastIndexOf(CharUtils.toPrimitive(value));
479        }
480    
481        /**
482         * Gets the first index of the specified <code>Character</code> value from an index.
483         * <p>
484         * This method follows the conventions of <code>String</code> in that an
485         * index greater than the list size will start searching at the list size,
486         * and a negative index simply returns <code>-1</code>.
487         *
488         * @param value  the value to search for
489         * @param fromIndexInclusive  the index to start searching from, inclusive
490         * @return the zero-based index, or <code>-1</code> if not found
491         * @throws NullPointerException if the value if null
492         * @throws ClassCastException if the object is not <code>Character</code>
493         */
494        public int lastIndexOf(Object value, int fromIndexInclusive) {
495            return lastIndexOf(CharUtils.toPrimitive(value), fromIndexInclusive);
496        }
497    
498        /**
499         * Adds the <code>Character</code> value to this collection (optional operation).
500         * <p>
501         * This method is optional, throwing an UnsupportedOperationException if the
502         * collection cannot be added to.
503         *
504         * @param value  the value to add to this collection
505         * @return <code>true</code> if this collection was modified by this method call
506         * @throws IllegalArgumentException if value is rejected by this collection
507         * @throws UnsupportedOperationException if not supported by this collection
508         */
509        public boolean add(Character value) {
510            checkAddModifiable();
511            return add(size(), CharUtils.toPrimitive(value));
512        }
513    
514        /**
515         * Adds the <code>Character</code> value to this list at an index (optional operation).
516         * <p>
517         * This method is optional, throwing an UnsupportedOperationException if the
518         * collection cannot be added to.
519         *
520         * @param index  the index to add at
521         * @param value  the value to add to this collection
522         * @throws IndexOutOfBoundsException if the index is invalid
523         * @throws ClassCastException if the object is not <code>Character</code>
524         * @throws IllegalArgumentException if value is rejected by this collection
525         * @throws UnsupportedOperationException if not supported by this collection
526         */
527        public void add(int index, Character value) {
528            checkAddModifiable();
529            checkIndex(index);
530            add(index, CharUtils.toPrimitive(value));
531        }
532    
533        /**
534         * Adds an array of <code>Character</code> values to this list at an index (optional operation).
535         * <p>
536         * This method is optional, throwing an UnsupportedOperationException if the
537         * collection cannot be added to.
538         *
539         * @param index  the index to add at
540         * @param coll  the values to add to this collection
541         * @return <code>true</code> if this list was modified by this method call
542         * @throws IndexOutOfBoundsException if the index is invalid
543         * @throws ClassCastException if any object is not <code>Character</code>
544         * @throws IllegalArgumentException if value is rejected by this collection
545         * @throws UnsupportedOperationException if not supported by this collection
546         */
547        public boolean addAll(int index, Collection<? extends Character> coll) {
548            checkAddModifiable();
549            checkIndex(index);
550            return addAll(index, CharUtils.toPrimitiveArray(coll));
551        }
552    
553        /**
554         * Removes a primitive value by index from the list (optional operation).
555         * <p>
556         * This implementation uses <code>removeCharAt(int)</code>.
557         *
558         * @deprecated This method should only be used when working with List and
559         *  not when working with CharList - use <code>removeCharAt(int)</code>
560         * @param index  the index to remove from
561         * @return the primitive value previously at this index
562         * @throws IndexOutOfBoundsException if the index is invalid
563         * @throws UnsupportedOperationException if not supported by this collection
564         */
565        public Character remove(int index) {
566            checkRemoveModifiable();
567            return CharUtils.toObject(removeCharAt(index));
568        }
569    
570        /**
571         * Sets the <code>Character</code> value at a specified index.
572         * <p>
573         * This implementation uses <code>set(int, char)</code>.
574         *
575         * @param index  the index to set
576         * @param value  the value to store
577         * @return the previous value at the index
578         * @throws IndexOutOfBoundsException if the index is invalid
579         * @throws IllegalArgumentException if value is rejected by this collection
580         * @throws UnsupportedOperationException if not supported by this collection
581         */
582        public Character set(int index, Character value) {
583            checkSetModifiable();
584            checkIndexExists(index);
585            return CharUtils.toObject(set(index, CharUtils.toPrimitive(value)));
586        }
587    
588        //-----------------------------------------------------------------------
589        /**
590         * Compares this list to another as per the contract of <code>List</code>.
591         *
592         * @param obj  the object to compare to
593         * @return <code>true</code> if the lists are equal
594         */
595        public boolean equals(Object obj) {
596            if (obj == this) {
597                return true;
598            }
599            if (obj instanceof CharList) {
600                CharList other = (CharList) obj;
601                if (size() != other.size()) {
602                    return false;
603                }
604                CharIterator it1 = listIterator();
605                CharIterator it2 = other.listIterator();
606                while (it1.hasNext() && it2.hasNext()) {
607                    if (it1.nextChar() != it2.nextChar()) {
608                        return false;
609                    }
610                }
611                return true;
612            } else if (obj instanceof List<?>) {
613                List<?> other = (List<?>) obj;
614                if (size() != other.size()) {
615                    return false;
616                }
617                CharIterator it1 = listIterator();
618                Iterator<?> it2 = other.listIterator();
619                while (it1.hasNext() && it2.hasNext()) {
620                    Object next = it2.next();
621                    if (isToPrimitivePossible(next) == false) {
622                        return false;
623                    }
624                    if (it1.nextChar() != toPrimitive(next)) {
625                        return false;
626                    }
627                }
628                return true;
629            } else {
630                return false;
631            }
632        }
633    
634        /**
635         * Gets the hashCode of this list as per the contract of <code>List</code>.
636         *
637         * @return the hash code for this list
638         */
639        public int hashCode() {
640            int hashCode = 1;
641            Iterator<Character> it = iterator();
642            while (it.hasNext()) {
643                Object obj = it.next();
644                hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
645            }
646            return hashCode;
647        }
648    
649        //-----------------------------------------------------------------------
650        /**
651         * Copies data from this collection into the specified array.
652         * This method is pre-validated.
653         * 
654         * @param fromIndex  the index to start from
655         * @param dest  the destination array
656         * @param destIndex  the destination start index
657         * @param size  the number of items to copy
658         */
659        protected void arrayCopy(int fromIndex, char[] dest, int destIndex, int size) {
660            for (int i = 0; i < size; i++) {
661                dest[i + destIndex] = getChar(i + fromIndex);
662            }
663        }
664    
665        /**
666         * Are the set methods supported.
667         * <p>
668         * This implementation returns false.
669         *
670         * @return true if supported
671         */
672        protected boolean isSetModifiable() {
673            return false;
674        }
675    
676        /**
677         * Is the collection modifiable in any way.
678         *
679         * @return true if supported
680         */
681        public boolean isModifiable() {
682            return isAddModifiable() || isRemoveModifiable() || isSetModifiable();
683        }
684    
685        /**
686         * Check whether add is suported and throw an exception.
687         */
688        protected void checkSetModifiable() {
689            if (isSetModifiable() == false) {
690                throw new UnsupportedOperationException("Collection does not support set");
691            }
692        }
693    
694        /**
695         * Checks whether an index is valid or not.
696         * 
697         * @param index  the index to check
698         * @throws IndexOutOfBoundsException if either index is invalid
699         */
700        protected void checkIndexExists(int index) {
701            if (index < 0) {
702                throw new ArrayIndexOutOfBoundsException(
703                    "Index less than zero: " + index + " < 0");
704            }
705            if (index >= size()) {
706                throw new ArrayIndexOutOfBoundsException(
707                    "Index greater than/equal to size(): " + index + " >= " + size());
708            }
709        }
710    
711        /**
712         * Checks whether an index is valid or not.
713         * 
714         * @param index  the index to check
715         * @throws IndexOutOfBoundsException if either index is invalid
716         */
717        protected void checkIndex(int index) {
718            if (index < 0) {
719                throw new ArrayIndexOutOfBoundsException(
720                    "Index less than zero: " + index + " < 0");
721            }
722            if (index > size()) {
723                throw new ArrayIndexOutOfBoundsException(
724                    "Index greater than size(): " + index + " > " + size());
725            }
726        }
727    
728        /**
729         * Checks whether a range is valid or not.
730         * 
731         * @param fromIndexInclusive  the index to start from, inclusive
732         * @param toIndexExclusive  the index to end at, exclusive
733         * @throws IndexOutOfBoundsException if either index is invalid
734         */
735        protected void checkRange(int fromIndexInclusive, int toIndexExclusive) {
736            if (fromIndexInclusive < 0) {
737                throw new ArrayIndexOutOfBoundsException(
738                    "From index less than zero: " + fromIndexInclusive + " < 0");
739            }
740            if (toIndexExclusive > size()) {
741                throw new ArrayIndexOutOfBoundsException(
742                    "To index greater than size(): " + toIndexExclusive + " > " + size());
743            }
744            if (fromIndexInclusive > toIndexExclusive) {
745                throw new ArrayIndexOutOfBoundsException(
746                    "To index greater than from index: " + fromIndexInclusive + " > " + toIndexExclusive);
747            }
748        }
749    
750        //-----------------------------------------------------------------------
751        /**
752         * List iterator.
753         */
754        protected static class PListIterator implements CharListIterator {
755    
756            private final AbstractCharList iList;
757            private final int iStart;
758            private int iCursor = 0;
759            private int iLastIndex = -1;
760            
761            protected PListIterator(AbstractCharList list, int start) {
762                super();
763                this.iList = list;
764                this.iStart = start;
765                this.iCursor = start;
766            }
767    
768            //-----------------------------------------------------------------------
769            public boolean hasNext() {
770                return (iCursor < iList.size());
771            }
772    
773            public char nextChar() {
774                if (hasNext() == false) {
775                    throw new NoSuchElementException("No more elements available");
776                }
777                iLastIndex = iCursor;
778                return iList.getChar(iCursor++);
779            }
780    
781            public Character next() {
782                return iList.toObject(nextChar());
783            }
784    
785            public int nextIndex() {
786                return iCursor;
787            }
788    
789            //-----------------------------------------------------------------------
790            public boolean hasPrevious() {
791                return (iCursor > 0);
792            }
793    
794            public char previousChar() {
795                if (hasPrevious() == false) {
796                    throw new NoSuchElementException("No more elements available");
797                }
798                iLastIndex = --iCursor;
799                return iList.getChar(iCursor);
800            }
801    
802            public Character previous() {
803                return iList.toObject(previousChar());
804            }
805    
806            public int previousIndex() {
807                return iCursor - 1;
808            }
809    
810            //-----------------------------------------------------------------------
811            public void remove() {
812                iList.checkRemoveModifiable();
813                if (iLastIndex == -1) {
814                    throw new IllegalStateException("Element cannot be removed");
815                }
816                iList.removeCharAt(iLastIndex);
817                iCursor = iLastIndex;
818                iLastIndex = -1;
819            }
820    
821            public void add(char value) {
822                iList.checkAddModifiable();
823                try {
824                    iList.add(iCursor++, value);
825                    iLastIndex = -1;
826                } catch (IndexOutOfBoundsException ex) {
827                    throw new ConcurrentModificationException("The underlying list was modified");
828                }
829            }
830    
831            public void add(Character obj) {
832                iList.checkAddModifiable();
833                add(iList.toPrimitive(obj));
834            }
835            
836            public void set(char value) {
837                iList.checkSetModifiable();
838                if (iLastIndex == -1) {
839                    throw new IllegalStateException("Element cannot be set");
840                }
841                try {
842                    iList.set(iLastIndex, value);
843                } catch (IndexOutOfBoundsException ex) {
844                    throw new ConcurrentModificationException("The underlying list was modified");
845                }
846            }
847    
848            public void set(Character obj) {
849                iList.checkSetModifiable();
850                set(iList.toPrimitive(obj));
851            }
852    
853            //-----------------------------------------------------------------------
854            public boolean isModifiable() {
855                return iList.isModifiable();
856            }
857    
858            public boolean isResettable() {
859                return true;
860            }
861    
862            public void reset() {
863                iCursor = iStart;
864            }
865    
866        }
867    
868    }
869