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 */
016package org.joda.primitives.list.impl;
017
018import java.util.Collection;
019import java.util.ConcurrentModificationException;
020import java.util.Iterator;
021import java.util.List;
022import java.util.NoSuchElementException;
023
024import org.joda.primitives.CharUtils;
025import org.joda.primitives.collection.impl.AbstractCharCollection;
026import org.joda.primitives.iterator.CharIterator;
027import org.joda.primitives.list.CharList;
028import 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 */
048public 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