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 org.joda.primitives.CharUtils;
019    import org.joda.primitives.list.CharList;
020    
021    /**
022     * Unmodifiable CharList wrapped around a String.
023     * <p>
024     * This class implements {@link java.util.List List} allowing
025     * seamless integration with other APIs.
026     *
027     * @author Stephen Colebourne
028     * @since 1.0
029     */
030    public class StringCharList extends AbstractCharList implements Cloneable {
031    
032        /** The String being wrapped */
033        protected final String string;
034    
035        /**
036         * Constructor that uses an empty string as the datasource.
037         */
038        public StringCharList() {
039            super();
040            this.string = "";
041        }
042    
043        /**
044         * Constructor that copies the specified list.
045         * 
046         * @param list  the list to copy, must not be null
047         * @throws IllegalArgumentException if the list is null
048         */
049        public StringCharList(CharList list) {
050            super();
051            if (list == null) {
052                throw new IllegalArgumentException("List must not be null");
053            }
054            this.string = new String(list.toCharArray());
055        }
056    
057        /**
058         * Constructor that uses the specified string as the datasource.
059         * 
060         * @param str  the string to wrap in a list, must not be null
061         * @throws IllegalArgumentException if the string is null
062         */
063        public StringCharList(String str) {
064            super();
065            if (str == null) {
066                throw new IllegalArgumentException("String must not be null");
067            }
068            this.string = str;
069        }
070    
071        // Implementation
072        //-----------------------------------------------------------------------
073        /**
074         * Gets the character at the specified index.
075         * 
076         * @param index  the index to retrieve
077         * @return the character at the specified index
078         */
079        public char getChar(int index) {
080            return string.charAt(index);
081        }
082    
083        /**
084         * Gets the size of the list, which is the string length.
085         * 
086         * @return the string length
087         */
088        public int size() {
089            return string.length();
090        }
091    
092        // Optimisation
093        //-----------------------------------------------------------------------
094        /**
095         * Checks whether this collection contains a specified primitive value.
096         * <p>
097         * This implementation uses <code>String.indexOf(char)</code>.
098         *
099         * @param value  the value to search for
100         * @return <code>true</code> if the value is found
101         */
102        public boolean contains(char value) {
103            return (string.indexOf(value) >= 0);
104        }
105    
106        /**
107         * Gets the first index of the specified primitive value.
108         * <p>
109         * This implementation uses <code>String.indexOf(char)</code>.
110         *
111         * @param value  the value to search for
112         * @return the zero-based index, or <code>-1</code> if not found
113         */
114        public int indexOf(char value) {
115            return string.indexOf(value);
116        }
117    
118        /**
119         * Gets the first index of the specified primitive value from an index.
120         * <p>
121         * This method follows the conventions of <code>String</code> in that a
122         * negative index is treated as zero, and an index greater than the list
123         * size will simply return <code>-1</code>.
124         * <p>
125         * This implementation uses <code>String.indexOf(char, int)</code>.
126         *
127         * @param value  the value to search for
128         * @param fromIndexInclusive  the index to start searching from, inclusive
129         * @return the zero-based index, or <code>-1</code> if not found
130         */
131        public int indexOf(char value, int fromIndexInclusive) {
132            return string.indexOf(value, fromIndexInclusive);
133        }
134    
135        /**
136         * Gets the last index of the specified primitive value.
137         * <p>
138         * This implementation uses <code>String.lastIndexOf(char)</code>.
139         *
140         * @param value  the value to search for
141         * @return the zero-based index, or <code>-1</code> if not found
142         */
143        public int lastIndexOf(char value) {
144            return string.lastIndexOf(value);
145        }
146    
147        /**
148         * Gets the first index of the specified primitive value from an index.
149         * <p>
150         * This method follows the conventions of <code>String</code> in that an
151         * index greater than the list size will start searching at the list size,
152         * and a negative index simply returns <code>-1</code>.
153         * <p>
154         * This implementation uses <code>String.lastIndexOf(char, int)</code>.
155         *
156         * @param value  the value to search for
157         * @param fromIndexInclusive  the index to start searching from, inclusive
158         * @return the zero-based index, or <code>-1</code> if not found
159         */
160        public int lastIndexOf(char value, int fromIndexInclusive) {
161            return string.lastIndexOf(value, fromIndexInclusive);
162        }
163    
164        /**
165         * Gets the String underlying the list.
166         * 
167         * @return the underlying string, not null
168         */
169        public String toStringContents() {
170            return string;
171        }
172    
173        /**
174         * Gets the elements of this collection as an array.
175         * <p>
176         * This implementation uses <code>String.toCharArray()</code>.
177         *
178         * @return a new array containing a copy of the elements of this collection, not null
179         */
180        public char[] toCharArray() {
181            if (size() == 0) {
182                return CharUtils.EMPTY_CHAR_ARRAY;
183            }
184            return string.toCharArray();
185        }
186    
187        /**
188         * Gets a range view of part of this list.
189         * <p>
190         * This method allows operations to work on a range within the greater list.
191         * StringCharList is unmodifiable, thus so is the view.
192         *
193         * @param fromIndexInclusive  the index to start from, inclusive
194         * @param toIndexExclusive  the index to end at, exclusive
195         * @return a new CharList for the subList, not null
196         * @throws IndexOutOfBoundsException if either index is invalid
197         */
198        public CharList subList(int fromIndexInclusive, int toIndexExclusive) {
199            checkRange(fromIndexInclusive, toIndexExclusive);
200            return new StringCharList(string.substring(fromIndexInclusive, toIndexExclusive));
201        }
202    
203    }