History

Refactored java.lang.String class to work with Inferno's jvm

Dmitry Kabak (userdima committed 13 years ago

Commit b7c872b1 parent d8adc111 file · +255 −515Browse files

Showing the changes to java/pkg/java/lang/String.java (1 of 1 file). Show all

Unified · Split

java/pkg/java/lang/String.java+255−515
@@ -110,14 +110,22 @@ import java.util.regex.PatternSyntaxException; · 109 unmodified lines
110110 public final class String
111111 implements java.io.Serializable, Comparable<String>, CharSequence
112112 {
113+ // [Inferno] <
114+
113115 /** The value is used for character storage. */
114− private final char value[];
116+ //private final char value[];
115117
116118 /** The offset is the first index of the storage that is used. */
117− private final int offset;
119+ //private final int offset;
118120
119121 /** The count is the number of characters in the String. */
120− private final int count;
122+ //private final int count;
123+
124+ /** The first field represents internal dis string. It is used by
125+ Inferno's jvm to store and manipulate the actual string data. */
126+ private transient String disString;
127+
128+ // [Inferno] >
121129
122130 /** Cache the hash code for the string */
123131 private int hash; // Default to 0
@@ -145,11 +153,10 @@ public final class String · 21 unmodified lines
145153 * an empty character sequence. Note that use of this constructor is
146154 * unnecessary since Strings are immutable.
147155 */
156+ // [Inferno] <
148157 public String() {
149− this.offset = 0;
150− this.count = 0;
151− this.value = new char[0];
152158 }
159+ // [Inferno] >
153160
154161 /**
155162 * Initializes a newly created {@code String} object so that it represents
@@ -162,23 +169,29 @@ public final class String · 6 unmodified lines
162169 * A {@code String}
163170 */
164171 public String(String original) {
165− int size = original.count;
166− char[] originalValue = original.value;
167− char[] v;
168− if (originalValue.length > size) {
169− // The array representing the String is bigger than the new
170− // String itself. Perhaps this constructor is being called
171− // in order to trim the baggage, so make a copy of the array.
172− int off = original.offset;
173− v = Arrays.copyOfRange(originalValue, off, off+size);
174− } else {
175− // The array representing the String is the same
176− // size as the String, so no point in making a copy.
177− v = originalValue;
178− }
179− this.offset = 0;
180− this.count = size;
181− this.value = v;
172+ //int size = original.count;
173+ //char[] originalValue = original.value;
174+ //char[] v;
175+ //if (originalValue.length > size) {
176+ // // The array representing the String is bigger than the new
177+ // // String itself. Perhaps this constructor is being called
178+ // // in order to trim the baggage, so make a copy of the array.
179+ // int off = original.offset;
180+ // v = Arrays.copyOfRange(originalValue, off, off+size);
181+ //} else {
182+ // // The array representing the String is the same
183+ // // size as the String, so no point in making a copy.
184+ // v = originalValue;
185+ //}
186+ //this.offset = 0;
187+ //this.count = size;
188+ //this.value = v;
189+ if (original == null)
190+ throw new NullPointerException();
191+
192+ // [Inferno] <
193+ disString = original.disString;
194+ // [Inferno] >
182195 }
183196
184197 /**
@@ -191,10 +204,16 @@ public final class String · 6 unmodified lines
191204 * The initial value of the string
192205 */
193206 public String(char value[]) {
194− int size = value.length;
195− this.offset = 0;
196− this.count = size;
197− this.value = Arrays.copyOf(value, size);
207+ //int size = value.length;
208+ //this.offset = 0;
209+ //this.count = size;
210+ //this.value = Arrays.copyOf(value, size);
211+ if (value == null)
212+ throw new NullPointerException();
213+
214+ // [Inferno] <
215+ fill(value, 0, value.length);
216+ // [Inferno] >
198217 }
199218
200219 /**
@@ -229,9 +248,12 @@ public final class String · 28 unmodified lines
229248 if (offset > value.length - count) {
230249 throw new StringIndexOutOfBoundsException(offset + count);
231250 }
232− this.offset = 0;
233− this.count = count;
234− this.value = Arrays.copyOfRange(value, offset, offset+count);
251+ //this.offset = 0;
252+ //this.count = count;
253+
254+ // [Inferno] <
255+ fill(value, offset, count);
256+ // [Inferno] >
235257 }
236258
237259 /**
@@ -298,9 +320,13 @@ public final class String · 60 unmodified lines
298320 Character.toSurrogates(c, v, j++);
299321 }
300322
301− this.value = v;
302− this.count = n;
303− this.offset = 0;
323+ //this.value = v;
324+ //this.count = n;
325+ //this.offset = 0;
326+
327+ // [Inferno] <
328+ fill(v, 0, v.length);
329+ // [Inferno] >
304330 }
305331
306332 /**
@@ -357,9 +383,13 @@ public final class String · 50 unmodified lines
357383 value[i] = (char) (hibyte | (ascii[i + offset] & 0xff));
358384 }
359385 }
360− this.offset = 0;
361− this.count = count;
362− this.value = value;
386+ //this.offset = 0;
387+ //this.count = count;
388+ //this.value = value;
389+
390+ // [Inferno] <
391+ fill(value, 0, value.length);
392+ // [Inferno] >
363393 }
364394
365395 /**
@@ -429,7 +459,7 @@ public final class String · 63 unmodified lines
429459 *
430460 * @param length
431461 * The number of bytes to decode
432−
462+ *
433463 * @param charsetName
434464 * The name of a supported {@linkplain java.nio.charset.Charset
435465 * charset}
@@ -450,9 +480,13 @@ public final class String · 14 unmodified lines
450480 throw new NullPointerException("charsetName");
451481 checkBounds(bytes, offset, length);
452482 char[] v = StringCoding.decode(charsetName, bytes, offset, length);
453− this.offset = 0;
454− this.count = v.length;
455− this.value = v;
483+ //this.offset = 0;
484+ //this.count = v.length;
485+ //this.value = v;
486+
487+ // [Inferno] <
488+ fill(v, 0, v.length);
489+ // [Inferno] >
456490 }
457491
458492 /**
@@ -490,9 +524,13 @@ public final class String · 31 unmodified lines
490524 throw new NullPointerException("charset");
491525 checkBounds(bytes, offset, length);
492526 char[] v = StringCoding.decode(charset, bytes, offset, length);
493− this.offset = 0;
494− this.count = v.length;
495− this.value = v;
527+ //this.offset = 0;
528+ //this.count = v.length;
529+ //this.value = v;
530+
531+ // [Inferno] <
532+ fill(v, 0, v.length);
533+ // [Inferno] >
496534 }
497535
498536 /**
@@ -577,9 +615,13 @@ public final class String · 78 unmodified lines
577615 public String(byte bytes[], int offset, int length) {
578616 checkBounds(bytes, offset, length);
579617 char[] v = StringCoding.decode(bytes, offset, length);
580− this.offset = 0;
581− this.count = v.length;
582− this.value = v;
618+ //this.offset = 0;
619+ //this.count = v.length;
620+ //this.value = v;
621+
622+ // [Inferno] <
623+ fill(v, 0, v.length);
624+ // [Inferno] >
583625 }
584626
585627 /**
@@ -612,10 +654,9 @@ public final class String · 26 unmodified lines
612654 * A {@code StringBuffer}
613655 */
614656 public String(StringBuffer buffer) {
615− String result = buffer.toString();
616− this.value = result.value;
617− this.count = result.count;
618− this.offset = result.offset;
657+ // [Inferno] <
658+ this(buffer.toString());
659+ // [Inferno] >
619660 }
620661
621662 /**
@@ -634,18 +675,19 @@ public final class String · 12 unmodified lines
634675 * @since 1.5
635676 */
636677 public String(StringBuilder builder) {
637− String result = builder.toString();
638− this.value = result.value;
639− this.count = result.count;
640− this.offset = result.offset;
678+ // [Inferno] <
679+ this(builder.toString());
680+ // [Inferno] >
641681 }
642682
643683
644684 // Package private constructor which shares value array for speed.
645685 String(int offset, int count, char value[]) {
646− this.value = value;
647− this.offset = offset;
648− this.count = count;
686+ // TODO: implement real sharing
687+
688+ // [Inferno] <
689+ fill(value, offset, count);
690+ // [Inferno] >
649691 }
650692
651693 /**
@@ -656,9 +698,9 @@ public final class String · 4 unmodified lines
656698 * @return the length of the sequence of characters represented by this
657699 * object.
658700 */
659− public int length() {
660− return count;
661− }
701+ // [Inferno] <
702+ public native int length();
703+ // [Inferno] >
662704
663705 /**
664706 * Returns <tt>true</tt> if, and only if, {@link #length()} is <tt>0</tt>.
@@ -669,7 +711,9 @@ public final class String · 4 unmodified lines
669711 * @since 1.6
670712 */
671713 public boolean isEmpty() {
672− return count == 0;
714+ // [Inferno] <
715+ return length() == 0;
716+ // [Inferno] >
673717 }
674718
675719 /**
@@ -690,12 +734,9 @@ public final class String · 14 unmodified lines
690734 * argument is negative or not less than the length of this
691735 * string.
692736 */
693− public char charAt(int index) {
694− if ((index < 0) || (index >= count)) {
695− throw new StringIndexOutOfBoundsException(index);
696− }
697− return value[index + offset];
698− }
737+ // [Inferno] <
738+ public native char charAt(int index);
739+ // [Inferno] >
699740
700741 /**
701742 * Returns the character (Unicode code point) at the specified
@@ -720,10 +761,11 @@ public final class String · 18 unmodified lines
720761 * @since 1.5
721762 */
722763 public int codePointAt(int index) {
723− if ((index < 0) || (index >= count)) {
724− throw new StringIndexOutOfBoundsException(index);
725− }
726− return Character.codePointAtImpl(value, offset + index, offset + count);
764+ //if ((index < 0) || (index >= count)) {
765+ // throw new StringIndexOutOfBoundsException(index);
766+ //}
767+ //return Character.codePointAtImpl(value, offset + index, offset + count);
768+ return 0;
727769 }
728770
729771 /**
@@ -749,11 +791,12 @@ public final class String · 19 unmodified lines
749791 * @since 1.5
750792 */
751793 public int codePointBefore(int index) {
752− int i = index - 1;
753− if ((i < 0) || (i >= count)) {
754− throw new StringIndexOutOfBoundsException(index);
755− }
756− return Character.codePointBeforeImpl(value, offset + index, offset);
794+ //int i = index - 1;
795+ //if ((i < 0) || (i >= count)) {
796+ // throw new StringIndexOutOfBoundsException(index);
797+ //}
798+ //return Character.codePointBeforeImpl(value, offset + index, offset);
799+ return 0;
757800 }
758801
759802 /**
@@ -778,10 +821,11 @@ public final class String · 18 unmodified lines
778821 * @since 1.5
779822 */
780823 public int codePointCount(int beginIndex, int endIndex) {
781− if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
782− throw new IndexOutOfBoundsException();
783− }
784− return Character.codePointCountImpl(value, offset+beginIndex, endIndex-beginIndex);
824+ //if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
825+ // throw new IndexOutOfBoundsException();
826+ //}
827+ //return Character.codePointCountImpl(value, offset+beginIndex, endIndex-beginIndex);
828+ return 0;
785829 }
786830
787831 /**
@@ -805,11 +849,12 @@ public final class String · 17 unmodified lines
805849 * @since 1.5
806850 */
807851 public int offsetByCodePoints(int index, int codePointOffset) {
808− if (index < 0 || index > count) {
809− throw new IndexOutOfBoundsException();
810− }
811− return Character.offsetByCodePointsImpl(value, offset, count,
812− offset+index, codePointOffset) - offset;
852+ //if (index < 0 || index > count) {
853+ // throw new IndexOutOfBoundsException();
854+ //}
855+ //return Character.offsetByCodePointsImpl(value, offset, count,
856+ // offset+index, codePointOffset) - offset;
857+ return 0;
813858 }
814859
815860 /**
@@ -817,7 +862,9 @@ public final class String · 1 unmodified line
817862 * This method doesn't perform any range checking.
818863 */
819864 void getChars(char dst[], int dstBegin) {
820− System.arraycopy(value, offset, dst, dstBegin, count);
865+ // [Inferno] <
866+ getChars(0, length(), dst, dstBegin);
867+ // [Inferno] >
821868 }
822869
823870 /**
@@ -850,19 +897,7 @@ public final class String · 26 unmodified lines
850897 * <li><code>dstBegin+(srcEnd-srcBegin)</code> is larger than
851898 * <code>dst.length</code></ul>
852899 */
853− public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
854− if (srcBegin < 0) {
855− throw new StringIndexOutOfBoundsException(srcBegin);
856− }
857− if (srcEnd > count) {
858− throw new StringIndexOutOfBoundsException(srcEnd);
859− }
860− if (srcBegin > srcEnd) {
861− throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
862− }
863− System.arraycopy(value, offset + srcBegin, dst, dstBegin,
864− srcEnd - srcBegin);
865− }
900+ public native void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin);
866901
867902 /**
868903 * Copies characters from this string into the destination byte array. Each
@@ -912,16 +947,16 @@ public final class String · 43 unmodified lines
912947 if (srcBegin < 0) {
913948 throw new StringIndexOutOfBoundsException(srcBegin);
914949 }
915− if (srcEnd > count) {
950+ if (srcEnd > length()) {
916951 throw new StringIndexOutOfBoundsException(srcEnd);
917952 }
918953 if (srcBegin > srcEnd) {
919954 throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
920955 }
921956 int j = dstBegin;
922− int n = offset + srcEnd;
923− int i = offset + srcBegin;
924− char[] val = value; /* avoid getfield opcode */
957+ int n = srcEnd;
958+ int i = srcBegin;
959+ char[] val = toCharArray();
925960
926961 while (i < n) {
927962 dst[j++] = (byte)val[i++];
@@ -952,7 +987,7 @@ public final class String · 24 unmodified lines
952987 throws UnsupportedEncodingException
953988 {
954989 if (charsetName == null) throw new NullPointerException();
955− return StringCoding.encode(charsetName, value, offset, count);
990+ return StringCoding.encode(charsetName, toCharArray(), 0, length());
956991 }
957992
958993 /**
@@ -975,7 +1010,7 @@ public final class String · 16 unmodified lines
9751010 */
9761011 public byte[] getBytes(Charset charset) {
9771012 if (charset == null) throw new NullPointerException();
978− return StringCoding.encode(charset, value, offset, count);
1013+ return StringCoding.encode(charset, toCharArray(), 0, length());
9791014 }
9801015
9811016 /**
@@ -992,7 +1027,7 @@ public final class String · 10 unmodified lines
9921027 * @since JDK1.1
9931028 */
9941029 public byte[] getBytes() {
995− return StringCoding.encode(value, offset, count);
1030+ return StringCoding.encode(toCharArray(), 0, length());
9961031 }
9971032
9981033 /**
@@ -1011,25 +1046,11 @@ public final class String · 12 unmodified lines
10111046 * @see #equalsIgnoreCase(String)
10121047 */
10131048 public boolean equals(Object anObject) {
1014− if (this == anObject) {
1015− return true;
1016− }
1017− if (anObject instanceof String) {
1018− String anotherString = (String)anObject;
1019− int n = count;
1020− if (n == anotherString.count) {
1021− char v1[] = value;
1022− char v2[] = anotherString.value;
1023− int i = offset;
1024− int j = anotherString.offset;
1025− while (n-- != 0) {
1026− if (v1[i++] != v2[j++])
1027− return false;
1028− }
1029− return true;
1030− }
1031− }
1049+ // [Inferno] <
1050+ if (anObject instanceof String)
1051+ return equality((String)anObject, false);
10321052 return false;
1053+ // [Inferno] >
10331054 }
10341055
10351056 /**
@@ -1067,13 +1088,15 @@ public final class String · 31 unmodified lines
10671088 * @since 1.5
10681089 */
10691090 public boolean contentEquals(CharSequence cs) {
1091+ // [Inferno] <
1092+ int count = length();
10701093 if (count != cs.length())
10711094 return false;
10721095 // Argument is a StringBuffer, StringBuilder
10731096 if (cs instanceof AbstractStringBuilder) {
1074− char v1[] = value;
1097+ char v1[] = toCharArray();
10751098 char v2[] = ((AbstractStringBuilder)cs).getValue();
1076− int i = offset;
1099+ int i = 0;
10771100 int j = 0;
10781101 int n = count;
10791102 while (n-- != 0) {
@@ -1086,8 +1109,8 @@ public final class String · 6 unmodified lines
10861109 if (cs.equals(this))
10871110 return true;
10881111 // Argument is a generic CharSequence
1089− char v1[] = value;
1090− int i = offset;
1112+ char v1[] = toCharArray();
1113+ int i = 0;
10911114 int j = 0;
10921115 int n = count;
10931116 while (n-- != 0) {
@@ -1095,6 +1118,7 @@ public final class String · 1 unmodified line
10951118 return false;
10961119 }
10971120 return true;
1121+ // [Inferno] >
10981122 }
10991123
11001124 /**
@@ -1126,9 +1150,9 @@ public final class String · 25 unmodified lines
11261150 * @see #equals(Object)
11271151 */
11281152 public boolean equalsIgnoreCase(String anotherString) {
1129− return (this == anotherString) ? true :
1130− (anotherString != null) && (anotherString.count == count) &&
1131− regionMatches(true, 0, anotherString, 0, count);
1153+ // [Inferno] <
1154+ return equality(anotherString, true);
1155+ // [Inferno] >
11321156 }
11331157
11341158 /**
@@ -1173,13 +1197,13 @@ public final class String · 38 unmodified lines
11731197 * lexicographically greater than the string argument.
11741198 */
11751199 public int compareTo(String anotherString) {
1176− int len1 = count;
1177− int len2 = anotherString.count;
1200+ int len1 = length();
1201+ int len2 = anotherString.length();
11781202 int n = Math.min(len1, len2);
1179− char v1[] = value;
1180− char v2[] = anotherString.value;
1181− int i = offset;
1182− int j = anotherString.offset;
1203+ char v1[] = toCharArray();
1204+ char v2[] = anotherString.toCharArray();
1205+ int i = 0;
1206+ int j = 0;
11831207
11841208 if (i == j) {
11851209 int k = i;
@@ -1304,21 +1328,9 @@ public final class String · 118 unmodified lines
13041328 */
13051329 public boolean regionMatches(int toffset, String other, int ooffset,
13061330 int len) {
1307− char ta[] = value;
1308− int to = offset + toffset;
1309− char pa[] = other.value;
1310− int po = other.offset + ooffset;
1311− // Note: toffset, ooffset, or len might be near -1>>>1.
1312− if ((ooffset < 0) || (toffset < 0) || (toffset > (long)count - len)
1313− || (ooffset > (long)other.count - len)) {
1314− return false;
1315− }
1316− while (len-- > 0) {
1317− if (ta[to++] != pa[po++]) {
1318− return false;
1319− }
1320− }
1321− return true;
1331+ // [Inferno] <
1332+ return regionMatches(false, toffset, other, ooffset, len);
1333+ // [Inferno] >
13221334 }
13231335
13241336 /**
@@ -1348,7 +1360,7 @@ public final class String · 23 unmodified lines
13481360 * integer <i>k</i> less than <tt>len</tt> such that:
13491361 * <blockquote><pre>
13501362 * Character.toLowerCase(this.charAt(toffset+k)) !=
1351− Character.toLowerCase(other.charAt(ooffset+k))
1363+ * Character.toLowerCase(other.charAt(ooffset+k))
13521364 * </pre></blockquote>
13531365 * and:
13541366 * <blockquote><pre>
@@ -1371,45 +1383,10 @@ public final class String · 16 unmodified lines
13711383 * or case insensitive depends on the <code>ignoreCase</code>
13721384 * argument.
13731385 */
1374− public boolean regionMatches(boolean ignoreCase, int toffset,
1375− String other, int ooffset, int len) {
1376− char ta[] = value;
1377− int to = offset + toffset;
1378− char pa[] = other.value;
1379− int po = other.offset + ooffset;
1380− // Note: toffset, ooffset, or len might be near -1>>>1.
1381− if ((ooffset < 0) || (toffset < 0) || (toffset > (long)count - len) ||
1382− (ooffset > (long)other.count - len)) {
1383− return false;
1384− }
1385− while (len-- > 0) {
1386− char c1 = ta[to++];
1387− char c2 = pa[po++];
1388− if (c1 == c2) {
1389− continue;
1390− }
1391− if (ignoreCase) {
1392− // If characters don't match but case may be ignored,
1393− // try converting both characters to uppercase.
1394− // If the results match, then the comparison scan should
1395− // continue.
1396− char u1 = Character.toUpperCase(c1);
1397− char u2 = Character.toUpperCase(c2);
1398− if (u1 == u2) {
1399− continue;
1400− }
1401− // Unfortunately, conversion to uppercase does not work properly
1402− // for the Georgian alphabet, which has strange rules about case
1403− // conversion. So we need to make one last check before
1404− // exiting.
1405− if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
1406− continue;
1407− }
1408− }
1409− return false;
1410− }
1411− return true;
1412− }
1386+ // [Inferno] <
1387+ public native boolean regionMatches(boolean ignoreCase, int toffset,
1388+ String other, int ooffset, int len);
1389+ // [Inferno] >
14131390
14141391 /**
14151392 * Tests if the substring of this string beginning at the
@@ -1429,21 +1406,9 @@ public final class String · 13 unmodified lines
14291406 * </pre>
14301407 */
14311408 public boolean startsWith(String prefix, int toffset) {
1432− char ta[] = value;
1433− int to = offset + toffset;
1434− char pa[] = prefix.value;
1435− int po = prefix.offset;
1436− int pc = prefix.count;
1437− // Note: toffset might be near -1>>>1.
1438− if ((toffset < 0) || (toffset > count - pc)) {
1439− return false;
1440− }
1441− while (--pc >= 0) {
1442− if (ta[to++] != pa[po++]) {
1443− return false;
1444− }
1445− }
1446− return true;
1409+ // [Inferno] <
1410+ return isPrefix(prefix, toffset);
1411+ // [Inferno] >
14471412 }
14481413
14491414 /**
@@ -1460,7 +1425,9 @@ public final class String · 10 unmodified lines
14601425 * @since 1. 0
14611426 */
14621427 public boolean startsWith(String prefix) {
1463− return startsWith(prefix, 0);
1428+ // [Inferno] <
1429+ return isPrefix(prefix, 0);
1430+ // [Inferno] >
14641431 }
14651432
14661433 /**
@@ -1475,7 +1442,9 @@ public final class String · 8 unmodified lines
14751442 * as determined by the {@link #equals(Object)} method.
14761443 */
14771444 public boolean endsWith(String suffix) {
1478− return startsWith(suffix, count - suffix.count);
1445+ // [Inferno] <
1446+ return isSuffix(suffix);
1447+ // [Inferno] >
14791448 }
14801449
14811450 /**
@@ -1491,20 +1460,9 @@ public final class String · 9 unmodified lines
14911460 *
14921461 * @return a hash code value for this object.
14931462 */
1494− public int hashCode() {
1495− int h = hash;
1496− if (h == 0 && count > 0) {
1497− int off = offset;
1498− char val[] = value;
1499− int len = count;
1500−
1501− for (int i = 0; i < len; i++) {
1502− h = 31*h + val[off++];
1503− }
1504− hash = h;
1505− }
1506− return h;
1507− }
1463+ // [Inferno] <
1464+ public native int hashCode();
1465+ // [Inferno] >
15081466
15091467 /**
15101468 * Returns the index within this string of the first occurrence of
@@ -1531,7 +1489,9 @@ public final class String · 20 unmodified lines
15311489 * <code>-1</code> if the character does not occur.
15321490 */
15331491 public int indexOf(int ch) {
1534− return indexOf(ch, 0);
1492+ // [Inferno] <
1493+ return index(ch, 0);
1494+ // [Inferno] >
15351495 }
15361496
15371497 /**
@@ -1574,47 +1534,9 @@ public final class String · 36 unmodified lines
15741534 * if the character does not occur.
15751535 */
15761536 public int indexOf(int ch, int fromIndex) {
1577− if (fromIndex < 0) {
1578− fromIndex = 0;
1579− } else if (fromIndex >= count) {
1580− // Note: fromIndex might be near -1>>>1.
1581− return -1;
1582− }
1583−
1584− if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
1585− // handle most cases here (ch is a BMP code point or a
1586− // negative value (invalid code point))
1587− final char[] value = this.value;
1588− final int offset = this.offset;
1589− final int max = offset + count;
1590− for (int i = offset + fromIndex; i < max ; i++) {
1591− if (value[i] == ch) {
1592− return i - offset;
1593− }
1594− }
1595− return -1;
1596− } else {
1597− return indexOfSupplementary(ch, fromIndex);
1598− }
1599− }
1600−
1601− /**
1602− * Handles (rare) calls of indexOf with a supplementary character.
1603− */
1604− private int indexOfSupplementary(int ch, int fromIndex) {
1605− if (Character.isValidCodePoint(ch)) {
1606− final char[] value = this.value;
1607− final int offset = this.offset;
1608− final char hi = Character.highSurrogate(ch);
1609− final char lo = Character.lowSurrogate(ch);
1610− final int max = offset + count - 1;
1611− for (int i = offset + fromIndex; i < max; i++) {
1612− if (value[i] == hi && value[i+1] == lo) {
1613− return i - offset;
1614− }
1615− }
1616− }
1617− return -1;
1537+ // [Inferno] <
1538+ return index(ch, fromIndex);
1539+ // [Inferno] >
16181540 }
16191541
16201542 /**
@@ -1641,7 +1563,9 @@ public final class String · 20 unmodified lines
16411563 * <code>-1</code> if the character does not occur.
16421564 */
16431565 public int lastIndexOf(int ch) {
1644− return lastIndexOf(ch, count - 1);
1566+ // [Inferno] <
1567+ return rindex(ch, 0, true);
1568+ // [Inferno] >
16451569 }
16461570
16471571 /**
@@ -1679,40 +1603,9 @@ public final class String · 31 unmodified lines
16791603 * if the character does not occur before that point.
16801604 */
16811605 public int lastIndexOf(int ch, int fromIndex) {
1682− if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
1683− // handle most cases here (ch is a BMP code point or a
1684− // negative value (invalid code point))
1685− final char[] value = this.value;
1686− final int offset = this.offset;
1687− int i = offset + Math.min(fromIndex, count - 1);
1688− for (; i >= offset ; i--) {
1689− if (value[i] == ch) {
1690− return i - offset;
1691− }
1692− }
1693− return -1;
1694− } else {
1695− return lastIndexOfSupplementary(ch, fromIndex);
1696− }
1697− }
1698−
1699− /**
1700− * Handles (rare) calls of lastIndexOf with a supplementary character.
1701− */
1702− private int lastIndexOfSupplementary(int ch, int fromIndex) {
1703− if (Character.isValidCodePoint(ch)) {
1704− final char[] value = this.value;
1705− final int offset = this.offset;
1706− char hi = Character.highSurrogate(ch);
1707− char lo = Character.lowSurrogate(ch);
1708− int i = offset + Math.min(fromIndex, count - 2);
1709− for (; i >= offset; i--) {
1710− if (value[i] == hi && value[i+1] == lo) {
1711− return i - offset;
1712− }
1713− }
1714− }
1715− return -1;
1606+ // [Inferno] <
1607+ return rindex(ch, fromIndex, false);
1608+ // [Inferno] >
17161609 }
17171610
17181611 /**
@@ -1730,7 +1623,9 @@ public final class String · 11 unmodified lines
17301623 * or {@code -1} if there is no such occurrence.
17311624 */
17321625 public int indexOf(String str) {
1733− return indexOf(str, 0);
1626+ // [Inferno] <
1627+ return index(str, 0);
1628+ // [Inferno] >
17341629 }
17351630
17361631 /**
@@ -1750,8 +1645,9 @@ public final class String · 13 unmodified lines
17501645 * or {@code -1} if there is no such occurrence.
17511646 */
17521647 public int indexOf(String str, int fromIndex) {
1753− return indexOf(value, offset, count,
1754− str.value, str.offset, str.count, fromIndex);
1648+ // [Inferno] <
1649+ return index(str, fromIndex);
1650+ // [Inferno] >
17551651 }
17561652
17571653 /**
@@ -1821,7 +1717,9 @@ public final class String · 63 unmodified lines
18211717 * or {@code -1} if there is no such occurrence.
18221718 */
18231719 public int lastIndexOf(String str) {
1824− return lastIndexOf(str, count);
1720+ // [Inferno] <
1721+ return rindex(str, 0, true);
1722+ // [Inferno] >
18251723 }
18261724
18271725 /**
@@ -1841,8 +1739,9 @@ public final class String · 13 unmodified lines
18411739 * or {@code -1} if there is no such occurrence.
18421740 */
18431741 public int lastIndexOf(String str, int fromIndex) {
1844− return lastIndexOf(value, offset, count,
1845− str.value, str.offset, str.count, fromIndex);
1742+ // [Inferno] <
1743+ return rindex(str, fromIndex, false);
1744+ // [Inferno] >
18461745 }
18471746
18481747 /**
@@ -1922,7 +1821,7 @@ public final class String · 73 unmodified lines
19221821 * length of this <code>String</code> object.
19231822 */
19241823 public String substring(int beginIndex) {
1925− return substring(beginIndex, count);
1824+ return substring(beginIndex, length());
19261825 }
19271826
19281827 /**
@@ -1947,19 +1846,9 @@ public final class String · 18 unmodified lines
19471846 * <code>beginIndex</code> is larger than
19481847 * <code>endIndex</code>.
19491848 */
1950− public String substring(int beginIndex, int endIndex) {
1951− if (beginIndex < 0) {
1952− throw new StringIndexOutOfBoundsException(beginIndex);
1953− }
1954− if (endIndex > count) {
1955− throw new StringIndexOutOfBoundsException(endIndex);
1956− }
1957− if (beginIndex > endIndex) {
1958− throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
1959− }
1960− return ((beginIndex == 0) && (endIndex == count)) ? this :
1961− new String(offset + beginIndex, endIndex - beginIndex, value);
1962− }
1849+ // [Inferno] <
1850+ public native String substring(int beginIndex, int endIndex);
1851+ // [Inferno] >
19631852
19641853 /**
19651854 * Returns a new character sequence that is a subsequence of this sequence.
@@ -2018,6 +1907,7 @@ public final class String · 52 unmodified lines
20181907 if (otherLen == 0) {
20191908 return this;
20201909 }
1910+ int count = length();
20211911 char buf[] = new char[count + otherLen];
20221912 getChars(0, count, buf, 0);
20231913 str.getChars(0, otherLen, buf, count);
@@ -2055,28 +1945,29 @@ public final class String · 31 unmodified lines
20551945 */
20561946 public String replace(char oldChar, char newChar) {
20571947 if (oldChar != newChar) {
2058− int len = count;
1948+ // [Inferno] <
20591949 int i = -1;
2060− char[] val = value; /* avoid getfield opcode */
2061− int off = offset; /* avoid getfield opcode */
1950+ int len = length();
1951+ char[] val = toCharArray();
20621952
20631953 while (++i < len) {
2064− if (val[off + i] == oldChar) {
1954+ if (val[i] == oldChar) {
20651955 break;
20661956 }
20671957 }
20681958 if (i < len) {
20691959 char buf[] = new char[len];
20701960 for (int j = 0 ; j < i ; j++) {
2071− buf[j] = val[off+j];
1961+ buf[j] = val[j];
20721962 }
20731963 while (i < len) {
2074− char c = val[off + i];
1964+ char c = val[i];
20751965 buf[i] = (c == oldChar) ? newChar : c;
20761966 i++;
20771967 }
20781968 return new String(0, len, buf);
20791969 }
1970+ // [Inferno] >
20801971 }
20811972 return this;
20821973 }
@@ -2317,7 +2208,9 @@ public final class String · 234 unmodified lines
23172208 the second is not the ascii digit or ascii letter.
23182209 */
23192210 char ch = 0;
2320− if (((regex.count == 1 &&
2211+ // [Inferno] <
2212+ int count = length();
2213+ if (((regex.length() == 1 &&
23212214 ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
23222215 (regex.length() == 2 &&
23232216 regex.charAt(0) == '\\' &&
@@ -2359,6 +2252,7 @@ public final class String · 35 unmodified lines
23592252 return list.subList(0, resultSize).toArray(result);
23602253 }
23612254 return Pattern.compile(regex).split(this, limit);
2255+ // [Inferno] >
23622256 }
23632257
23642258 /**
@@ -2456,97 +2350,9 @@ public final class String · 91 unmodified lines
24562350 * @since 1.1
24572351 */
24582352 public String toLowerCase(Locale locale) {
2459− if (locale == null) {
2460− throw new NullPointerException();
2461− }
2462−
2463− int firstUpper;
2464−
2465− /* Now check if there are any characters that need to be changed. */
2466− scan: {
2467− for (firstUpper = 0 ; firstUpper < count; ) {
2468− char c = value[offset+firstUpper];
2469− if ((c >= Character.MIN_HIGH_SURROGATE) &&
2470− (c <= Character.MAX_HIGH_SURROGATE)) {
2471− int supplChar = codePointAt(firstUpper);
2472− if (supplChar != Character.toLowerCase(supplChar)) {
2473− break scan;
2474− }
2475− firstUpper += Character.charCount(supplChar);
2476− } else {
2477− if (c != Character.toLowerCase(c)) {
2478− break scan;
2479− }
2480− firstUpper++;
2481− }
2482− }
2483− return this;
2484− }
2485−
2486− char[] result = new char[count];
2487− int resultOffset = 0; /* result may grow, so i+resultOffset
2488− * is the write location in result */
2489−
2490− /* Just copy the first few lowerCase characters. */
2491− System.arraycopy(value, offset, result, 0, firstUpper);
2492−
2493− String lang = locale.getLanguage();
2494− boolean localeDependent =
2495− (lang == "tr" || lang == "az" || lang == "lt");
2496− char[] lowerCharArray;
2497− int lowerChar;
2498− int srcChar;
2499− int srcCount;
2500− for (int i = firstUpper; i < count; i += srcCount) {
2501− srcChar = (int)value[offset+i];
2502− if ((char)srcChar >= Character.MIN_HIGH_SURROGATE &&
2503− (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
2504− srcChar = codePointAt(i);
2505− srcCount = Character.charCount(srcChar);
2506− } else {
2507− srcCount = 1;
2508− }
2509− if (localeDependent || srcChar == '\u03A3') { // GREEK CAPITAL LETTER SIGMA
2510− lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
2511− } else if (srcChar == '\u0130') { // LATIN CAPITAL LETTER I DOT
2512− lowerChar = Character.ERROR;
2513− } else {
2514− lowerChar = Character.toLowerCase(srcChar);
2515− }
2516− if ((lowerChar == Character.ERROR) ||
2517− (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
2518− if (lowerChar == Character.ERROR) {
2519− if (!localeDependent && srcChar == '\u0130') {
2520− lowerCharArray =
2521− ConditionalSpecialCasing.toLowerCaseCharArray(this, i, Locale.ENGLISH);
2522− } else {
2523− lowerCharArray =
2524− ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
2525− }
2526− } else if (srcCount == 2) {
2527− resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount;
2528− continue;
2529− } else {
2530− lowerCharArray = Character.toChars(lowerChar);
2531− }
2532−
2533− /* Grow result if needed */
2534− int mapLen = lowerCharArray.length;
2535− if (mapLen > srcCount) {
2536− char[] result2 = new char[result.length + mapLen - srcCount];
2537− System.arraycopy(result, 0, result2, 0,
2538− i + resultOffset);
2539− result = result2;
2540− }
2541− for (int x=0; x<mapLen; ++x) {
2542− result[i+resultOffset+x] = lowerCharArray[x];
2543− }
2544− resultOffset += (mapLen - srcCount);
2545− } else {
2546− result[i+resultOffset] = (char)lowerChar;
2547− }
2548− }
2549− return new String(0, count+resultOffset, result);
2353+ // [Inferno] <
2354+ return lowercase();
2355+ // [Inferno] >
25502356 }
25512357
25522358 /**
@@ -2569,7 +2375,7 @@ public final class String · 16 unmodified lines
25692375 * @see java.lang.String#toLowerCase(Locale)
25702376 */
25712377 public String toLowerCase() {
2572− return toLowerCase(Locale.getDefault());
2378+ return lowercase();
25732379 }
25742380
25752381 /**
@@ -2621,95 +2427,9 @@ public final class String · 45 unmodified lines
26212427 * @since 1.1
26222428 */
26232429 public String toUpperCase(Locale locale) {
2624− if (locale == null) {
2625− throw new NullPointerException();
2626− }
2627−
2628− int firstLower;
2629−
2630− /* Now check if there are any characters that need to be changed. */
2631− scan: {
2632− for (firstLower = 0 ; firstLower < count; ) {
2633− int c = (int)value[offset+firstLower];
2634− int srcCount;
2635− if ((c >= Character.MIN_HIGH_SURROGATE) &&
2636− (c <= Character.MAX_HIGH_SURROGATE)) {
2637− c = codePointAt(firstLower);
2638− srcCount = Character.charCount(c);
2639− } else {
2640− srcCount = 1;
2641− }
2642− int upperCaseChar = Character.toUpperCaseEx(c);
2643− if ((upperCaseChar == Character.ERROR) ||
2644− (c != upperCaseChar)) {
2645− break scan;
2646− }
2647− firstLower += srcCount;
2648− }
2649− return this;
2650− }
2651−
2652− char[] result = new char[count]; /* may grow */
2653− int resultOffset = 0; /* result may grow, so i+resultOffset
2654− * is the write location in result */
2655−
2656− /* Just copy the first few upperCase characters. */
2657− System.arraycopy(value, offset, result, 0, firstLower);
2658−
2659− String lang = locale.getLanguage();
2660− boolean localeDependent =
2661− (lang == "tr" || lang == "az" || lang == "lt");
2662− char[] upperCharArray;
2663− int upperChar;
2664− int srcChar;
2665− int srcCount;
2666− for (int i = firstLower; i < count; i += srcCount) {
2667− srcChar = (int)value[offset+i];
2668− if ((char)srcChar >= Character.MIN_HIGH_SURROGATE &&
2669− (char)srcChar <= Character.MAX_HIGH_SURROGATE) {
2670− srcChar = codePointAt(i);
2671− srcCount = Character.charCount(srcChar);
2672− } else {
2673− srcCount = 1;
2674− }
2675− if (localeDependent) {
2676− upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
2677− } else {
2678− upperChar = Character.toUpperCaseEx(srcChar);
2679− }
2680− if ((upperChar == Character.ERROR) ||
2681− (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
2682− if (upperChar == Character.ERROR) {
2683− if (localeDependent) {
2684− upperCharArray =
2685− ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
2686− } else {
2687− upperCharArray = Character.toUpperCaseCharArray(srcChar);
2688− }
2689− } else if (srcCount == 2) {
2690− resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount;
2691− continue;
2692− } else {
2693− upperCharArray = Character.toChars(upperChar);
2694− }
2695−
2696− /* Grow result if needed */
2697− int mapLen = upperCharArray.length;
2698− if (mapLen > srcCount) {
2699− char[] result2 = new char[result.length + mapLen - srcCount];
2700− System.arraycopy(result, 0, result2, 0,
2701− i + resultOffset);
2702− result = result2;
2703− }
2704− for (int x=0; x<mapLen; ++x) {
2705− result[i+resultOffset+x] = upperCharArray[x];
2706− }
2707− resultOffset += (mapLen - srcCount);
2708− } else {
2709− result[i+resultOffset] = (char)upperChar;
2710− }
2711− }
2712− return new String(0, count+resultOffset, result);
2430+ // [Inferno] <
2431+ return uppercase();
2432+ // [Inferno] >
27132433 }
27142434
27152435 /**
@@ -2732,7 +2452,7 @@ public final class String · 16 unmodified lines
27322452 * @see java.lang.String#toUpperCase(Locale)
27332453 */
27342454 public String toUpperCase() {
2735− return toUpperCase(Locale.getDefault());
2455+ return uppercase();
27362456 }
27372457
27382458 /**
@@ -2767,18 +2487,19 @@ public final class String · 28 unmodified lines
27672487 * trailing white space.
27682488 */
27692489 public String trim() {
2770− int len = count;
2490+ // [Inferno] <
27712491 int st = 0;
2772− int off = offset; /* avoid getfield opcode */
2773− char[] val = value; /* avoid getfield opcode */
2492+ int len = length();
2493+ char[] val = toCharArray();
27742494
2775− while ((st < len) && (val[off + st] <= ' ')) {
2495+ while ((st < len) && (val[st] <= ' ')) {
27762496 st++;
27772497 }
2778− while ((st < len) && (val[off + len - 1] <= ' ')) {
2498+ while ((st < len) && (val[len - 1] <= ' ')) {
27792499 len--;
27802500 }
2781− return ((st > 0) || (len < count)) ? substring(st, len) : this;
2501+ return ((st > 0) || (len < length())) ? substring(st, len) : this;
2502+ // [Inferno] >
27822503 }
27832504
27842505 /**
@@ -2798,6 +2519,9 @@ public final class String · 13 unmodified lines
27982519 * the character sequence represented by this string.
27992520 */
28002521 public char[] toCharArray() {
2522+ // [Inferno] <
2523+ int count = length();
2524+ // [Inferno] >
28012525 char result[] = new char[count];
28022526 getChars(0, count, result, 0);
28032527 return result;
@@ -3074,4 +2798,20 @@ public final class String · 270 unmodified lines
30742798 */
30752799 public native String intern();
30762800
2801+ // [Inferno] Some native platform-specific methods
2802+
2803+ private native boolean equality(String other, boolean ignoreCase);
2804+
2805+ private native void fill(char[] chars, int idx, int count);
2806+ private native boolean isPrefix(String str, int index);
2807+ private native boolean isSuffix(String str);
2808+ private native String uppercase();
2809+ private native String lowercase();
2810+
2811+ private native int index(String str, int begin);
2812+ private native int index(int ch, int begin);
2813+
2814+ private native int rindex(String str, int begin, boolean fromend);
2815+ private native int rindex(int ch, int begin, boolean fromend);
2816+
30772817 }