X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Feclipse%2Fjdt%2Fcore%2Fcompiler%2FCharOperation.java;fp=src%2Forg%2Feclipse%2Fjdt%2Fcore%2Fcompiler%2FCharOperation.java;h=07d23e3b877bd2d81745a1b1a93eb2e2a7d56dcc;hb=040fa5af2cd00017cf3575950cdaade34a6d7f6c;hp=0000000000000000000000000000000000000000;hpb=a580fb8376d315d05e4d6bfdff9ff1101a151cd6;p=org.ibex.tool.git diff --git a/src/org/eclipse/jdt/core/compiler/CharOperation.java b/src/org/eclipse/jdt/core/compiler/CharOperation.java new file mode 100644 index 0000000..07d23e3 --- /dev/null +++ b/src/org/eclipse/jdt/core/compiler/CharOperation.java @@ -0,0 +1,2686 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.compiler; + +/** + * This class is a collection of helper methods to manipulate char arrays. + * + * @since 2.1 + */ +public final class CharOperation { + + /** + * Constant for an empty char array + */ + public static final char[] NO_CHAR = new char[0]; + + /** + * Constant for an empty char array with two dimensions. + */ + public static final char[][] NO_CHAR_CHAR = new char[0][]; + + /** + * Answers a new array with appending the suffix character at the end of the array. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    array = { 'a', 'b' }
    +	 *    suffix = 'c'
    +	 *    => result = { 'a', 'b' , 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = null
    +	 *    suffix = 'c'
    +	 *    => result = { 'c' }
    +	 * 
  4. + *
+ * + * @param array the array that is concanated with the suffix character + * @param suffix the suffix character + * @return the new array + */ + public static final char[] append(char[] array, char suffix) { + if (array == null) + return new char[] { suffix }; + int length = array.length; + System.arraycopy(array, 0, array = new char[length + 1], 0, length); + array[length] = suffix; + return array; + } + /** + * Append the given subarray to the target array starting at the given index in the target array. + * The start of the subarray is inclusive, the end is exclusive. + * Answers a new target array if it needs to grow, otherwise answers the same target array. + *
+ * For example:
+ *
    + *
  1. +	 *    target = { 'a', 'b', '0' }
    +	 *    index = 2
    +	 *    array = { 'c', 'd' }
    +	 *    start = 0
    +	 *    end = 1
    +	 *    => result = { 'a', 'b' , 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    target = { 'a', 'b' }
    +	 *    index = 2
    +	 *    array = { 'c', 'd' }
    +	 *    start = 0
    +	 *    end = 1
    +	 *    => result = { 'a', 'b' , 'c', '0', '0' , '0' } (new array)
    +	 * 
  4. + *
  5. +	 *    target = { 'a', 'b', 'c' }
    +	 *    index = 1
    +	 *    array = { 'c', 'd', 'e', 'f' }
    +	 *    start = 1
    +	 *    end = 4
    +	 *    => result = { 'a', 'd' , 'e', 'f', '0', '0', '0', '0' } (new array)
    +	 * 
  6. + *
+ * + * @param target the given target + * @param index the given index + * @param array the given array + * @param start the given start index + * @param end the given end index + * + * @return the new array + * @throws NullPointerException if the target array is null + */ + public static final char[] append(char[] target, int index, char[] array, int start, int end) { + int targetLength = target.length; + int subLength = end-start; + int newTargetLength = subLength+index; + if (newTargetLength > targetLength) { + System.arraycopy(target, 0, target = new char[newTargetLength*2], 0, index); + } + System.arraycopy(array, start, target, index, subLength); + return target; + } + + /** + * Answers the concatenation of the two arrays. It answers null if the two arrays are null. + * If the first array is null, then the second array is returned. + * If the second array is null, then the first array is returned. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    => result = null
    +	 * 
    + *
  2. + *
  3. +	 *    first = { { ' a' } }
    +	 *    second = null
    +	 *    => result = { { ' a' } }
    +	 * 
    + *
  4. + *
  5. +	 *    first = null
    +	 *    second = { { ' a' } }
    +	 *    => result = { { ' a' } }
    +	 * 
    + *
  6. + *
  7. +	 *    first = { { ' b' } }
    +	 *    second = { { ' a' } }
    +	 *    => result = { { ' b' }, { ' a' } }
    +	 * 
    + *
  8. + *
+ * + * @param first the first array to concatenate + * @param second the second array to concatenate + * @return the concatenation of the two arrays, or null if the two arrays are null. + */ + public static final char[][] arrayConcat(char[][] first, char[][] second) { + if (first == null) + return second; + if (second == null) + return first; + + int length1 = first.length; + int length2 = second.length; + char[][] result = new char[length1 + length2][]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + return result; + } + /** + * Returns the char arrays as an array of Strings + * + * @param charArrays the char array to convert + * @return the char arrays as an array of Strings or null if the given char arrays is null. + * @since 3.0 + */ + public static String[] charArrayToStringArray(char[][] charArrays) { + if (charArrays == null) { + return null; + } + String[] strings= new String[charArrays.length]; + for (int i= 0; i < charArrays.length; i++) { + strings[i]= new String(charArrays[i]); + } + return strings; + } + /** + * Returns the char array as a String + + * @param charArray the char array to convert + * @return the char array as a String or null if the given char array is null. + * @since 3.0 + */ + public static String charToString(char[] charArray) { + if (charArray == null) return null; + return new String(charArray); + } + + /** + * Answers a new array adding the second array at the end of first array. + * It answers null if the first and second are null. + * If the first array is null, then a new array char[][] is created with second. + * If the second array is null, then the first array is returned. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = { 'a' }
    +	 *    => result = { { ' a' } }
    +	 * 
    + *
  2. +	 *    first = { { ' a' } }
    +	 *    second = null
    +	 *    => result = { { ' a' } }
    +	 * 
    + *
  3. + *
  4. +	 *    first = { { ' a' } }
    +	 *    second = { ' b' }
    +	 *    => result = { { ' a' } , { ' b' } }
    +	 * 
    + *
  5. + *
+ * + * @param first the first array to concatenate + * @param second the array to add at the end of the first array + * @return a new array adding the second array at the end of first array, or null if the two arrays are null. + */ + public static final char[][] arrayConcat(char[][] first, char[] second) { + if (second == null) + return first; + if (first == null) + return new char[][] { second }; + + int length = first.length; + char[][] result = new char[length + 1][]; + System.arraycopy(first, 0, result, 0, length); + result[length] = second; + return result; + } + + /** + * Compares the contents of the two arrays array and prefix. Returns + * + *

+ * For example: + *

    + *
  1. +	 *    array = null
    +	 *    prefix = null
    +	 *    => result = NullPointerException
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a', 'b', 'c', 'd', 'e' }
    +	 *    prefix = { 'a', 'b', 'c'}
    +	 *    => result = 0
    +	 * 
    + *
  4. + *
  5. +	 *    array = { 'a', 'b', 'c', 'd', 'e' }
    +	 *    prefix = { 'a', 'B', 'c'}
    +	 *    => result = 32
    +	 * 
    + *
  6. + *
  7. +	 *    array = { 'd', 'b', 'c', 'd', 'e' }
    +	 *    prefix = { 'a', 'b', 'c'}
    +	 *    => result = 3
    +	 * 
    + *
  8. + *
  9. +	 *    array = { 'a', 'b', 'c', 'd', 'e' }
    +	 *    prefix = { 'd', 'b', 'c'}
    +	 *    => result = -3
    +	 * 
    + *
  10. + *
  11. +	 *    array = { 'a', 'a', 'c', 'd', 'e' }
    +	 *    prefix = { 'a', 'e', 'c'}
    +	 *    => result = -4
    +	 * 
    + *
  12. + *
+ *

+ * + * @param array the given array + * @param prefix the given prefix + * @return the result of the comparison (>=0 if array>prefix) + * @throws NullPointerException if either array or prefix is null + */ + public static final int compareWith(char[] array, char[] prefix) { + int arrayLength = array.length; + int prefixLength = prefix.length; + int min = Math.min(arrayLength, prefixLength); + int i = 0; + while (min-- != 0) { + char c1 = array[i]; + char c2 = prefix[i++]; + if (c1 != c2) + return c1 - c2; + } + if (prefixLength == i) + return 0; + return -1; // array is shorter than prefix (e.g. array:'ab' < prefix:'abc'). + } + + /** + * Answers the concatenation of the two arrays. It answers null if the two arrays are null. + * If the first array is null, then the second array is returned. + * If the second array is null, then the first array is returned. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = { 'a' }
    +	 *    => result = { ' a' }
    +	 * 
    + *
  2. + *
  3. +	 *    first = { ' a' }
    +	 *    second = null
    +	 *    => result = { ' a' }
    +	 * 
    + *
  4. + *
  5. +	 *    first = { ' a' }
    +	 *    second = { ' b' }
    +	 *    => result = { ' a' , ' b' }
    +	 * 
    + *
  6. + *
+ * + * @param first the first array to concatenate + * @param second the second array to concatenate + * @return the concatenation of the two arrays, or null if the two arrays are null. + */ + public static final char[] concat(char[] first, char[] second) { + if (first == null) + return second; + if (second == null) + return first; + + int length1 = first.length; + int length2 = second.length; + char[] result = new char[length1 + length2]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + return result; + } + + /** + * Answers the concatenation of the three arrays. It answers null if the three arrays are null. + * If first is null, it answers the concatenation of second and third. + * If second is null, it answers the concatenation of first and third. + * If third is null, it answers the concatenation of first and second. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = { 'a' }
    +	 *    third = { 'b' }
    +	 *    => result = { ' a', 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    first = { 'a' }
    +	 *    second = null
    +	 *    third = { 'b' }
    +	 *    => result = { ' a', 'b' }
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'a' }
    +	 *    second = { 'b' }
    +	 *    third = null
    +	 *    => result = { ' a', 'b' }
    +	 * 
    + *
  6. + *
  7. +	 *    first = null
    +	 *    second = null
    +	 *    third = null
    +	 *    => result = null
    +	 * 
    + *
  8. + *
  9. +	 *    first = { 'a' }
    +	 *    second = { 'b' }
    +	 *    third = { 'c' }
    +	 *    => result = { 'a', 'b', 'c' }
    +	 * 
    + *
  10. + *
+ * + * @param first the first array to concatenate + * @param second the second array to concatenate + * @param third the third array to concatenate + * + * @return the concatenation of the three arrays, or null if the three arrays are null. + */ + public static final char[] concat( + char[] first, + char[] second, + char[] third) { + if (first == null) + return concat(second, third); + if (second == null) + return concat(first, third); + if (third == null) + return concat(first, second); + + int length1 = first.length; + int length2 = second.length; + int length3 = third.length; + char[] result = new char[length1 + length2 + length3]; + System.arraycopy(first, 0, result, 0, length1); + System.arraycopy(second, 0, result, length1, length2); + System.arraycopy(third, 0, result, length1 + length2, length3); + return result; + } + + /** + * Answers the concatenation of the two arrays inserting the separator character between the two arrays. + * It answers null if the two arrays are null. + * If the first array is null, then the second array is returned. + * If the second array is null, then the first array is returned. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = { 'a' }
    +	 *    separator = '/'
    +	 *    => result = { ' a' }
    +	 * 
    + *
  2. + *
  3. +	 *    first = { ' a' }
    +	 *    second = null
    +	 *    separator = '/'
    +	 *    => result = { ' a' }
    +	 * 
    + *
  4. + *
  5. +	 *    first = { ' a' }
    +	 *    second = { ' b' }
    +	 *    separator = '/'
    +	 *    => result = { ' a' , '/', 'b' }
    +	 * 
    + *
  6. + *
+ * + * @param first the first array to concatenate + * @param second the second array to concatenate + * @param separator the character to insert + * @return the concatenation of the two arrays inserting the separator character + * between the two arrays , or null if the two arrays are null. + */ + public static final char[] concat( + char[] first, + char[] second, + char separator) { + if (first == null) + return second; + if (second == null) + return first; + + int length1 = first.length; + if (length1 == 0) + return second; + int length2 = second.length; + if (length2 == 0) + return first; + + char[] result = new char[length1 + length2 + 1]; + System.arraycopy(first, 0, result, 0, length1); + result[length1] = separator; + System.arraycopy(second, 0, result, length1 + 1, length2); + return result; + } + + /** + * Answers the concatenation of the three arrays inserting the sep1 character between the + * two arrays and sep2 between the last two. + * It answers null if the three arrays are null. + * If the first array is null, then it answers the concatenation of second and third inserting + * the sep2 character between them. + * If the second array is null, then it answers the concatenation of first and third inserting + * the sep1 character between them. + * If the third array is null, then it answers the concatenation of first and second inserting + * the sep1 character between them. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    sep1 = '/'
    +	 *    second = { 'a' }
    +	 *    sep2 = ':'
    +	 *    third = { 'b' }
    +	 *    => result = { ' a' , ':', 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    first = { 'a' }
    +	 *    sep1 = '/'
    +	 *    second = null
    +	 *    sep2 = ':'
    +	 *    third = { 'b' }
    +	 *    => result = { ' a' , '/', 'b' }
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'a' }
    +	 *    sep1 = '/'
    +	 *    second = { 'b' }
    +	 *    sep2 = ':'
    +	 *    third = null
    +	 *    => result = { ' a' , '/', 'b' }
    +	 * 
    + *
  6. + *
  7. +	 *    first = { 'a' }
    +	 *    sep1 = '/'
    +	 *    second = { 'b' }
    +	 *    sep2 = ':'
    +	 *    third = { 'c' }
    +	 *    => result = { ' a' , '/', 'b' , ':', 'c' }
    +	 * 
    + *
  8. + *
+ * + * @param first the first array to concatenate + * @param sep1 the character to insert + * @param second the second array to concatenate + * @param sep2 the character to insert + * @param third the second array to concatenate + * @return the concatenation of the three arrays inserting the sep1 character between the + * two arrays and sep2 between the last two. + */ + public static final char[] concat( + char[] first, + char sep1, + char[] second, + char sep2, + char[] third) { + if (first == null) + return concat(second, third, sep2); + if (second == null) + return concat(first, third, sep1); + if (third == null) + return concat(first, second, sep1); + + int length1 = first.length; + int length2 = second.length; + int length3 = third.length; + char[] result = new char[length1 + length2 + length3 + 2]; + System.arraycopy(first, 0, result, 0, length1); + result[length1] = sep1; + System.arraycopy(second, 0, result, length1 + 1, length2); + result[length1 + length2 + 1] = sep2; + System.arraycopy(third, 0, result, length1 + length2 + 2, length3); + return result; + } + + /** + * Answers a new array with prepending the prefix character and appending the suffix + * character at the end of the array. If array is null, it answers a new array containing the + * prefix and the suffix characters. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    prefix = 'a'
    +	 *    array = { 'b' }
    +	 *    suffix = 'c'
    +	 *    => result = { 'a', 'b' , 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    prefix = 'a'
    +	 *    array = null
    +	 *    suffix = 'c'
    +	 *    => result = { 'a', 'c' }
    +	 * 
  4. + *
+ * + * @param prefix the prefix character + * @param array the array that is concanated with the prefix and suffix characters + * @param suffix the suffix character + * @return the new array + */ + public static final char[] concat(char prefix, char[] array, char suffix) { + if (array == null) + return new char[] { prefix, suffix }; + + int length = array.length; + char[] result = new char[length + 2]; + result[0] = prefix; + System.arraycopy(array, 0, result, 1, length); + result[length + 1] = suffix; + return result; + } + + /** + * Answers the concatenation of the given array parts using the given separator between each + * part and appending the given name at the end. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    name = { 'c' }
    +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' , '.', 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    name = null
    +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' }
    +	 * 
  4. + *
  5. +	 *    name = { ' c' }
    +	 *    array = null
    +	 *    separator = '.'
    +	 *    => result = { 'c' }
    +	 * 
  6. + *
+ * + * @param name the given name + * @param array the given array + * @param separator the given separator + * @return the concatenation of the given array parts using the given separator between each + * part and appending the given name at the end + */ + public static final char[] concatWith( + char[] name, + char[][] array, + char separator) { + int nameLength = name == null ? 0 : name.length; + if (nameLength == 0) + return concatWith(array, separator); + + int length = array == null ? 0 : array.length; + if (length == 0) + return name; + + int size = nameLength; + int index = length; + while (--index >= 0) + if (array[index].length > 0) + size += array[index].length + 1; + char[] result = new char[size]; + index = size; + for (int i = length - 1; i >= 0; i--) { + int subLength = array[i].length; + if (subLength > 0) { + index -= subLength; + System.arraycopy(array[i], 0, result, index, subLength); + result[--index] = separator; + } + } + System.arraycopy(name, 0, result, 0, nameLength); + return result; + } + + /** + * Answers the concatenation of the given array parts using the given separator between each + * part and appending the given name at the end. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    name = { 'c' }
    +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' , '.', 'c' }
    +	 * 
    + *
  2. + *
  3. +	 *    name = null
    +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' }
    +	 * 
  4. + *
  5. +	 *    name = { ' c' }
    +	 *    array = null
    +	 *    separator = '.'
    +	 *    => result = { 'c' }
    +	 * 
  6. + *
+ * + * @param array the given array + * @param name the given name + * @param separator the given separator + * @return the concatenation of the given array parts using the given separator between each + * part and appending the given name at the end + */ + public static final char[] concatWith( + char[][] array, + char[] name, + char separator) { + int nameLength = name == null ? 0 : name.length; + if (nameLength == 0) + return concatWith(array, separator); + + int length = array == null ? 0 : array.length; + if (length == 0) + return name; + + int size = nameLength; + int index = length; + while (--index >= 0) + if (array[index].length > 0) + size += array[index].length + 1; + char[] result = new char[size]; + index = 0; + for (int i = 0; i < length; i++) { + int subLength = array[i].length; + if (subLength > 0) { + System.arraycopy(array[i], 0, result, index, subLength); + index += subLength; + result[index++] = separator; + } + } + System.arraycopy(name, 0, result, index, nameLength); + return result; + } + + /** + * Answers the concatenation of the given array parts using the given separator between each part. + *
+ *
+ * For example:
+ *
    + *
  1. +	 *    array = { { 'a' }, { 'b' } }
    +	 *    separator = '.'
    +	 *    => result = { 'a', '.', 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = null
    +	 *    separator = '.'
    +	 *    => result = { }
    +	 * 
  4. + *
+ * + * @param array the given array + * @param separator the given separator + * @return the concatenation of the given array parts using the given separator between each part + */ + public static final char[] concatWith(char[][] array, char separator) { + int length = array == null ? 0 : array.length; + if (length == 0) + return CharOperation.NO_CHAR; + + int size = length - 1; + int index = length; + while (--index >= 0) { + if (array[index].length == 0) + size--; + else + size += array[index].length; + } + if (size <= 0) + return CharOperation.NO_CHAR; + char[] result = new char[size]; + index = length; + while (--index >= 0) { + length = array[index].length; + if (length > 0) { + System.arraycopy( + array[index], + 0, + result, + (size -= length), + length); + if (--size >= 0) + result[size] = separator; + } + } + return result; + } + + /** + * Answers true if the array contains an occurrence of character, false otherwise. + * + *
+ *
+ * For example: + *
    + *
  1. +	 *    character = 'c'
    +	 *    array = { { ' a' }, { ' b' } }
    +	 *    result => false
    +	 * 
    + *
  2. + *
  3. +	 *    character = 'a'
    +	 *    array = { { ' a' }, { ' b' } }
    +	 *    result => true
    +	 * 
    + *
  4. + *
+ * + * @param character the character to search + * @param array the array in which the search is done + * @return true if the array contains an occurrence of character, false otherwise. + * @throws NullPointerException if array is null. + */ + public static final boolean contains(char character, char[][] array) { + for (int i = array.length; --i >= 0;) { + char[] subarray = array[i]; + for (int j = subarray.length; --j >= 0;) + if (subarray[j] == character) + return true; + } + return false; + } + + /** + * Answers true if the array contains an occurrence of character, false otherwise. + * + *
+ *
+ * For example: + *
    + *
  1. +	 *    character = 'c'
    +	 *    array = { ' b'  }
    +	 *    result => false
    +	 * 
    + *
  2. + *
  3. +	 *    character = 'a'
    +	 *    array = { ' a' , ' b' }
    +	 *    result => true
    +	 * 
    + *
  4. + *
+ * + * @param character the character to search + * @param array the array in which the search is done + * @return true if the array contains an occurrence of character, false otherwise. + * @throws NullPointerException if array is null. + */ + public static final boolean contains(char character, char[] array) { + for (int i = array.length; --i >= 0;) + if (array[i] == character) + return true; + return false; + } + + /** + * Answers a deep copy of the toCopy array. + * + * @param toCopy the array to copy + * @return a deep copy of the toCopy array. + */ + public static final char[][] deepCopy(char[][] toCopy) { + int toCopyLength = toCopy.length; + char[][] result = new char[toCopyLength][]; + for (int i = 0; i < toCopyLength; i++) { + char[] toElement = toCopy[i]; + int toElementLength = toElement.length; + char[] resultElement = new char[toElementLength]; + System.arraycopy(toElement, 0, resultElement, 0, toElementLength); + result[i] = resultElement; + } + return result; + } + + /** + * Return true if array ends with the sequence of characters contained in toBeFound, + * otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { 'a', 'b', 'c', 'd' }
    +	 *    toBeFound = { 'b', 'c' }
    +	 *    result => false
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a', 'b', 'c' }
    +	 *    toBeFound = { 'b', 'c' }
    +	 *    result => true
    +	 * 
    + *
  4. + *
+ * + * @param array the array to check + * @param toBeFound the array to find + * @return true if array ends with the sequence of characters contained in toBeFound, + * otherwise false. + * @throws NullPointerException if array is null or toBeFound is null + */ + public static final boolean endsWith(char[] array, char[] toBeFound) { + int i = toBeFound.length; + int j = array.length - i; + + if (j < 0) + return false; + while (--i >= 0) + if (toBeFound[i] != array[i + j]) + return false; + return true; + } + + /** + * Answers true if the two arrays are identical character by character, otherwise false. + * The equality is case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { { } }
    +	 *    second = null
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { { 'a' } }
    +	 *    second = { { 'a' } }
    +	 *    result => true
    +	 * 
    + *
  6. + *
  7. +	 *    first = { { 'A' } }
    +	 *    second = { { 'a' } }
    +	 *    result => false
    +	 * 
    + *
  8. + *
+ * @param first the first array + * @param second the second array + * @return true if the two arrays are identical character by character, otherwise false + */ + public static final boolean equals(char[][] first, char[][] second) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (!equals(first[i], second[i])) + return false; + return true; + } + + /** + * If isCaseSensite is true, answers true if the two arrays are identical character + * by character, otherwise false. + * If it is false, answers true if the two arrays are identical character by + * character without checking the case, otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { { } }
    +	 *    second = null
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { { 'A' } }
    +	 *    second = { { 'a' } }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  6. + *
  7. +	 *    first = { { 'A' } }
    +	 *    second = { { 'a' } }
    +	 *    isCaseSensitive = false
    +	 *    result => true
    +	 * 
    + *
  8. + *
+ * + * @param first the first array + * @param second the second array + * @param isCaseSensitive check whether or not the equality should be case sensitive + * @return true if the two arrays are identical character by character according to the value + * of isCaseSensitive, otherwise false + */ + public static final boolean equals( + char[][] first, + char[][] second, + boolean isCaseSensitive) { + + if (isCaseSensitive) { + return equals(first, second); + } + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (!equals(first[i], second[i], false)) + return false; + return true; + } + + /** + * Answers true if the two arrays are identical character by character, otherwise false. + * The equality is case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { }
    +	 *    second = null
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'a' }
    +	 *    second = { 'a' }
    +	 *    result => true
    +	 * 
    + *
  6. + *
  7. +	 *    first = { 'a' }
    +	 *    second = { 'A' }
    +	 *    result => false
    +	 * 
    + *
  8. + *
+ * @param first the first array + * @param second the second array + * @return true if the two arrays are identical character by character, otherwise false + */ + public static final boolean equals(char[] first, char[] second) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (first[i] != second[i]) + return false; + return true; + } + + /** + * Answers true if the first array is identical character by character to a portion of the second array + * delimited from position secondStart (inclusive) to secondEnd(exclusive), otherwise false. + * The equality is case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    secondStart = 0
    +	 *    secondEnd = 0
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { }
    +	 *    second = null
    +	 *    secondStart = 0
    +	 *    secondEnd = 0
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'a' }
    +	 *    second = { 'a' }
    +	 *    secondStart = 0
    +	 *    secondEnd = 1
    +	 *    result => true
    +	 * 
    + *
  6. + *
  7. +	 *    first = { 'a' }
    +	 *    second = { 'A' }
    +	 *    secondStart = 0
    +	 *    secondEnd = 1
    +	 *    result => false
    +	 * 
    + *
  8. + *
+ * @param first the first array + * @param second the second array + * @param secondStart inclusive start position in the second array to compare + * @param secondEnd exclusive end position in the second array to compare + * @return true if the first array is identical character by character to fragment of second array ranging from secondStart to secondEnd-1, otherwise false + * @since 3.0 + */ + public static final boolean equals(char[] first, char[] second, int secondStart, int secondEnd) { + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != secondEnd - secondStart) + return false; + + for (int i = first.length; --i >= 0;) + if (first[i] != second[i+secondStart]) + return false; + return true; + } + + /** + * If isCaseSensite is true, answers true if the two arrays are identical character + * by character, otherwise false. + * If it is false, answers true if the two arrays are identical character by + * character without checking the case, otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    first = null
    +	 *    second = null
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    first = { }
    +	 *    second = null
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    first = { 'A' }
    +	 *    second = { 'a' }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  6. + *
  7. +	 *    first = { 'A' }
    +	 *    second = { 'a' }
    +	 *    isCaseSensitive = false
    +	 *    result => true
    +	 * 
    + *
  8. + *
+ * + * @param first the first array + * @param second the second array + * @param isCaseSensitive check whether or not the equality should be case sensitive + * @return true if the two arrays are identical character by character according to the value + * of isCaseSensitive, otherwise false + */ + public static final boolean equals( + char[] first, + char[] second, + boolean isCaseSensitive) { + + if (isCaseSensitive) { + return equals(first, second); + } + if (first == second) + return true; + if (first == null || second == null) + return false; + if (first.length != second.length) + return false; + + for (int i = first.length; --i >= 0;) + if (Character.toLowerCase(first[i]) + != Character.toLowerCase(second[i])) + return false; + return true; + } + /** + * If isCaseSensite is true, the equality is case sensitive, otherwise it is case insensitive. + * + * Answers true if the name contains the fragment at the starting index startIndex, otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    fragment = { 'b', 'c' , 'd' }
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    startIndex = 1
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    fragment = { 'b', 'c' , 'd' }
    +	 *    name = { 'a', 'b', 'C' , 'd' }
    +	 *    startIndex = 1
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    fragment = { 'b', 'c' , 'd' }
    +	 *    name = { 'a', 'b', 'C' , 'd' }
    +	 *    startIndex = 0
    +	 *    isCaseSensitive = false
    +	 *    result => false
    +	 * 
    + *
  6. + *
  7. +	 *    fragment = { 'b', 'c' , 'd' }
    +	 *    name = { 'a', 'b'}
    +	 *    startIndex = 0
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  8. + *
+ * + * @param fragment the fragment to check + * @param name the array to check + * @param startIndex the starting index + * @param isCaseSensitive check whether or not the equality should be case sensitive + * @return true if the name contains the fragment at the starting index startIndex according to the + * value of isCaseSensitive, otherwise false. + * @throws NullPointerException if fragment or name is null. + */ + public static final boolean fragmentEquals( + char[] fragment, + char[] name, + int startIndex, + boolean isCaseSensitive) { + + int max = fragment.length; + if (name.length < max + startIndex) + return false; + if (isCaseSensitive) { + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (fragment[i] != name[i + startIndex]) + return false; + return true; + } + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (Character.toLowerCase(fragment[i]) + != Character.toLowerCase(name[i + startIndex])) + return false; + return true; + } + + /** + * Answers a hashcode for the array + * + * @param array the array for which a hashcode is required + * @return the hashcode + * @throws NullPointerException if array is null + */ + public static final int hashCode(char[] array) { + int hash = 0; + int offset = 0; + int length = array.length; + if (length < 16) { + for (int i = length; i > 0; i--) + hash = (hash * 37) + array[offset++]; + } else { + // only sample some characters + int skip = length / 8; + for (int i = length; i > 0; i -= skip, offset += skip) + hash = (hash * 39) + array[offset]; + } + return hash & 0x7FFFFFFF; + } + /** + * Answers true if c is a whitespace according to the JLS (\u000a, \u000c, \u000d, \u0009), otherwise false. + *
+ *
+ * For example: + *
    + *
  1. +	 *    c = ' '
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    c = '\u3000'
    +	 *    result => false
    +	 * 
    + *
  4. + *
+ * + * @param c the character to check + * @return true if c is a whitespace according to the JLS, otherwise false. + */ + public static boolean isWhitespace(char c) { + switch (c) { + case 10 : /* \ u000a: LINE FEED */ + case 12 : /* \ u000c: FORM FEED */ + case 13 : /* \ u000d: CARRIAGE RETURN */ + case 32 : /* \ u0020: SPACE */ + case 9 : /* \ u0009: HORIZONTAL TABULATION */ + return true; + default : + return false; + } + } + + /** + * Answers the first index in the array for which the corresponding character is + * equal to toBeFound. Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    result => -1
    +	 * 
    + *
  4. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @return the first index in the array for which the corresponding character is + * equal to toBeFound, -1 otherwise + * @throws NullPointerException if array is null + */ + public static final int indexOf(char toBeFound, char[] array) { + for (int i = 0; i < array.length; i++) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the first index in the array for which the corresponding character is + * equal to toBeFound starting the search at index start. + * Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    start = 2
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    start = 3
    +	 *    result => -1
    +	 * 
    + *
  4. + *
  5. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    start = 1
    +	 *    result => -1
    +	 * 
    + *
  6. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @param start the starting index + * @return the first index in the array for which the corresponding character is + * equal to toBeFound, -1 otherwise + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if start is lower than 0 + */ + public static final int indexOf(char toBeFound, char[] array, int start) { + for (int i = start; i < array.length; i++) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last index in the array for which the corresponding character is + * equal to toBeFound starting from the end of the array. + * Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' , 'c', 'e' }
    +	 *    result => 4
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    result => -1
    +	 * 
    + *
  4. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @return the last index in the array for which the corresponding character is + * equal to toBeFound starting from the end of the array, -1 otherwise + * @throws NullPointerException if array is null + */ + public static final int lastIndexOf(char toBeFound, char[] array) { + for (int i = array.length; --i >= 0;) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last index in the array for which the corresponding character is + * equal to toBeFound stopping at the index startIndex. + * Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    startIndex = 2
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd', 'e' }
    +	 *    startIndex = 3
    +	 *    result => -1
    +	 * 
    + *
  4. + *
  5. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    startIndex = 0
    +	 *    result => -1
    +	 * 
    + *
  6. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @param startIndex the stopping index + * @return the last index in the array for which the corresponding character is + * equal to toBeFound stopping at the index startIndex, -1 otherwise + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if startIndex is lower than 0 + */ + public static final int lastIndexOf( + char toBeFound, + char[] array, + int startIndex) { + for (int i = array.length; --i >= startIndex;) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last index in the array for which the corresponding character is + * equal to toBeFound starting from endIndex to startIndex. + * Answers -1 if no occurrence of this character is found. + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    startIndex = 2
    +	 *    endIndex = 2
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { ' a', 'b', 'c', 'd', 'e' }
    +	 *    startIndex = 3
    +	 *    endIndex = 4
    +	 *    result => -1
    +	 * 
    + *
  4. + *
  5. +	 *    toBeFound = 'e'
    +	 *    array = { ' a', 'b', 'c', 'd' }
    +	 *    startIndex = 0
    +	 *    endIndex = 3
    +	 *    result => -1
    +	 * 
    + *
  6. + *
+ * + * @param toBeFound the character to search + * @param array the array to be searched + * @param startIndex the stopping index + * @param endIndex the starting index + * @return the last index in the array for which the corresponding character is + * equal to toBeFound starting from endIndex to startIndex, -1 otherwise + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if endIndex is greater or equals to array length or starting is lower than 0 + */ + public static final int lastIndexOf( + char toBeFound, + char[] array, + int startIndex, + int endIndex) { + for (int i = endIndex; --i >= startIndex;) + if (toBeFound == array[i]) + return i; + return -1; + } + + /** + * Answers the last portion of a name given a separator. + *
+ *
+ * For example, + *
+	 * 	lastSegment("java.lang.Object".toCharArray(),'.') --> Object
+	 * 
+ * + * @param array the array + * @param separator the given separator + * @return the last portion of a name given a separator + * @throws NullPointerException if array is null + */ + final static public char[] lastSegment(char[] array, char separator) { + int pos = lastIndexOf(separator, array); + if (pos < 0) + return array; + return subarray(array, pos + 1, array.length); + } + + /** + * Answers true if the pattern matches the given name, false otherwise. This char[] pattern matching + * accepts wild-cards '*' and '?'. + * + * When not case sensitive, the pattern is assumed to already be lowercased, the + * name will be lowercased character per character as comparing. + * If name is null, the answer is false. + * If pattern is null, the answer is true if name is not null. + *
+ *
+ * For example: + *
    + *
  1. +	 *    pattern = { '?', 'b', '*' }
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    pattern = { '?', 'b', '?' }
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
  5. +	 *    pattern = { 'b', '*' }
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  6. + *
+ * + * @param pattern the given pattern + * @param name the given name + * @param isCaseSensitive flag to know whether or not the matching should be case sensitive + * @return true if the pattern matches the given name, false otherwise + */ + public static final boolean match( + char[] pattern, + char[] name, + boolean isCaseSensitive) { + + if (name == null) + return false; // null name cannot match + if (pattern == null) + return true; // null pattern is equivalent to '*' + + return match( + pattern, + 0, + pattern.length, + name, + 0, + name.length, + isCaseSensitive); + } + + /** + * Answers true if the a sub-pattern matches the subpart of the given name, false otherwise. + * char[] pattern matching, accepting wild-cards '*' and '?'. Can match only subset of name/pattern. + * end positions are non-inclusive. + * The subpattern is defined by the patternStart and pattternEnd positions. + * When not case sensitive, the pattern is assumed to already be lowercased, the + * name will be lowercased character per character as comparing. + *
+ *
+ * For example: + *
    + *
  1. +	 *    pattern = { '?', 'b', '*' }
    +	 *    patternStart = 1
    +	 *    patternEnd = 3
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    nameStart = 1
    +	 *    nameEnd = 4
    +	 *    isCaseSensitive = true
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    pattern = { '?', 'b', '*' }
    +	 *    patternStart = 1
    +	 *    patternEnd = 2
    +	 *    name = { 'a', 'b', 'c' , 'd' }
    +	 *    nameStart = 1
    +	 *    nameEnd = 2
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
+ * + * @param pattern the given pattern + * @param patternStart the given pattern start + * @param patternEnd the given pattern end + * @param name the given name + * @param nameStart the given name start + * @param nameEnd the given name end + * @param isCaseSensitive flag to know if the matching should be case sensitive + * @return true if the a sub-pattern matches the subpart of the given name, false otherwise + */ + public static final boolean match( + char[] pattern, + int patternStart, + int patternEnd, + char[] name, + int nameStart, + int nameEnd, + boolean isCaseSensitive) { + + if (name == null) + return false; // null name cannot match + if (pattern == null) + return true; // null pattern is equivalent to '*' + int iPattern = patternStart; + int iName = nameStart; + + if (patternEnd < 0) + patternEnd = pattern.length; + if (nameEnd < 0) + nameEnd = name.length; + + /* check first segment */ + char patternChar = 0; + while ((iPattern < patternEnd) + && (patternChar = pattern[iPattern]) != '*') { + if (iName == nameEnd) + return false; + if (patternChar + != (isCaseSensitive + ? name[iName] + : Character.toLowerCase(name[iName])) + && patternChar != '?') { + return false; + } + iName++; + iPattern++; + } + /* check sequence of star+segment */ + int segmentStart; + if (patternChar == '*') { + segmentStart = ++iPattern; // skip star + } else { + segmentStart = 0; // force iName check + } + int prefixStart = iName; + checkSegment : while (iName < nameEnd) { + if (iPattern == patternEnd) { + iPattern = segmentStart; // mismatch - restart current segment + iName = ++prefixStart; + continue checkSegment; + } + /* segment is ending */ + if ((patternChar = pattern[iPattern]) == '*') { + segmentStart = ++iPattern; // skip start + if (segmentStart == patternEnd) { + return true; + } + prefixStart = iName; + continue checkSegment; + } + /* check current name character */ + if ((isCaseSensitive ? name[iName] : Character.toLowerCase(name[iName])) + != patternChar + && patternChar != '?') { + iPattern = segmentStart; // mismatch - restart current segment + iName = ++prefixStart; + continue checkSegment; + } + iName++; + iPattern++; + } + + return (segmentStart == patternEnd) + || (iName == nameEnd && iPattern == patternEnd) + || (iPattern == patternEnd - 1 && pattern[iPattern] == '*'); + } + + /** + * Answers true if the pattern matches the filepath using the pathSepatator, false otherwise. + * + * Path char[] pattern matching, accepting wild-cards '**', '*' and '?' (using Ant directory tasks + * conventions, also see "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes"). + * Path pattern matching is enhancing regular pattern matching in supporting extra rule where '**' represent + * any folder combination. + * Special rule: + * - foo\ is equivalent to foo\** + * When not case sensitive, the pattern is assumed to already be lowercased, the + * name will be lowercased character per character as comparing. + * + * @param pattern the given pattern + * @param filepath the given path + * @param isCaseSensitive to find out whether or not the matching should be case sensitive + * @param pathSeparator the given path separator + * @return true if the pattern matches the filepath using the pathSepatator, false otherwise + */ + public static final boolean pathMatch( + char[] pattern, + char[] filepath, + boolean isCaseSensitive, + char pathSeparator) { + + if (filepath == null) + return false; // null name cannot match + if (pattern == null) + return true; // null pattern is equivalent to '*' + + // offsets inside pattern + int pSegmentStart = pattern[0] == pathSeparator ? 1 : 0; + int pLength = pattern.length; + int pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, pSegmentStart+1); + if (pSegmentEnd < 0) pSegmentEnd = pLength; + + // special case: pattern foo\ is equivalent to foo\** + boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator; + + // offsets inside filepath + int fSegmentStart, fLength = filepath.length; + if (filepath[0] != pathSeparator){ + fSegmentStart = 0; + } else { + fSegmentStart = 1; + } + if (fSegmentStart != pSegmentStart) { + return false; // both must start with a separator or none. + } + int fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, fSegmentStart+1); + if (fSegmentEnd < 0) fSegmentEnd = fLength; + + // first segments + while (pSegmentStart < pLength + && !(pSegmentEnd == pLength && freeTrailingDoubleStar + || (pSegmentEnd == pSegmentStart + 2 + && pattern[pSegmentStart] == '*' + && pattern[pSegmentStart + 1] == '*'))) { + + if (fSegmentStart >= fLength) + return false; + if (!CharOperation + .match( + pattern, + pSegmentStart, + pSegmentEnd, + filepath, + fSegmentStart, + fSegmentEnd, + isCaseSensitive)) { + return false; + } + + // jump to next segment + pSegmentEnd = + CharOperation.indexOf( + pathSeparator, + pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + + fSegmentEnd = + CharOperation.indexOf( + pathSeparator, + filepath, + fSegmentStart = fSegmentEnd + 1); + // skip separator + if (fSegmentEnd < 0) fSegmentEnd = fLength; + } + + /* check sequence of doubleStar+segment */ + int pSegmentRestart; + if ((pSegmentStart >= pLength && freeTrailingDoubleStar) + || (pSegmentEnd == pSegmentStart + 2 + && pattern[pSegmentStart] == '*' + && pattern[pSegmentStart + 1] == '*')) { + pSegmentEnd = + CharOperation.indexOf( + pathSeparator, + pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) pSegmentEnd = pLength; + pSegmentRestart = pSegmentStart; + } else { + if (pSegmentStart >= pLength) return fSegmentStart >= fLength; // true if filepath is done too. + pSegmentRestart = 0; // force fSegmentStart check + } + int fSegmentRestart = fSegmentStart; + checkSegment : while (fSegmentStart < fLength) { + + if (pSegmentStart >= pLength) { + if (freeTrailingDoubleStar) return true; + // mismatch - restart current path segment + pSegmentEnd = + CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart); + if (pSegmentEnd < 0) pSegmentEnd = pLength; + + fSegmentRestart = + CharOperation.indexOf(pathSeparator, filepath, fSegmentRestart + 1); + // skip separator + if (fSegmentRestart < 0) { + fSegmentRestart = fLength; + } else { + fSegmentRestart++; + } + fSegmentEnd = + CharOperation.indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart); + if (fSegmentEnd < 0) fSegmentEnd = fLength; + continue checkSegment; + } + + /* path segment is ending */ + if (pSegmentEnd == pSegmentStart + 2 + && pattern[pSegmentStart] == '*' + && pattern[pSegmentStart + 1] == '*') { + pSegmentEnd = + CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) pSegmentEnd = pLength; + pSegmentRestart = pSegmentStart; + fSegmentRestart = fSegmentStart; + if (pSegmentStart >= pLength) return true; + continue checkSegment; + } + /* chech current path segment */ + if (!CharOperation.match( + pattern, + pSegmentStart, + pSegmentEnd, + filepath, + fSegmentStart, + fSegmentEnd, + isCaseSensitive)) { + // mismatch - restart current path segment + pSegmentEnd = + CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart); + if (pSegmentEnd < 0) pSegmentEnd = pLength; + + fSegmentRestart = + CharOperation.indexOf(pathSeparator, filepath, fSegmentRestart + 1); + // skip separator + if (fSegmentRestart < 0) { + fSegmentRestart = fLength; + } else { + fSegmentRestart++; + } + fSegmentEnd = + CharOperation.indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart); + if (fSegmentEnd < 0) fSegmentEnd = fLength; + continue checkSegment; + } + // jump to next segment + pSegmentEnd = + CharOperation.indexOf( + pathSeparator, + pattern, + pSegmentStart = pSegmentEnd + 1); + // skip separator + if (pSegmentEnd < 0) + pSegmentEnd = pLength; + + fSegmentEnd = + CharOperation.indexOf( + pathSeparator, + filepath, + fSegmentStart = fSegmentEnd + 1); + // skip separator + if (fSegmentEnd < 0) + fSegmentEnd = fLength; + } + + return (pSegmentRestart >= pSegmentEnd) + || (fSegmentStart >= fLength && pSegmentStart >= pLength) + || (pSegmentStart == pLength - 2 + && pattern[pSegmentStart] == '*' + && pattern[pSegmentStart + 1] == '*') + || (pSegmentStart == pLength && freeTrailingDoubleStar); + } + + /** + * Answers the number of occurrences of the given character in the given array, 0 if any. + * + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => 3
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => 0
    +	 * 
    + *
  4. + *
+ * + * @param toBeFound the given character + * @param array the given array + * @return the number of occurrences of the given character in the given array, 0 if any + * @throws NullPointerException if array is null + */ + public static final int occurencesOf(char toBeFound, char[] array) { + int count = 0; + for (int i = 0; i < array.length; i++) + if (toBeFound == array[i]) + count++; + return count; + } + + /** + * Answers the number of occurrences of the given character in the given array starting + * at the given index, 0 if any. + * + *
+ *
+ * For example: + *
    + *
  1. +	 *    toBeFound = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    start = 2
    +	 *    result => 2
    +	 * 
    + *
  2. + *
  3. +	 *    toBeFound = 'c'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    start = 0
    +	 *    result => 0
    +	 * 
    + *
  4. + *
+ * + * @param toBeFound the given character + * @param array the given array + * @param start the given index + * @return the number of occurrences of the given character in the given array, 0 if any + * @throws NullPointerException if array is null + * @throws ArrayIndexOutOfBoundsException if start is lower than 0 + */ + public static final int occurencesOf( + char toBeFound, + char[] array, + int start) { + int count = 0; + for (int i = start; i < array.length; i++) + if (toBeFound == array[i]) + count++; + return count; + } + + /** + * Answers true if the given name starts with the given prefix, false otherwise. + * The comparison is case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    prefix = { 'a' , 'b' }
    +	 *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    prefix = { 'a' , 'c' }
    +	 *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => false
    +	 * 
    + *
  4. + *
+ * + * @param prefix the given prefix + * @param name the given name + * @return true if the given name starts with the given prefix, false otherwise + * @throws NullPointerException if the given name is null or if the given prefix is null + */ + public static final boolean prefixEquals(char[] prefix, char[] name) { + + int max = prefix.length; + if (name.length < max) + return false; + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (prefix[i] != name[i]) + return false; + return true; + } + + /** + * Answers true if the given name starts with the given prefix, false otherwise. + * isCaseSensitive is used to find out whether or not the comparison should be case sensitive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    prefix = { 'a' , 'B' }
    +	 *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    isCaseSensitive = false
    +	 *    result => true
    +	 * 
    + *
  2. + *
  3. +	 *    prefix = { 'a' , 'B' }
    +	 *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    isCaseSensitive = true
    +	 *    result => false
    +	 * 
    + *
  4. + *
+ * + * @param prefix the given prefix + * @param name the given name + * @param isCaseSensitive to find out whether or not the comparison should be case sensitive + * @return true if the given name starts with the given prefix, false otherwise + * @throws NullPointerException if the given name is null or if the given prefix is null + */ + public static final boolean prefixEquals( + char[] prefix, + char[] name, + boolean isCaseSensitive) { + + int max = prefix.length; + if (name.length < max) + return false; + if (isCaseSensitive) { + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (prefix[i] != name[i]) + return false; + return true; + } + + for (int i = max; + --i >= 0; + ) // assumes the prefix is not larger than the name + if (Character.toLowerCase(prefix[i]) + != Character.toLowerCase(name[i])) + return false; + return true; + } + + /** + * Replace all occurrence of the character to be replaced with the remplacement character in the + * given array. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    toBeReplaced = 'b'
    +	 *    replacementChar = 'a'
    +	 *    result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    toBeReplaced = 'c'
    +	 *    replacementChar = 'a'
    +	 *    result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @param toBeReplaced the character to be replaced + * @param replacementChar the replacement character + * @throws NullPointerException if the given array is null + */ + public static final void replace( + char[] array, + char toBeReplaced, + char replacementChar) { + if (toBeReplaced != replacementChar) { + for (int i = 0, max = array.length; i < max; i++) { + if (array[i] == toBeReplaced) + array[i] = replacementChar; + } + } + } + + /** + * Answers a new array of characters with substitutions. No side-effect is operated on the original + * array, in case no substitution happened, then the result is the same as the + * original one. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    toBeReplaced = { 'b' }
    +	 *    replacementChar = { 'a', 'a' }
    +	 *    result => { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    toBeReplaced = { 'c' }
    +	 *    replacementChar = { 'a' }
    +	 *    result => { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @param toBeReplaced characters to be replaced + * @param replacementChars the replacement characters + * @return a new array of characters with substitutions or the given array if none + * @throws NullPointerException if the given array is null + */ + public static final char[] replace( + char[] array, + char[] toBeReplaced, + char[] replacementChars) { + + int max = array.length; + int replacedLength = toBeReplaced.length; + int replacementLength = replacementChars.length; + + int[] starts = new int[5]; + int occurrenceCount = 0; + + if (!equals(toBeReplaced, replacementChars)) { + + next : for (int i = 0; i < max; i++) { + int j = 0; + while (j < replacedLength) { + if (i + j == max) + continue next; + if (array[i + j] != toBeReplaced[j++]) + continue next; + } + if (occurrenceCount == starts.length) { + System.arraycopy( + starts, + 0, + starts = new int[occurrenceCount * 2], + 0, + occurrenceCount); + } + starts[occurrenceCount++] = i; + } + } + if (occurrenceCount == 0) + return array; + char[] result = + new char[max + + occurrenceCount * (replacementLength - replacedLength)]; + int inStart = 0, outStart = 0; + for (int i = 0; i < occurrenceCount; i++) { + int offset = starts[i] - inStart; + System.arraycopy(array, inStart, result, outStart, offset); + inStart += offset; + outStart += offset; + System.arraycopy( + replacementChars, + 0, + result, + outStart, + replacementLength); + inStart += replacedLength; + outStart += replacementLength; + } + System.arraycopy(array, inStart, result, outStart, max - inStart); + return result; + } + + /** + * Return a new array which is the split of the given array using the given divider and triming each subarray to remove + * whitespaces equals to ' '. + *
+ *
+ * For example: + *
    + *
  1. +	 *    divider = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
    +	 * 
    + *
  2. + *
  3. +	 *    divider = 'c'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
    +	 * 
    + *
  4. + *
  5. +	 *    divider = 'b'
    +	 *    array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
    +	 * 
    + *
  6. + *
  7. +	 *    divider = 'c'
    +	 *    array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
    +	 *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
    +	 * 
    + *
  8. + *
+ * + * @param divider the given divider + * @param array the given array + * @return a new array which is the split of the given array using the given divider and triming each subarray to remove + * whitespaces equals to ' ' + */ + public static final char[][] splitAndTrimOn(char divider, char[] array) { + int length = array == null ? 0 : array.length; + if (length == 0) + return NO_CHAR_CHAR; + + int wordCount = 1; + for (int i = 0; i < length; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = 0, currentWord = 0; + for (int i = 0; i < length; i++) { + if (array[i] == divider) { + int start = last, end = i - 1; + while (start < i && array[start] == ' ') + start++; + while (end > start && array[end] == ' ') + end--; + split[currentWord] = new char[end - start + 1]; + System.arraycopy( + array, + start, + split[currentWord++], + 0, + end - start + 1); + last = i + 1; + } + } + int start = last, end = length - 1; + while (start < length && array[start] == ' ') + start++; + while (end > start && array[end] == ' ') + end--; + split[currentWord] = new char[end - start + 1]; + System.arraycopy( + array, + start, + split[currentWord++], + 0, + end - start + 1); + return split; + } + + /** + * Return a new array which is the split of the given array using the given divider. + *
+ *
+ * For example: + *
    + *
  1. +	 *    divider = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
    +	 * 
    + *
  2. + *
  3. +	 *    divider = 'c'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
    +	 * 
    + *
  4. + *
  5. +	 *    divider = 'c'
    +	 *    array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
    +	 *    result => { { ' ', 'a', 'b', 'b', 'a', 'b', 'a', ' ' } }
    +	 * 
    + *
  6. + *
+ * + * @param divider the given divider + * @param array the given array + * @return a new array which is the split of the given array using the given divider + */ + public static final char[][] splitOn(char divider, char[] array) { + int length = array == null ? 0 : array.length; + if (length == 0) + return NO_CHAR_CHAR; + + int wordCount = 1; + for (int i = 0; i < length; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = 0, currentWord = 0; + for (int i = 0; i < length; i++) { + if (array[i] == divider) { + split[currentWord] = new char[i - last]; + System.arraycopy( + array, + last, + split[currentWord++], + 0, + i - last); + last = i + 1; + } + } + split[currentWord] = new char[length - last]; + System.arraycopy(array, last, split[currentWord], 0, length - last); + return split; + } + + /** + * Return a new array which is the split of the given array using the given divider. The given end + * is exclusive and the given start is inclusive. + *
+ *
+ * For example: + *
    + *
  1. +	 *    divider = 'b'
    +	 *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    +	 *    start = 2
    +	 *    end = 5
    +	 *    result => { {  }, { 'a' }, {  } }
    +	 * 
    + *
  2. + *
+ * + * @param divider the given divider + * @param array the given array + * @param start the given starting index + * @param end the given ending index + * @return a new array which is the split of the given array using the given divider + * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length + */ + public static final char[][] splitOn( + char divider, + char[] array, + int start, + int end) { + int length = array == null ? 0 : array.length; + if (length == 0 || start > end) + return NO_CHAR_CHAR; + + int wordCount = 1; + for (int i = start; i < end; i++) + if (array[i] == divider) + wordCount++; + char[][] split = new char[wordCount][]; + int last = start, currentWord = 0; + for (int i = start; i < end; i++) { + if (array[i] == divider) { + split[currentWord] = new char[i - last]; + System.arraycopy( + array, + last, + split[currentWord++], + 0, + i - last); + last = i + 1; + } + } + split[currentWord] = new char[end - last]; + System.arraycopy(array, last, split[currentWord], 0, end - last); + return split; + } + + /** + * Answers a new array which is a copy of the given array starting at the given start and + * ending at the given end. The given start is inclusive and the given end is exclusive. + * Answers null if start is greater than end, if start is lower than 0 or if end is greater + * than the length of the given array. If end equals -1, it is converted to the array length. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { { 'a' } , { 'b' } }
    +	 *    start = 0
    +	 *    end = 1
    +	 *    result => { { 'a' } }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { { 'a' } , { 'b' } }
    +	 *    start = 0
    +	 *    end = -1
    +	 *    result => { { 'a' }, { 'b' } }
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @param start the given starting index + * @param end the given ending index + * @return a new array which is a copy of the given array starting at the given start and + * ending at the given end + * @throws NullPointerException if the given array is null + */ + public static final char[][] subarray(char[][] array, int start, int end) { + if (end == -1) + end = array.length; + if (start > end) + return null; + if (start < 0) + return null; + if (end > array.length) + return null; + + char[][] result = new char[end - start][]; + System.arraycopy(array, start, result, 0, end - start); + return result; + } + + /** + * Answers a new array which is a copy of the given array starting at the given start and + * ending at the given end. The given start is inclusive and the given end is exclusive. + * Answers null if start is greater than end, if start is lower than 0 or if end is greater + * than the length of the given array. If end equals -1, it is converted to the array length. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { 'a' , 'b' }
    +	 *    start = 0
    +	 *    end = 1
    +	 *    result => { 'a' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'a', 'b' }
    +	 *    start = 0
    +	 *    end = -1
    +	 *    result => { 'a' , 'b' }
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @param start the given starting index + * @param end the given ending index + * @return a new array which is a copy of the given array starting at the given start and + * ending at the given end + * @throws NullPointerException if the given array is null + */ + public static final char[] subarray(char[] array, int start, int end) { + if (end == -1) + end = array.length; + if (start > end) + return null; + if (start < 0) + return null; + if (end > array.length) + return null; + + char[] result = new char[end - start]; + System.arraycopy(array, start, result, 0, end - start); + return result; + } + /** + * Answers the result of a char[] conversion to lowercase. Answers null if the given chars array is null. + *
+ * NOTE: If no conversion was necessary, then answers back the argument one. + *
+ *
+ * For example: + *
    + *
  1. +	 *    chars = { 'a' , 'b' }
    +	 *    result => { 'a' , 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'A', 'b' }
    +	 *    result => { 'a' , 'b' }
    +	 * 
    + *
  4. + *
+ * + * @param chars the chars to convert + * @return the result of a char[] conversion to lowercase + */ + final static public char[] toLowerCase(char[] chars) { + if (chars == null) + return null; + int length = chars.length; + char[] lowerChars = null; + for (int i = 0; i < length; i++) { + char c = chars[i]; + char lc = Character.toLowerCase(c); + if ((c != lc) || (lowerChars != null)) { + if (lowerChars == null) { + System.arraycopy( + chars, + 0, + lowerChars = new char[length], + 0, + i); + } + lowerChars[i] = lc; + } + } + return lowerChars == null ? chars : lowerChars; + } + + /** + * Answers a new array removing leading and trailing spaces (' '). Answers the given array if there is no + * space characters to remove. + *
+ *
+ * For example: + *
    + *
  1. +	 *    chars = { ' ', 'a' , 'b', ' ',  ' ' }
    +	 *    result => { 'a' , 'b' }
    +	 * 
    + *
  2. + *
  3. +	 *    array = { 'A', 'b' }
    +	 *    result => { 'A' , 'b' }
    +	 * 
    + *
  4. + *
+ * + * @param chars the given array + * @return a new array removing leading and trailing spaces (' ') + */ + final static public char[] trim(char[] chars) { + + if (chars == null) + return null; + + int start = 0, length = chars.length, end = length - 1; + while (start < length && chars[start] == ' ') { + start++; + } + while (end > start && chars[end] == ' ') { + end--; + } + if (start != 0 || end != length - 1) { + return subarray(chars, start, end + 1); + } + return chars; + } + + /** + * Answers a string which is the concatenation of the given array using the '.' as a separator. + *
+ *
+ * For example: + *
    + *
  1. +	 *    array = { { 'a' } , { 'b' } }
    +	 *    result => "a.b"
    +	 * 
    + *
  2. + *
  3. +	 *    array = { { ' ',  'a' } , { 'b' } }
    +	 *    result => " a.b"
    +	 * 
    + *
  4. + *
+ * + * @param array the given array + * @return a string which is the concatenation of the given array using the '.' as a separator + */ + final static public String toString(char[][] array) { + char[] result = concatWith(array, '.'); + return new String(result); + } + /** + * Answers an array of strings from the given array of char array. + * + * @param array the given array + * @return an array of strings + * @since 3.0 + */ + final static public String[] toStrings(char[][] array) { + int length = array.length; + String[] result = new String[length]; + for (int i = 0; i < length; i++) + result[i] = new String(array[i]); + return result; + } +}