1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.util;
13 import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
15 public final class CharOperation {
17 public static final char[] append(char[] array, char suffix){
18 if (array == null) return new char[]{suffix};
19 int length = array.length;
20 System.arraycopy(array, 0, array = new char[length+1], 0, length);
25 public static final char[][] arrayConcat(char[][] first, char[][] second) {
31 int length1 = first.length;
32 int length2 = second.length;
33 char[][] result = new char[length1 + length2][];
34 /* if we do not trust System.arraycopy on our VM with char[][]'s
36 for (i = 0; i < length1; i++)
38 for (int j = 0; j < length2; j++)
39 result[i++] = second[j];
41 System.arraycopy(first, 0, result, 0, length1);
42 System.arraycopy(second, 0, result, length1, length2);
45 public static final char[][] arrayConcat(char[][] first, char[] second) {
49 return new char[][] {second};
51 int length = first.length;
52 char[][] result = new char[length + 1][];
53 /* if we do not trust System.arraycopy on our VM with char[][]'s
54 for (int i = 0; i < length; i++)
57 System.arraycopy(first, 0, result, 0, length);
58 result[length] = second;
61 public static final char[] concat(char[] first, char[] second) {
67 int length1 = first.length;
68 int length2 = second.length;
69 char[] result = new char[length1 + length2];
70 System.arraycopy(first, 0, result, 0, length1);
71 System.arraycopy(second, 0, result, length1, length2);
74 public static final char[] concat(char[] first, char[] second, char[] third) {
76 return concat(second, third);
78 return concat(first, third);
80 return concat(first, second);
82 int length1 = first.length;
83 int length2 = second.length;
84 int length3 = third.length;
85 char[] result = new char[length1 + length2 + length3];
86 System.arraycopy(first, 0, result, 0, length1);
87 System.arraycopy(second, 0, result, length1, length2);
88 System.arraycopy(third, 0, result, length1 + length2, length3);
91 public static final char[] concat(char[] first, char[] second, char separator) {
97 int length1 = first.length;
100 int length2 = second.length;
104 char[] result = new char[length1 + length2 + 1];
105 System.arraycopy(first, 0, result, 0, length1);
106 result[length1] = separator;
107 System.arraycopy(second, 0, result, length1 + 1, length2);
110 public static final char[] concat(char[] first, char sep1, char[] second, char sep2, char[] third) {
112 return concat(second, third, sep2);
114 return concat(first, third, sep1);
116 return concat(first, second, sep1);
118 int length1 = first.length;
119 int length2 = second.length;
120 int length3 = third.length;
121 char[] result = new char[length1 + length2 + length3 + 2];
122 System.arraycopy(first, 0, result, 0, length1);
123 result[length1] = sep1;
124 System.arraycopy(second, 0, result, length1 + 1, length2);
125 result[length1+length2+1] = sep2;
126 System.arraycopy(third, 0, result, length1 + length2 + 2, length3);
129 public static final char[] concat(char prefix, char[] array, char suffix) {
131 return new char[] {prefix, suffix};
133 int length = array.length;
134 char[] result = new char[length + 2];
136 System.arraycopy(array, 0, result, 1, length);
137 result[length + 1] = suffix;
140 public static final char[] concatWith(char[] name, char[][] array, char separator) {
141 int nameLength = name == null ? 0 : name.length;
143 return concatWith(array, separator);
145 int length = array == null ? 0 : array.length;
149 int size = nameLength;
152 if (array[index].length > 0)
153 size += array[index].length + 1;
154 char[] result = new char[size];
156 for (int i = length-1; i >= 0; i--) {
157 int subLength = array[i].length;
160 System.arraycopy(array[i], 0, result, index, subLength);
161 result[--index] = separator;
164 System.arraycopy(name, 0, result, 0, nameLength);
167 public static final char[] concatWith(char[][] array, char[] name, char separator) {
168 int nameLength = name == null ? 0 : name.length;
170 return concatWith(array, separator);
172 int length = array == null ? 0 : array.length;
176 int size = nameLength;
179 if (array[index].length > 0)
180 size += array[index].length + 1;
181 char[] result = new char[size];
183 for (int i = 0; i < length; i++) {
184 int subLength = array[i].length;
186 System.arraycopy(array[i], 0, result, index, subLength);
188 result[index++] = separator;
191 System.arraycopy(name, 0, result, index, nameLength);
194 public static final char[] concatWith(char[][] array, char separator) {
195 int length = array == null ? 0 : array.length;
197 return TypeConstants.NoChar;
199 int size = length - 1;
201 while (--index >= 0) {
202 if (array[index].length == 0)
205 size += array[index].length;
208 return TypeConstants.NoChar;
209 char[] result = new char[size];
211 while (--index >= 0) {
212 length = array[index].length;
214 System.arraycopy(array[index], 0, result, (size -= length), length);
216 result[size] = separator;
221 public static final boolean contains(char character, char[][] array) {
222 for (int i = array.length; --i >= 0;) {
223 char[] subarray = array[i];
224 for (int j = subarray.length; --j >= 0;)
225 if (subarray[j] == character)
230 public static final boolean contains(char character, char[] array) {
231 for (int i = array.length; --i >= 0;)
232 if (array[i] == character)
236 public static final char[][] deepCopy(char[][] toCopy) {
237 int toCopyLength = toCopy.length;
238 char[][] result = new char[toCopyLength][];
239 for (int i = 0; i < toCopyLength; i++) {
240 char[] toElement = toCopy[i];
241 int toElementLength = toElement.length;
242 char[] resultElement = new char[toElementLength];
243 System.arraycopy(toElement, 0, resultElement, 0, toElementLength);
244 result[i] = resultElement;
249 public static final boolean endsWith(char[] array, char[] toBeFound) {
250 int i = toBeFound.length;
251 int j = array.length - i;
256 if (toBeFound[i] != array[i + j])
261 public static final boolean equals(char[][] first, char[][] second) {
264 if (first == null || second == null)
266 if (first.length != second.length)
269 for (int i = first.length; --i >= 0;)
270 if (!equals(first[i], second[i]))
274 public static final boolean equals(char[][] first, char[][] second, boolean isCaseSensitive) {
276 if (isCaseSensitive){
277 return equals(first, second);
281 if (first == null || second == null)
283 if (first.length != second.length)
286 for (int i = first.length; --i >= 0;)
287 if (!equals(first[i], second[i], false))
291 public static final boolean equals(char[] first, char[] second) {
294 if (first == null || second == null)
296 if (first.length != second.length)
299 for (int i = first.length; --i >= 0;)
300 if (first[i] != second[i])
304 public static final boolean equals(char[] first, char[] second, boolean isCaseSensitive) {
306 if (isCaseSensitive){
307 return equals(first, second);
311 if (first == null || second == null)
313 if (first.length != second.length)
316 for (int i = first.length; --i >= 0;)
317 if (Character.toLowerCase(first[i]) != Character.toLowerCase(second[i]))
321 public static final boolean fragmentEquals(char[] fragment, char[] name, int startIndex, boolean isCaseSensitive) {
323 int max = fragment.length;
324 if (name.length < max+startIndex) return false;
325 if (isCaseSensitive){
326 for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
327 if (fragment[i] != name[i + startIndex])
331 for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
332 if (Character.toLowerCase(fragment[i]) != Character.toLowerCase(name[i + startIndex]))
336 public static final int hashCode(char[] array) {
339 int length = array.length;
341 for (int i = length; i > 0; i--)
342 hash = (hash * 37) + array[offset++];
344 // only sample some characters
345 int skip = length / 8;
346 for (int i = length; i > 0; i -= skip, offset += skip)
347 hash = (hash * 39) + array[offset];
349 return hash & 0x7FFFFFFF;
351 public static final int indexOf(char toBeFound, char[] array) {
352 for (int i = 0; i < array.length; i++)
353 if (toBeFound == array[i])
357 public static final int indexOf(char toBeFound, char[] array, int start) {
358 for (int i = start; i < array.length; i++)
359 if (toBeFound == array[i])
363 public static final int lastIndexOf(char toBeFound, char[] array) {
364 for (int i = array.length; --i >= 0;)
365 if (toBeFound == array[i])
369 public static final int lastIndexOf(char toBeFound, char[] array, int startIndex) {
370 for (int i = array.length; --i >= startIndex;)
371 if (toBeFound == array[i])
375 public static final int lastIndexOf(char toBeFound, char[] array, int startIndex, int endIndex) {
376 for (int i = endIndex; --i >= startIndex;)
377 if (toBeFound == array[i])
382 * Answer the last portion of a name given a separator
383 * e.g. lastSegment("java.lang.Object".toCharArray(),'.') --> Object
385 final static public char[] lastSegment(char[] array, char separator) {
386 int pos = lastIndexOf(separator, array);
387 if (pos < 0) return array;
388 return subarray(array, pos+1, array.length);
391 * char[] pattern matching, accepting wild-cards '*'.
393 * When not case sensitive, the pattern is assumed to already be lowercased, the
394 * name will be lowercased character per character as comparing.
396 public static final boolean match(char[] pattern, char[] name, boolean isCaseSensitive) {
398 if (name == null) return false; // null name cannot match
399 if (pattern == null) return true; // null pattern is equivalent to '*'
400 int iPattern = 0, patternLength = pattern.length;
401 int iName = 0, nameLength = name.length;
403 /* check first segment */
404 char patternChar = 0;
405 while ((iPattern < patternLength) && (patternChar = pattern[iPattern]) != '*'){
406 if (iName == nameLength) return false;
407 if (patternChar != (isCaseSensitive
409 : Character.toLowerCase(name[iName]))){
415 /* check sequence of star+segment */
417 if (patternChar == '*'){
418 segmentStart = ++iPattern; // skip star
420 segmentStart = 0; // force iName check
422 int prefixStart = iName;
423 checkSegment: while (iName < nameLength && iPattern < patternLength){
424 /* segment is ending */
425 if ((patternChar = pattern[iPattern]) == '*'){
426 segmentStart = ++iPattern; // skip start
428 continue checkSegment;
430 /* chech current name character */
433 : Character.toLowerCase(name[iName]))!= patternChar){
434 iPattern = segmentStart; // mismatch - restart current segment
435 iName = ++prefixStart;
436 continue checkSegment;
442 return (segmentStart == patternLength)
443 || (iName == nameLength && iPattern == patternLength)
444 || (iPattern == patternLength - 1 && pattern[iPattern] == '*');
446 public static final int occurencesOf(char toBeFound, char[] array) {
448 for (int i = 0; i < array.length; i++)
449 if (toBeFound == array[i]) count++;
452 public static final int occurencesOf(char toBeFound, char[] array, int start) {
454 for (int i = start; i < array.length; i++)
455 if (toBeFound == array[i]) count++;
458 public static final boolean prefixEquals(char[] prefix, char[] name) {
460 int max = prefix.length;
461 if (name.length < max) return false;
462 for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
463 if (prefix[i] != name[i])
467 public static final boolean prefixEquals(char[] prefix, char[] name, boolean isCaseSensitive) {
469 int max = prefix.length;
470 if (name.length < max) return false;
471 if (isCaseSensitive){
472 for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
473 if (prefix[i] != name[i])
478 for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name
479 if (Character.toLowerCase(prefix[i]) != Character.toLowerCase(name[i]))
483 public static final void replace(
486 char replacementChar) {
487 if (toBeReplaced != replacementChar) {
488 for (int i = 0, max = array.length; i < max; i++) {
489 if (array[i] == toBeReplaced)
490 array[i] = replacementChar;
496 * Returns a char[] with substitutions. No side-effect is operated on the original
497 * array, in case no substitution happened, then the result might be the same as the
501 public static final char[] replace(
504 char[] replacementChars) {
507 int max = array.length;
508 int replacedLength = toBeReplaced.length;
509 int replacementLength = replacementChars.length;
511 int[] starts = new int[5];
512 int occurrenceCount = 0;
514 if (!equals(toBeReplaced,replacementChars)) {
516 next: for (int i = 0; i < max; i++) {
518 while (j < replacedLength){
519 if (i+j == max) continue next;
520 if (array[i + j] != toBeReplaced[j++]) continue next;
522 if (occurrenceCount == starts.length){
523 System.arraycopy(starts, 0, starts = new int[occurrenceCount * 2], 0, occurrenceCount);
525 starts[occurrenceCount++] = i;
528 if (occurrenceCount == 0) return array;
529 char[] result = new char[max + occurrenceCount * (replacementLength - replacedLength)];
530 int inStart = 0, outStart = 0;
531 for( int i = 0; i < occurrenceCount; i++){
532 int offset = starts[i] - inStart;
533 System.arraycopy(array, inStart, result, outStart, offset);
536 System.arraycopy(replacementChars, 0, result, outStart, replacementLength);
537 inStart += replacedLength;
538 outStart += replacementLength;
540 System.arraycopy(array, inStart, result, outStart, max - inStart);
544 public static final char[][] splitAndTrimOn(char divider, char[] array) {
545 int length = array == null ? 0 : array.length;
547 return TypeConstants.NoCharChar;
550 for (int i = 0; i < length; i++)
551 if (array[i] == divider)
553 char[][] split = new char[wordCount][];
554 int last = 0, currentWord = 0;
555 for (int i = 0; i < length; i++) {
556 if (array[i] == divider) {
557 int start = last, end = i - 1;
558 while (start < i && array[start] == ' ') start++;
559 while (end > start && array[end] == ' ') end--;
560 split[currentWord] = new char[end - start + 1];
561 System.arraycopy(array, start, split[currentWord++], 0, end - start + 1);
565 int start = last, end = length - 1;
566 while (start < length && array[start] == ' ') start++;
567 while (end > start && array[end] == ' ') end--;
568 split[currentWord] = new char[end - start + 1];
569 System.arraycopy(array, start, split[currentWord++], 0, end - start + 1);
573 public static final char[][] splitOn(char divider, char[] array) {
574 int length = array == null ? 0 : array.length;
576 return TypeConstants.NoCharChar;
579 for (int i = 0; i < length; i++)
580 if (array[i] == divider)
582 char[][] split = new char[wordCount][];
583 int last = 0, currentWord = 0;
584 for (int i = 0; i < length; i++) {
585 if (array[i] == divider) {
586 split[currentWord] = new char[i - last];
587 System.arraycopy(array, last, split[currentWord++], 0, i - last);
591 split[currentWord] = new char[length - last];
592 System.arraycopy(array, last, split[currentWord], 0, length - last);
595 public static final char[][] splitOn(char divider, char[] array, int start, int end) {
596 int length = array == null ? 0 : array.length;
597 if (length == 0 || start > end)
598 return TypeConstants.NoCharChar;
601 for (int i = start; i < end; i++)
602 if (array[i] == divider)
604 char[][] split = new char[wordCount][];
605 int last = start, currentWord = 0;
606 for (int i = start; i < end; i++) {
607 if (array[i] == divider) {
608 split[currentWord] = new char[i - last];
609 System.arraycopy(array, last, split[currentWord++], 0, i - last);
613 split[currentWord] = new char[end - last + 1];
614 System.arraycopy(array, last, split[currentWord], 0, end - last + 1);
617 public static final boolean startsWith(char[] array, char[] toBeFound) {
618 int i = toBeFound.length;
619 if (i > array.length)
622 if (toBeFound[i] != array[i])
627 * copies from array[start] through array[end - 1] (does not copy array[end])
629 public static final char[][] subarray(char[][] array, int start, int end) {
630 if (end == -1) end = array.length;
631 if (start > end) return null;
632 if (start < 0) return null;
633 if (end > array.length) return null;
635 char[][] result = new char[end - start][];
636 /* if we do not trust System.arraycopy on our VM with char[][]'s
637 for (int i = 0, s = start; s < end; i++, s++)
638 result[i] = array[s];
640 System.arraycopy(array, start, result, 0, end - start);
644 * copies from array[start] through array[end - 1] (does not copy array[end])
646 public static final char[] subarray(char[] array, int start, int end) {
647 if (end == -1) end = array.length;
648 if (start > end) return null;
649 if (start < 0) return null;
650 if (end > array.length) return null;
652 char[] result = new char[end - start];
653 System.arraycopy(array, start, result, 0, end - start);
657 * Answers the result of a char[] conversion to lowercase.
658 * NOTE: if no conversion was necessary, then answers back the argument one.
660 final static public char[] toLowerCase(char[] chars) {
661 if (chars == null) return null;
662 int length = chars.length;
663 char[] lowerChars = null;
664 for (int i = 0; i < length; i++){
666 char lc = Character.toLowerCase(c);
667 if ((c != lc) || (lowerChars != null)){
668 if (lowerChars == null){
669 System.arraycopy(chars, 0, lowerChars = new char[length], 0, i);
674 return lowerChars == null ? chars : lowerChars;
678 * Remove leading and trailing spaces
680 final static public char[] trim(char[] chars){
682 if (chars == null) return null;
684 char[] result = chars;
685 int start = 0, length = chars.length, end = length - 1;
686 while (start < length && chars[start] == ' ') {
689 while (end > start && chars[end] == ' '){
692 if (start != 0 || end != length - 1){
693 return subarray(chars, start, end+1);
697 final static public String toString(char[][] array) {
698 char[] result = concatWith(array, '.');
700 return ""; //$NON-NLS-1$
701 return new String(result);