001 
002 /*
003  *  JScripter Emulation 1.0 - To Script Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package org.jscripter.emu.java.lang;
021 
022 import org.jscripter.emu.java.io.Serializable;
023 
024 import js.ArrayLike;
025 import js.Js;
026 import js.Vars;
027 import jsx.core.ArrayLikes;
028 
029 /**
030  * <p><b>Internally</b> represents a mutable sequence of characters, emulating a standard <tt>java.lang</tt> interface or 
031  * class with the same simple name as this one.</p>
032  * <p>This interface or class is only used internally by JS re-compiler implementations.</p>
033  * <p>This class is exactly same as {@link StringBuffer} for the emulation purpose.</p>
034  * <p>Please refer to <a href="http://java.sun.com/docs/">the Java API Standards</a> for detail description of the original class or interface.</p>
035  * 
036  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
037  * 
038  * @javascript Re-compilers must redirect the resolution of the emulated original Java class or interface to this one.
039  */
040 public final class StringBuilder implements java.lang.CharSequence, Serializable, java.lang.Appendable
041 {
042     private ArrayLike<java.lang.String> arr  = new Vars<java.lang.String>().var();
043     private int len = 0;
044     private int capacity = 16;
045 
046     /**
047      * <p>Constructs a string builder with no characters in it and an initial capacity of 16 characters.</p>
048      * @since 1.0
049      * @javascript Re-compilers must report error on end-users directly using this constructor.
050      * A re-compiler simply replaces an invocation of this empty constructor with its argument.
051      */
052     public StringBuilder() {
053     }
054 
055     /**
056      * <p>Constructs a string builder with no characters in it and an initial capacity specified by the argument.</p>
057      * @param capacity The initial capacity.
058      * @throws java.lang.NegativeArraySizeException if the <tt>capacity</tt> argument is less than 0.
059      * @since 1.0
060      * @javascript Re-compilers must report error on end-users directly using this constructor.
061      * A re-compiler simply replaces an invocation of this empty constructor with its argument.
062      */
063     public StringBuilder(int capacity) {
064         if (capacity < 0) {
065             throw new java.lang.NegativeArraySizeException(String.valueOf(capacity));
066         }
067         this.capacity = capacity;
068     }
069 
070     /**
071      * <p>Constructs a string builder initialized to the contents of the specified string.</p>
072      * <p>The initial capacity of the string builder is 16 plus the length of the string argument.</p>
073      * @param str The initial contents of the buffer.
074      * @throws java.lang.NullPointerException - if <tt>str</tt> is <tt>null</tt>.
075      * @since 1.0
076      * @javascript Re-compilers must report error on end-users directly using this constructor.
077      * A re-compiler simply replaces an invocation of this empty constructor with its argument.
078      */
079     public StringBuilder(java.lang.String str) {
080         if (Js.undefined(str)) {
081             throw new java.lang.NullPointerException();
082         }
083         capacity += str.length();
084         append(str);
085     }
086 
087     /**
088      * <p>Constructs a string builder that contains the same characters as the specified {@link CharSequence}.
089      * <p>The initial capacity of the string builder is 16 plus the length of the {@link CharSequence} argument.</p>
090      * @param seq The sequence to copy.
091      * @throws java.lang.NullPointerException - if <tt>seq</tt> is <tt>null</tt>.
092      * @since 1.0
093      * @javascript Re-compilers must report error on end-users directly using this constructor.
094      * A re-compiler simply replaces an invocation of this empty constructor with its argument.
095      */
096     public StringBuilder(java.lang.CharSequence seq) {
097         if (Js.undefined(seq)) {
098             throw new java.lang.NullPointerException();
099         }
100         capacity += seq.length();
101         append(seq.toString());
102     }
103 
104     /**
105      * <p>Appends the string representation of the value argument to the sequence.</p>
106      * @param x A value.
107      * @return This object itself.
108      * @since 1.0
109      * @javascript Re-compilers must report error on end-users directly using this method.
110      */
111     public StringBuilder append(boolean x) {
112         return append(java.lang.String.valueOf(x));
113     }
114 
115     /**
116      * <p>Appends the string representation of the value argument to the sequence.</p>
117      * @param x A value.
118      * @return This object itself.
119      * @since 1.0
120      * @javascript Re-compilers must report error on end-users directly using this method.
121      */
122     public StringBuilder append(char x) {
123         return append(java.lang.String.valueOf(x));
124     }
125 
126     /**
127      * <p>Appends the string representation of the char array argument to this sequence.</p>
128      * @param x A char array.
129      * @return This object itself.
130      * @since 1.0
131      * @javascript Re-compilers must report error on end-users directly using this method.
132      */
133     public StringBuilder append(char[] x) {
134         return append(java.lang.String.valueOf(x));
135     }
136 
137     /**
138      * <p>Appends the string representation of a subarray of the char array argument to this sequence.</p>
139      * @param x A char array.
140      * @param offset The index of the first char to append.
141      * @param len The number of chars to append.
142      * @return This object itself.
143      * @since 1.0
144      * @javascript Re-compilers must report error on end-users directly using this method.
145      */
146     public StringBuilder append(char[] x, int offset, int len) {
147         return append(java.lang.String.valueOf(x, offset, len));
148     }
149 
150     /**
151      * <p>Appends the specified character sequence to this sequence.</p>
152      * @param q A char sequence.
153      * @return This object itself.
154      * @since 1.0
155      * @javascript Re-compilers must report error on end-users directly using this method.
156      */
157     public StringBuilder append(java.lang.CharSequence q) {
158         return append(q.toString());
159     }
160 
161     /**
162      * <p>Appends a subsequence of the specified char sequence to this sequence.</p>
163      * @param q A char sequence.
164      * @param start The starting index of the subsequence to be appended.
165      * @param end The end index of the subsequence to be appended.
166      * @return This object itself.
167      * @since 1.0
168      * @javascript Re-compilers must report error on end-users directly using this method.
169      */
170     public StringBuilder append(java.lang.CharSequence q, int start, int end) {
171         return append(q.subSequence(start, end));
172     }
173 
174     /**
175      * <p>Appends the string representation of the value argument to the sequence.</p>
176      * @param x A value.
177      * @return This object itself.
178      * @since 1.0
179      * @javascript Re-compilers must report error on end-users directly using this method.
180      */
181     public StringBuilder append(double x) {
182         return append(java.lang.String.valueOf(x));
183     }
184 
185     /**
186      * <p>Appends the string representation of the value argument to the sequence.</p>
187      * @param x A value.
188      * @return This object itself.
189      * @since 1.0
190      * @javascript Re-compilers must report error on end-users directly using this method.
191      */
192     public StringBuilder append(float x) {
193         return append(java.lang.String.valueOf(x));
194     }
195 
196     /**
197      * <p>Appends the string representation of the value argument to the sequence.</p>
198      * @param x A value.
199      * @return This object itself.
200      * @since 1.0
201      * @javascript Re-compilers must report error on end-users directly using this method.
202      */
203     public StringBuilder append(int x) {
204         return append(java.lang.String.valueOf(x));
205     }
206 
207     /**
208      * <p>Appends the string representation of the value argument to the sequence.</p>
209      * @param x A value.
210      * @return This object itself.
211      * @since 1.0
212      * @javascript Re-compilers must report error on end-users directly using this method.
213      */
214     public StringBuilder append(long x) {
215         return append(java.lang.String.valueOf(x));
216     }
217 
218     /**
219      * <p>Appends the string representation of the value argument to the sequence.</p>
220      * @param x A value.
221      * @return This object itself.
222      * @since 1.0
223      * @javascript Re-compilers must report error on end-users directly using this method.
224      */
225     public StringBuilder append(Object x) {
226         return append(java.lang.String.valueOf(x));
227     }
228 
229     /**
230      * <p>Appends the specified string to this character sequence.</p>
231      * @param str A string.
232      * @return This object itself.
233      * @since 1.0
234      * @javascript Re-compilers must report error on end-users directly using this method.
235      */
236     public StringBuilder append(java.lang.String str) {
237         if (Js.undefined(str)) {
238             str = "null";
239         }
240         int appendLength = str.length();
241         if (appendLength > 0) {
242             ArrayLikes.push(arr, str);
243             len += appendLength;
244             capacity();
245         }
246         return this;
247     };
248 
249     /**
250      * <p>Appends the specified string buffer to this sequence.</p>
251      * @param x A {@link java.lang.StringBuffer}.
252      * @return This object itself.
253      * @since 1.0
254      * @javascript Re-compilers must report error on end-users directly using this method.
255      */
256     public StringBuilder append(java.lang.StringBuffer x) {
257         return append(java.lang.String.valueOf(x));
258     }
259 
260     /**
261      * <p>Returns the current capacity.</p>
262      * @return The current capacity.
263      * @since 1.0
264      * @javascript Re-compilers must report error on end-users directly using this method.
265      */
266     public int capacity() {
267         int arrlen = ArrayLikes.length(arr);
268         if (arrlen > capacity) {
269             toString();
270             ensureCapacity(arrlen);
271         }
272         return capacity;
273     }
274 
275     /**
276      * <p>Returns the char value in this sequence at the specified index.</p>
277      * @param index The index of the desired char value.
278      * @return The char value at the specified index.
279      * @throws java.lang.IndexOutOfBoundsException - if <tt>index</tt> is negative or greater than or 
280      * equal to {@link #length()}.
281      * @since 1.0
282      * @javascript Re-compilers must report error on end-users directly using this method.
283      */
284     public char charAt(int index) {
285         return toString().charAt(index);
286     }
287 
288     /**
289      * <p>Removes the characters in a substring of this sequence.</p>
290      * @param start The beginning index, inclusive.
291      * @param end The ending index, exclusive.
292      * @return This object itself.
293      * @throws java.lang.StringIndexOutOfBoundsException - if <tt>start</tt> is negative or greater than 
294      * {@link #length()}, or greater than <tt>end</tt>.
295      * @since 1.0
296      * @javascript Re-compilers must report error on end-users directly using this method.
297      */
298     public StringBuilder delete(int start, int end) {
299         return replace(start, end, "");
300     }
301 
302     /**
303      * <p>Removes the char at the specified position in this sequence.</p>
304      * @param start The index of char to remove.
305      * @return This object itself.
306      * @throws java.lang.StringIndexOutOfBoundsException - if <tt>index</tt> is negative or greater than or 
307      * equal to {@link #length()}.
308      * @since 1.0
309      * @javascript Re-compilers must report error on end-users directly using this method.
310      */
311     public StringBuilder deleteCharAt(int start) {
312         return delete(start, start + 1);
313     }
314 
315     /**
316      * <p>Ensures that the capacity is at least equal to the specified minimum.</p>
317      * @param minimumCapacity The minimum desired capacity.
318      * @since 1.0
319      * @javascript Re-compilers must report error on end-users directly using this method.
320      */
321     public void ensureCapacity(int minimumCapacity) {
322         if (minimumCapacity > capacity()) {
323             capacity = minimumCapacity * 2 + 2;
324             ArrayLikes.length(arr, capacity);
325         }
326     }
327 
328     /**
329      * <p>Characters are copied from this sequence into the destination character array.</p>
330      * @param srcStart Start copying at this offset.
331      * @param srcEnd Stop copying at this offset.
332      * @param dst The array to copy the data into.
333      * @param dstStart The offset into <tt>dst</tt>.
334      * @since 1.0
335      * @javascript Re-compilers must report error on end-users directly using this method.
336      */
337     public void getChars(int srcStart, int srcEnd, char[] dst, int dstStart) {
338         String.checkBounds(srcStart, srcEnd, len);
339         String.checkBounds(dstStart, dstStart + (srcEnd - srcStart), dst.length);
340         java.lang.String s = toString();
341         while (srcStart < srcEnd) {
342             dst[dstStart++] = s.charAt(srcStart++);
343         }
344     }
345 
346     /**
347      * <p>Returns the index within this string of the first occurrence of the specified substring.</p>
348      * @param x A string.
349      * @return The index of the first character of the first such substring if the string argument occurs 
350      * as a substring within this object; -1 otherwise.
351      * @since 1.0
352      * @javascript Re-compilers must report error on end-users directly using this method.
353      */
354     public int indexOf(java.lang.String x) {
355         return toString().indexOf(x);
356     }
357 
358     /**
359      * <p>Returns the index within this string of the first occurrence of the specified substring, 
360      * starting at the specified index.</p>
361      * @param x A string.
362      * @param start The index from which to start the search.
363      * @return The index within this string of the first occurrence of the specified substring, 
364      * starting at the specified index.
365      * @since 1.0
366      * @javascript Re-compilers must report error on end-users directly using this method.
367      */
368     public int indexOf(java.lang.String x, int start) {
369         return toString().indexOf(x, start);
370     }
371 
372     /**
373      * <p>Inserts the string representation of the argument into this sequence.</p>
374      * @param index The offset index.
375      * @param x A value.
376      * @return This object itself.
377      * @since 1.0
378      * @javascript Re-compilers must report error on end-users directly using this method.
379      */
380     public StringBuilder insert(int index, boolean x) {
381         return insert(index, java.lang.String.valueOf(x));
382     }
383 
384     /**
385      * <p>Inserts the string representation of the argument into this sequence.</p>
386      * @param index The offset index.
387      * @param x A value.
388      * @return This object itself.
389      * @since 1.0
390      * @javascript Re-compilers must report error on end-users directly using this method.
391      */
392     public StringBuilder insert(int index, char x) {
393         return insert(index, java.lang.String.valueOf(x));
394     }
395 
396     /**
397      * <p>Inserts the string representation of the char array argument into this sequence.</p>
398      * @param index The offset index.
399      * @param x A char array.
400      * @return This object itself.
401      * @since 1.0
402      * @javascript Re-compilers must report error on end-users directly using this method.
403      */
404     public StringBuilder insert(int index, char[] x) {
405         return insert(index, java.lang.String.valueOf(x));
406     }
407 
408     /**
409      * <p>Inserts the string representation of a subarray of the char array argument to this sequence.</p>
410      * @param index The index at which to insert subarray.
411      * @param x A char array.
412      * @param offset The index of the first char in subarray to be inserted.
413      * @param len The number of chars in the subarray to be inserted.
414      * @return This object itself.
415      * @since 1.0
416      * @javascript Re-compilers must report error on end-users directly using this method.
417      */
418     public StringBuilder insert(int index, char[] x, int offset, int len) {
419         return insert(index, java.lang.String.valueOf(x, offset, len));
420     }
421 
422     /**
423      * <p>Inserts the string representation of the char sequence argument into this sequence.</p>
424      * @param index The offset index.
425      * @param x A char sequence.
426      * @return This object itself.
427      * @since 1.0
428      * @javascript Re-compilers must report error on end-users directly using this method.
429      */
430     public StringBuilder insert(int index, CharSequence x) {
431         return insert(index, x.toString());
432     }
433 
434     /**
435      * <p>Inserts the string representation of the char sequence argument into this sequence.</p>
436      * @param index The offset index.
437      * @param x A char sequence.
438      * @param start The starting index of the subsequence to be inserted.
439      * @param end The end index of the subsequence to be inserted.
440      * @return This object itself.
441      * @since 1.0
442      * @javascript Re-compilers must report error on end-users directly using this method.
443      */
444     public StringBuilder insert(int index, CharSequence x, int start, int end) {
445         return insert(index, x.subSequence(start, end).toString());
446     }
447 
448     /**
449      * <p>Inserts the string representation of the argument into this sequence.</p>
450      * @param index The offset index.
451      * @param x A value.
452      * @return This object itself.
453      * @since 1.0
454      * @javascript Re-compilers must report error on end-users directly using this method.
455      */
456     public StringBuilder insert(int index, double x) {
457         return insert(index, java.lang.String.valueOf(x));
458     }
459 
460     /**
461      * <p>Inserts the string representation of the argument into this sequence.</p>
462      * @param index The offset index.
463      * @param x A value.
464      * @return This object itself.
465      * @since 1.0
466      * @javascript Re-compilers must report error on end-users directly using this method.
467      */
468     public StringBuilder insert(int index, float x) {
469         return insert(index, java.lang.String.valueOf(x));
470     }
471 
472     /**
473      * <p>Inserts the string representation of the argument into this sequence.</p>
474      * @param index The offset index.
475      * @param x A value.
476      * @return This object itself.
477      * @since 1.0
478      * @javascript Re-compilers must report error on end-users directly using this method.
479      */
480     public StringBuilder insert(int index, int x) {
481         return insert(index, java.lang.String.valueOf(x));
482     }
483 
484     /**
485      * <p>Inserts the string representation of the argument into this sequence.</p>
486      * @param index The offset index.
487      * @param x A value.
488      * @return This object itself.
489      * @since 1.0
490      * @javascript Re-compilers must report error on end-users directly using this method.
491      */
492     public StringBuilder insert(int index, long x) {
493         return insert(index, java.lang.String.valueOf(x));
494     }
495 
496     /**
497      * <p>Inserts the string representation of the argument into this sequence.</p>
498      * @param index The offset index.
499      * @param x A value.
500      * @return This object itself.
501      * @since 1.0
502      * @javascript Re-compilers must report error on end-users directly using this method.
503      */
504     public StringBuilder insert(int index, Object x) {
505         return insert(index, java.lang.String.valueOf(x));
506     }
507 
508     /**
509      * <p>Inserts a string into this sequence.</p>
510      * @param index The offset index.
511      * @param x A string.
512      * @return This object itself.
513      * @since 1.0
514      * @javascript Re-compilers must report error on end-users directly using this method.
515      */
516     public StringBuilder insert(int index, java.lang.String x) {
517         return replace(index, index, x);
518     }
519 
520     /**
521      * <p>Returns the index within this string of the last occurrence of the specified substring.</p>
522      * @param x A string.
523      * @return The index within this string of the last occurrence of the specified substring.
524      * @since 1.0
525      * @javascript Re-compilers must report error on end-users directly using this method.
526      */
527     public int lastIndexOf(java.lang.String x) {
528         return toString().lastIndexOf(x);
529     }
530 
531     /**
532      * <p>Returns the index within this string of the last occurrence of the specified substring, 
533      * starting at the specified index.</p>
534      * @param x A string.
535      * @param start The index from which to start the search.
536      * @return The index within this string of the last occurrence of the specified substring, 
537      * starting at the specified index.
538      * @since 1.0
539      * @javascript Re-compilers must report error on end-users directly using this method.
540      */
541     public int lastIndexOf(java.lang.String x, int start) {
542         return toString().lastIndexOf(x, start);
543     }
544 
545     /**
546      * <p>Returns the length (character count).</p>
547      * @return The length of the sequence of characters currently represented by this object.
548      * @since 1.0
549      * @javascript Re-compilers must report error on end-users directly using this method.
550      */
551     public int length() {
552         return len;
553     }
554 
555     /**
556      * <p>Replaces the characters in a substring of this sequence with characters in the specified String.</p>
557      * @param start The beginning index, inclusive.
558      * @param end The ending index, exclusive.
559      * @param str A string.
560      * @return This object itself.
561      * @since 1.0
562      * @javascript Re-compilers must report error on end-users directly using this method.
563      */
564     public StringBuilder replace(int start, int end, java.lang.String str) {
565         java.lang.String s = toString();
566         arr = new Vars<java.lang.String>()
567                 .add(s.substring(0, start))
568                 .add(str)
569                 .add(s.substring(end)).var();
570         len += str.length() - (end - start);
571         return this;
572     }
573 
574     /**
575      * <p>Modifies a character at the specified index.</p>
576      * @param index The index of the character to modify.
577      * @param x A char.
578      * @since 1.0
579      * @javascript Re-compilers must report error on end-users directly using this method.
580      */
581     public void setCharAt(int index, char x) {
582         replace(index, index + 1, java.lang.String.valueOf(x));
583     }
584 
585     /**
586      * <p>Sets the length of the character sequence.</p>
587      * @param newLength The new length.
588      * @since 1.0
589      * @javascript Re-compilers must report error on end-users directly using this method.
590      */
591     public void setLength(int newLength) {
592         if (newLength < len) {
593             delete(newLength, len);
594         } else if (newLength > len) {
595             append(new char[newLength - len]);
596         }
597     }
598 
599     /**
600      * <p>Returns a new character sequence that is a subsequence of this sequence.</p>
601      * @param start The start index, inclusive.
602      * @param end The end index, exclusive.
603      * @return The specified subsequence.
604      * @since 1.0
605      * @javascript Re-compilers must report error on end-users directly using this method.
606      */
607     public java.lang.CharSequence subSequence(int start, int end) {
608         return this.substring(start, end);
609     }
610 
611     /**
612      * <p>Returns a new string that contains a subsequence of characters currently 
613      * contained in this sequence.</p>
614      * @param start The start index, inclusive.
615      * @return The new string.
616      * @throws java.lang.StringIndexOutOfBoundsException - if <tt>index</tt> is negative or greater than or 
617      * equal to {@link #length()}.
618      * @since 1.0
619      * @javascript Re-compilers must report error on end-users directly using this method.
620      */
621     public java.lang.String substring(int start) {
622         return toString().substring(start);
623     }
624 
625     /**
626      * <p>Returns a new string that contains a subsequence of characters currently 
627      * contained in this sequence.</p>
628      * @param start The start index, inclusive.
629      * @param end The end index, exclusive.
630      * @return The new string.
631      * @throws java.lang.StringIndexOutOfBoundsException - if <tt>start</tt> is negative or greater than 
632      * {@link #length()}, or greater than <tt>end</tt>.
633      * @since 1.0
634      * @javascript Re-compilers must report error on end-users directly using this method.
635      */
636     public java.lang.String substring(int start, int end) {
637         return toString().substring(start, end);
638     }
639 
640     /**
641      * <p>Returns a string representing this sequence.</p>
642      * @return A string representation of this sequence.
643      * @since 1.0
644      * @javascript Re-compilers must report error on end-users directly using this method.
645      */
646     @Override
647     public java.lang.String toString() {
648         if (ArrayLikes.length(arr) > 1) {
649             java.lang.String s = ArrayLikes.join(arr);
650             arr = new Vars<java.lang.String>().add(s).var();
651         }
652         return arr.get(0);
653     }
654 }