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 org.joda.primitives.CharUtils;
019import 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 */
030public 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}