/*
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
* Copyright (C) 2012 - Javolution (http://javolution.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javolution.text;
import javolution.util.function.Equalities;
/**
* <p> A {@link CharSequence} backed up by a <code>char</code> array.
* Instances of this class are
* typically used/reused to provide <code>CharSequence</code> views
* over existing character buffers.</p>
*
* <p> Instances of this classes have the following properties:<ul>
*
* <li> They support equality or lexical comparison with any
* <code>CharSequence</code> (e.g. <code>String</code>).</li>
*
* <li> They have the same hashcode than <code>String</code> and can be
* used to retrieve data from maps for which the keys are
* <code>String</code> instances.</li>
*
* <li> They support fast conversions to primitive types
* (e.g. {@link #toBoolean() Boolean}, {@link #toInt int}).</li>
*
* </ul></p>
*
* @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
* @version 5.3, January 10, 2007
*/
public final class CharArray implements CharSequence, Comparable<CharSequence> {
/**
* Holds the character array.
*/
private char[] _array;
/**
* Holds the index of the first character.
*/
private int _offset;
/**
* Holds the length of char sequence.
*/
private int _length;
/**
* Default constructor (empty character array).
*/
public CharArray() {
_array = NO_CHAR;
}
private static final char[] NO_CHAR = new char[0];
/**
* Creates a character array of specified default capacity.
*
* @param capacity the backing array default capacity.
*/
public CharArray(int capacity) {
_array = new char[capacity];
}
/**
* Creates a character array from the specified String.
*
* @param string the string source.
*/
public CharArray(String string) {
_array = string.toCharArray();
_length = string.length();
}
/**
* Returns the underlying array.
*
* @return the underlying array.
*/
public char[] array() {
return _array;
}
/**
* Returns the length of this character sequence.
*
* @return the number of characters (16-bits Unicode).
*/
public int length() {
return _length;
}
/**
* Returns the offset of the first character in the underlying array.
*
* @return the offset of the first character.
*/
public int offset() {
return _offset;
}
/**
* Sets the underlying array of this CharArray.
*
* @param offset the new offset.
* @param array the new underlying array.
* @param length the new length.
* @return <code>this</code>
*/
public CharArray setArray(char[] array, int offset, int length) {
_array = array;
_offset = offset;
_length = length;
return this;
}
/**
* Returns the index within this character sequence of the first occurrence
* of the specified characters sequence searching forward.
*
* @param csq a character sequence searched for.
* @return the index of the specified character sequence in the range
* <code>[0, length()[</code>
* or <code>-1</code> if the character sequence is not found.
*/
public final int indexOf(java.lang.CharSequence csq) {
final char c = csq.charAt(0);
final int csqLength = csq.length();
for (int i = _offset, end = _offset + _length - csqLength + 1; i < end; i++) {
if (_array[i] == c) { // Potential match.
boolean match = true;
for (int j = 1; j < csqLength; j++) {
if (_array[i + j] != csq.charAt(j)) {
match = false;
break;
}
}
if (match) { return i - _offset; }
}
}
return -1;
}
/**
* Returns the index within this character sequence of the first occurrence
* of the specified character searching forward.
*
* @param c the character to search for.
* @return the indext of the specified character in the range
* <code>[0, length()[</code>
* or <code>-1</code> if the character is not found.
*/
public final int indexOf(char c) {
for (int i = _offset, end = _offset + _length; i < end; i++) {
if (_array[i] == c) return i - _offset;
}
return -1;
}
/**
* Returns the <code>String</code> corresponding to this character
* sequence. The <code>String</code> returned is always allocated on the
* heap and can safely be referenced elsewhere.
*
* @return the <code>java.lang.String</code> for this character sequence.
*/
@Override
public String toString() {
return new String(_array, _offset, _length);
}
/**
* Returns the hash code for this {@link CharArray}.
*
* <p> Note: Returns the same hashCode as <code>java.lang.String</code>
* (consistent with {@link #equals})</p>
* @return the hash code value.
*/
@Override
public int hashCode() {
int h = 0;
for (int i = 0, j = _offset; i < _length; i++) {
h = 31 * h + _array[j++];
}
return h;
}
/**
* Compares this character sequence against the specified object
* (<code>String</code> or <code>CharSequence</code>).
*
* @param that the object to compare with.
* @return <code>true</code> if both objects represent the same sequence;
* <code>false</code> otherwise.
*/
@Override
public boolean equals(Object that) {
if (that instanceof String) {
return equals((String) that);
} else if (that instanceof CharArray) {
return equals((CharArray) that);
} else if (that instanceof java.lang.CharSequence) {
return contentEquals((java.lang.CharSequence) that);
} else {
return false;
}
}
/**
* Compares this character array against the specified character sequence.
*
* @param chars the character sequence to compare with.
* @return <code>true</code> if both objects represent the same sequence;
* <code>false</code> otherwise.
*/
public boolean contentEquals(CharSequence chars) {
if (chars == null) return false;
if (this._length != chars.length()) return false;
for (int i = _length, j = _offset + _length; --i >= 0;) {
if (_array[--j] != chars.charAt(i)) return false;
}
return true;
}
/**
* Compares this character array against the specified {@link CharArray}.
*
* @param that the character array to compare with.
* @return <code>true</code> if both objects represent the same sequence;
* <code>false</code> otherwise.
*/
public boolean equals(CharArray that) {
if (this == that) return true;
if (that == null) return false;
if (this._length != that._length) return false;
final char[] thatArray = that._array;
for (int i = that._offset + _length, j = _offset + _length; --j >= _offset;) {
if (_array[j] != thatArray[--i]) return false;
}
return true;
}
/**
* Compares this character array against the specified String.
* In case of equality, the CharArray keeps a reference to the
* String for future comparisons.
*
* @param str the string to compare with.
* @return <code>true</code> if both objects represent the same sequence;
* <code>false</code> otherwise.
*/
public boolean equals(String str) {
if (str == null) return false;
if (_length != str.length()) return false;
for (int i = _length, j = _offset + _length; --i >= 0;) {
if (_array[--j] != str.charAt(i)) return false;
}
return true;
}
/**
* Compares this character array with the specified character
* sequence lexicographically.
*
* @param seq the character sequence to be compared.
* @return <code>{@link Equalities#LEXICAL}.compare(this, seq)</code>
* @throws ClassCastException if the specifed object is not a
* <code>CharSequence</code>.
*/
public int compareTo(CharSequence seq) {
return Equalities.LEXICAL.compare(this, seq);
}
/**
* Returns the <code>boolean</code> represented by this character array.
*
* @return the corresponding <code>boolean</code> value.
* @throws NumberFormatException if this character sequence
* does not contain a parsable <code>boolean</code>.
*/
public boolean toBoolean() {
return TypeFormat.parseBoolean(this);
}
/**
* Returns the decimal <code>int</code> represented by this character array.
*
* @return <code>toInt(10)</code>
* @throws NumberFormatException if this character sequence
* does not contain a parsable <code>int</code>.
*/
public int toInt() {
return TypeFormat.parseInt(this);
}
/**
* Returns the <code>int</code> represented by this character array
* in the specified radix.
*
* @param radix the radix (e.g. <code>16</code> for hexadecimal).
* @return the corresponding <code>int</code> value.
* @throws NumberFormatException if this character sequence
* does not contain a parsable <code>int</code>.
*/
public int toInt(int radix) {
return TypeFormat.parseInt(this, radix);
}
/**
* Returns the decimal <code>long</code> represented by this character
* array.
*
* @return the corresponding <code>long</code> value.
* @throws NumberFormatException if this character sequence
* does not contain a parsable <code>long</code>.
*/
public long toLong() {
return TypeFormat.parseLong(this);
}
/**
* Returns the decimal <code>long</code> represented by this character
* array in the specified radix.
*
* @param radix the radix (e.g. <code>16</code> for hexadecimal).
* @return the corresponding <code>long</code> value.
* @throws NumberFormatException if this character sequence
* does not contain a parsable <code>long</code>.
*/
public long toLong(int radix) {
return TypeFormat.parseLong(this, radix);
}
/**
* Returns the <code>float</code> represented by this character array.
*
* @return the corresponding <code>float</code> value.
* @return <code>TypeFormat.parseFloat(this)</code>
* @throws NumberFormatException if this character sequence
* does not contain a parsable <code>float</code>.
*/
public float toFloat() {
return TypeFormat.parseFloat(this);
}
/**
* Returns the <code>double</code> represented by this character array.
*
* @return the corresponding <code>double</code> value.
* @throws NumberFormatException if this character sequence
* does not contain a parsable <code>double</code>.
*/
public double toDouble() {
return TypeFormat.parseDouble(this);
}
// Implements CharSequence
public char charAt(int index) {
if ((index < 0) || (index >= _length)) throw new IndexOutOfBoundsException(
"index: " + index);
return _array[_offset + index];
}
// Implements CharSequence
public java.lang.CharSequence subSequence(int start, int end) {
if ((start < 0) || (end < 0) || (start > end) || (end > this.length())) throw new IndexOutOfBoundsException();
CharArray chars = new CharArray();
chars._array = _array;
chars._offset = _offset + start;
chars._length = end - start;
return chars;
}
// Implements CharSequence
public void getChars(int start, int end, char dest[], int destPos) {
if ((start < 0) || (end < 0) || (start > end) || (end > _length)) throw new IndexOutOfBoundsException();
System.arraycopy(_array, start + _offset, dest, destPos, end - start);
}
}