/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
* Microsystems, Inc. All Rights Reserved.
*
* If you wish your version of this file to be governed by only the CDDL
* or only the GPL Version 2, indicate your decision by adding
* "[Contributor] elects to include this software in this distribution
* under the [CDDL or GPL Version 2] license." If you do not indicate a
* single choice of license, a recipient has the option to distribute
* your version of this file under either the CDDL, the GPL Version 2 or
* to extend the choice of license to its licensees as provided above.
* However, if you add GPL Version 2 code and therefore, elected the GPL
* Version 2 license, then the option applies only if the new code is
* made subject to such option by the copyright holder.
*/
package org.das2.jythoncompletion.nbadapt;
/**
* Utility methods related to character sequences.
*
* @author Miloslav Metelka
* @version 1.00
*/
public final class CharSequenceUtilities {
private CharSequenceUtilities() {
// no instances
}
/**
* Compute {@link String}-like hashcode over given {@link CharSequence}.
*
* @param text character sequence for which the hashcode is being computed.
* @return hashcode of the given character sequence.
*/
public static int stringLikeHashCode(CharSequence text) {
int len = text.length();
int h = 0;
for (int i = 0; i < len; i++) {
h = 31 * h + text.charAt(i);
}
return h;
}
/**
* Compare character sequence to another object.
* The match is successful if the second object is a character sequence as well
* and both character sequences contain the same characters (or if both objects are null).
*
* @param text character sequence being compared to the given object.
* It may be null
.
* @param o object to be compared to the character sequence.
* It may be null
.
* @return true if both parameters are null or both are non-null
* and they contain the same text.
*/
public static boolean equals(CharSequence text, Object o) {
if (text == o) {
return true;
}
if (text != null && o instanceof CharSequence) { // both non-null
return textEquals(text, (CharSequence)o);
}
return false;
}
/**
* Test whether whether the given character sequences
* represent the same text.
*
* The match is successful if the contained characters
* of the two character sequences are the same.
*
* @param text1 first character sequence being compared.
* It must not be null
.
* @param text2 second character sequence being compared.
* It must not be null
.
* @return true if both parameters are equal in String-like manner.
*/
public static boolean textEquals(CharSequence text1, CharSequence text2) {
if (text1 == text2) {
return true;
}
int len = text1.length();
if (len == text2.length()) {
for (int i = len - 1; i >= 0; i--) {
if (text1.charAt(i) != text2.charAt(i)) {
return false;
}
}
return true;
}
return false;
}
/**
* Create a string from the given character sequence by first creating
* a StringBuilder
and appending the whole character sequence
* to it.
*
* The method does not call toString()
on the given character
* sequence.
*
* @param text character sequence for which the String
form
* should be created.
* @return string representation of the character sequence.
*/
public static String toString(CharSequence text) {
StringBuilder sb = new StringBuilder(text.length());
sb.append(text);
return sb.toString();
}
/**
* Create string for the given portion of the character sequence.
*
* @param text non-null text.
* @param start >=0 and =start and
* This method is no longer needed in JDK 1.5 where the implementation
* does not create an extra java.lang.String instance.
*/
public static void append(StringBuffer sb, CharSequence text) {
sb.append(text); // Only assume to run on 1.5
}
/**
* Append part of the character sequence to the given string buffer.
*
* This method is no longer needed in JDK 1.5 where the implementation
* of the same functionality is available in the StringBuffer directly.
*/
public static void append(StringBuffer sb, CharSequence text, int start, int end) {
checkIndexesValid(text, start, end);
while (start < end) {
sb.append(text.charAt(start++));
}
}
/**
* Implementation of {@link String#indexOf(int)} for character sequences.
*/
public static int indexOf(CharSequence text, int ch) {
return indexOf(text, ch, 0);
}
/**
* Implementation of {@link String#indexOf(int,int)} for character sequences.
*/
public static int indexOf(CharSequence text, int ch, int fromIndex) {
int length = text.length();
while (fromIndex < length) {
if (text.charAt(fromIndex) == ch) {
return fromIndex;
}
fromIndex++;
}
return -1;
}
/**
* Implementation of {@link String#indexOf(String)} for character sequences.
*/
public static int indexOf(CharSequence text, CharSequence seq) {
return indexOf(text, seq, 0);
}
/**
* Implementation of {@link String#indexOf(String,int)} for character sequences.
*/
public static int indexOf(CharSequence text, CharSequence seq, int fromIndex) {
int textLength = text.length();
int seqLength = seq.length();
if (fromIndex >= textLength) {
return (seqLength == 0 ? textLength : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (seqLength == 0) {
return fromIndex;
}
char first = seq.charAt(0);
int max = textLength - seqLength;
for (int i = fromIndex; i <= max; i++) {
// look for first character
if (text.charAt(i) != first) {
while (++i <= max && text.charAt(i) != first);
}
// found first character, now look at the rest of seq
if (i <= max) {
int j = i + 1;
int end = j + seqLength - 1;
for (int k = 1; j < end && text.charAt(j) == seq.charAt(k); j++, k++);
if (j == end) {
// found whole sequence
return i;
}
}
}
return -1;
}
/**
* Implementation of {@link String#lastIndexOf(String)} for character sequences.
*/
public static int lastIndexOf(CharSequence text, CharSequence seq) {
return lastIndexOf(text, seq, text.length());
}
/**
* Implementation of {@link String#lastIndexOf(String,int)} for character sequences.
*/
public static int lastIndexOf(CharSequence text, CharSequence seq, int fromIndex) {
int textLength = text.length();
int seqLength = seq.length();
int rightIndex = textLength - seqLength;
if (fromIndex < 0) {
return -1;
}
if (fromIndex > rightIndex) {
fromIndex = rightIndex;
}
// empty string always matches
if (seqLength == 0) {
return fromIndex;
}
int strLastIndex = seqLength - 1;
char strLastChar = seq.charAt(strLastIndex);
int min = seqLength - 1;
int i = min + fromIndex;
startSearchForLastChar:
while (true) {
while (i >= min && text.charAt(i) != strLastChar) {
i--;
}
if (i < min) {
return -1;
}
int j = i - 1;
int start = j - (seqLength - 1);
int k = strLastIndex - 1;
while (j > start) {
if (text.charAt(j--) != seq.charAt(k--)) {
i--;
continue startSearchForLastChar;
}
}
return start + 1;
}
}
/**
* Implementation of {@link String#lastIndexOf(int)} for character sequences.
*/
public static int lastIndexOf(CharSequence text, int ch) {
return lastIndexOf(text, ch, text.length() - 1);
}
/**
* Implementation of {@link String#lastIndexOf(int,int)} for character sequences.
*/
public static int lastIndexOf(CharSequence text, int ch, int fromIndex) {
if (fromIndex > text.length() - 1) {
fromIndex = text.length() - 1;
}
while (fromIndex >= 0) {
if (text.charAt(fromIndex) == ch) {
return fromIndex;
}
fromIndex--;
}
return -1;
}
/**
* Implementation of {@link String#startsWith(String)} for character sequences.
*/
public static boolean startsWith(CharSequence text, CharSequence prefix) {
int p_length = prefix.length();
if (p_length > text.length()) {
return false;
}
for (int x = 0; x < p_length; x++) {
if (text.charAt(x) != prefix.charAt(x))
return false;
}
return true;
}
/**
* Implementation of {@link String#endsWith(String)} for character sequences.
*/
public static boolean endsWith(CharSequence text, CharSequence suffix) {
int s_length = suffix.length();
int text_length = text.length();
if (s_length > text_length) {
return false;
}
for (int x = 0; x < s_length; x++) {
if (text.charAt(text_length - s_length + x) != suffix.charAt(x))
return false;
}
return true;
}
/**
* Implementation of {@link String#trim()} for character sequences.
*/
public static CharSequence trim(CharSequence text) {
int length = text.length();
if (length == 0)
return text;
int start = 0;
int end = length - 1;
while (start < length && text.charAt(start) <= ' ') {
start++;
}
if (start == length)
return text.subSequence(0, 0);
while (end > start && text.charAt(end) <= ' ') {
end--;
}
return text.subSequence(start, end + 1);
}
/**
* Append the character description to the given string buffer
* translating the special characters (and '\') into escape sequences.
*
* @param sb non-null string buffer to append to.
* @param ch character to be debugged.
*/
public static void debugChar(StringBuffer sb, char ch) {
switch (ch) {
case '\n':
sb.append("\\n"); // NOI18N
break;
case '\r':
sb.append("\\r"); // NOI18N
break;
case '\t':
sb.append("\\t"); // NOI18N
break;
case '\b':
sb.append("\\b"); // NOI18N
break;
case '\f':
sb.append("\\f"); // NOI18N
break;
case '\\':
sb.append("\\\\"); // NOI18N
break;
default:
sb.append(ch);
break;
}
}
/**
* Append the character description to the given string builder
* translating the special characters (and '\') into escape sequences.
*
* @param sb non-null string buffer to append to.
* @param ch character to be debugged.
*/
public static void debugChar(StringBuilder sb, char ch) {
switch (ch) {
case '\n':
sb.append("\\n"); // NOI18N
break;
case '\r':
sb.append("\\r"); // NOI18N
break;
case '\t':
sb.append("\\t"); // NOI18N
break;
case '\b':
sb.append("\\b"); // NOI18N
break;
case '\f':
sb.append("\\f"); // NOI18N
break;
case '\\':
sb.append("\\\\"); // NOI18N
break;
default:
sb.append(ch);
break;
}
}
/**
* Return the text description of the given character
* translating the special characters (and '\') into escape sequences.
*
* @param ch char to debug.
* @return non-null debug text.
*/
public static String debugChar(char ch) {
StringBuilder sb = new StringBuilder();
debugChar(sb, ch);
return sb.toString();
}
/**
* Append the text description to the given string buffer
* translating the special characters (and '\') into escape sequences.
*
* @param sb non-null string buffer to append to.
* @param text non-null text to be debugged.
*/
public static void debugText(StringBuffer sb, CharSequence text) {
for (int i = 0; i < text.length(); i++) {
debugChar(sb, text.charAt(i));
}
}
/**
* Append the text description to the given string builder
* translating the special characters (and '\') into escape sequences.
*
* @param sb non-null string builder to append to.
* @param text non-null text to be debugged.
*/
public static void debugText(StringBuilder sb, CharSequence text) {
for (int i = 0; i < text.length(); i++) {
debugChar(sb, text.charAt(i));
}
}
/**
* Create text description as String
* translating the special characters (and '\') into escape sequences.
*
* @param text non-null text to be debugged.
* @return non-null string containing the debug text.
*/
public static String debugText(CharSequence text) {
StringBuilder sb = new StringBuilder();
debugText(sb, text);
return sb.toString();
}
/**
* Ensure that the given index is >=0 and lower than the given length.
* @throws IndexOutOfBoundsException if the index is not within bounds.
*/
public static void checkIndexNonNegative(int index) {
if (index < 0) {
throw new IndexOutOfBoundsException("index=" + index + " < 0"); // NOI18N
}
}
/**
* Ensure that the given index is >=0 and lower than the given length.
* @throws IndexOutOfBoundsException if the index is not within bounds.
*/
public static void checkIndexValid(int index, int length) {
checkIndexNonNegative(index);
if (index >= length) {
throw new IndexOutOfBoundsException("index=" + index // NOI18N
+ " >= length()=" + length); // NOI18N
}
}
/**
* Ensure that the given start and end parameters are valid indices
* of the given text.
* @throws IndexOutOfBoundsException if the start or end are not within bounds
* of the given text.
*/
public static void checkIndexesValid(CharSequence text, int start, int end) {
if (start < 0) {
throw new IndexOutOfBoundsException("start=" + start + " < 0"); // NOI18N
}
if (end < start) {
throw new IndexOutOfBoundsException("end=" + end + " < start=" + start); // NOI18N
}
if (end > text.length()) {
throw new IndexOutOfBoundsException("end=" + end // NOI18N
+ " > text.length()=" + text.length()); // NOI18N
}
}
}