Add support for creating a Xaraya module
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / util / CharOperation.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.util;
12
13 import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
14
15 public final class CharOperation {
16         
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);
21         array[length]=suffix;
22         return array;
23 }       
24
25 public static final char[][] arrayConcat(char[][] first, char[][] second) {
26         if (first == null)
27                 return second;
28         if (second == null)
29                 return first;
30
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
35         int i;
36         for (i = 0; i < length1; i++)
37                 result[i] = first[i];
38         for (int j = 0; j < length2; j++)
39                 result[i++] = second[j];
40 */
41         System.arraycopy(first, 0, result, 0, length1);
42         System.arraycopy(second, 0, result, length1, length2);
43         return result;
44 }
45 public static final char[][] arrayConcat(char[][] first, char[] second) {
46         if (second == null)
47                 return first;
48         if (first == null)
49                 return new char[][] {second};
50
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++)
55                 result[i] = first[i];
56 */
57         System.arraycopy(first, 0, result, 0, length);
58         result[length] = second;
59         return result;
60 }
61 public static final char[] concat(char[] first, char[] second) {
62         if (first == null)
63                 return second;
64         if (second == null)
65                 return first;
66
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);
72         return result;
73 }
74 public static final char[] concat(char[] first, char[] second, char[] third) {
75         if (first == null)
76                 return concat(second, third);
77         if (second == null)
78                 return concat(first, third);
79         if (third == null)
80                 return concat(first, second);
81
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);
89         return result;
90 }
91 public static final char[] concat(char[] first, char[] second, char separator) {
92         if (first == null)
93                 return second;
94         if (second == null)
95                 return first;
96
97         int length1 = first.length;
98         if (length1 == 0)
99                 return second;
100         int length2 = second.length;
101         if (length2 == 0)
102                 return first;
103
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);
108         return result;
109 }
110 public static final char[] concat(char[] first, char sep1, char[] second, char sep2, char[] third) {
111         if (first == null)
112                 return concat(second, third, sep2);
113         if (second == null)
114                 return concat(first, third, sep1);
115         if (third == null)
116                 return concat(first, second, sep1);
117
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);
127         return result;
128 }
129 public static final char[] concat(char prefix, char[] array, char suffix) {
130         if (array == null)
131                 return new char[] {prefix, suffix};
132
133         int length = array.length;
134         char[] result = new char[length + 2];
135         result[0] = prefix;
136         System.arraycopy(array, 0, result, 1, length);
137         result[length + 1] = suffix;
138         return result;
139 }
140 public static final char[] concatWith(char[] name, char[][] array, char separator) {
141         int nameLength = name == null ? 0 : name.length;
142         if (nameLength == 0)
143                 return concatWith(array, separator);
144
145         int length = array == null ? 0 : array.length;
146         if (length == 0)
147                 return name;
148
149         int size = nameLength;
150         int index = length;
151         while (--index >= 0)
152                 if (array[index].length > 0)
153                         size += array[index].length + 1;
154         char[] result = new char[size];
155         index = size;
156         for (int i = length-1; i >= 0; i--) {
157                 int subLength = array[i].length;
158                 if (subLength > 0) {
159                         index -= subLength;
160                         System.arraycopy(array[i], 0, result, index, subLength);
161                         result[--index] = separator;
162                 }
163         }
164         System.arraycopy(name, 0, result, 0, nameLength);
165         return result;
166 }
167 public static final char[] concatWith(char[][] array, char[] name, char separator) {
168         int nameLength = name == null ? 0 : name.length;
169         if (nameLength == 0)
170                 return concatWith(array, separator);
171
172         int length = array == null ? 0 : array.length;
173         if (length == 0)
174                 return name;
175
176         int size = nameLength;
177         int index = length;
178         while (--index >= 0)
179                 if (array[index].length > 0)
180                         size += array[index].length + 1;
181         char[] result = new char[size];
182         index = 0;
183         for (int i = 0; i < length; i++) {
184                 int subLength = array[i].length;
185                 if (subLength > 0) {
186                         System.arraycopy(array[i], 0, result, index, subLength);
187                         index += subLength;
188                         result[index++] = separator;
189                 }
190         }
191         System.arraycopy(name, 0, result, index, nameLength);
192         return result;
193 }
194 public static final char[] concatWith(char[][] array, char separator) {
195         int length = array == null ? 0 : array.length;
196         if (length == 0)
197                 return TypeConstants.NoChar;
198
199         int size = length - 1;
200         int index = length;
201         while (--index >= 0) {
202                 if (array[index].length == 0)
203                         size--;
204                 else
205                         size += array[index].length;
206         }
207         if (size <= 0)
208                 return TypeConstants.NoChar;
209         char[] result = new char[size];
210         index = length;
211         while (--index >= 0) {
212                 length = array[index].length;
213                 if (length > 0) {
214                         System.arraycopy(array[index], 0, result, (size -= length), length);
215                         if (--size >= 0)
216                                 result[size] = separator;
217                 }
218         }
219         return result;
220 }
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)
226                                 return true;
227         }
228         return false;
229 }
230 public static final boolean contains(char character, char[] array) {
231         for (int i = array.length; --i >= 0;)
232                 if (array[i] == character)
233                         return true;
234         return false;
235 }
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;
245         }
246         return result;
247 }
248
249 public static final boolean endsWith(char[] array, char[] toBeFound) {
250         int i = toBeFound.length;
251         int j = array.length - i;
252         
253         if (j < 0)
254                 return false;
255         while (--i >= 0)
256                 if (toBeFound[i] != array[i + j])
257                         return false;
258         return true;
259 }
260
261 public static final boolean equals(char[][] first, char[][] second) {
262         if (first == second)
263                 return true;
264         if (first == null || second == null)
265                 return false;
266         if (first.length != second.length)
267                 return false;
268
269         for (int i = first.length; --i >= 0;)
270                 if (!equals(first[i], second[i]))
271                         return false;
272         return true;
273 }
274 public static final boolean equals(char[][] first, char[][] second, boolean isCaseSensitive) {
275
276         if (isCaseSensitive){
277                 return equals(first, second);
278         }
279         if (first == second)
280                 return true;
281         if (first == null || second == null)
282                 return false;
283         if (first.length != second.length)
284                 return false;
285
286         for (int i = first.length; --i >= 0;)
287                 if (!equals(first[i], second[i], false))
288                         return false;
289         return true;
290 }
291 public static final boolean equals(char[] first, char[] second) {
292         if (first == second)
293                 return true;
294         if (first == null || second == null)
295                 return false;
296         if (first.length != second.length)
297                 return false;
298
299         for (int i = first.length; --i >= 0;)
300                 if (first[i] != second[i])
301                         return false;
302         return true;
303 }
304 public static final boolean equals(char[] first, char[] second, boolean isCaseSensitive) {
305
306         if (isCaseSensitive){
307                 return equals(first, second);
308         }
309         if (first == second)
310                 return true;
311         if (first == null || second == null)
312                 return false;
313         if (first.length != second.length)
314                 return false;
315
316         for (int i = first.length; --i >= 0;)
317                 if (Character.toLowerCase(first[i]) != Character.toLowerCase(second[i]))
318                         return false;
319         return true;
320 }
321 public static final boolean fragmentEquals(char[] fragment, char[] name, int startIndex, boolean isCaseSensitive) {
322
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])
328                                 return false;
329                 return true;
330         }
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]))
333                         return false;
334         return true;
335 }
336 public static final int hashCode(char[] array) {
337         int hash = 0;
338         int offset = 0;
339         int length = array.length;
340         if (length < 16) {
341                 for (int i = length; i > 0; i--)
342                         hash = (hash * 37) + array[offset++];
343         } else {
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];
348         }
349         return hash & 0x7FFFFFFF;
350 }
351 public static final int indexOf(char toBeFound, char[] array) {
352         for (int i = 0; i < array.length; i++)
353                 if (toBeFound == array[i])
354                         return i;
355         return -1;
356 }
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])
360                         return i;
361         return -1;
362 }
363 public static final int lastIndexOf(char toBeFound, char[] array) {
364         for (int i = array.length; --i >= 0;)
365                 if (toBeFound == array[i])
366                         return i;
367         return -1;
368 }
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])
372                         return i;
373         return -1;
374 }
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])
378                         return i;
379         return -1;
380 }
381 /**
382  * Answer the last portion of a name given a separator
383  * e.g. lastSegment("java.lang.Object".toCharArray(),'.') --> Object
384  */
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);
389 }
390 /**
391  * char[] pattern matching, accepting wild-cards '*'.
392  *
393  * When not case sensitive, the pattern is assumed to already be lowercased, the
394  * name will be lowercased character per character as comparing.
395  */
396 public static final boolean match(char[] pattern, char[] name, boolean isCaseSensitive) {
397
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;
402
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 
408                                                                 ? name[iName] 
409                                                                 : Character.toLowerCase(name[iName]))){
410                         return false;
411                 }
412                 iName++;
413                 iPattern++;
414         }
415         /* check sequence of star+segment */
416         int segmentStart;
417         if (patternChar == '*'){
418                 segmentStart = ++iPattern; // skip star
419         } else {
420                 segmentStart = 0; // force iName check
421         }
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
427                         prefixStart = iName;
428                         continue checkSegment;
429                 }
430                 /* chech current name character */
431                 if ((isCaseSensitive 
432                                 ? name[iName] 
433                                 : Character.toLowerCase(name[iName]))!= patternChar){
434                         iPattern = segmentStart; // mismatch - restart current segment
435                         iName = ++prefixStart;
436                         continue checkSegment;
437                 }
438                 iName++;
439                 iPattern++;
440         }
441
442         return (segmentStart == patternLength)
443                         || (iName == nameLength && iPattern == patternLength)   
444                         || (iPattern == patternLength - 1 && pattern[iPattern] == '*'); 
445 }
446 public static final int occurencesOf(char toBeFound, char[] array) {
447         int count = 0;
448         for (int i = 0; i < array.length; i++)
449                 if (toBeFound == array[i]) count++;
450         return count;
451 }
452 public static final int occurencesOf(char toBeFound, char[] array, int start) {
453         int count = 0;
454         for (int i = start; i < array.length; i++)
455                 if (toBeFound == array[i]) count++;
456         return count;
457 }
458 public static final boolean prefixEquals(char[] prefix, char[] name) {
459
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])
464                         return false;
465         return true;
466 }
467 public static final boolean prefixEquals(char[] prefix, char[] name, boolean isCaseSensitive) {
468
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])
474                                 return false;
475                 return true;
476         }
477         
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]))
480                         return false;
481         return true;
482 }
483 public static final void replace(
484         char[] array, 
485         char toBeReplaced, 
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;
491                 }
492         }
493 }
494
495 /*
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
498  * original one.
499  * 
500  */
501 public static final char[] replace(
502         char[] array, 
503         char[] toBeReplaced, 
504         char[] replacementChars) {
505
506
507         int max = array.length;
508         int replacedLength = toBeReplaced.length;
509         int replacementLength = replacementChars.length;
510
511         int[] starts = new int[5];
512         int occurrenceCount = 0;
513         
514         if (!equals(toBeReplaced,replacementChars)) {
515                 
516                 next: for (int i = 0; i < max; i++) {
517                         int j = 0;
518                         while (j < replacedLength){
519                                 if (i+j == max) continue next;
520                                 if (array[i + j] != toBeReplaced[j++]) continue next;
521                         }
522                         if (occurrenceCount == starts.length){
523                                 System.arraycopy(starts, 0, starts = new int[occurrenceCount * 2], 0, occurrenceCount);
524                         }
525                         starts[occurrenceCount++] = i;
526                 }
527         }
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);
534                 inStart += offset;
535                 outStart += offset;
536                 System.arraycopy(replacementChars, 0, result, outStart, replacementLength);
537                 inStart += replacedLength;
538                 outStart += replacementLength;
539         }
540         System.arraycopy(array, inStart, result, outStart, max - inStart);
541         return result;
542 }
543
544 public static final char[][] splitAndTrimOn(char divider, char[] array) {
545         int length = array == null ? 0 : array.length;
546         if (length == 0)
547                 return TypeConstants.NoCharChar;
548
549         int wordCount = 1;
550         for (int i = 0; i < length; i++)
551                 if (array[i] == divider)
552                         wordCount++;
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);
562                         last = i + 1;
563                 }
564         }
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);
570         return split;
571 }
572
573 public static final char[][] splitOn(char divider, char[] array) {
574         int length = array == null ? 0 : array.length;
575         if (length == 0)
576                 return TypeConstants.NoCharChar;
577
578         int wordCount = 1;
579         for (int i = 0; i < length; i++)
580                 if (array[i] == divider)
581                         wordCount++;
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);
588                         last = i + 1;
589                 }
590         }
591         split[currentWord] = new char[length - last];
592         System.arraycopy(array, last, split[currentWord], 0, length - last);
593         return split;
594 }
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;
599
600         int wordCount = 1;
601         for (int i = start; i < end; i++)
602                 if (array[i] == divider)
603                         wordCount++;
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);
610                         last = i + 1;
611                 }
612         }
613         split[currentWord] = new char[end - last + 1];
614         System.arraycopy(array, last, split[currentWord], 0, end - last + 1);
615         return split;
616 }
617 public static final boolean startsWith(char[] array, char[] toBeFound) {
618         int i = toBeFound.length;
619         if (i > array.length)
620                 return false;
621         while (--i >= 0)
622                 if (toBeFound[i] != array[i])
623                         return false;
624         return true;
625 }
626 /*
627  * copies from array[start] through array[end - 1] (does not copy array[end])
628  */
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;
634
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];
639 */
640         System.arraycopy(array, start, result, 0, end - start);
641         return result;
642 }
643 /*
644  * copies from array[start] through array[end - 1] (does not copy array[end])
645  */
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;
651
652         char[] result = new char[end - start];
653         System.arraycopy(array, start, result, 0, end - start);
654         return result;
655 }
656 /**
657  *      Answers the result of a char[] conversion to lowercase.
658  *      NOTE: if no conversion was necessary, then answers back the argument one.
659  */
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++){
665                 char c = chars[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);
670                         }
671                         lowerChars[i] = lc;
672                 }
673         }
674         return lowerChars == null ? chars : lowerChars;
675 }
676
677 /**
678  * Remove leading and trailing spaces
679  */
680 final static public char[] trim(char[] chars){
681         
682         if (chars == null) return null;
683         
684         char[] result = chars;
685         int start = 0, length = chars.length, end = length - 1;
686         while (start < length && chars[start] == ' ') {
687                 start++;
688         }
689         while (end > start && chars[end] == ' '){
690                 end--;
691         }
692         if (start != 0 || end != length - 1){
693                 return subarray(chars, start, end+1);
694         }
695         return chars;
696 }
697 final static public String toString(char[][] array) {
698         char[] result = concatWith(array, '.');
699         if (result == null)
700                 return ""; //$NON-NLS-1$
701         return new String(result);
702 }
703 }